mirror of
https://github.com/zadam/trilium.git
synced 2025-11-03 21:19:01 +01:00
Merge remote-tracking branch 'origin/main' into feature/pdf_export_presentation
This commit is contained in:
commit
44b9c6e0f6
@ -24,6 +24,10 @@ See [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) for q
|
|||||||
|
|
||||||
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
|
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
|
||||||
|
|
||||||
|
## ⏬ 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
|
## 📚 Documentation
|
||||||
|
|
||||||
**Visit our comprehensive documentation at [docs.triliumnotes.org](https://docs.triliumnotes.org/)**
|
**Visit our comprehensive documentation at [docs.triliumnotes.org](https://docs.triliumnotes.org/)**
|
||||||
|
|||||||
@ -35,6 +35,7 @@
|
|||||||
"autocomplete.js": "0.38.1",
|
"autocomplete.js": "0.38.1",
|
||||||
"bootstrap": "5.3.8",
|
"bootstrap": "5.3.8",
|
||||||
"boxicons": "2.1.4",
|
"boxicons": "2.1.4",
|
||||||
|
"color": "5.0.2",
|
||||||
"dayjs": "1.11.18",
|
"dayjs": "1.11.18",
|
||||||
"dayjs-plugin-utc": "0.1.2",
|
"dayjs-plugin-utc": "0.1.2",
|
||||||
"debounce": "2.2.0",
|
"debounce": "2.2.0",
|
||||||
|
|||||||
@ -1,21 +1,40 @@
|
|||||||
|
import {readCssVar} from "../utils/css-var";
|
||||||
|
import Color, { ColorInstance } from "color";
|
||||||
|
|
||||||
const registeredClasses = new Set<string>();
|
const registeredClasses = new Set<string>();
|
||||||
|
|
||||||
function createClassForColor(color: string | null) {
|
// Read the color lightness limits defined in the theme as CSS variables
|
||||||
if (!color?.trim()) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
const normalizedColorName = color.replace(/[^a-z0-9]/gi, "");
|
const lightThemeColorMaxLightness = readCssVar(
|
||||||
|
document.documentElement,
|
||||||
|
"tree-item-light-theme-max-color-lightness"
|
||||||
|
).asNumber(70);
|
||||||
|
|
||||||
if (!normalizedColorName.trim()) {
|
const darkThemeColorMinLightness = readCssVar(
|
||||||
return "";
|
document.documentElement,
|
||||||
}
|
"tree-item-dark-theme-min-color-lightness"
|
||||||
|
).asNumber(50);
|
||||||
|
|
||||||
const className = `color-${normalizedColorName}`;
|
function createClassForColor(colorString: string | null) {
|
||||||
|
if (!colorString?.trim()) return "";
|
||||||
|
|
||||||
|
const color = parseColor(colorString);
|
||||||
|
if (!color) return "";
|
||||||
|
|
||||||
|
const className = `color-${color.hex().substring(1)}`;
|
||||||
|
|
||||||
if (!registeredClasses.has(className)) {
|
if (!registeredClasses.has(className)) {
|
||||||
// make the active fancytree selector more specific than the normal color setting
|
const adjustedColor = adjustColorLightness(color, lightThemeColorMaxLightness!,
|
||||||
$("head").append(`<style>.${className}, span.fancytree-active.${className} { color: ${color} !important; }</style>`);
|
darkThemeColorMinLightness!);
|
||||||
|
|
||||||
|
$("head").append(`<style>
|
||||||
|
.${className}, span.fancytree-active.${className} {
|
||||||
|
--light-theme-custom-color: ${adjustedColor.lightThemeColor};
|
||||||
|
--light-theme-custom-bg-color: ${adjustedColor.lightThemeBackgroundColor};
|
||||||
|
--dark-theme-custom-color: ${adjustedColor.darkThemeColor};
|
||||||
|
--dark-theme-custom-bg-color: ${adjustedColor.darkThemeBackgroundColor};
|
||||||
|
}
|
||||||
|
</style>`);
|
||||||
|
|
||||||
registeredClasses.add(className);
|
registeredClasses.add(className);
|
||||||
}
|
}
|
||||||
@ -23,6 +42,44 @@ function createClassForColor(color: string | null) {
|
|||||||
return className;
|
return className;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseColor(color: string) {
|
||||||
|
try {
|
||||||
|
return Color(color);
|
||||||
|
} catch (ex) {
|
||||||
|
console.error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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: ColorInstance, lightThemeMaxLightness: number, darkThemeMinLightness: number) {
|
||||||
|
const labColor = color.lab();
|
||||||
|
const lightness = labColor.l();
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
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: 37, l: 89, alpha: 1}).hexa();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {lightThemeColor, lightThemeBackgroundColor, darkThemeColor, darkThemeBackgroundColor};
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
createClassForColor
|
createClassForColor
|
||||||
};
|
};
|
||||||
|
|||||||
@ -82,6 +82,11 @@ body ::-webkit-calendar-picker-indicator {
|
|||||||
filter: invert(1);
|
filter: invert(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#left-pane span.fancytree-node {
|
||||||
|
--custom-color: var(--dark-theme-custom-color);
|
||||||
|
--custom-bg-color: var(--dark-theme-custom-bg-color);
|
||||||
|
}
|
||||||
|
|
||||||
.excalidraw.theme--dark {
|
.excalidraw.theme--dark {
|
||||||
--theme-filter: invert(80%) hue-rotate(180deg) !important;
|
--theme-filter: invert(80%) hue-rotate(180deg) !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -81,3 +81,8 @@ html {
|
|||||||
--mermaid-theme: default;
|
--mermaid-theme: default;
|
||||||
--native-titlebar-background: #ffffff00;
|
--native-titlebar-background: #ffffff00;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#left-pane span.fancytree-node {
|
||||||
|
--custom-color: var(--light-theme-custom-color);
|
||||||
|
--custom-bg-color: var(--light-theme-custom-bg-color);
|
||||||
|
}
|
||||||
@ -268,6 +268,11 @@
|
|||||||
* Dark color scheme tweaks
|
* Dark color scheme tweaks
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#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 {
|
body ::-webkit-calendar-picker-indicator {
|
||||||
filter: invert(1);
|
filter: invert(1);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -82,6 +82,20 @@
|
|||||||
|
|
||||||
/* Theme capabilities */
|
/* Theme capabilities */
|
||||||
--tab-note-icons: true;
|
--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 perceptual lightness for the custom color in the light theme (%): */
|
||||||
|
--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: 65;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.backdrop-effects-disabled {
|
body.backdrop-effects-disabled {
|
||||||
|
|||||||
@ -639,7 +639,7 @@ body.layout-vertical.background-effects div.quick-search .dropdown-menu {
|
|||||||
#left-pane span.fancytree-node.fancytree-active {
|
#left-pane span.fancytree-node.fancytree-active {
|
||||||
position: relative;
|
position: relative;
|
||||||
background: transparent !important;
|
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 {
|
@keyframes left-pane-item-select {
|
||||||
@ -658,7 +658,7 @@ body.layout-vertical.background-effects div.quick-search .dropdown-menu {
|
|||||||
inset-inline-start: var(--left-pane-item-selected-shadow-size);
|
inset-inline-start: var(--left-pane-item-selected-shadow-size);
|
||||||
bottom: 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);
|
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);
|
box-shadow: var(--left-pane-item-selected-shadow);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
animation: left-pane-item-select 200ms ease-out;
|
animation: left-pane-item-select 200ms ease-out;
|
||||||
|
|||||||
@ -40,6 +40,7 @@ span.fancytree-node.fancytree-hide {
|
|||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
user-select: none !important;
|
user-select: none !important;
|
||||||
-webkit-user-select: none !important;
|
-webkit-user-select: none !important;
|
||||||
|
color: var(--custom-color, inherit);
|
||||||
}
|
}
|
||||||
|
|
||||||
.fancytree-node:not(.fancytree-loading) .fancytree-expander {
|
.fancytree-node:not(.fancytree-loading) .fancytree-expander {
|
||||||
|
|||||||
45
apps/client/src/utils/css-var.ts
Normal file
45
apps/client/src/utils/css-var.ts
Normal file
@ -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 = parseFloat(this.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (!isNaN(number.valueOf()) ? number.valueOf() : defaultValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
asEnum<T>(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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
30
pnpm-lock.yaml
generated
30
pnpm-lock.yaml
generated
@ -184,6 +184,9 @@ importers:
|
|||||||
boxicons:
|
boxicons:
|
||||||
specifier: 2.1.4
|
specifier: 2.1.4
|
||||||
version: 2.1.4
|
version: 2.1.4
|
||||||
|
color:
|
||||||
|
specifier: 5.0.2
|
||||||
|
version: 5.0.2
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: 1.11.18
|
specifier: 1.11.18
|
||||||
version: 1.11.18
|
version: 1.11.18
|
||||||
@ -6328,10 +6331,18 @@ packages:
|
|||||||
color-parse@2.0.2:
|
color-parse@2.0.2:
|
||||||
resolution: {integrity: sha512-eCtOz5w5ttWIUcaKLiktF+DxZO1R9KLNY/xhbV6CkhM7sR3GhVghmt6X6yOnzeaM24po+Z9/S1apbXMwA3Iepw==}
|
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:
|
color-support@1.1.3:
|
||||||
resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==}
|
resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
color@5.0.2:
|
||||||
|
resolution: {integrity: sha512-e2hz5BzbUPcYlIRHo8ieAhYgoajrJr+hWoceg6E345TPsATMUKqDgzt8fSXZJJbxfpiPzkWyphz8yn8At7q3fA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
colord@2.9.3:
|
colord@2.9.3:
|
||||||
resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==}
|
resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==}
|
||||||
|
|
||||||
@ -14681,8 +14692,6 @@ snapshots:
|
|||||||
'@ckeditor/ckeditor5-core': 47.1.0
|
'@ckeditor/ckeditor5-core': 47.1.0
|
||||||
'@ckeditor/ckeditor5-upload': 47.1.0
|
'@ckeditor/ckeditor5-upload': 47.1.0
|
||||||
ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41)
|
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)':
|
'@ckeditor/ckeditor5-ai@47.1.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)':
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -15083,6 +15092,8 @@ snapshots:
|
|||||||
'@ckeditor/ckeditor5-utils': 47.1.0
|
'@ckeditor/ckeditor5-utils': 47.1.0
|
||||||
ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41)
|
ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41)
|
||||||
es-toolkit: 1.39.5
|
es-toolkit: 1.39.5
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
'@ckeditor/ckeditor5-editor-multi-root@47.1.0':
|
'@ckeditor/ckeditor5-editor-multi-root@47.1.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -15252,8 +15263,6 @@ snapshots:
|
|||||||
'@ckeditor/ckeditor5-utils': 47.1.0
|
'@ckeditor/ckeditor5-utils': 47.1.0
|
||||||
'@ckeditor/ckeditor5-widget': 47.1.0
|
'@ckeditor/ckeditor5-widget': 47.1.0
|
||||||
ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41)
|
ckeditor5: 47.1.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41)
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
|
|
||||||
'@ckeditor/ckeditor5-html-embed@47.1.0':
|
'@ckeditor/ckeditor5-html-embed@47.1.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -16338,7 +16347,7 @@ snapshots:
|
|||||||
make-fetch-happen: 10.2.1
|
make-fetch-happen: 10.2.1
|
||||||
nopt: 6.0.0
|
nopt: 6.0.0
|
||||||
proc-log: 2.0.1
|
proc-log: 2.0.1
|
||||||
semver: 7.7.2
|
semver: 7.7.3
|
||||||
tar: 6.2.1
|
tar: 6.2.1
|
||||||
which: 2.0.2
|
which: 2.0.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@ -17685,7 +17694,7 @@ snapshots:
|
|||||||
'@npmcli/fs@2.1.2':
|
'@npmcli/fs@2.1.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@gar/promisify': 1.1.3
|
'@gar/promisify': 1.1.3
|
||||||
semver: 7.7.2
|
semver: 7.7.3
|
||||||
|
|
||||||
'@npmcli/fs@4.0.0':
|
'@npmcli/fs@4.0.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -21148,9 +21157,18 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
color-name: 2.0.0
|
color-name: 2.0.0
|
||||||
|
|
||||||
|
color-string@2.1.2:
|
||||||
|
dependencies:
|
||||||
|
color-name: 2.0.0
|
||||||
|
|
||||||
color-support@1.1.3:
|
color-support@1.1.3:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
color@5.0.2:
|
||||||
|
dependencies:
|
||||||
|
color-convert: 3.1.0
|
||||||
|
color-string: 2.1.2
|
||||||
|
|
||||||
colord@2.9.3: {}
|
colord@2.9.3: {}
|
||||||
|
|
||||||
colorette@2.0.20: {}
|
colorette@2.0.20: {}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user