mirror of
https://github.com/mara-li/obsidian-simple-colored-folder.git
synced 2026-07-22 05:46:20 +00:00
feat: add more styles in the exported file in snippets
This commit is contained in:
parent
7e0d61dcd0
commit
d4ce4ee361
10 changed files with 156 additions and 71 deletions
Binary file not shown.
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 135 KiB |
|
|
@ -5,14 +5,15 @@ import {
|
|||
type PluginManifest,
|
||||
type TAbstractFile,
|
||||
} from "obsidian";
|
||||
import type {
|
||||
Prefix,
|
||||
SimpleColoredFolderSettings,
|
||||
StyleSettingValue,
|
||||
import {
|
||||
type Prefix,
|
||||
type SimpleColoredFolderSettings,
|
||||
STYLE_SPLIT,
|
||||
type StyleSettingValue,
|
||||
} from "./interfaces";
|
||||
import type SimpleColoredFolder from "./main";
|
||||
import { convertStyleSettings, convertToCSS, generateName, themes } from "./template";
|
||||
import { minifyCss, removeExtraNewLine } from "./utils";
|
||||
import { formatCss, removeExtraNewLine } from "./utils";
|
||||
import dedent from "dedent";
|
||||
import i18next from "i18next";
|
||||
|
||||
|
|
@ -39,27 +40,37 @@ export class ColorCompiler {
|
|||
id: ${this.manifest.id}
|
||||
settings:
|
||||
-
|
||||
id: FolderRadius
|
||||
type: variable-number-slider
|
||||
id: spf-FolderRadius
|
||||
type: variable-number
|
||||
title: ${i18next.t("common.radius")}
|
||||
description: "Format: px"
|
||||
default: 5
|
||||
min: 0
|
||||
max: 20
|
||||
step: 1
|
||||
format: px
|
||||
-
|
||||
id: space-between
|
||||
type: variable-number-slider
|
||||
id: spf-space-between
|
||||
type: variable-number
|
||||
default: 0.3
|
||||
max: 5
|
||||
step: 0.1
|
||||
min: 0
|
||||
format: em
|
||||
description: "Format: em"
|
||||
title: ${i18next.t("common.space")}
|
||||
-
|
||||
id: spf-saturate
|
||||
type: variable-number
|
||||
default: 500
|
||||
title: ${i18next.t("common.saturate")}
|
||||
format: "%"
|
||||
description: "Format: %"
|
||||
-
|
||||
id: spf-saturate-hover
|
||||
default: 150
|
||||
type: variable-number
|
||||
format: "%"
|
||||
title: ${i18next.t("common.saturateHover")}
|
||||
description: "Format: %"
|
||||
-`);
|
||||
}
|
||||
|
||||
createStyles(folders: TFolder[]) {
|
||||
createStyles(folders: TFolder[], minify?: boolean) {
|
||||
let darkTheme = `.theme-dark {`;
|
||||
let lightTheme = `.theme-light {`;
|
||||
let css = "";
|
||||
|
|
@ -80,7 +91,7 @@ export class ColorCompiler {
|
|||
darkTheme += "}";
|
||||
lightTheme += "}";
|
||||
stylesSettings = `${stylesSettings.replace(/-+$/, "").trimEnd()}\n*/`;
|
||||
return `\n${removeExtraNewLine(stylesSettings)}\n${minifyCss(darkTheme)}\n${minifyCss(lightTheme)}\n${minifyCss(css)}`;
|
||||
return `\n${removeExtraNewLine(stylesSettings)}\n${formatCss(darkTheme, minify)}\n${formatCss(lightTheme, minify)}\n${formatCss(css, minify)}`;
|
||||
}
|
||||
|
||||
async injectToBody(content: string) {
|
||||
|
|
@ -94,18 +105,38 @@ export class ColorCompiler {
|
|||
}
|
||||
|
||||
async injectToSnippets(content: string) {
|
||||
const obsidianDir = normalizePath(`${this.app.vault.configDir}/snippets`);
|
||||
if (!(await this.app.vault.adapter.exists(obsidianDir))) {
|
||||
const snippetsDir = normalizePath(`${this.app.vault.configDir}/snippets`);
|
||||
if (!(await this.app.vault.adapter.exists(snippetsDir))) {
|
||||
//create
|
||||
console.log("Creating snippets directory");
|
||||
await this.app.vault.adapter.mkdir(obsidianDir);
|
||||
console.warn("Creating snippets directory");
|
||||
await this.app.vault.adapter.mkdir(snippetsDir);
|
||||
}
|
||||
const rules = `/* This file is generated by Simple Colored Folder. Do not edit it manually */\n${content}`;
|
||||
let rules = `/* This file is generated by Simple Colored Folder. Do not edit it manually */`;
|
||||
if (this.settings.includeStyleInExport)
|
||||
rules += await this.injectPluginStyles();
|
||||
|
||||
rules += `\n${content}\n`;
|
||||
await this.app.vault.adapter.write(this.snippetPath, rules);
|
||||
//enable the snippet
|
||||
this.app.customCss.setCssEnabledStatus("generated.colored-folder", true);
|
||||
}
|
||||
|
||||
private async injectPluginStyles() {
|
||||
const pluginDir = normalizePath(
|
||||
`${this.app.vault.configDir}/plugins/${this.manifest.id}`
|
||||
);
|
||||
const stylesPath = normalizePath(`${pluginDir}/styles.css`);
|
||||
if (await this.app.vault.adapter.exists(stylesPath)) {
|
||||
const styles = (await this.app.vault.adapter.read(stylesPath))
|
||||
.split(STYLE_SPLIT)
|
||||
.filter((x) => x.length > 0)[0];
|
||||
return `\n\n/* ---- */\n${styles}`;
|
||||
} else
|
||||
console.error("The plugin folder doesn't exists.");
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
async injectStyles(reload = true) {
|
||||
const folders = this.app.vault
|
||||
.getAllFolders()
|
||||
|
|
@ -113,8 +144,9 @@ export class ColorCompiler {
|
|||
(folder: TFolder) => folder.parent && folder.parent === this.app.vault.getRoot()
|
||||
);
|
||||
this.style?.detach();
|
||||
const style = this.createStyles(folders);
|
||||
if (this.settings.exportToCSS) await this.injectToSnippets(style);
|
||||
const exportToCSS = this.settings.exportToCSS;
|
||||
const style = this.createStyles(folders, !exportToCSS);
|
||||
if (exportToCSS) await this.injectToSnippets(style);
|
||||
else await this.injectToBody(style);
|
||||
if (reload) this.reload();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,19 +4,27 @@
|
|||
"color": "Text color",
|
||||
"folderName": "FolderName",
|
||||
"radius": "Folder radius",
|
||||
"saturate": "Saturation while being dragged",
|
||||
"saturateHover": "Saturation during hover",
|
||||
"space": "Space between folder",
|
||||
"warning": "Warning"
|
||||
},
|
||||
"notEnabled": "Style Settings is not installed or enabled. Please, activate it before using this plugin.",
|
||||
"prefix": {
|
||||
"settings": {
|
||||
"generation": "The variable will be generated as follow:"
|
||||
}
|
||||
},
|
||||
"reload": "It is possible that you need to reload Obsidian to make it works.",
|
||||
"settings": {
|
||||
"customCss": {
|
||||
"desc": "Custom CSS template to generate a style from folders. Please use the following variables:",
|
||||
"title": "Custom CSS"
|
||||
},
|
||||
"export": {
|
||||
"desc": "Add the plugin style into the exported style snippets.",
|
||||
"title": "Export plugin style"
|
||||
},
|
||||
"prefix": {
|
||||
"desc": "Prefix for variable generation. This will allow Style Settings to works, but you can edit them also in a CSS snippets.",
|
||||
"folderName": "where folder name will be standardized (removing all points, space and set to lowercase).",
|
||||
|
|
@ -37,4 +45,4 @@
|
|||
"warning": "This will reset your Style Settings! "
|
||||
},
|
||||
"warning": "Please enable 'Style Settings' plugin"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,19 +4,27 @@
|
|||
"color": "Couleur du texte",
|
||||
"folderName": "NomDossier",
|
||||
"radius": "Radius du dossier",
|
||||
"saturate": "Saturation durant le déplacement",
|
||||
"saturateHover": "Saturation durant la sélection",
|
||||
"space": "Espace entre les dossiers",
|
||||
"warning": "Attention"
|
||||
},
|
||||
"notEnabled": "Style Settings n'est pas installé ou activé. Merci de l'activer avant d'utiliser ce plugin.",
|
||||
"prefix": {
|
||||
"settings": {
|
||||
"generation": "Les variables seront générées tel que :"
|
||||
}
|
||||
},
|
||||
"reload": "Il est possible que vous ayez besoin de recharger Obsidian pour que cela fonctionne.",
|
||||
"settings": {
|
||||
"customCss": {
|
||||
"desc": "Modèle CSS personnalisé qui sera utilisé pour générer un CSS depuis les dossiers. Merci d'utiliser les variables suivantes : ",
|
||||
"title": "CSS personnalisé"
|
||||
},
|
||||
"export": {
|
||||
"desc": "Ajouter les styles du plugin dans le fichier exporté.",
|
||||
"title": "Exporter le style du plugin"
|
||||
},
|
||||
"prefix": {
|
||||
"desc": "Préfixe pour la génération de variable. Cela permettra au plugin \"Style settings\" de fonctionner, mais vous pourrez aussi les utiliser dans un snippet css.",
|
||||
"folderName": "où le nom du dossier sera normalisé (en supprimant tous les points, les espaces et en mettant le nom en minuscules).",
|
||||
|
|
@ -37,4 +45,4 @@
|
|||
"warning": "Cela aura pour conséquence de réinitialiser vos paramètres Style Settings ! "
|
||||
},
|
||||
"warning": "Merci d'activer le module \"Style Settings\"."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,11 @@ export interface SimpleColoredFolderSettings {
|
|||
customStyleSettings: string;
|
||||
exportToCSS: boolean;
|
||||
defaultColors: Colors;
|
||||
/**
|
||||
* Allow to includes some other style in the export to CSS file
|
||||
* See the first part of the style.css file for more information.
|
||||
*/
|
||||
includeStyleInExport: boolean;
|
||||
}
|
||||
|
||||
export type ThemedColors = {
|
||||
|
|
@ -42,6 +47,9 @@ export const DEFAULT_SETTINGS: SimpleColoredFolderSettings = {
|
|||
customStyleSettings: "",
|
||||
exportToCSS: false,
|
||||
defaultColors: DEFAULT_COLORS,
|
||||
includeStyleInExport: false,
|
||||
};
|
||||
|
||||
export type StyleSettingValue = number | string | boolean;
|
||||
|
||||
export const STYLE_SPLIT = "/** ---- **/";
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ export default class SimpleColoredFolder extends Plugin {
|
|||
}
|
||||
|
||||
await this.compiler.injectStyles();
|
||||
this.app.workspace.trigger("parse-style-settings");
|
||||
this.addSettingTab(new SimpleColoredFolderSettingTab(this.app, this));
|
||||
|
||||
this.app.vault.on("rename", async (file, oldPath) => {
|
||||
|
|
@ -60,7 +59,6 @@ export default class SimpleColoredFolder extends Plugin {
|
|||
this.compiler.style?.detach();
|
||||
this.compiler.style?.remove();
|
||||
this.app.workspace.trigger("css-change");
|
||||
this.app.workspace.trigger("parse-style-settings");
|
||||
}
|
||||
async loadSettings() {
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import { type App, PluginSettingTab, sanitizeHTMLToDom, Setting } from "obsidian";
|
||||
import { type App, MarkdownRenderer, PluginSettingTab, sanitizeHTMLToDom, Setting } from "obsidian";
|
||||
import type SimpleColoredFolder from "./main";
|
||||
import i18next from "i18next";
|
||||
import type { ColorCompiler } from "./compiler";
|
||||
import type { SimpleColoredFolderSettings } from "./interfaces";
|
||||
import { PickerSettingsComponent } from "./color-picker";
|
||||
import dedent from "dedent";
|
||||
|
||||
export class SimpleColoredFolderSettingTab extends PluginSettingTab {
|
||||
plugin: SimpleColoredFolder;
|
||||
|
|
@ -17,8 +18,19 @@ export class SimpleColoredFolderSettingTab extends PluginSettingTab {
|
|||
this.compiler = plugin.compiler;
|
||||
}
|
||||
|
||||
display(): void {
|
||||
async display() {
|
||||
const { containerEl } = this;
|
||||
|
||||
containerEl.empty();
|
||||
if (!this.app.plugins.enabledPlugins.has("obsidian-style-settings")) {
|
||||
await MarkdownRenderer.render(this.app, dedent`> [!warning]
|
||||
> ${i18next.t("notEnabled")}
|
||||
>
|
||||
> ${i18next.t("reload")}
|
||||
`, this.containerEl, "", this.plugin);
|
||||
return;
|
||||
}
|
||||
|
||||
this.containerEl.addClass(`spf`);
|
||||
|
||||
containerEl.empty();
|
||||
|
|
@ -31,8 +43,22 @@ export class SimpleColoredFolderSettingTab extends PluginSettingTab {
|
|||
this.settings.exportToCSS = value;
|
||||
await this.plugin.saveSettings();
|
||||
await this.compiler.injectStyles();
|
||||
this.display();
|
||||
})
|
||||
);
|
||||
if (this.settings.exportToCSS) {
|
||||
new Setting(containerEl)
|
||||
.setName(i18next.t("settings.export.title"))
|
||||
.setDesc(i18next.t("settings.export.desc"))
|
||||
.setClass("no-border")
|
||||
.addToggle((cb) =>
|
||||
cb.setValue(this.settings.includeStyleInExport).onChange(async (value) => {
|
||||
this.settings.includeStyleInExport = value;
|
||||
await this.plugin.saveSettings();
|
||||
await this.compiler.injectStyles();
|
||||
})
|
||||
);
|
||||
}
|
||||
this.containerEl.createEl("hr");
|
||||
new Setting(containerEl).setName("Default color").setClass("no-border").setHeading();
|
||||
|
||||
|
|
@ -61,12 +87,12 @@ export class SimpleColoredFolderSettingTab extends PluginSettingTab {
|
|||
this.containerEl.createEl("hr");
|
||||
new Setting(containerEl).setName(i18next.t("settings.prefix.title")).setHeading();
|
||||
|
||||
this.containerEl.appendChild(
|
||||
sanitizeHTMLToDom(`${i18next.t("settings.prefix.desc")}<br>${i18next.t("prefix.settings.generation")} <code>prefix.[${i18next.t("common.folderName")}]</code> ${i18next.t("settings.prefix.folderName")}
|
||||
<div data-callout-metadata="" data-callout-fold="" data-callout="warning" class="callout"><div class="callout-title" dir="auto"><div class="callout-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-alert-triangle"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"></path><path d="M12 9v4"></path><path d="M12 17h.01"></path></svg></div><div class="callout-title-inner">${i18next.t("common.warning")}</div></div><div class="callout-content">
|
||||
<p dir="auto">${i18next.t("settings.warning")}</p>
|
||||
</div></div>`)
|
||||
);
|
||||
await MarkdownRenderer.render(this.app, dedent`
|
||||
${i18next.t("settings.prefix.desc")}
|
||||
${i18next.t("prefix.settings.generation")} « \`prefix.${i18next.t("common.folderName")}\` » ${i18next.t("settings.prefix.folderName")}
|
||||
> [!warning] ${i18next.t("common.warning")}
|
||||
> ${i18next.t("settings.warning")}
|
||||
`, this.containerEl, "", this.plugin);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(i18next.t("common.color"))
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
/** ---- **/
|
||||
:root {
|
||||
--FolderRadius: 5px;
|
||||
--space-between: 1px;
|
||||
--spf-FolderRadius: 5px;
|
||||
--spf-space-between: 1px;
|
||||
--spf-saturate-dragging: 500%;
|
||||
--spaf-saturate-hover: 150%;
|
||||
}
|
||||
|
||||
.nav-file-title,
|
||||
|
|
@ -29,59 +32,49 @@ body:not(.is-grabbing) .nav-folder-title:hover .nav-folder-collapse-indicator {
|
|||
.nav-folder-title.is-being-dragged-over {
|
||||
background-color: transparent !important;
|
||||
color: currentColor !important;
|
||||
filter: saturate(500%) !important;
|
||||
filter: saturate(var(--spf-saturate-dragging)) !important;
|
||||
}
|
||||
|
||||
.nav-files-container.node-insert-event
|
||||
> div
|
||||
> .tree-item.nav-folder
|
||||
> .tree-item-self.nav-folder-title {
|
||||
.nav-files-container.node-insert-event>div>.tree-item.nav-folder>.tree-item-self.nav-folder-title {
|
||||
margin-top: 5px !important;
|
||||
}
|
||||
|
||||
.nav-files-container.node-insert-event
|
||||
> div
|
||||
> .tree-item.nav-folder
|
||||
> .tree-item-self.nav-folder-title {
|
||||
.nav-files-container.node-insert-event>div>.tree-item.nav-folder>.tree-item-self.nav-folder-title {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/*& Set up explorer container margins */
|
||||
|
||||
.nav-files-container {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.nav-folder.mod-root > .nav-folder-children > .nav-folder > .nav-folder-title {
|
||||
.nav-folder.mod-root>.nav-folder-children>.nav-folder>.nav-folder-title {
|
||||
padding-left: 5px;
|
||||
margin-top: 7px;
|
||||
/* space between top level sections */
|
||||
border-radius: var(--FolderRadius) var(--FolderRadius) 0 0;
|
||||
border-radius: var(--spf-FolderRadius) var(--spf-FolderRadius) 0 0;
|
||||
}
|
||||
|
||||
.nav-folder.mod-root
|
||||
> .nav-folder-children
|
||||
> .nav-folder.is-collapsed
|
||||
> .nav-folder-title {
|
||||
border-radius: var(--FolderRadius);
|
||||
.nav-folder.mod-root>.nav-folder-children>.nav-folder.is-collapsed>.nav-folder-title {
|
||||
border-radius: var(--spf-FolderRadius);
|
||||
}
|
||||
|
||||
.nav-folder.mod-root > .nav-folder-children > .nav-folder > .nav-folder-children {
|
||||
.nav-folder.mod-root>.nav-folder-children>.nav-folder>.nav-folder-children {
|
||||
padding-left: 0;
|
||||
border-radius: 0 0 var(--FolderRadius) var(--FolderRadius);
|
||||
border-radius: 0 0 var(--spf-FolderRadius) var(--spf-FolderRadius);
|
||||
}
|
||||
|
||||
.nav-file-title[class*="is-active"],
|
||||
.nav-file-title:hover,
|
||||
body:not(.is-grabbing) .nav-folder-title:hover {
|
||||
border-radius: var(--FolderRadius);
|
||||
border-radius: var(--spf-FolderRadius);
|
||||
}
|
||||
|
||||
.nav-files-container > div > .tree-item.nav-folder:not(.mod-root) {
|
||||
margin-bottom: var(--space-between) !important;
|
||||
.nav-files-container>div>.tree-item.nav-folder:not(.mod-root) {
|
||||
margin-bottom: var(--spf-space-between) !important;
|
||||
}
|
||||
|
||||
/** ---- Settings ---- **/
|
||||
/** ---- **/
|
||||
/* ---- Settings ---- */
|
||||
|
||||
.spf textarea {
|
||||
width: 100%;
|
||||
|
|
@ -109,14 +102,14 @@ body:not(.is-grabbing) .nav-folder-title:hover {
|
|||
--hr-thickness: 1px;
|
||||
}
|
||||
|
||||
/* Aligne le composant avec les autres settings */
|
||||
/* Settings alignments */
|
||||
.spf .picker-settings-component .setting-item-control {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* Le wrapper des deux pickers */
|
||||
/* Picker wrapper */
|
||||
.spf .dual-alpha-picker-controls {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
|
|
@ -129,7 +122,7 @@ body:not(.is-grabbing) .nav-folder-title:hover {
|
|||
position: relative;
|
||||
}
|
||||
|
||||
/* Conteneur individuel d’un picker + bouton reset */
|
||||
/* Picker + reset button */
|
||||
.spf .alpha-picker-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -148,7 +141,7 @@ body:not(.is-grabbing) .nav-folder-title:hover {
|
|||
background-color: #1e1e1e;
|
||||
}
|
||||
|
||||
/* Boutons de reset (↺) */
|
||||
/* Reset button */
|
||||
.spf .alpha-picker-wrapper .clickable-icon {
|
||||
font-size: 14px;
|
||||
opacity: 0.6;
|
||||
|
|
@ -162,4 +155,4 @@ body:not(.is-grabbing) .nav-folder-title:hover {
|
|||
.spf .setting-item .pickr .pcr-button:after,
|
||||
.spf .setting-item .pickr .pcr-button:before {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ export function convertToCSS(folderName: string, prefix: Prefix, template: strin
|
|||
|
||||
.tree-item.nav-folder:has([data-path="${folderName}"]) {
|
||||
background-color: var(${variableNames.bg}) !important;
|
||||
border-radius: var(--FolderRadius);
|
||||
border-radius: var(--spf-FolderRadius);
|
||||
}
|
||||
|
||||
.nav-file-title[class*="is-active"][data-path^="${folderName}"],
|
||||
|
|
@ -43,7 +43,7 @@ export function convertToCSS(folderName: string, prefix: Prefix, template: strin
|
|||
.nav-folder-title[class*="is-active"][data-path^="${folderName}"] {
|
||||
color: var(${variableNames.color}) !important;
|
||||
background-color: var(${variableNames.bg}) !important;
|
||||
filter: saturate(150%);
|
||||
filter: saturate(var(--spf-saturate-hover));
|
||||
}
|
||||
|
||||
${dedent(remplaceTemplate(template, folderName, variableNames.bg, variableNames.color))}
|
||||
|
|
|
|||
16
src/utils.ts
16
src/utils.ts
|
|
@ -1,8 +1,20 @@
|
|||
export function minifyCss(css: string): string {
|
||||
export function formatCss(css: string, minify?: boolean): string {
|
||||
const styleSheet = new CSSStyleSheet();
|
||||
styleSheet.replaceSync(css);
|
||||
return [...styleSheet.cssRules].map((rule) => rule.cssText).join("");
|
||||
const formattedCss = [...styleSheet.cssRules].map((rule) => {
|
||||
if (!minify) {
|
||||
return rule.cssText
|
||||
.replaceAll("{", "{\n ")
|
||||
.replaceAll(";", ";\n ")
|
||||
.replace(/\n\s*}/g, "\n}")
|
||||
.replace(/\s*,/g, ",\n")
|
||||
.replace(/ \./g, ".")
|
||||
}
|
||||
return rule.cssText
|
||||
}).join(minify ? "" : "\n");
|
||||
return formattedCss;
|
||||
}
|
||||
|
||||
export function standardize(str: string) {
|
||||
return str
|
||||
.standardize()
|
||||
|
|
|
|||
Loading…
Reference in a new issue