From 34b57eb1738a9b739eb42b1e59236c4b193e9364 Mon Sep 17 00:00:00 2001 From: Mara Date: Sat, 28 Jun 2025 21:21:51 +0200 Subject: [PATCH] feat: inject the data-path into `.tree-item.nav-folder` to avoid using `:has` selector. Improve the perf on large vault --- README.md | 8 ++++---- src/compiler.ts | 43 +++++++++++++++++++++++++++++++++++++++++-- src/main.ts | 13 ++++++++++--- src/template.ts | 2 +- 4 files changed, 56 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index a47668a..30bbaa3 100644 --- a/README.md +++ b/README.md @@ -29,11 +29,10 @@ Automagically add color to roots folders, and customize them with Style Settings ## 🎨 Configuration In the plugin settings, you can customize : -- Export to a css snippets (instead of inject into the DOM) +- Export to a css snippets (instead of inject into the DOM)[^1] - Default colors (when creating new folders) -- Folder name prefix for CSS varaible -- Custom CSS templates -- Custom style settings template +- Folder name prefix for CSS variable +- Custom CSS and Style Settings templates ![settings](./docs/assets/plugin_settings.png) @@ -66,3 +65,4 @@ To add a translation: - Add `import * as from "./locales/.json";` - Edit the `ressource` part with adding : ` : {translation: }` +[^1]: Some styles can be broken while disabling the plugin, as it injects the folder path into `tree-item.nav-folder` to improve performance, instead to use `:has`. \ No newline at end of file diff --git a/src/compiler.ts b/src/compiler.ts index 0637987..c6efca8 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -16,6 +16,7 @@ import { convertStyleSettings, convertToCSS, generateName, themes } from "./temp import { formatCss, removeExtraNewLine } from "./utils"; import dedent from "dedent"; import i18next from "i18next"; +import type { DeferredView, FileExplorerView, MaybeDeferredView } from "obsidian-typings"; export class ColorCompiler { plugin: SimpleColoredFolder; @@ -135,12 +136,50 @@ export class ColorCompiler { return ""; } - async injectStyles(reload = true) { - const folders = this.app.vault + getFolder() { + return this.app.vault .getAllFolders() .filter( (folder: TFolder) => folder.parent && folder.parent === this.app.vault.getRoot() ); + } + + private getFileExplorerView() { + const navigation = this.app.workspace.getLeavesOfType("file-explorer"); + if (navigation.length === 0) return null; + return navigation[0].view; + } + + injectDataPathFromFolder(folder: TFolder, fileExplorer = this.getFileExplorerView()) { + const navigation = this.app.workspace.getLeavesOfType("file-explorer"); + if (!navigation.length) return; + if (!fileExplorer) return; + const treeItems = fileExplorer.containerEl.querySelectorAll( + `.tree-item.nav-folder > .nav-folder-title[data-path="${folder.path}"]` + ); + if (treeItems.length === 0) return; + treeItems.forEach((item) => { + const treeItem = item.closest(".tree-item.nav-folder"); + if (treeItem) treeItem.setAttribute("data-path", folder.path); + + }); + } + + + /** + * Inject the data-path into the .tree-item.nav-folder + */ + injectDataPath(folders: TFolder[] = this.getFolder()) { + const navigation = this.app.workspace.getLeavesOfType("file-explorer"); + if (!navigation.length) return; + const fileExplorer = navigation[0].view; + for (const folder of folders) { + this.injectDataPathFromFolder(folder, fileExplorer); + } + } + + async injectStyles(reload = true, folders?: TFolder[]) { + if (!folders) folders = this.getFolder(); this.style?.detach(); const exportToCSS = this.settings.exportToCSS; const style = this.createStyles(folders, !exportToCSS); diff --git a/src/main.ts b/src/main.ts index eaa2099..efbbf20 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,5 @@ import i18next from "i18next"; -import { Plugin, Notice, sanitizeHTMLToDom, normalizePath } from "obsidian"; +import { Plugin, Notice, sanitizeHTMLToDom, normalizePath, TFolder } from "obsidian"; import { resources, translationLanguage } from "./i18n"; import { DEFAULT_SETTINGS, type SimpleColoredFolderSettings } from "./interfaces"; @@ -34,11 +34,13 @@ export default class SimpleColoredFolder extends Plugin { this.registerEvent( this.app.vault.on("rename", async (file, oldPath) => { await this.compiler.renameCss(file, oldPath); + if (file instanceof TFolder && file.parent === this.app.vault.getRoot()) + this.compiler.injectDataPathFromFolder(file); }) ); this.registerEvent( - this.app.vault.on("delete", async (file) => { + this.app.vault.on("delete", async () => { await this.compiler.injectStyles(); }) ); @@ -52,9 +54,14 @@ export default class SimpleColoredFolder extends Plugin { ) ); } - await this.compiler.injectStyles(true); + const folders = this.compiler.getFolder(); + this.compiler.injectDataPath(folders); + await this.compiler.injectStyles(true, folders); this.app.vault.on("create", async (file) => { await this.compiler.injectToRoot(file); + if (file instanceof TFolder && file.parent === this.app.vault.getRoot()) { + await this.compiler.injectDataPathFromFolder(file); + } }); }); } diff --git a/src/template.ts b/src/template.ts index 8e48783..8d2a5b8 100644 --- a/src/template.ts +++ b/src/template.ts @@ -32,7 +32,7 @@ export function convertToCSS(folderName: string, prefix: Prefix, template: strin color: var(${variableNames.color}) !important; } - .tree-item.nav-folder:has([data-path="${folderName}"]) { + .tree-item.nav-folder[data-path="${folderName}"] { background-color: var(${variableNames.bg}) !important; border-radius: var(--spf-FolderRadius); }