From 2b460be63a94b8ebd224fe63c376d8ca2ac65abb Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sat, 18 Oct 2025 21:05:34 +0300 Subject: [PATCH 01/14] client/note tree: adjust the custom color of tree items to maintain readability --- apps/client/src/services/css_class_manager.ts | 53 +++++++++++++++++-- apps/client/src/stylesheets/theme-dark.css | 4 ++ apps/client/src/stylesheets/theme-light.css | 4 ++ .../src/stylesheets/theme-next-dark.css | 6 ++- .../src/stylesheets/theme-next/base.css | 14 +++++ .../src/stylesheets/theme-next/shell.css | 2 +- apps/client/src/stylesheets/tree.css | 1 + apps/client/src/utils/css-var.ts | 45 ++++++++++++++++ apps/server/package.json | 1 + pnpm-lock.yaml | 34 +++++++++--- 10 files changed, 151 insertions(+), 13 deletions(-) create mode 100644 apps/client/src/utils/css-var.ts diff --git a/apps/client/src/services/css_class_manager.ts b/apps/client/src/services/css_class_manager.ts index f5d2e9649..6c26b5dcb 100644 --- a/apps/client/src/services/css_class_manager.ts +++ b/apps/client/src/services/css_class_manager.ts @@ -1,5 +1,20 @@ +import {readCssVar} from "../utils/css-var"; +import Color, { ColorInstance } from "color"; + const registeredClasses = new Set(); +// Read the color lightness limits defined in the theme as CSS variables + +const lightThemeColorMaxLightness = readCssVar( + document.documentElement, + "tree-item-light-theme-max-color-lightness" + ).asNumber(70); + +const darkThemeColorMinLightness = readCssVar( + document.documentElement, + "tree-item-dark-theme-min-color-lightness" + ).asNumber(50); + function createClassForColor(color: string | null) { if (!color?.trim()) { return ""; @@ -13,9 +28,16 @@ function createClassForColor(color: string | null) { const className = `color-${normalizedColorName}`; + const adjustedColor = adjustColorLightness(color, lightThemeColorMaxLightness!, darkThemeColorMinLightness!); + if (!adjustedColor) return ""; + if (!registeredClasses.has(className)) { - // make the active fancytree selector more specific than the normal color setting - $("head").append(``); + $("head").append(``); registeredClasses.add(className); } @@ -23,6 +45,31 @@ function createClassForColor(color: string | null) { return className; } +/** + * Returns a pair of colors — one optimized for light themes and the other for dark themes, derived + * from the specified color to maintain sufficient contrast with each theme. + * The adjustment is performed by limiting the color’s lightness in the CIELAB color space, + * according to the lightThemeMaxLightness and darkThemeMinLightness parameters. + */ +function adjustColorLightness(color: string, lightThemeMaxLightness: number, darkThemeMinLightness: number) { + let labColor: ColorInstance | undefined = undefined; + + try { + // Parse the given color in the CIELAB color space + labColor = Color(color).lab(); + } catch (ex) { + console.error(`Failed to parse color: "${color}"`, ex); + return; + } + + // For the light theme, limit the maximum lightness + const lightThemeColor = labColor.l(Math.min(labColor.l(), lightThemeMaxLightness)).hex(); + // For the light theme, limit the minimum lightness + const darkThemeColor = labColor.l(Math.max(labColor.l(), darkThemeMinLightness)).hex(); + + return {lightThemeColor, darkThemeColor}; +} + export default { createClassForColor -}; +}; \ No newline at end of file diff --git a/apps/client/src/stylesheets/theme-dark.css b/apps/client/src/stylesheets/theme-dark.css index f56e73232..01bd125ec 100644 --- a/apps/client/src/stylesheets/theme-dark.css +++ b/apps/client/src/stylesheets/theme-dark.css @@ -82,6 +82,10 @@ body ::-webkit-calendar-picker-indicator { filter: invert(1); } +#left-pane span.fancytree-node { + --custom-color: var(--dark-theme-custom-color); +} + .excalidraw.theme--dark { --theme-filter: invert(80%) hue-rotate(180deg) !important; } diff --git a/apps/client/src/stylesheets/theme-light.css b/apps/client/src/stylesheets/theme-light.css index 7aca1b3f9..55203712e 100644 --- a/apps/client/src/stylesheets/theme-light.css +++ b/apps/client/src/stylesheets/theme-light.css @@ -81,3 +81,7 @@ html { --mermaid-theme: default; --native-titlebar-background: #ffffff00; } + +#left-pane span.fancytree-node { + --custom-color: var(--light-theme-custom-color); +} \ No newline at end of file diff --git a/apps/client/src/stylesheets/theme-next-dark.css b/apps/client/src/stylesheets/theme-next-dark.css index c54cb26b7..b2192a2a0 100644 --- a/apps/client/src/stylesheets/theme-next-dark.css +++ b/apps/client/src/stylesheets/theme-next-dark.css @@ -268,6 +268,10 @@ * Dark color scheme tweaks */ +#left-pane span.fancytree-node { + --custom-color: var(--dark-theme-custom-color); +} + body ::-webkit-calendar-picker-indicator { filter: invert(1); } @@ -278,4 +282,4 @@ body ::-webkit-calendar-picker-indicator { body .todo-list input[type="checkbox"]:not(:checked):before { border-color: var(--muted-text-color) !important; -} +} \ No newline at end of file diff --git a/apps/client/src/stylesheets/theme-next/base.css b/apps/client/src/stylesheets/theme-next/base.css index 1ec859c3a..54e0ebf04 100644 --- a/apps/client/src/stylesheets/theme-next/base.css +++ b/apps/client/src/stylesheets/theme-next/base.css @@ -82,6 +82,20 @@ /* Theme capabilities */ --tab-note-icons: true; + + /* To ensure that a tree item's custom color remains sufficiently contrasted and readable, + * the color is adjusted based on the current color scheme (light or dark). The lightness + * component of the color represented in the CIELAB color space, will be + * constrained to a certain percentage defined below. + * + * Note: the tree background may vary when background effects are enabled, so it is recommended + * to maintain a higher contrast margin than on the usual note tree solid background. */ + + /* The maximum lightness for the custom color in the light theme (%): */ + --tree-item-light-theme-max-color-lightness: 50; + + /* The minimum lightness for the custom color in the dark theme (%): */ + --tree-item-dark-theme-min-color-lightness: 60; } body.backdrop-effects-disabled { diff --git a/apps/client/src/stylesheets/theme-next/shell.css b/apps/client/src/stylesheets/theme-next/shell.css index 5e713c249..ff0245ab2 100644 --- a/apps/client/src/stylesheets/theme-next/shell.css +++ b/apps/client/src/stylesheets/theme-next/shell.css @@ -639,7 +639,7 @@ body.layout-vertical.background-effects div.quick-search .dropdown-menu { #left-pane span.fancytree-node.fancytree-active { position: relative; background: transparent !important; - color: var(--left-pane-item-selected-color); + color: var(--custom-color, var(--left-pane-item-selected-color)); } @keyframes left-pane-item-select { diff --git a/apps/client/src/stylesheets/tree.css b/apps/client/src/stylesheets/tree.css index a85ee7f63..9a718310e 100644 --- a/apps/client/src/stylesheets/tree.css +++ b/apps/client/src/stylesheets/tree.css @@ -40,6 +40,7 @@ span.fancytree-node.fancytree-hide { text-overflow: ellipsis; user-select: none !important; -webkit-user-select: none !important; + color: var(--custom-color, inherit); } .fancytree-node:not(.fancytree-loading) .fancytree-expander { diff --git a/apps/client/src/utils/css-var.ts b/apps/client/src/utils/css-var.ts new file mode 100644 index 000000000..a0a16402f --- /dev/null +++ b/apps/client/src/utils/css-var.ts @@ -0,0 +1,45 @@ +export function readCssVar(element: HTMLElement, varName: string) { + return new CssVarReader(getComputedStyle(element).getPropertyValue("--" + varName)); +} + +export class CssVarReader { + protected value: string; + + constructor(rawValue: string) { + this.value = rawValue; + } + + asString(defaultValue?: string) { + return (this.value) ? this.value : defaultValue; + } + + asNumber(defaultValue?: number) { + let number: Number = NaN; + + if (this.value) { + number = new Number(this.value); + } + + return (!isNaN(number.valueOf()) ? number.valueOf() : defaultValue) + } + + asEnum(enumType: T, defaultValue?: T[keyof T]): T[keyof T] | undefined { + let result: T[keyof T] | undefined; + + result = enumType[this.value as keyof T]; + + if (result === undefined) { + result = defaultValue; + } + + return result; + } + + asArray(delimiter: string = " "): CssVarReader[] { + // Note: ignoring delimiters inside quotation marks is currently unsupported + let values = this.value.split(delimiter); + + return values.map((v) => new CssVarReader(v)); + } + +} \ No newline at end of file diff --git a/apps/server/package.json b/apps/server/package.json index aff4901b2..f16ea110a 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -26,6 +26,7 @@ }, "dependencies": { "better-sqlite3": "12.4.1", + "color": "5.0.2", "node-html-parser": "7.0.1" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bae171169..5b8c5382c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -452,6 +452,9 @@ importers: better-sqlite3: specifier: 12.4.1 version: 12.4.1 + color: + specifier: 5.0.2 + version: 5.0.2 node-html-parser: specifier: 7.0.1 version: 7.0.1 @@ -6328,10 +6331,18 @@ packages: color-parse@2.0.2: resolution: {integrity: sha512-eCtOz5w5ttWIUcaKLiktF+DxZO1R9KLNY/xhbV6CkhM7sR3GhVghmt6X6yOnzeaM24po+Z9/S1apbXMwA3Iepw==} + color-string@2.1.2: + resolution: {integrity: sha512-RxmjYxbWemV9gKu4zPgiZagUxbH3RQpEIO77XoSSX0ivgABDZ+h8Zuash/EMFLTI4N9QgFPOJ6JQpPZKFxa+dA==} + engines: {node: '>=18'} + color-support@1.1.3: resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} hasBin: true + color@5.0.2: + resolution: {integrity: sha512-e2hz5BzbUPcYlIRHo8ieAhYgoajrJr+hWoceg6E345TPsATMUKqDgzt8fSXZJJbxfpiPzkWyphz8yn8At7q3fA==} + engines: {node: '>=18'} + colord@2.9.3: resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} @@ -14681,8 +14692,6 @@ snapshots: '@ckeditor/ckeditor5-core': 47.1.0 '@ckeditor/ckeditor5-upload': 47.1.0 ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-ai@47.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)': dependencies: @@ -14892,6 +14901,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.1.0 '@ckeditor/ckeditor5-watchdog': 47.1.0 es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-dev-build-tools@43.1.0(@swc/helpers@0.5.17)(tslib@2.8.1)(typescript@5.9.3)': dependencies: @@ -15083,6 +15094,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.1.0 ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-editor-multi-root@47.1.0': dependencies: @@ -15252,8 +15265,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.1.0 '@ckeditor/ckeditor5-widget': 47.1.0 ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-html-embed@47.1.0': dependencies: @@ -15669,8 +15680,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.1.0 '@ckeditor/ckeditor5-utils': 47.1.0 ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-special-characters@47.1.0': dependencies: @@ -16338,7 +16347,7 @@ snapshots: make-fetch-happen: 10.2.1 nopt: 6.0.0 proc-log: 2.0.1 - semver: 7.7.2 + semver: 7.7.3 tar: 6.2.1 which: 2.0.2 transitivePeerDependencies: @@ -17685,7 +17694,7 @@ snapshots: '@npmcli/fs@2.1.2': dependencies: '@gar/promisify': 1.1.3 - semver: 7.7.2 + semver: 7.7.3 '@npmcli/fs@4.0.0': dependencies: @@ -21148,9 +21157,18 @@ snapshots: dependencies: color-name: 2.0.0 + color-string@2.1.2: + dependencies: + color-name: 2.0.0 + color-support@1.1.3: optional: true + color@5.0.2: + dependencies: + color-convert: 3.1.0 + color-string: 2.1.2 + colord@2.9.3: {} colorette@2.0.20: {} From 93c7b8dea7d73754488b8f7369cb90c0c4ad6064 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sat, 18 Oct 2025 21:22:55 +0300 Subject: [PATCH 02/14] client: fix the issues pointed by gemini-code-assist --- apps/client/package.json | 1 + apps/client/src/services/css_class_manager.ts | 9 ++++++--- apps/client/src/utils/css-var.ts | 2 +- apps/server/package.json | 1 - pnpm-lock.yaml | 10 +++++----- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/client/package.json b/apps/client/package.json index 4459d2cb2..dceb6e8b8 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -35,6 +35,7 @@ "autocomplete.js": "0.38.1", "bootstrap": "5.3.8", "boxicons": "2.1.4", + "color": "5.0.2", "dayjs": "1.11.18", "dayjs-plugin-utc": "0.1.2", "debounce": "2.2.0", diff --git a/apps/client/src/services/css_class_manager.ts b/apps/client/src/services/css_class_manager.ts index 6c26b5dcb..3b7f8ce1f 100644 --- a/apps/client/src/services/css_class_manager.ts +++ b/apps/client/src/services/css_class_manager.ts @@ -62,10 +62,13 @@ function adjustColorLightness(color: string, lightThemeMaxLightness: number, dar return; } + const lightness = labColor.l(); + // For the light theme, limit the maximum lightness - const lightThemeColor = labColor.l(Math.min(labColor.l(), lightThemeMaxLightness)).hex(); - // For the light theme, limit the minimum lightness - const darkThemeColor = labColor.l(Math.max(labColor.l(), darkThemeMinLightness)).hex(); + const lightThemeColor = labColor.l(Math.min(lightness, lightThemeMaxLightness)).hex(); + + // For the dark theme, limit the minimum lightness + const darkThemeColor = labColor.l(Math.max(lightness, darkThemeMinLightness)).hex(); return {lightThemeColor, darkThemeColor}; } diff --git a/apps/client/src/utils/css-var.ts b/apps/client/src/utils/css-var.ts index a0a16402f..886247881 100644 --- a/apps/client/src/utils/css-var.ts +++ b/apps/client/src/utils/css-var.ts @@ -17,7 +17,7 @@ export class CssVarReader { let number: Number = NaN; if (this.value) { - number = new Number(this.value); + number = parseFloat(this.value); } return (!isNaN(number.valueOf()) ? number.valueOf() : defaultValue) diff --git a/apps/server/package.json b/apps/server/package.json index f16ea110a..aff4901b2 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -26,7 +26,6 @@ }, "dependencies": { "better-sqlite3": "12.4.1", - "color": "5.0.2", "node-html-parser": "7.0.1" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5b8c5382c..77e4d877e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -184,6 +184,9 @@ importers: boxicons: specifier: 2.1.4 version: 2.1.4 + color: + specifier: 5.0.2 + version: 5.0.2 dayjs: specifier: 1.11.18 version: 1.11.18 @@ -452,9 +455,6 @@ importers: better-sqlite3: specifier: 12.4.1 version: 12.4.1 - color: - specifier: 5.0.2 - version: 5.0.2 node-html-parser: specifier: 7.0.1 version: 7.0.1 @@ -14901,8 +14901,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.1.0 '@ckeditor/ckeditor5-watchdog': 47.1.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-dev-build-tools@43.1.0(@swc/helpers@0.5.17)(tslib@2.8.1)(typescript@5.9.3)': dependencies: @@ -15680,6 +15678,8 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.1.0 '@ckeditor/ckeditor5-utils': 47.1.0 ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41) + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-special-characters@47.1.0': dependencies: From 0390fadf34e1ac9354d2391ce96876b6c3f9b1e7 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sat, 18 Oct 2025 21:29:39 +0300 Subject: [PATCH 03/14] style/note tree: tweak the light theme custom color lightness limit --- apps/client/src/stylesheets/theme-next/base.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/client/src/stylesheets/theme-next/base.css b/apps/client/src/stylesheets/theme-next/base.css index 54e0ebf04..80e529823 100644 --- a/apps/client/src/stylesheets/theme-next/base.css +++ b/apps/client/src/stylesheets/theme-next/base.css @@ -92,7 +92,7 @@ * to maintain a higher contrast margin than on the usual note tree solid background. */ /* The maximum lightness for the custom color in the light theme (%): */ - --tree-item-light-theme-max-color-lightness: 50; + --tree-item-light-theme-max-color-lightness: 60; /* The minimum lightness for the custom color in the dark theme (%): */ --tree-item-dark-theme-min-color-lightness: 60; From 177577e80f8fe5aba2a923c92bd4b0ca7a84aefa Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sat, 18 Oct 2025 21:31:42 +0300 Subject: [PATCH 04/14] style: improve comment --- apps/client/src/stylesheets/theme-next/base.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/client/src/stylesheets/theme-next/base.css b/apps/client/src/stylesheets/theme-next/base.css index 80e529823..9b9ffc887 100644 --- a/apps/client/src/stylesheets/theme-next/base.css +++ b/apps/client/src/stylesheets/theme-next/base.css @@ -91,10 +91,10 @@ * Note: the tree background may vary when background effects are enabled, so it is recommended * to maintain a higher contrast margin than on the usual note tree solid background. */ - /* The maximum lightness for the custom color in the light theme (%): */ + /* The maximum perceptual lightness for the custom color in the light theme (%): */ --tree-item-light-theme-max-color-lightness: 60; - /* The minimum lightness for the custom color in the dark theme (%): */ + /* The minimum perceptual lightness for the custom color in the dark theme (%): */ --tree-item-dark-theme-min-color-lightness: 60; } From 0ae5270f5bede0e94b463dc8e27de896b4844f45 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sat, 18 Oct 2025 21:45:37 +0300 Subject: [PATCH 05/14] docs: add a notice for the "color" label --- docs/User Guide/User Guide/Advanced Usage/Attributes/Labels.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/User Guide/User Guide/Advanced Usage/Attributes/Labels.md b/docs/User Guide/User Guide/Advanced Usage/Attributes/Labels.md index 53307238f..071bbb7cf 100644 --- a/docs/User Guide/User Guide/Advanced Usage/Attributes/Labels.md +++ b/docs/User Guide/User Guide/Advanced Usage/Attributes/Labels.md @@ -39,4 +39,4 @@ This is a list of labels that Trilium natively supports. > [!TIP] > Some labels presented here end with a `*`. That means that there are multiple labels with the same prefix, consult the specific page linked in the description of that label for more information. -
LabelDescription
disableVersioningDisables automatic creation of Note Revisions for a particular note. Useful for e.g. large, but unimportant notes - e.g. large JS libraries used for scripting.
versioningLimitLimits the maximum number of Note Revisions for a particular note, overriding the global settings.
calendarRootMarks the note which should be used as root for Day Notes. Only one should be marked as such.
archivedHides notes from default search results and dialogs. Archived notes can optionally be hidden in the Note Tree.
excludeFromExportExcludes this note and its children when exporting.
run, runOnInstance, runAtHourSee Events.
disableInclusionScripts with this label won't be included into parent script execution.
sorted

Keeps child notes sorted by title alphabetically.

When given a value, it will sort by the value of another label instead. If one of the child notes doesn't have the specified label, the title will be used for them instead.

sortDirection

If sorted is applied, specifies the direction of the sort:

  • ASC, ascending (default)
  • DESC, descending
sortFoldersFirstIf sorted is applied, folders (notes with children) will be sorted as a group at the top, and the rest will be sorted.
topIf sorted is applied to the parent note, keeps given note on top in its parent.
hidePromotedAttributesHide Promoted Attributes on this note. Generally useful when defining inherited attributes, but the parent note doesn't need them.
readOnlyMarks a note to be always be read-only, if it's a supported note (text, code, mermaid).
autoReadOnlyDisabledDisables automatic read-only mode for the given note.
appCssMarks CSS notes which are loaded into the Trilium application and can thus be used to modify Trilium's looks. See Custom app-wide CSS for more info.
appThemeMarks CSS notes which are full Trilium themes and are thus available in Trilium options. See Theme development for more information.
appThemeBaseSet to next, next-light, or next-dark to use the corresponding TriliumNext theme (auto, light or dark) as the base for a custom theme, instead of the legacy one. See Customize the Next theme for more information.
cssClassValue of this label is then added as CSS class to the node representing given note in the Note Tree. This can be useful for advanced theming. Can be used in template notes.
iconClassvalue of this label is added as a CSS class to the icon on the tree which can help visually distinguish the notes in the tree. Example might be bx bx-home - icons are taken from boxicons. Can be used in template notes.
pageSizeSpecifies the number of items per page in Note List.
customRequestHandlerSee Custom Request Handler.
customResourceProviderSee Custom Resource Providers.
widgetMarks this note as a custom widget which will be added to the Trilium component tree. See Custom Widgets for more information.
searchHomeNew search notes will be created as children of this note (see Saved Search).
workspace and related attributesSee Workspaces.
inboxdefault inbox location for new notes - when you create a note using new note button in the sidebar, notes will be created as child notes in the note marked as with #inbox label.
sqlConsoleHomeDefault location of SQL Console notes
bookmarkedIndicates this note is a bookmark.
bookmarkFolderNote with this label will appear in bookmarks as folder (allowing access to its children). See Bookmarks for more information.
share*See the attribute reference in Sharing.
displayRelations, hideRelationsComma delimited names of relations which should be displayed/hidden in a Relation Map (both the note type and the Note Map (Link map, Tree map) general functionality).
titleTemplate

Default title of notes created as children of this note. This value is evaluated as a JavaScript string and thus can be enriched with dynamic content via the injected now and parentNote variables.

Examples:

  • \({parentNote.getLabel('authorName')}'s literary works
  • Log for \){now.format('YYYY-MM-DD HH:mm:ss')}
  • to mirror the parent's template.

See Default Note Title for more info.

templateThis note will appear in the selection of available template when creating new note. See Templates for more information.
tocControls the display of the Table of contents for a given note. #toc or #toc=show to always display the table of contents, #toc=false to always hide it.
colordefines color of the note in note tree, links etc. Use any valid CSS color value like 'red' or #a13d5f
keyboardShortcutDefines a keyboard shortcut which will immediately jump to this note. Example: 'ctrl+alt+e'. Requires frontend reload for the change to take effect.
keepCurrentHoistingOpening this link won't change hoisting even if the note is not displayable in the current hoisted subtree.
executeButtonTitle of the button which will execute the current code note
executeDescriptionLonger description of the current code note displayed together with the execute button
excludeFromNoteMapNotes with this label will be hidden from the Note Map.
newNotesOnTopNew notes will be created at the top of the parent note, not on the bottom.
hideHighlightWidgetHides the Highlights list widget
hideChildrenOverviewHides the Note List for that particular note.
printLandscapeWhen exporting to PDF, changes the orientation of the page to landscape instead of portrait.
printPageSizeWhen exporting to PDF, changes the size of the page. Supported values: A0, A1, A2, A3, A4, A5, A6, Legal, Letter, Tabloid, Ledger.
geolocationIndicates the latitude and longitude of a note, to be displayed in a Geo Map.
calendar:*Defines specific options for the Calendar View.
viewTypeSets the view of child notes (e.g. grid or list). See Note List for more information.
\ No newline at end of file +
LabelDescription
disableVersioningDisables automatic creation of Note Revisions for a particular note. Useful for e.g. large, but unimportant notes - e.g. large JS libraries used for scripting.
versioningLimitLimits the maximum number of Note Revisions for a particular note, overriding the global settings.
calendarRootMarks the note which should be used as root for Day Notes. Only one should be marked as such.
archivedHides notes from default search results and dialogs. Archived notes can optionally be hidden in the Note Tree.
excludeFromExportExcludes this note and its children when exporting.
run, runOnInstance, runAtHourSee Events.
disableInclusionScripts with this label won't be included into parent script execution.
sorted

Keeps child notes sorted by title alphabetically.

When given a value, it will sort by the value of another label instead. If one of the child notes doesn't have the specified label, the title will be used for them instead.

sortDirection

If sorted is applied, specifies the direction of the sort:

  • ASC, ascending (default)
  • DESC, descending
sortFoldersFirstIf sorted is applied, folders (notes with children) will be sorted as a group at the top, and the rest will be sorted.
topIf sorted is applied to the parent note, keeps given note on top in its parent.
hidePromotedAttributesHide Promoted Attributes on this note. Generally useful when defining inherited attributes, but the parent note doesn't need them.
readOnlyMarks a note to be always be read-only, if it's a supported note (text, code, mermaid).
autoReadOnlyDisabledDisables automatic read-only mode for the given note.
appCssMarks CSS notes which are loaded into the Trilium application and can thus be used to modify Trilium's looks. See Custom app-wide CSS for more info.
appThemeMarks CSS notes which are full Trilium themes and are thus available in Trilium options. See Theme development for more information.
appThemeBaseSet to next, next-light, or next-dark to use the corresponding TriliumNext theme (auto, light or dark) as the base for a custom theme, instead of the legacy one. See Customize the Next theme for more information.
cssClassValue of this label is then added as CSS class to the node representing given note in the Note Tree. This can be useful for advanced theming. Can be used in template notes.
iconClassvalue of this label is added as a CSS class to the icon on the tree which can help visually distinguish the notes in the tree. Example might be bx bx-home - icons are taken from boxicons. Can be used in template notes.
pageSizeSpecifies the number of items per page in Note List.
customRequestHandlerSee Custom Request Handler.
customResourceProviderSee Custom Resource Providers.
widgetMarks this note as a custom widget which will be added to the Trilium component tree. See Custom Widgets for more information.
searchHomeNew search notes will be created as children of this note (see Saved Search).
workspace and related attributesSee Workspaces.
inboxdefault inbox location for new notes - when you create a note using new note button in the sidebar, notes will be created as child notes in the note marked as with #inbox label.
sqlConsoleHomeDefault location of SQL Console notes
bookmarkedIndicates this note is a bookmark.
bookmarkFolderNote with this label will appear in bookmarks as folder (allowing access to its children). See Bookmarks for more information.
share*See the attribute reference in Sharing.
displayRelations, hideRelationsComma delimited names of relations which should be displayed/hidden in a Relation Map (both the note type and the Note Map (Link map, Tree map) general functionality).
titleTemplate

Default title of notes created as children of this note. This value is evaluated as a JavaScript string and thus can be enriched with dynamic content via the injected now and parentNote variables.

Examples:

  • \({parentNote.getLabel('authorName')}'s literary works
  • Log for \){now.format('YYYY-MM-DD HH:mm:ss')}
  • to mirror the parent's template.

See Default Note Title for more info.

templateThis note will appear in the selection of available template when creating new note. See Templates for more information.
tocControls the display of the Table of contents for a given note. #toc or #toc=show to always display the table of contents, #toc=false to always hide it.
colordefines color of the note in note tree, links etc. Use any valid CSS color value like 'red' or #a13d5f
Note: this color may be automatically adjusted when displayed to ensure sufficient contrast with the background.
keyboardShortcutDefines a keyboard shortcut which will immediately jump to this note. Example: 'ctrl+alt+e'. Requires frontend reload for the change to take effect.
keepCurrentHoistingOpening this link won't change hoisting even if the note is not displayable in the current hoisted subtree.
executeButtonTitle of the button which will execute the current code note
executeDescriptionLonger description of the current code note displayed together with the execute button
excludeFromNoteMapNotes with this label will be hidden from the Note Map.
newNotesOnTopNew notes will be created at the top of the parent note, not on the bottom.
hideHighlightWidgetHides the Highlights list widget
hideChildrenOverviewHides the Note List for that particular note.
printLandscapeWhen exporting to PDF, changes the orientation of the page to landscape instead of portrait.
printPageSizeWhen exporting to PDF, changes the size of the page. Supported values: A0, A1, A2, A3, A4, A5, A6, Legal, Letter, Tabloid, Ledger.
geolocationIndicates the latitude and longitude of a note, to be displayed in a Geo Map.
calendar:*Defines specific options for the Calendar View.
viewTypeSets the view of child notes (e.g. grid or list). See Note List for more information.
\ No newline at end of file From 21581c78f9e8ca3cedd341e620969740cf98dfeb Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sat, 18 Oct 2025 23:52:43 +0300 Subject: [PATCH 06/14] client: refactor --- apps/client/src/services/css_class_manager.ts | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/apps/client/src/services/css_class_manager.ts b/apps/client/src/services/css_class_manager.ts index 3b7f8ce1f..748b7a01d 100644 --- a/apps/client/src/services/css_class_manager.ts +++ b/apps/client/src/services/css_class_manager.ts @@ -15,21 +15,19 @@ const darkThemeColorMinLightness = readCssVar( "tree-item-dark-theme-min-color-lightness" ).asNumber(50); -function createClassForColor(color: string | null) { - if (!color?.trim()) { +function createClassForColor(colorString: string | null) { + if (!colorString?.trim()) { return ""; } - const normalizedColorName = color.replace(/[^a-z0-9]/gi, ""); - - if (!normalizedColorName.trim()) { - return ""; + const color = parseColor(colorString); + if (!color) { + return; } - const className = `color-${normalizedColorName}`; - - const adjustedColor = adjustColorLightness(color, lightThemeColorMaxLightness!, darkThemeColorMinLightness!); - if (!adjustedColor) return ""; + const className = `color-${color.hex().substring(1)}`; + const adjustedColor = adjustColorLightness(color, lightThemeColorMaxLightness!, + darkThemeColorMinLightness!); if (!registeredClasses.has(className)) { $("head").append(``); From e0614d14f3ec40134c8ffe9361335e16fbb54701 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sun, 19 Oct 2025 00:48:39 +0300 Subject: [PATCH 10/14] readme: add a download section --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 5b96a65d8..45c4ef89c 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,10 @@ See [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) for q Trilium Screenshot +## ⏬ Download +- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest) — stable version, recommended for most users. +- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly) — unstable development version, updated daily with the latest features and fixes. + ## 📚 Documentation **Visit our comprehensive documentation at [docs.triliumnotes.org](https://docs.triliumnotes.org/)** From c95577c478f0edcea36d56b58748e4133fc96851 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sun, 19 Oct 2025 00:53:40 +0300 Subject: [PATCH 11/14] readme: use en-dash instead of em-dash --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 45c4ef89c..be62b5370 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,8 @@ See [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) for q Trilium Screenshot ## ⏬ Download -- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest) — stable version, recommended for most users. -- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly) — unstable development version, updated daily with the latest features and fixes. +- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest) – stable version, recommended for most users. +- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly) – unstable development version, updated daily with the latest features and fixes. ## 📚 Documentation From 75a79775f4fc939f4bff5f9287dda8ca2ce3a6a4 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sun, 19 Oct 2025 03:28:34 +0300 Subject: [PATCH 12/14] client/note tree: tint the active item background according to the item's custom color --- apps/client/src/services/css_class_manager.ts | 18 +++++++++++++++--- apps/client/src/stylesheets/theme-dark.css | 1 + apps/client/src/stylesheets/theme-light.css | 1 + .../client/src/stylesheets/theme-next-dark.css | 1 + .../src/stylesheets/theme-next/shell.css | 2 +- 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/apps/client/src/services/css_class_manager.ts b/apps/client/src/services/css_class_manager.ts index f148707c2..ad4ac1a41 100644 --- a/apps/client/src/services/css_class_manager.ts +++ b/apps/client/src/services/css_class_manager.ts @@ -34,7 +34,9 @@ function createClassForColor(colorString: string | null) { $("head").append(``); @@ -59,8 +61,7 @@ function parseColor(color: string) { * according to the lightThemeMaxLightness and darkThemeMinLightness parameters. */ function adjustColorLightness(color: ColorInstance, lightThemeMaxLightness: number, darkThemeMinLightness: number) { - let labColor = color.lab(); - + const labColor = color.lab(); const lightness = labColor.l(); // For the light theme, limit the maximum lightness @@ -69,7 +70,18 @@ function adjustColorLightness(color: ColorInstance, lightThemeMaxLightness: numb // For the dark theme, limit the minimum lightness const darkThemeColor = labColor.l(Math.max(lightness, darkThemeMinLightness)).hex(); - return {lightThemeColor, darkThemeColor}; + let darkThemeBackgroundColor = "unset"; + let lightThemeBackgroundColor = "unset"; + + const hslColor = color.hsl(); + const hue = hslColor.hue(); + + if (color.saturationl() > 0) { + darkThemeBackgroundColor = Color({h: hue, s: 20, l: 33, alpha: .4}).hexa(); + lightThemeBackgroundColor = Color({h: hue, s: 100, l: 25, alpha: .1}).hexa(); + } + + return {lightThemeColor, lightThemeBackgroundColor, darkThemeColor, darkThemeBackgroundColor}; } export default { diff --git a/apps/client/src/stylesheets/theme-dark.css b/apps/client/src/stylesheets/theme-dark.css index 01bd125ec..95e6dccd8 100644 --- a/apps/client/src/stylesheets/theme-dark.css +++ b/apps/client/src/stylesheets/theme-dark.css @@ -84,6 +84,7 @@ body ::-webkit-calendar-picker-indicator { #left-pane span.fancytree-node { --custom-color: var(--dark-theme-custom-color); + --custom-bg-color: var(--dark-theme-custom-bg-color); } .excalidraw.theme--dark { diff --git a/apps/client/src/stylesheets/theme-light.css b/apps/client/src/stylesheets/theme-light.css index 55203712e..933f5bfe6 100644 --- a/apps/client/src/stylesheets/theme-light.css +++ b/apps/client/src/stylesheets/theme-light.css @@ -84,4 +84,5 @@ html { #left-pane span.fancytree-node { --custom-color: var(--light-theme-custom-color); + --custom-bg-color: var(--light-theme-custom-bg-color); } \ No newline at end of file diff --git a/apps/client/src/stylesheets/theme-next-dark.css b/apps/client/src/stylesheets/theme-next-dark.css index b2192a2a0..b9a66da0d 100644 --- a/apps/client/src/stylesheets/theme-next-dark.css +++ b/apps/client/src/stylesheets/theme-next-dark.css @@ -270,6 +270,7 @@ #left-pane span.fancytree-node { --custom-color: var(--dark-theme-custom-color); + --custom-bg-color: var(--dark-theme-custom-bg-color); } body ::-webkit-calendar-picker-indicator { diff --git a/apps/client/src/stylesheets/theme-next/shell.css b/apps/client/src/stylesheets/theme-next/shell.css index ff0245ab2..b6bd38789 100644 --- a/apps/client/src/stylesheets/theme-next/shell.css +++ b/apps/client/src/stylesheets/theme-next/shell.css @@ -658,7 +658,7 @@ body.layout-vertical.background-effects div.quick-search .dropdown-menu { inset-inline-start: var(--left-pane-item-selected-shadow-size); bottom: var(--left-pane-item-selected-shadow-size); inset-inline-end: var(--left-pane-item-selected-shadow-size); - background: var(--left-pane-item-selected-background) !important; + background: var(--custom-bg-color, var(--left-pane-item-selected-background)) !important; box-shadow: var(--left-pane-item-selected-shadow); border-radius: 6px; animation: left-pane-item-select 200ms ease-out; From 1aad2d8c09a4318895368712adc5bd5983a14deb Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sun, 19 Oct 2025 03:58:28 +0300 Subject: [PATCH 13/14] client/note tree item tinting: tweak colors for the light theme --- apps/client/src/services/css_class_manager.ts | 4 ++-- apps/client/src/stylesheets/theme-next/base.css | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/client/src/services/css_class_manager.ts b/apps/client/src/services/css_class_manager.ts index ad4ac1a41..c716ec001 100644 --- a/apps/client/src/services/css_class_manager.ts +++ b/apps/client/src/services/css_class_manager.ts @@ -72,13 +72,13 @@ function adjustColorLightness(color: ColorInstance, lightThemeMaxLightness: numb let darkThemeBackgroundColor = "unset"; let lightThemeBackgroundColor = "unset"; - + const hslColor = color.hsl(); const hue = hslColor.hue(); if (color.saturationl() > 0) { darkThemeBackgroundColor = Color({h: hue, s: 20, l: 33, alpha: .4}).hexa(); - lightThemeBackgroundColor = Color({h: hue, s: 100, l: 25, alpha: .1}).hexa(); + lightThemeBackgroundColor = Color({h: hue, s: 37, l: 89, alpha: 1}).hexa(); } return {lightThemeColor, lightThemeBackgroundColor, darkThemeColor, darkThemeBackgroundColor}; diff --git a/apps/client/src/stylesheets/theme-next/base.css b/apps/client/src/stylesheets/theme-next/base.css index 9b9ffc887..a33da2bc5 100644 --- a/apps/client/src/stylesheets/theme-next/base.css +++ b/apps/client/src/stylesheets/theme-next/base.css @@ -95,7 +95,7 @@ --tree-item-light-theme-max-color-lightness: 60; /* The minimum perceptual lightness for the custom color in the dark theme (%): */ - --tree-item-dark-theme-min-color-lightness: 60; + --tree-item-dark-theme-min-color-lightness: 65; } body.backdrop-effects-disabled { From e04bd36dfea05401dd2e63c0a05a3e881b439dbc Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 19 Oct 2025 11:38:34 +0300 Subject: [PATCH 14/14] chore(client): fix typecheck --- apps/client/src/services/css_class_manager.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/apps/client/src/services/css_class_manager.ts b/apps/client/src/services/css_class_manager.ts index c716ec001..fc839c9b1 100644 --- a/apps/client/src/services/css_class_manager.ts +++ b/apps/client/src/services/css_class_manager.ts @@ -16,14 +16,10 @@ const darkThemeColorMinLightness = readCssVar( ).asNumber(50); function createClassForColor(colorString: string | null) { - if (!colorString?.trim()) { - return ""; - } + if (!colorString?.trim()) return ""; const color = parseColor(colorString); - if (!color) { - return; - } + if (!color) return ""; const className = `color-${color.hex().substring(1)}`; @@ -54,7 +50,7 @@ function parseColor(color: string) { } } -/** +/** * Returns a pair of colors — one optimized for light themes and the other for dark themes, derived * from the specified color to maintain sufficient contrast with each theme. * The adjustment is performed by limiting the color’s lightness in the CIELAB color space, @@ -66,7 +62,7 @@ function adjustColorLightness(color: ColorInstance, lightThemeMaxLightness: numb // For the light theme, limit the maximum lightness const lightThemeColor = labColor.l(Math.min(lightness, lightThemeMaxLightness)).hex(); - + // For the dark theme, limit the minimum lightness const darkThemeColor = labColor.l(Math.max(lightness, darkThemeMinLightness)).hex(); @@ -86,4 +82,4 @@ function adjustColorLightness(color: ColorInstance, lightThemeMaxLightness: numb export default { createClassForColor -}; \ No newline at end of file +};