From 07f273fda40b138c0262d8c1aea172948af62855 Mon Sep 17 00:00:00 2001 From: Wael Nasreddine Date: Sat, 31 Jan 2026 01:00:57 -0800 Subject: [PATCH 001/247] feat: enhance build-docs utility with pnpm and Nix support This enhances the `build-docs` utility to allow running it via pnpm and packaging it as a Nix application. Changes include: - Added `build` and `cli` scripts to `apps/build-docs/package.json`. - Implemented a standalone CLI wrapper for documentation generation. - Added a `trilium-build-docs` package to the Nix flake for use in other projects. - Integrated `apps/build-docs` into the Nix workspace and build pipeline. These changes make the documentation build process more portable and easier to integrate into CI/CD pipelines outside of the main repository. --- apps/build-docs/package.json | 10 +- apps/build-docs/scripts/build.ts | 23 +++ .../src/backend_script_entrypoint.ts | 11 +- apps/build-docs/src/build-docs.ts | 189 +++++++++++++++--- apps/build-docs/src/cli.ts | 89 +++++++++ .../src/frontend_script_entrypoint.ts | 9 +- apps/build-docs/src/main.ts | 7 +- apps/build-docs/src/script-api.ts | 3 +- apps/build-docs/src/swagger.ts | 10 +- apps/build-docs/tsconfig.json | 4 +- apps/build-docs/typedoc.backend.json | 1 + apps/build-docs/typedoc.frontend.json | 1 + apps/server/src/services/export/zip.ts | 4 +- apps/server/src/services/utils.ts | 11 +- flake.nix | 42 +++- pnpm-lock.yaml | 6 +- 16 files changed, 365 insertions(+), 55 deletions(-) create mode 100644 apps/build-docs/scripts/build.ts create mode 100644 apps/build-docs/src/cli.ts diff --git a/apps/build-docs/package.json b/apps/build-docs/package.json index ac5be7e9be..e8934b71ec 100644 --- a/apps/build-docs/package.json +++ b/apps/build-docs/package.json @@ -1,10 +1,15 @@ { "name": "build-docs", "version": "1.0.0", - "description": "", + "description": "Build documentation from Trilium notes", "main": "src/main.ts", + "bin": { + "trilium-build-docs": "dist/cli.js" + }, "scripts": { - "start": "tsx ." + "start": "tsx .", + "cli": "tsx src/cli.ts", + "build": "tsx scripts/build.ts" }, "keywords": [], "author": "Elian Doran ", @@ -14,6 +19,7 @@ "@redocly/cli": "2.15.0", "archiver": "7.0.1", "fs-extra": "11.3.3", + "js-yaml": "4.1.1", "react": "19.2.4", "react-dom": "19.2.4", "typedoc": "0.28.16", diff --git a/apps/build-docs/scripts/build.ts b/apps/build-docs/scripts/build.ts new file mode 100644 index 0000000000..79fa01f3f6 --- /dev/null +++ b/apps/build-docs/scripts/build.ts @@ -0,0 +1,23 @@ +import BuildHelper from "../../../scripts/build-utils"; + +const build = new BuildHelper("apps/build-docs"); + +async function main() { + // Build the CLI and other TypeScript files + await build.buildBackend([ + "src/cli.ts", + "src/main.ts", + "src/build-docs.ts", + "src/swagger.ts", + "src/script-api.ts", + "src/context.ts" + ]); + + // Copy HTML template + build.copy("src/index.html", "index.html"); + + // Copy node modules dependencies if needed + build.copyNodeModules([ "better-sqlite3", "bindings", "file-uri-to-path" ]); +} + +main(); diff --git a/apps/build-docs/src/backend_script_entrypoint.ts b/apps/build-docs/src/backend_script_entrypoint.ts index bc9087c0c1..0447900b6b 100644 --- a/apps/build-docs/src/backend_script_entrypoint.ts +++ b/apps/build-docs/src/backend_script_entrypoint.ts @@ -13,8 +13,12 @@ * Make sure to keep in line with backend's `script_context.ts`. */ -export type { default as AbstractBeccaEntity } from "../../server/src/becca/entities/abstract_becca_entity.js"; -export type { default as BAttachment } from "../../server/src/becca/entities/battachment.js"; +export type { + default as AbstractBeccaEntity +} from "../../server/src/becca/entities/abstract_becca_entity.js"; +export type { + default as BAttachment +} from "../../server/src/becca/entities/battachment.js"; export type { default as BAttribute } from "../../server/src/becca/entities/battribute.js"; export type { default as BBranch } from "../../server/src/becca/entities/bbranch.js"; export type { default as BEtapiToken } from "../../server/src/becca/entities/betapi_token.js"; @@ -31,6 +35,7 @@ export type { Api }; const fakeNote = new BNote(); /** - * The `api` global variable allows access to the backend script API, which is documented in {@link Api}. + * The `api` global variable allows access to the backend script API, + * which is documented in {@link Api}. */ export const api: Api = new BackendScriptApi(fakeNote, {}); diff --git a/apps/build-docs/src/build-docs.ts b/apps/build-docs/src/build-docs.ts index 5d1a0cdd6f..357ecb1d41 100644 --- a/apps/build-docs/src/build-docs.ts +++ b/apps/build-docs/src/build-docs.ts @@ -1,19 +1,90 @@ process.env.TRILIUM_INTEGRATION_TEST = "memory-no-store"; -process.env.TRILIUM_RESOURCE_DIR = "../server/src"; +// Only set TRILIUM_RESOURCE_DIR if not already set (e.g., by Nix wrapper) +if (!process.env.TRILIUM_RESOURCE_DIR) { + process.env.TRILIUM_RESOURCE_DIR = "../server/src"; +} process.env.NODE_ENV = "development"; import cls from "@triliumnext/server/src/services/cls.js"; -import { dirname, join, resolve } from "path"; +import archiver from "archiver"; +import { execSync } from "child_process"; +import { WriteStream } from "fs"; import * as fs from "fs/promises"; import * as fsExtra from "fs-extra"; -import archiver from "archiver"; -import { WriteStream } from "fs"; -import { execSync } from "child_process"; +import yaml from "js-yaml"; +import { dirname, join, resolve } from "path"; + import BuildContext from "./context.js"; +interface NoteMapping { + rootNoteId: string; + path: string; + format: "markdown" | "html" | "share"; + ignoredFiles?: string[]; + exportOnly?: boolean; +} + +interface Config { + baseUrl: string; + noteMappings: NoteMapping[]; +} + const DOCS_ROOT = "../../../docs"; const OUTPUT_DIR = "../../site"; +// Load configuration from edit-docs-config.yaml +async function loadConfig(configPath?: string): Promise { + const pathsToTry = configPath + ? [resolve(configPath)] + : [ + join(process.cwd(), "edit-docs-config.yaml"), + join(__dirname, "../../../edit-docs-config.yaml") + ]; + + for (const path of pathsToTry) { + try { + const configContent = await fs.readFile(path, "utf-8"); + const config = yaml.load(configContent) as Config; + + // Resolve all paths relative to the config file's directory + const CONFIG_DIR = dirname(path); + config.noteMappings = config.noteMappings.map((mapping) => ({ + ...mapping, + path: resolve(CONFIG_DIR, mapping.path) + })); + + return config; + } catch (error) { + if (error.code !== "ENOENT") { + throw error; // rethrow unexpected errors + } + } + } + + return null; // No config file found +} + +async function exportDocs( + noteId: string, + format: "markdown" | "html" | "share", + outputPath: string, + ignoredFiles?: string[] +) { + const zipFilePath = `output-${noteId}.zip`; + try { + const { exportToZipFile } = (await import("@triliumnext/server/src/services/export/zip.js")) + .default; + await exportToZipFile(noteId, format, zipFilePath, {}); + + const ignoredSet = ignoredFiles ? new Set(ignoredFiles) : undefined; + await extractZip(zipFilePath, outputPath, ignoredSet); + } finally { + if (await fsExtra.exists(zipFilePath)) { + await fsExtra.rm(zipFilePath); + } + } +} + async function importAndExportDocs(sourcePath: string, outputSubDir: string) { const note = await importData(sourcePath); @@ -21,15 +92,18 @@ async function importAndExportDocs(sourcePath: string, outputSubDir: string) { const zipName = outputSubDir || "user-guide"; const zipFilePath = `output-${zipName}.zip`; try { - const { exportToZip } = (await import("@triliumnext/server/src/services/export/zip.js")).default; + const { exportToZip } = (await import("@triliumnext/server/src/services/export/zip.js")) + .default; const branch = note.getParentBranches()[0]; - const taskContext = new (await import("@triliumnext/server/src/services/task_context.js")).default( - "no-progress-reporting", - "export", - null - ); + const taskContext = new (await import("@triliumnext/server/src/services/task_context.js")) + .default( + "no-progress-reporting", + "export", + null + ); const fileOutputStream = fsExtra.createWriteStream(zipFilePath); await exportToZip(taskContext, branch, "share", fileOutputStream); + const { waitForStreamToFinish } = await import("@triliumnext/server/src/services/utils.js"); await waitForStreamToFinish(fileOutputStream); // Output to root directory if outputSubDir is empty, otherwise to subdirectory @@ -42,7 +116,7 @@ async function importAndExportDocs(sourcePath: string, outputSubDir: string) { } } -async function buildDocsInner() { +async function buildDocsInner(config?: Config) { const i18n = await import("@triliumnext/server/src/services/i18n.js"); await i18n.initializeTranslations(); @@ -53,18 +127,49 @@ async function buildDocsInner() { const beccaLoader = await import("../../server/src/becca/becca_loader.js"); await beccaLoader.beccaLoaded; - // Build User Guide - console.log("Building User Guide..."); - await importAndExportDocs(join(__dirname, DOCS_ROOT, "User Guide"), "user-guide"); + if (config) { + // Config-based build (reads from edit-docs-config.yaml) + console.log("Building documentation from config file..."); - // Build Developer Guide - console.log("Building Developer Guide..."); - await importAndExportDocs(join(__dirname, DOCS_ROOT, "Developer Guide"), "developer-guide"); + // Import all non-export-only mappings + for (const mapping of config.noteMappings) { + if (!mapping.exportOnly) { + console.log(`Importing from ${mapping.path}...`); + await importData(mapping.path); + } + } - // Copy favicon. - await fs.copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "favicon.ico")); - await fs.copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "user-guide", "favicon.ico")); - await fs.copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "developer-guide", "favicon.ico")); + // Export all mappings + for (const mapping of config.noteMappings) { + if (mapping.exportOnly) { + console.log(`Exporting ${mapping.format} to ${mapping.path}...`); + await exportDocs( + mapping.rootNoteId, + mapping.format, + mapping.path, + mapping.ignoredFiles + ); + } + } + } else { + // Legacy hardcoded build (for backward compatibility) + console.log("Building User Guide..."); + await importAndExportDocs(join(__dirname, DOCS_ROOT, "User Guide"), "user-guide"); + + console.log("Building Developer Guide..."); + await importAndExportDocs( + join(__dirname, DOCS_ROOT, "Developer Guide"), + "developer-guide" + ); + + // Copy favicon. + await fs.copyFile("../../apps/website/src/assets/favicon.ico", + join(OUTPUT_DIR, "favicon.ico")); + await fs.copyFile("../../apps/website/src/assets/favicon.ico", + join(OUTPUT_DIR, "user-guide", "favicon.ico")); + await fs.copyFile("../../apps/website/src/assets/favicon.ico", + join(OUTPUT_DIR, "developer-guide", "favicon.ico")); + } console.log("Documentation built successfully!"); } @@ -91,12 +196,13 @@ async function createImportZip(path: string) { zlib: { level: 0 } }); - console.log("Archive path is ", resolve(path)) + console.log("Archive path is ", resolve(path)); archive.directory(path, "/"); const outputStream = fsExtra.createWriteStream(inputFile); archive.pipe(outputStream); archive.finalize(); + const { waitForStreamToFinish } = await import("@triliumnext/server/src/services/utils.js"); await waitForStreamToFinish(outputStream); try { @@ -106,15 +212,15 @@ async function createImportZip(path: string) { } } -function waitForStreamToFinish(stream: WriteStream) { - return new Promise((res, rej) => { - stream.on("finish", () => res()); - stream.on("error", (err) => rej(err)); - }); -} -export async function extractZip(zipFilePath: string, outputPath: string, ignoredFiles?: Set) { - const { readZipFile, readContent } = (await import("@triliumnext/server/src/services/import/zip.js")); +export async function extractZip( + zipFilePath: string, + outputPath: string, + ignoredFiles?: Set +) { + const { readZipFile, readContent } = (await import( + "@triliumnext/server/src/services/import/zip.js" + )); await readZipFile(await fs.readFile(zipFilePath), async (zip, entry) => { // We ignore directories since they can appear out of order anyway. if (!entry.fileName.endsWith("/") && !ignoredFiles?.has(entry.fileName)) { @@ -129,6 +235,27 @@ export async function extractZip(zipFilePath: string, outputPath: string, ignore }); } +export async function buildDocsFromConfig(configPath?: string, gitRootDir?: string) { + const config = await loadConfig(configPath); + + if (gitRootDir) { + // Build the share theme if we have a gitRootDir (for Trilium project) + execSync(`pnpm run --filter share-theme build`, { + stdio: "inherit", + cwd: gitRootDir + }); + } + + // Trigger the actual build. + await new Promise((res, rej) => { + cls.init(() => { + buildDocsInner(config ?? undefined) + .catch(rej) + .then(res); + }); + }); +} + export default async function buildDocs({ gitRootDir }: BuildContext) { // Build the share theme. execSync(`pnpm run --filter share-theme build`, { diff --git a/apps/build-docs/src/cli.ts b/apps/build-docs/src/cli.ts new file mode 100644 index 0000000000..8aee089701 --- /dev/null +++ b/apps/build-docs/src/cli.ts @@ -0,0 +1,89 @@ +#!/usr/bin/env node + +import packageJson from "../package.json" with { type: "json" }; +import { buildDocsFromConfig } from "./build-docs.js"; + +// Parse command-line arguments +function parseArgs() { + const args = process.argv.slice(2); + let configPath: string | undefined; + let showHelp = false; + let showVersion = false; + + for (let i = 0; i < args.length; i++) { + if (args[i] === "--config" || args[i] === "-c") { + configPath = args[i + 1]; + if (!configPath) { + console.error("Error: --config/-c requires a path argument"); + process.exit(1); + } + i++; // Skip the next argument as it's the value + } else if (args[i] === "--help" || args[i] === "-h") { + showHelp = true; + } else if (args[i] === "--version" || args[i] === "-v") { + showVersion = true; + } + } + + return { configPath, showHelp, showVersion }; +} + +function getVersion(): string { + return packageJson.version; +} + +function printHelp() { + const version = getVersion(); + console.log(` +Usage: trilium-build-docs [options] + +Options: + -c, --config Path to the configuration file + (default: edit-docs-config.yaml in current directory) + -h, --help Display this help message + -v, --version Display version information + +Description: + Builds documentation from Trilium note structure and exports to various formats. + Configuration file should be in YAML format with the following structure: + + baseUrl: "https://example.com" + noteMappings: + - rootNoteId: "noteId123" + path: "docs" + format: "markdown" + - rootNoteId: "noteId456" + path: "public/docs" + format: "share" + exportOnly: true + +Version: ${version} +`); +} + +function printVersion() { + const version = getVersion(); + console.log(version); +} + +async function main() { + const { configPath, showHelp, showVersion } = parseArgs(); + + if (showHelp) { + printHelp(); + process.exit(0); + } else if (showVersion) { + printVersion(); + process.exit(0); + } + + try { + await buildDocsFromConfig(configPath); + process.exit(0); + } catch (error) { + console.error("Error building documentation:", error); + process.exit(1); + } +} + +main(); diff --git a/apps/build-docs/src/frontend_script_entrypoint.ts b/apps/build-docs/src/frontend_script_entrypoint.ts index 768774eca6..7aba11b2a4 100644 --- a/apps/build-docs/src/frontend_script_entrypoint.ts +++ b/apps/build-docs/src/frontend_script_entrypoint.ts @@ -13,16 +13,19 @@ * Make sure to keep in line with frontend's `script_context.ts`. */ -export type { default as BasicWidget } from "../../client/src/widgets/basic_widget.js"; export type { default as FAttachment } from "../../client/src/entities/fattachment.js"; export type { default as FAttribute } from "../../client/src/entities/fattribute.js"; export type { default as FBranch } from "../../client/src/entities/fbranch.js"; export type { default as FNote } from "../../client/src/entities/fnote.js"; export type { Api } from "../../client/src/services/frontend_script_api.js"; -export type { default as NoteContextAwareWidget } from "../../client/src/widgets/note_context_aware_widget.js"; +export type { default as BasicWidget } from "../../client/src/widgets/basic_widget.js"; +export type { + default as NoteContextAwareWidget +} from "../../client/src/widgets/note_context_aware_widget.js"; export type { default as RightPanelWidget } from "../../client/src/widgets/right_panel_widget.js"; import FrontendScriptApi, { type Api } from "../../client/src/services/frontend_script_api.js"; -//@ts-expect-error + +// @ts-expect-error - FrontendScriptApi is not directly exportable as Api without this simulation. export const api: Api = new FrontendScriptApi(); diff --git a/apps/build-docs/src/main.ts b/apps/build-docs/src/main.ts index d94ada167b..cca17125d8 100644 --- a/apps/build-docs/src/main.ts +++ b/apps/build-docs/src/main.ts @@ -1,9 +1,10 @@ -import { join } from "path"; -import BuildContext from "./context"; -import buildSwagger from "./swagger"; import { cpSync, existsSync, mkdirSync, rmSync } from "fs"; +import { join } from "path"; + import buildDocs from "./build-docs"; +import BuildContext from "./context"; import buildScriptApi from "./script-api"; +import buildSwagger from "./swagger"; const context: BuildContext = { gitRootDir: join(__dirname, "../../../"), diff --git a/apps/build-docs/src/script-api.ts b/apps/build-docs/src/script-api.ts index 8473ae3a02..2c62477474 100644 --- a/apps/build-docs/src/script-api.ts +++ b/apps/build-docs/src/script-api.ts @@ -1,7 +1,8 @@ import { execSync } from "child_process"; -import BuildContext from "./context"; import { join } from "path"; +import BuildContext from "./context"; + export default function buildScriptApi({ baseDir, gitRootDir }: BuildContext) { // Generate types execSync(`pnpm typecheck`, { stdio: "inherit", cwd: gitRootDir }); diff --git a/apps/build-docs/src/swagger.ts b/apps/build-docs/src/swagger.ts index b3677aeebe..2af458ec47 100644 --- a/apps/build-docs/src/swagger.ts +++ b/apps/build-docs/src/swagger.ts @@ -1,7 +1,8 @@ -import BuildContext from "./context"; -import { join } from "path"; import { execSync } from "child_process"; import { mkdirSync } from "fs"; +import { join } from "path"; + +import BuildContext from "./context"; interface BuildInfo { specPath: string; @@ -27,6 +28,9 @@ export default function buildSwagger({ baseDir, gitRootDir }: BuildContext) { const absSpecPath = join(gitRootDir, specPath); const targetDir = join(baseDir, outDir); mkdirSync(targetDir, { recursive: true }); - execSync(`pnpm redocly build-docs ${absSpecPath} -o ${targetDir}/index.html`, { stdio: "inherit" }); + execSync( + `pnpm redocly build-docs ${absSpecPath} -o ${targetDir}/index.html`, + { stdio: "inherit" } + ); } } diff --git a/apps/build-docs/tsconfig.json b/apps/build-docs/tsconfig.json index 858921cfb6..99c9b71b37 100644 --- a/apps/build-docs/tsconfig.json +++ b/apps/build-docs/tsconfig.json @@ -1,6 +1,8 @@ { "extends": "../../tsconfig.base.json", - "include": [], + "include": [ + "scripts/**/*.ts" + ], "references": [ { "path": "../server" diff --git a/apps/build-docs/typedoc.backend.json b/apps/build-docs/typedoc.backend.json index 1781774c6f..a7f91c42e4 100644 --- a/apps/build-docs/typedoc.backend.json +++ b/apps/build-docs/typedoc.backend.json @@ -4,6 +4,7 @@ "entryPoints": [ "src/backend_script_entrypoint.ts" ], + "tsconfig": "tsconfig.app.json", "plugin": [ "typedoc-plugin-missing-exports" ] diff --git a/apps/build-docs/typedoc.frontend.json b/apps/build-docs/typedoc.frontend.json index f07d20dc71..c462004712 100644 --- a/apps/build-docs/typedoc.frontend.json +++ b/apps/build-docs/typedoc.frontend.json @@ -4,6 +4,7 @@ "entryPoints": [ "src/frontend_script_entrypoint.ts" ], + "tsconfig": "tsconfig.app.json", "plugin": [ "typedoc-plugin-missing-exports" ] diff --git a/apps/server/src/services/export/zip.ts b/apps/server/src/services/export/zip.ts index 4a9f140411..a6cd5b59c3 100644 --- a/apps/server/src/services/export/zip.ts +++ b/apps/server/src/services/export/zip.ts @@ -3,7 +3,7 @@ import dateUtils from "../date_utils.js"; import path from "path"; import packageInfo from "../../../package.json" with { type: "json" }; -import { getContentDisposition } from "../utils.js"; +import { getContentDisposition, waitForStreamToFinish } from "../utils.js"; import protectedSessionService from "../protected_session.js"; import sanitize from "sanitize-filename"; import fs from "fs"; @@ -468,6 +468,7 @@ async function exportToZip(taskContext: TaskContext<"export">, branch: BBranch, taskContext.taskSucceeded(null); } + async function exportToZipFile(noteId: string, format: ExportFormat, zipFilePath: string, zipExportOptions?: AdvancedExportOptions) { const fileOutputStream = fs.createWriteStream(zipFilePath); const taskContext = new TaskContext("no-progress-reporting", "export", null); @@ -479,6 +480,7 @@ async function exportToZipFile(noteId: string, format: ExportFormat, zipFilePath } await exportToZip(taskContext, note.getParentBranches()[0], format, fileOutputStream, false, zipExportOptions); + await waitForStreamToFinish(fileOutputStream); log.info(`Exported '${noteId}' with format '${format}' to '${zipFilePath}'`); } diff --git a/apps/server/src/services/utils.ts b/apps/server/src/services/utils.ts index a97b84a6c7..a2b707edf9 100644 --- a/apps/server/src/services/utils.ts +++ b/apps/server/src/services/utils.ts @@ -1,5 +1,4 @@ - import chardet from "chardet"; import crypto from "crypto"; import escape from "escape-html"; @@ -516,6 +515,13 @@ function slugify(text: string) { .replace(/(^-|-$)+/g, ""); // trim dashes } +export function waitForStreamToFinish(stream: any): Promise { + return new Promise((resolve, reject) => { + stream.on("finish", () => resolve()); + stream.on("error", (err) => reject(err)); + }); +} + export default { compareVersions, constantTimeCompare, @@ -556,5 +562,6 @@ export default { toBase64, toMap, toObject, - unescapeHtml + unescapeHtml, + waitForStreamToFinish }; diff --git a/flake.nix b/flake.nix index 23a7a38cf4..69a0482b8c 100644 --- a/flake.nix +++ b/flake.nix @@ -113,7 +113,7 @@ [ moreutils # sponge nodejs.python - removeReferencesTo + removeReferencesTo ] ++ lib.optionals (app == "desktop" || app == "edit-docs") [ copyDesktopItems @@ -126,7 +126,7 @@ which electron ] - ++ lib.optionals (app == "server") [ + ++ lib.optionals (app == "server" || app == "build-docs") [ makeBinaryWrapper ] ++ lib.optionals stdenv.hostPlatform.isDarwin [ @@ -153,7 +153,7 @@ # This file is a symlink into /build which is not allowed. postFixup = '' - rm $out/opt/trilium*/node_modules/better-sqlite3/node_modules/.bin/prebuild-install || true + find $out/opt -name prebuild-install -path "*/better-sqlite3/node_modules/.bin/*" -delete || true ''; components = [ @@ -169,6 +169,7 @@ "packages/highlightjs" "packages/turndown-plugin-gfm" + "apps/build-docs" "apps/client" "apps/db-compare" "apps/desktop" @@ -277,11 +278,46 @@ ''; }; + build-docs = makeApp { + app = "build-docs"; + preBuildCommands = '' + pushd apps/server + pnpm rebuild || true + popd + ''; + buildTask = "client:build && pnpm run server:build && pnpm run --filter build-docs build"; + mainProgram = "trilium-build-docs"; + installCommands = '' + mkdir -p $out/{bin,opt/trilium-build-docs} + + # Copy build-docs dist + cp --archive apps/build-docs/dist/* $out/opt/trilium-build-docs + + # Copy server dist (needed for runtime) + mkdir -p $out/opt/trilium-build-docs/server + cp --archive apps/server/dist/* $out/opt/trilium-build-docs/server/ + + # Copy client dist (needed for runtime) + mkdir -p $out/opt/trilium-build-docs/client + cp --archive apps/client/dist/* $out/opt/trilium-build-docs/client/ + + # Copy share-theme (needed for exports) + mkdir -p $out/opt/trilium-build-docs/packages/share-theme + cp --archive packages/share-theme/dist/* $out/opt/trilium-build-docs/packages/share-theme/ + + # Create wrapper script + makeWrapper ${lib.getExe nodejs} $out/bin/trilium-build-docs \ + --add-flags $out/opt/trilium-build-docs/cli.cjs \ + --set TRILIUM_RESOURCE_DIR $out/opt/trilium-build-docs/server + ''; + }; + in { packages.desktop = desktop; packages.server = server; packages.edit-docs = edit-docs; + packages.build-docs = build-docs; packages.default = desktop; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3e48992b05..f584515033 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -164,6 +164,9 @@ importers: fs-extra: specifier: 11.3.3 version: 11.3.3 + js-yaml: + specifier: 4.1.1 + version: 4.1.1 react: specifier: 19.2.4 version: 19.2.4 @@ -16544,8 +16547,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-markdown-gfm@47.4.0': dependencies: @@ -16954,6 +16955,7 @@ snapshots: ckeditor5: 47.4.0 transitivePeerDependencies: - bufferutil + - supports-color - utf-8-validate '@ckeditor/ckeditor5-utils@47.4.0': From 3742cd4a51c26c197dd0603dd646f20174a00678 Mon Sep 17 00:00:00 2001 From: hulmgulm Date: Sun, 8 Feb 2026 10:29:43 +0100 Subject: [PATCH 002/247] doc: enhanced icon pack creation --- .../Themes/Icon Packs.html | 7 +- .../Creating an icon pack.html | 263 ++++++++++-------- .../Developer Guide/Documentation.md | 2 +- docs/User Guide/!!!meta.json | 4 +- .../Creating an icon pack.md | 120 ++++---- 5 files changed, 219 insertions(+), 177 deletions(-) diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Themes/Icon Packs.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Themes/Icon Packs.html index 5d41a23941..fa8837c3ac 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Themes/Icon Packs.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Themes/Icon Packs.html @@ -26,10 +26,9 @@
  • Ideally, create a dedicated spot in your note tree where to place the icon packs.
  • Right click the note where to put it and select Import into note.
  • -
  • Uncheck Safe import.
  • -
  • Select Import.
  • -
  • Refresh the application.
  • +
  • Uncheck Safe import.
  • +
  • Select Import.
  • +
  • Refresh the application.
  • -

    Creating the icon pack

    +

    Assigning the prefix

    +

    Before an icon pack can be used, it needs to have a prefix defined. This + prefix uniquely identifies the icon pack so that it can be used throughout + the application.

    +

    To do so, Trilium makes use of the same format that was used for the internal + icon pack (Boxicons). For example, when an icon from Boxicons is set, it + looks like this: #iconClass="bx bxs-sushi". + In this case, the icon pack prefix is bx and + the icon class name is bxs-sushi.

    +

    In order for an icon pack to be recognized, the prefix must be specified + in the #iconPack label. 

    +

    For our example with Phosphor Icons, we can use the ph prefix + since it also matches the prefix set in the original CSS. So in this case + it would be #iconPack=ph.

    + +

    Creating the Trilium icon pack note

    1. Create a note of type Code.
    2. Set the language to JSON.
    3. +
    4. Rename the note. The name of the note will also be the name of the icon + pack as displayed in the list of icons.
    5. Copy and paste the manifest generated in the previous step as the content of this note.
    6. Go to the note attachment and upload the @@ -181,28 +229,9 @@ console.log(processIconPack("light")); much reason to upload more than one font per icon pack.
    -
  • Go back to the note and rename it. The name of the note will also be the - name of the icon pack as displayed in the list of icons.
  • +
  • Add label: #iconPack=<prefix> (for + Phosphor example: #iconPack=ph).
  • -

    Assigning the prefix

    -

    Before an icon pack can be used, it needs to have a prefix defined. This - prefix uniquely identifies the icon pack so that it can be used throughout - the application.

    -

    To do so, Trilium makes use of the same format that was used for the internal - icon pack (Boxicons). For example, when an icon from Boxicons is set, it - looks like this: #iconClass="bx bxs-sushi". - In this case, the icon pack prefix is bx and - the icon class name is bxs-sushi.

    -

    In order for an icon pack to be recognized, the prefix must be specified - in the #iconPack label. 

    -

    For our example with Phosphor Icons, we can use the ph prefix - since it also matches the prefix set in the original CSS. So in this case - it would be #iconPack=ph.

    -

    Final steps

    • Refresh the client @@ -217,24 +246,26 @@ console.log(processIconPack("light"));
    • Optionally, assign an icon from the new icon pack to this note. This icon will be used in the icon pack filter for a visual distinction.
    • -
    • The icon pack can then be exported as ZIP in +
    • The icon pack can then be exported as ZIP in order to be distributed to other users.
      • It's important to note that icon packs are considered “unsafe” by default, so “Safe mode” must be disabled when importing the ZIP.
      • -
      • Consider linking new users to the Icon Packs documentation +
      • Consider linking new users to the [missing note] documentation in order to understand how to import and use an icon pack.
      -
    • +

    Troubleshooting

    If the icon pack doesn't show up, look through the Backend (server) logs for clues.

    + href="#root/_help_bnyigUA2UK7s">[missing note] for clues.

    • One example is if the font could not be retrieved: ERROR: Icon pack is missing WOFF/WOFF2/TTF attachment: Boxicons v3 400 (dup) (XRzqDQ67fHEK).
    • -
    • Make sure the prefix is unique and not already taken by some other icon +
    • Make sure the prefix is unique and not already taken by some other icon pack. When there are two icon packs with the same prefix, only one is used. The server logs will indicate if this situation occurs.
    • -
    • Make sure the prefix consists only of alphanumeric characters, hyphens - and underscore.
    • +
    • Make sure the prefix consists only of alphanumeric characters, hyphens + and underscore.
    \ No newline at end of file diff --git a/docs/Developer Guide/Developer Guide/Documentation.md b/docs/Developer Guide/Developer Guide/Documentation.md index 8b43e75bd5..f2f92cc5c2 100644 --- a/docs/Developer Guide/Developer Guide/Documentation.md +++ b/docs/Developer Guide/Developer Guide/Documentation.md @@ -1,5 +1,5 @@ # Documentation -There are multiple types of documentation for Trilium: +There are multiple types of documentation for Trilium: * The _User Guide_ represents the user-facing documentation. This documentation can be browsed by users directly from within Trilium, by pressing F1. * The _Developer's Guide_ represents a set of Markdown documents that present the internals of Trilium, for developers. diff --git a/docs/User Guide/!!!meta.json b/docs/User Guide/!!!meta.json index df7c61602d..8da42b5304 100644 --- a/docs/User Guide/!!!meta.json +++ b/docs/User Guide/!!!meta.json @@ -12290,14 +12290,14 @@ { "type": "relation", "name": "internalLink", - "value": "0vhv7lsOLy82", + "value": "bnyigUA2UK7s", "isInheritable": false, "position": 20 }, { "type": "relation", "name": "internalLink", - "value": "bnyigUA2UK7s", + "value": "0vhv7lsOLy82", "isInheritable": false, "position": 30 }, diff --git a/docs/User Guide/User Guide/Theme development/Creating an icon pack.md b/docs/User Guide/User Guide/Theme development/Creating an icon pack.md index 20bc897899..c9034bd7c0 100644 --- a/docs/User Guide/User Guide/Theme development/Creating an icon pack.md +++ b/docs/User Guide/User Guide/Theme development/Creating an icon pack.md @@ -1,8 +1,20 @@ # Creating an icon pack > [!NOTE] -> This page describes how to create custom icon packs. For a general description of how to use already existing icon packs, see Icon Packs. +> This page explains, step‑by‑step, how to create a create a custom icon pack. For a general description of how to use already existing icon packs, see [missing note]. -## Supported formats +First read the quick flow to get the overall steps. After that there is a concrete example (Phosphor) with a small Node.js script you can run to generate the manifest. + +## Quick flow (what you need to do) + +1. Verify the icon set is a font (one of: .woff2, .woff, .ttf). +2. Obtain a list that maps icon names to Unicode code points (often provided as a JSON like `selection.json` or a CSS file). +3. Create a manifest JSON that maps icon ids to glyphs and search terms. +4. Create a Trilium note of type Code, set language to JSON, paste the manifest as the note content. +5. Upload the font file as an attachment to the same note (MIME type must be `font/woff2`, `font/woff`, or `font/ttf` and role `file`). +6. Add the label `#iconPack=` to the note (prefix: alphanumeric, hyphen, underscore only). +7. Refresh the client and verify the icon pack appears in the icon selector. + +## Verify the icon set The first step is to analyze if the icon set being packed can be integrated into Trilium. @@ -14,8 +26,6 @@ Trilium only supports **font-based icon sets**, with the following formats: | `.woff` | `font/woff` | Higher compatibility, but the font file is bigger. | | `.ttf` | `font/ttf` | Most common, but highest font size. | -## Unsupported formats - Trilium **does not** support the following formats: * SVG-based fonts. @@ -26,46 +36,42 @@ Trilium **does not** support the following formats: In this case, the font must be manually converted to one of the supported formats (ideally `.woff2`). -## Prerequisites +## Manifest format -In order to create a new icon pack from a set of icons, it must meet the following criteria: +The manifest is a JSON object with an `icons` map. Each entry key is the CSS/class id you will use (Trilium uses the CSS class when rendering). Value object: -1. It must have a web font of the supported format (see above). -2. It must have some kind of list, containing the name of each icon and the corresponding Unicode code point. If this is missing, icon fonts usually ship with a `.css` file that can be used to extract the icon names from. +* glyph: the single character (the glyph) — can be the escaped Unicode (e.g. "\\ue9c2") or the literal character. +* terms: array of search aliases; the first term is used as display name in the selector. -## Step-by-step process +Example minimal manifest: -As an example throughout this page, we are going to go through the steps of integrating [Phosphor Icons](https://phosphoricons.com/). - -### Creating the manifest - -This is the most difficult part of creating an icon pack, since it requires processing of the icon list to match Trilium's format. - -The icon pack manifest is a JSON file with the following structure: - -```json +``` { - "icons": { - "bx-ball": { - "glyph": "\ue9c2", - "terms": [ "ball" ] - }, - "bxs-party": { - "glyph": "\uec92", - "terms": [ "party" ] - } - } + "icons": { + "ph-acorn": { + "glyph": "\uea3f", + "terms": ["acorn", "nut"] + }, + "ph-book": { + "glyph": "\uea40", + "terms": ["book", "read"] + } + } } ``` -* The JSON example is a sample from the Boxicons font. -* This is simply a mapping between the CSS classes (`bx-ball`), to its corresponding code point in the font (`\ue9c2`) and the terms/aliases used for search purposes. -* Note that it's also possible to use the unescaped glyph inside the JSON. It will appear strange (e.g. ), but it will be rendered properly regardless. -* The first term is also considered the “name” of the icon, which is displayed while hovering over it in the icon selector. +> [!NOTE] +> * You can supply glyph as the escaped `\uXXXX` sequence or as the actual UTF‑8 character. +> * It is also possible to use the unescaped glyph inside the JSON. It will appear strange (e.g. ), but it will be rendered properly regardless. +> * The manifest keys (e.g. `ph-acorn`) should match the class names used by the font (prefix + name is a common pattern). -In order to generate this manifest, generally a script is needed that processes an already existing list. In the case of Phosphor Icons, the icon list comes in a file called `selection.json` with the following format: +## Concrete example: Phosphor Icons -```json +[Phosphor Icons](https://phosphoricons.com/) provide a `selection.json` that includes `properties.code` (the codepoint) and `properties.name` (the icon name). The goal: convert that into Trilium's manifest. + +Sample `selection.json` excerpt: + +``` { "icons": [ { @@ -95,11 +101,11 @@ In order to generate this manifest, generally a script is needed that processes } ``` -As such, we can write a Node.js script to automatically process the manifest file: +A tiny Node.js script to produce the manifest (place `selection.json` in the same directory and run with Node 20+): ```javascript import { join } from "node:path"; -import { readFileSync } from "node:fs"; +import { readFileSync, writeFileSync } from "node:fs"; function processIconPack(packName) { const path = join(packName); @@ -119,14 +125,19 @@ function processIconPack(packName) { }; } - return JSON.stringify({ - icons - }, null, 2); + writeFileSync("manifest.json", JSON.stringify(icons, null, 2), "utf8"); + console.log("manifest.json created"); } -console.log(processIconPack("light")); +processIconPack("light"); ``` +What to do with the script: + +* Put `selection.json` and `build-manifest.js` in a folder. +* Run: node build-manifest.js +* The script writes `manifest.json` — open it, verify contents, then copy into a Trilium Code note (language: JSON). + > [!TIP] > **Mind the escape format when processing CSS** > @@ -134,17 +145,6 @@ console.log(processIconPack("light")); > > As a more compact alternative, provide the un-escaped character directly, as UTF-8 is supported. -### Creating the icon pack - -1. Create a note of type _Code_. -2. Set the language to _JSON_. -3. Copy and paste the manifest generated in the previous step as the content of this note. -4. Go to the [note attachment](../Basic%20Concepts%20and%20Features/Notes/Attachments.md) and upload the font file (in `.woff2`, `.woff`, `.ttf`) format. - 1. Trilium identifies the font to use from attachments via the MIME type, make sure the MIME type is displayed correctly after uploading the attachment (for example `font/woff2`). - 2. Make sure the `role` appears as `file`, otherwise the font will not be identified. - 3. Multiple attachments are supported, but only one font will actually be used in Trilium's order of preference: `.woff2`, `.woff`, `.ttf`. As such, there's not much reason to upload more than one font per icon pack. -5. Go back to the note and rename it. The name of the note will also be the name of the icon pack as displayed in the list of icons. - ### Assigning the prefix Before an icon pack can be used, it needs to have a prefix defined. This prefix uniquely identifies the icon pack so that it can be used throughout the application. @@ -156,7 +156,19 @@ In order for an icon pack to be recognized, the prefix must be specified in the For our example with Phosphor Icons, we can use the `ph` prefix since it also matches the prefix set in the original CSS. So in this case it would be `#iconPack=ph`. > [!IMPORTANT] -> The prefix must consist of only alphanumeric characters, hyphens and underscore. If the prefix doesn't match these constraints, the icon pack will be ignored and an error will be logged in Backend (server) logs. +> The prefix must consist of only alphanumeric characters, hyphens and underscore. If the prefix doesn't match these constraints, the icon pack will be ignored and an error will be logged in [missing note]. + +## Creating the Trilium icon pack note + +1. Create a note of type _Code_. +2. Set the language to _JSON_. +3. Rename the note. The name of the note will also be the name of the icon pack as displayed in the list of icons. +4. Copy and paste the manifest generated in the previous step as the content of this note. +5. Go to the [note attachment](../Basic%20Concepts%20and%20Features/Notes/Attachments.md) and upload the font file (in `.woff2`, `.woff`, `.ttf`) format. + 1. Trilium identifies the font to use from attachments via the MIME type, make sure the MIME type is displayed correctly after uploading the attachment (for example `font/woff2`). + 2. Make sure the `role` appears as `file`, otherwise the font will not be identified. + 3. Multiple attachments are supported, but only one font will actually be used in Trilium's order of preference: `.woff2`, `.woff`, `.ttf`. As such, there's not much reason to upload more than one font per icon pack. +6. Add label: `#iconPack=` (for Phosphor example: `#iconPack=ph`). ### Final steps @@ -167,11 +179,11 @@ For our example with Phosphor Icons, we can use the `ph` prefix since it also ma * Optionally, assign an icon from the new icon pack to this note. This icon will be used in the icon pack filter for a visual distinction. * The icon pack can then be [exported as ZIP](../Basic%20Concepts%20and%20Features/Import%20%26%20Export.md) in order to be distributed to other users. * It's important to note that icon packs are considered “unsafe” by default, so “Safe mode” must be disabled when importing the ZIP. - * Consider linking new users to the Icon Packs documentation in order to understand how to import and use an icon pack. + * Consider linking new users to the [missing note] documentation in order to understand how to import and use an icon pack. ### Troubleshooting -If the icon pack doesn't show up, look through the Backend (server) logs for clues. +If the icon pack doesn't show up, look through the [missing note] for clues. * One example is if the font could not be retrieved: `ERROR: Icon pack is missing WOFF/WOFF2/TTF attachment: Boxicons v3 400 (dup) (XRzqDQ67fHEK)`. * Make sure the prefix is unique and not already taken by some other icon pack. When there are two icon packs with the same prefix, only one is used. The server logs will indicate if this situation occurs. From 34d691341bd4c8e60a2652f08ee721bbb09fc4f4 Mon Sep 17 00:00:00 2001 From: hulmgulm Date: Sun, 8 Feb 2026 10:41:57 +0100 Subject: [PATCH 003/247] Fixed export --- .../Theme development/Creating an icon pack.html | 8 ++++---- docs/Developer Guide/Developer Guide/Documentation.md | 2 +- .../User Guide/Theme development/Creating an icon pack.md | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Theme development/Creating an icon pack.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Theme development/Creating an icon pack.html index 14c9e94a03..dc27d6050f 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Theme development/Creating an icon pack.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Theme development/Creating an icon pack.html @@ -1,7 +1,7 @@

    First read the quick flow to get the overall steps. After that there is a concrete example (Phosphor) with a small Node.js script you can run to @@ -202,7 +202,7 @@ processIconPack("light");

    Creating the Trilium icon pack note

      @@ -252,14 +252,14 @@ processIconPack("light");
      • It's important to note that icon packs are considered “unsafe” by default, so “Safe mode” must be disabled when importing the ZIP.
      • -
      • Consider linking new users to the [missing note] documentation +
      • Consider linking new users to the Icon Packs documentation in order to understand how to import and use an icon pack.

      Troubleshooting

      If the icon pack doesn't show up, look through the [missing note] for clues.

      + href="#root/_help_bnyigUA2UK7s">Backend (server) logs for clues.

      • One example is if the font could not be retrieved: ERROR: Icon pack is missing WOFF/WOFF2/TTF attachment: Boxicons v3 400 (dup) (XRzqDQ67fHEK).
      • +There are multiple types of documentation for Trilium: * The _User Guide_ represents the user-facing documentation. This documentation can be browsed by users directly from within Trilium, by pressing F1. * The _Developer's Guide_ represents a set of Markdown documents that present the internals of Trilium, for developers. diff --git a/docs/User Guide/User Guide/Theme development/Creating an icon pack.md b/docs/User Guide/User Guide/Theme development/Creating an icon pack.md index c9034bd7c0..6adc6f9868 100644 --- a/docs/User Guide/User Guide/Theme development/Creating an icon pack.md +++ b/docs/User Guide/User Guide/Theme development/Creating an icon pack.md @@ -1,6 +1,6 @@ # Creating an icon pack > [!NOTE] -> This page explains, step‑by‑step, how to create a create a custom icon pack. For a general description of how to use already existing icon packs, see [missing note]. +> This page explains, step‑by‑step, how to create a create a custom icon pack. For a general description of how to use already existing icon packs, see Icon Packs. First read the quick flow to get the overall steps. After that there is a concrete example (Phosphor) with a small Node.js script you can run to generate the manifest. @@ -156,7 +156,7 @@ In order for an icon pack to be recognized, the prefix must be specified in the For our example with Phosphor Icons, we can use the `ph` prefix since it also matches the prefix set in the original CSS. So in this case it would be `#iconPack=ph`. > [!IMPORTANT] -> The prefix must consist of only alphanumeric characters, hyphens and underscore. If the prefix doesn't match these constraints, the icon pack will be ignored and an error will be logged in [missing note]. +> The prefix must consist of only alphanumeric characters, hyphens and underscore. If the prefix doesn't match these constraints, the icon pack will be ignored and an error will be logged in Backend (server) logs. ## Creating the Trilium icon pack note @@ -179,11 +179,11 @@ For our example with Phosphor Icons, we can use the `ph` prefix since it also ma * Optionally, assign an icon from the new icon pack to this note. This icon will be used in the icon pack filter for a visual distinction. * The icon pack can then be [exported as ZIP](../Basic%20Concepts%20and%20Features/Import%20%26%20Export.md) in order to be distributed to other users. * It's important to note that icon packs are considered “unsafe” by default, so “Safe mode” must be disabled when importing the ZIP. - * Consider linking new users to the [missing note] documentation in order to understand how to import and use an icon pack. + * Consider linking new users to the Icon Packs documentation in order to understand how to import and use an icon pack. ### Troubleshooting -If the icon pack doesn't show up, look through the [missing note] for clues. +If the icon pack doesn't show up, look through the Backend (server) logs for clues. * One example is if the font could not be retrieved: `ERROR: Icon pack is missing WOFF/WOFF2/TTF attachment: Boxicons v3 400 (dup) (XRzqDQ67fHEK)`. * Make sure the prefix is unique and not already taken by some other icon pack. When there are two icon packs with the same prefix, only one is used. The server logs will indicate if this situation occurs. From 0c552eb0c094685af765915b7f3bb654bb5b45e9 Mon Sep 17 00:00:00 2001 From: hulmgulm Date: Sun, 8 Feb 2026 10:45:48 +0100 Subject: [PATCH 004/247] Update apps/server/src/assets/doc_notes/en/User Guide/User Guide/Theme development/Creating an icon pack.html Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../User Guide/Theme development/Creating an icon pack.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Theme development/Creating an icon pack.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Theme development/Creating an icon pack.html index dc27d6050f..301602420c 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Theme development/Creating an icon pack.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Theme development/Creating an icon pack.html @@ -1,5 +1,5 @@ From 639b81b2282c82d1c0f062958cbf78a942c257fc Mon Sep 17 00:00:00 2001 From: hulmgulm Date: Sun, 8 Feb 2026 10:46:02 +0100 Subject: [PATCH 005/247] Update docs/User Guide/User Guide/Theme development/Creating an icon pack.md Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../User Guide/Theme development/Creating an icon pack.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/User Guide/User Guide/Theme development/Creating an icon pack.md b/docs/User Guide/User Guide/Theme development/Creating an icon pack.md index 6adc6f9868..5b18610b72 100644 --- a/docs/User Guide/User Guide/Theme development/Creating an icon pack.md +++ b/docs/User Guide/User Guide/Theme development/Creating an icon pack.md @@ -1,6 +1,6 @@ # Creating an icon pack > [!NOTE] -> This page explains, step‑by‑step, how to create a create a custom icon pack. For a general description of how to use already existing icon packs, see Icon Packs. +> This page explains, step‑by‑step, how to create a custom icon pack. For a general description of how to use already existing icon packs, see Icon Packs. First read the quick flow to get the overall steps. After that there is a concrete example (Phosphor) with a small Node.js script you can run to generate the manifest. From badfa23f866bda2c5ba91d269675efcb9acbe307 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Thu, 12 Feb 2026 19:12:56 +0200 Subject: [PATCH 006/247] refactor(geomap): delegate layer data handling to index --- .../src/widgets/collections/geomap/index.tsx | 4 ++-- .../src/widgets/collections/geomap/map.tsx | 12 +++++------- .../widgets/collections/geomap/map_layer.ts | 19 ++++++++----------- 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/apps/client/src/widgets/collections/geomap/index.tsx b/apps/client/src/widgets/collections/geomap/index.tsx index 6e490a81e8..36996eba62 100644 --- a/apps/client/src/widgets/collections/geomap/index.tsx +++ b/apps/client/src/widgets/collections/geomap/index.tsx @@ -22,7 +22,7 @@ import { ViewModeProps } from "../interface"; import { createNewNote, moveMarker } from "./api"; import openContextMenu, { openMapContextMenu } from "./context_menu"; import Map from "./map"; -import { DEFAULT_MAP_LAYER_NAME } from "./map_layer"; +import { DEFAULT_MAP_LAYER_NAME, MAP_LAYERS } from "./map_layer"; import Marker, { GpxTrack } from "./marker"; const DEFAULT_COORDINATES: [number, number] = [3.878638227135724, 446.6630455551659]; @@ -152,7 +152,7 @@ export default function GeoView({ note, noteIds, viewConfig, saveConfig }: ViewM apiRef={apiRef} containerRef={containerRef} coordinates={coordinates} zoom={zoom} - layerName={layerName ?? DEFAULT_MAP_LAYER_NAME} + layerData={MAP_LAYERS[layerName ?? ""] ?? MAP_LAYERS[DEFAULT_MAP_LAYER_NAME]} viewportChanged={(coordinates, zoom) => { if (!viewConfig) viewConfig = {}; viewConfig.view = { center: coordinates, zoom }; diff --git a/apps/client/src/widgets/collections/geomap/map.tsx b/apps/client/src/widgets/collections/geomap/map.tsx index 035f863cc8..19a4586c83 100644 --- a/apps/client/src/widgets/collections/geomap/map.tsx +++ b/apps/client/src/widgets/collections/geomap/map.tsx @@ -1,7 +1,7 @@ import { useEffect, useImperativeHandle, useRef, useState } from "preact/hooks"; import L, { control, LatLng, Layer, LeafletMouseEvent } from "leaflet"; import "leaflet/dist/leaflet.css"; -import { MAP_LAYERS } from "./map_layer"; +import { MAP_LAYERS, type MapLayer } from "./map_layer"; import { ComponentChildren, createContext, RefObject } from "preact"; import { useElementSize, useSyncedRef } from "../../react/hooks"; @@ -12,7 +12,7 @@ interface MapProps { containerRef?: RefObject; coordinates: LatLng | [number, number]; zoom: number; - layerName: string; + layerData: MapLayer; viewportChanged: (coordinates: LatLng, zoom: number) => void; children: ComponentChildren; onClick?: (e: LeafletMouseEvent) => void; @@ -21,7 +21,7 @@ interface MapProps { scale: boolean; } -export default function Map({ coordinates, zoom, layerName, viewportChanged, children, onClick, onContextMenu, scale, apiRef, containerRef: _containerRef, onZoom }: MapProps) { +export default function Map({ coordinates, zoom, layerData, viewportChanged, children, onClick, onContextMenu, scale, apiRef, containerRef: _containerRef, onZoom }: MapProps) { const mapRef = useRef(null); const containerRef = useSyncedRef(_containerRef); @@ -49,8 +49,6 @@ export default function Map({ coordinates, zoom, layerName, viewportChanged, chi const [ layer, setLayer ] = useState(); useEffect(() => { async function load() { - const layerData = MAP_LAYERS[layerName]; - if (layerData.type === "vector") { const style = (typeof layerData.style === "string" ? layerData.style : await layerData.style()); await import("@maplibre/maplibre-gl-leaflet"); @@ -68,7 +66,7 @@ export default function Map({ coordinates, zoom, layerName, viewportChanged, chi } load(); - }, [ layerName ]); + }, [ layerData ]); // Attach layer to the map. useEffect(() => { @@ -139,7 +137,7 @@ export default function Map({ coordinates, zoom, layerName, viewportChanged, chi return (
        {children} diff --git a/apps/client/src/widgets/collections/geomap/map_layer.ts b/apps/client/src/widgets/collections/geomap/map_layer.ts index 7b12a10761..bb5f6174e6 100644 --- a/apps/client/src/widgets/collections/geomap/map_layer.ts +++ b/apps/client/src/widgets/collections/geomap/map_layer.ts @@ -1,20 +1,17 @@ -export interface MapLayer { - name: string; - isDarkTheme?: boolean; -} - -interface VectorLayer extends MapLayer { +export type MapLayer = ({ type: "vector"; style: string | (() => Promise<{}>) -} - -interface RasterLayer extends MapLayer { +} | { type: "raster"; url: string; attribution: string; -} +}) & { + // Common properties + name: string; + isDarkTheme?: boolean; +}; -export const MAP_LAYERS: Record = { +export const MAP_LAYERS: Record = { "openstreetmap": { name: "OpenStreetMap", type: "raster", From 54a52f05893256cd48398808ebf08528e7b6735f Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Thu, 12 Feb 2026 19:32:22 +0200 Subject: [PATCH 007/247] feat(geomap): support for custom tile URLs --- .../src/widgets/collections/geomap/index.tsx | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/apps/client/src/widgets/collections/geomap/index.tsx b/apps/client/src/widgets/collections/geomap/index.tsx index 36996eba62..b22531c727 100644 --- a/apps/client/src/widgets/collections/geomap/index.tsx +++ b/apps/client/src/widgets/collections/geomap/index.tsx @@ -22,7 +22,7 @@ import { ViewModeProps } from "../interface"; import { createNewNote, moveMarker } from "./api"; import openContextMenu, { openMapContextMenu } from "./context_menu"; import Map from "./map"; -import { DEFAULT_MAP_LAYER_NAME, MAP_LAYERS } from "./map_layer"; +import { DEFAULT_MAP_LAYER_NAME, MAP_LAYERS, MapLayer } from "./map_layer"; import Marker, { GpxTrack } from "./marker"; const DEFAULT_COORDINATES: [number, number] = [3.878638227135724, 446.6630455551659]; @@ -45,10 +45,10 @@ export default function GeoView({ note, noteIds, viewConfig, saveConfig }: ViewM const [ state, setState ] = useState(State.Normal); const [ coordinates, setCoordinates ] = useState(viewConfig?.view?.center); const [ zoom, setZoom ] = useState(viewConfig?.view?.zoom); - const [ layerName ] = useNoteLabel(note, "map:style"); const [ hasScale ] = useNoteLabelBoolean(note, "map:scale"); const [ isReadOnly ] = useNoteLabelBoolean(note, "readOnly"); const [ notes, setNotes ] = useState([]); + const layerData = useLayerData(note); const spacedUpdate = useSpacedUpdate(() => { if (viewConfig) { saveConfig(viewConfig); @@ -152,7 +152,7 @@ export default function GeoView({ note, noteIds, viewConfig, saveConfig }: ViewM apiRef={apiRef} containerRef={containerRef} coordinates={coordinates} zoom={zoom} - layerData={MAP_LAYERS[layerName ?? ""] ?? MAP_LAYERS[DEFAULT_MAP_LAYER_NAME]} + layerData={layerData} viewportChanged={(coordinates, zoom) => { if (!viewConfig) viewConfig = {}; viewConfig.view = { center: coordinates, zoom }; @@ -169,6 +169,28 @@ export default function GeoView({ note, noteIds, viewConfig, saveConfig }: ViewM ); } +function useLayerData(note: FNote) { + const [ layerName ] = useNoteLabel(note, "map:style"); + // Memo is needed because it would generate unnecessary reloads due to layer change. + const layerData = useMemo(() => { + // Custom layers. + if (layerName?.startsWith("http")) { + return { + name: "Custom", + type: "raster", + url: layerName, + attribution: "" + } satisfies MapLayer; + } + + // Built-in layers. + const layerData = MAP_LAYERS[layerName ?? ""] ?? MAP_LAYERS[DEFAULT_MAP_LAYER_NAME]; + return layerData; + }, [ layerName ]); + + return layerData; +} + function ToggleReadOnlyButton({ note }: { note: FNote }) { const [ isReadOnly, setReadOnly ] = useNoteLabelBoolean(note, "readOnly"); From e6d728715f5951167cf07f5b3da72195ab572fe9 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Thu, 12 Feb 2026 19:47:24 +0200 Subject: [PATCH 008/247] feat(geomap): support hiding labels --- .../src/translations/en/translation.json | 3 ++- .../src/widgets/collections/geomap/index.tsx | 26 ++++++++++++------- .../note_bars/CollectionProperties.tsx | 4 +-- .../ribbon/collection-properties-config.tsx | 9 +++++++ packages/commons/src/lib/attribute_names.ts | 1 + 5 files changed, 30 insertions(+), 13 deletions(-) diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index f434ffeddd..8609044efa 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -2104,7 +2104,8 @@ "raster": "Raster", "vector_light": "Vector (Light)", "vector_dark": "Vector (Dark)", - "show-scale": "Show scale" + "show-scale": "Show scale", + "show-labels": "Show marker names" }, "table_context_menu": { "delete_row": "Delete row" diff --git a/apps/client/src/widgets/collections/geomap/index.tsx b/apps/client/src/widgets/collections/geomap/index.tsx index b22531c727..8be547fa3a 100644 --- a/apps/client/src/widgets/collections/geomap/index.tsx +++ b/apps/client/src/widgets/collections/geomap/index.tsx @@ -46,6 +46,7 @@ export default function GeoView({ note, noteIds, viewConfig, saveConfig }: ViewM const [ coordinates, setCoordinates ] = useState(viewConfig?.view?.center); const [ zoom, setZoom ] = useState(viewConfig?.view?.zoom); const [ hasScale ] = useNoteLabelBoolean(note, "map:scale"); + const [ hideLabels ] = useNoteLabelBoolean(note, "map:hideLabels"); const [ isReadOnly ] = useNoteLabelBoolean(note, "readOnly"); const [ notes, setNotes ] = useState([]); const layerData = useLayerData(note); @@ -162,7 +163,7 @@ export default function GeoView({ note, noteIds, viewConfig, saveConfig }: ViewM onContextMenu={onContextMenu} scale={hasScale} > - {notes.map(note => )} + {notes.map(note => )} }
        @@ -201,22 +202,26 @@ function ToggleReadOnlyButton({ note }: { note: FNote }) { />; } -function NoteWrapper({ note, isReadOnly }: { note: FNote, isReadOnly: boolean }) { +function NoteWrapper({ note, isReadOnly, hideLabels }: { + note: FNote, + isReadOnly: boolean, + hideLabels: boolean +}) { const mime = useNoteProperty(note, "mime"); const [ location ] = useNoteLabel(note, LOCATION_ATTRIBUTE); if (mime === "application/gpx+xml") { - return ; + return ; } if (location) { const latLng = location?.split(",", 2).map((el) => parseFloat(el)) as [ number, number ] | undefined; if (!latLng) return; - return ; + return ; } } -function NoteMarker({ note, editable, latLng }: { note: FNote, editable: boolean, latLng: [number, number] }) { +function NoteMarker({ note, editable, latLng, hideLabels }: { note: FNote, editable: boolean, latLng: [number, number], hideLabels: boolean }) { // React to changes const [ color ] = useNoteLabel(note, "color"); const [ iconClass ] = useNoteLabel(note, "iconClass"); @@ -224,8 +229,9 @@ function NoteMarker({ note, editable, latLng }: { note: FNote, editable: boolean const title = useNoteProperty(note, "title"); const icon = useMemo(() => { - return buildIcon(note.getIcon(), note.getColorClass() ?? undefined, title, note.noteId, archived); - }, [ iconClass, color, title, note.noteId, archived]); + const titleOrNone = hideLabels ? undefined : title; + return buildIcon(note.getIcon(), note.getColorClass() ?? undefined, titleOrNone, note.noteId, archived); + }, [ iconClass, color, title, note.noteId, archived, hideLabels ]); const onClick = useCallback(() => { appContext.triggerCommand("openInPopup", { noteIdOrPath: note.noteId }); @@ -257,7 +263,7 @@ function NoteMarker({ note, editable, latLng }: { note: FNote, editable: boolean />; } -function NoteGpxTrack({ note }: { note: FNote }) { +function NoteGpxTrack({ note, hideLabels }: { note: FNote, hideLabels?: boolean }) { const [ xmlString, setXmlString ] = useState(); const blob = useNoteBlob(note); @@ -278,7 +284,7 @@ function NoteGpxTrack({ note }: { note: FNote }) { const options = useMemo(() => ({ markers: { - startIcon: buildIcon(note.getIcon(), note.getColorClass(), note.title), + startIcon: buildIcon(note.getIcon(), note.getColorClass(), hideLabels ? undefined : note.title), endIcon: buildIcon("bxs-flag-checkered"), wptIcons: { "": buildIcon("bx bx-pin") @@ -287,7 +293,7 @@ function NoteGpxTrack({ note }: { note: FNote }) { polyline_options: { color: note.getLabelValue("color") ?? "blue" } - }), [ color, iconClass ]); + }), [ color, iconClass, hideLabels ]); return xmlString && ; } diff --git a/apps/client/src/widgets/note_bars/CollectionProperties.tsx b/apps/client/src/widgets/note_bars/CollectionProperties.tsx index 5dba675e6d..7f739e34bb 100644 --- a/apps/client/src/widgets/note_bars/CollectionProperties.tsx +++ b/apps/client/src/widgets/note_bars/CollectionProperties.tsx @@ -226,8 +226,8 @@ function CheckBoxPropertyView({ note, property }: { note: FNote, property: Check setValue(property.reverseValue ? !newValue : newValue)} /> ); } diff --git a/apps/client/src/widgets/ribbon/collection-properties-config.tsx b/apps/client/src/widgets/ribbon/collection-properties-config.tsx index 1f79217e9c..17bdff5052 100644 --- a/apps/client/src/widgets/ribbon/collection-properties-config.tsx +++ b/apps/client/src/widgets/ribbon/collection-properties-config.tsx @@ -20,6 +20,8 @@ export interface CheckBoxProperty { label: string; bindToLabel: FilterLabelsByType; icon?: string; + /** When true, the checkbox will be checked when the label value is false. Useful when the label represents a "hide" action, without exposing double negatives to the user. */ + reverseValue?: boolean; } export interface ButtonProperty { @@ -156,6 +158,13 @@ export const bookPropertiesConfig: Record = { icon: "bx bx-ruler", type: "checkbox", bindToLabel: "map:scale" + }, + { + label: t("book_properties_config.show-labels"), + icon: "bx bx-label", + type: "checkbox", + bindToLabel: "map:hideLabels", + reverseValue: true } ] }, diff --git a/packages/commons/src/lib/attribute_names.ts b/packages/commons/src/lib/attribute_names.ts index b524b409f0..a73f97d30f 100644 --- a/packages/commons/src/lib/attribute_names.ts +++ b/packages/commons/src/lib/attribute_names.ts @@ -48,6 +48,7 @@ type Labels = { "calendar:initialDate": string; "map:style": string; "map:scale": boolean; + "map:hideLabels": boolean; "board:groupBy": string; maxNestingDepth: number; includeArchived: boolean; From b618e5a00f6c456b49a37f679f53c27774467888 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Fri, 13 Feb 2026 22:50:03 +0200 Subject: [PATCH 009/247] client: define the foundation of sectioned cards with multi-level nesting --- apps/client/src/widgets/react/Card.css | 36 +++++++++++++++++++++ apps/client/src/widgets/react/Card.tsx | 43 ++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 apps/client/src/widgets/react/Card.css create mode 100644 apps/client/src/widgets/react/Card.tsx diff --git a/apps/client/src/widgets/react/Card.css b/apps/client/src/widgets/react/Card.css new file mode 100644 index 0000000000..ea906cc0a8 --- /dev/null +++ b/apps/client/src/widgets/react/Card.css @@ -0,0 +1,36 @@ +.tn-card { + --card-border-radius: 8px; + --card-padding: 8px 16px; + --card-section-gap: 3px; + + display: flex; + flex-direction: column; + gap: var(--card-section-gap); + + .tn-card-section { + padding: var(--card-padding); + border: 1px solid var(--card-border-color); + background: var(--card-background-color); + + &:first-of-type { + border-top-left-radius: var(--card-border-radius); + border-top-right-radius: var(--card-border-radius); + } + + &:last-of-type { + border-bottom-left-radius: var(--card-border-radius); + border-bottom-right-radius: var(--card-border-radius); + } + + &.tn-card-section-nested { + padding-left: calc(30px * var(--tn-card-section-nesting-level)); + opacity: .5; + } + + &.tn-action:hover { + background-color: var(--card-background-hover-color); + transition: background-color .2s ease-out; + } + + } +} \ No newline at end of file diff --git a/apps/client/src/widgets/react/Card.tsx b/apps/client/src/widgets/react/Card.tsx new file mode 100644 index 0000000000..fa6a0f489f --- /dev/null +++ b/apps/client/src/widgets/react/Card.tsx @@ -0,0 +1,43 @@ +import "./Card.css"; +import { ComponentChildren, createContext } from "preact"; +import { JSX } from "preact"; +import { useContext } from "preact/hooks"; +import clsx from "clsx"; + +interface CardProps { +} + +export function Card(props: {children: ComponentChildren} & CardProps) { + return
        + {props.children} +
        ; +} + +interface CardSectionProps { + subSections?: JSX.Element | JSX.Element[]; + childrenVisible?: boolean; +} + +export function CardSection(props: {children: ComponentChildren} & CardSectionProps) { + const parentContext = useContext(CardSectionContext); + const nestingLevel = (parentContext && parentContext.nestingLevel + 1) ?? 0; + + return <> +
        0}])} + style={"--tn-card-section-nesting-level: " + nestingLevel}> + {props.children} {nestingLevel} +
        + + {props?.childrenVisible && + + {props.subSections} + + } + ; +} + +interface CardSectionContextType { + nestingLevel: number; +} + +export const CardSectionContext = createContext(undefined); \ No newline at end of file From be12658864448d24d9beacab8ff07280548d3303 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sat, 14 Feb 2026 00:08:00 +0200 Subject: [PATCH 010/247] client/ui/cards: add support for custom class names and action callbacks --- apps/client/src/widgets/react/Card.tsx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/client/src/widgets/react/Card.tsx b/apps/client/src/widgets/react/Card.tsx index fa6a0f489f..1573c2fe0b 100644 --- a/apps/client/src/widgets/react/Card.tsx +++ b/apps/client/src/widgets/react/Card.tsx @@ -5,17 +5,21 @@ import { useContext } from "preact/hooks"; import clsx from "clsx"; interface CardProps { + className?: string; } export function Card(props: {children: ComponentChildren} & CardProps) { - return
        + return
        {props.children}
        ; } interface CardSectionProps { + className?: string; subSections?: JSX.Element | JSX.Element[]; childrenVisible?: boolean; + hasAction: boolean; + onAction?: () => void; } export function CardSection(props: {children: ComponentChildren} & CardSectionProps) { @@ -23,9 +27,13 @@ export function CardSection(props: {children: ComponentChildren} & CardSectionPr const nestingLevel = (parentContext && parentContext.nestingLevel + 1) ?? 0; return <> -
        0}])} - style={"--tn-card-section-nesting-level: " + nestingLevel}> - {props.children} {nestingLevel} +
        0, + "tn-action": props?.hasAction} + ], props.className)} + style={"--tn-card-section-nesting-level: " + nestingLevel} + onClick={() => {props.onAction?.()}}> + {props.children}
        {props?.childrenVisible && From 62ddf3a11bf430b5c680a20f8cfe70c91d898e87 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sat, 14 Feb 2026 00:08:59 +0200 Subject: [PATCH 011/247] client/ui/cards: automatically determine the opacity of the background color of nested card sections --- apps/client/src/widgets/react/Card.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/client/src/widgets/react/Card.css b/apps/client/src/widgets/react/Card.css index ea906cc0a8..d717354be1 100644 --- a/apps/client/src/widgets/react/Card.css +++ b/apps/client/src/widgets/react/Card.css @@ -24,7 +24,7 @@ &.tn-card-section-nested { padding-left: calc(30px * var(--tn-card-section-nesting-level)); - opacity: .5; + background-color: color-mix(in srgb, var(--card-background-color) calc(100% / (var(--tn-card-section-nesting-level) + 1)) , transparent); } &.tn-action:hover { From 61953fd7132ebee7e6e06f77357cf43213b23582 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sat, 14 Feb 2026 00:10:54 +0200 Subject: [PATCH 012/247] client/ui/cards: make a property optional --- apps/client/src/widgets/react/Card.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/client/src/widgets/react/Card.tsx b/apps/client/src/widgets/react/Card.tsx index 1573c2fe0b..34eea094af 100644 --- a/apps/client/src/widgets/react/Card.tsx +++ b/apps/client/src/widgets/react/Card.tsx @@ -18,7 +18,7 @@ interface CardSectionProps { className?: string; subSections?: JSX.Element | JSX.Element[]; childrenVisible?: boolean; - hasAction: boolean; + hasAction?: boolean; onAction?: () => void; } From 218343ca144882f3a6d4406e60f3206374588ecc Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sat, 14 Feb 2026 01:14:54 +0200 Subject: [PATCH 013/247] client/list view: use a sectioned card to display the list items --- .../collections/legacy/ListOrGridView.css | 35 +++++++++++++++++-- .../collections/legacy/ListOrGridView.tsx | 33 ++++++++++------- apps/client/src/widgets/react/Card.css | 3 +- 3 files changed, 56 insertions(+), 15 deletions(-) diff --git a/apps/client/src/widgets/collections/legacy/ListOrGridView.css b/apps/client/src/widgets/collections/legacy/ListOrGridView.css index 1bfa389e5c..ef609c1d0d 100644 --- a/apps/client/src/widgets/collections/legacy/ListOrGridView.css +++ b/apps/client/src/widgets/collections/legacy/ListOrGridView.css @@ -102,9 +102,8 @@ .note-expander { font-size: x-large; - position: relative; - top: 3px; cursor: pointer; + opacity: .65; } .note-list-pager { @@ -117,6 +116,38 @@ opacity: 0.5; } +:root .list-view-card { + --card-nested-section-indent: 40px; +} + +.note-list h5 { + display: flex; + align-items: center; + font-size: 1em; + margin: 0; + + .tn-icon { + color: var(--left-pane-icon-color); + margin-inline-end: 8px; + font-size: 1.2em; + } + + .note-book-title { + color: inherit; + } + + .note-list-attributes { + flex-grow: 1; + text-align: right; + font-size: .75em; + opacity: .75; + } +} + +.note-content-preview:has(.note-book-content:empty) { + display: none; +} + /* #region Grid view */ .note-list.grid-view .note-list-container { display: flex; diff --git a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx index 61c7193a6e..6bf77c644f 100644 --- a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx +++ b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx @@ -1,4 +1,5 @@ import "./ListOrGridView.css"; +import { Card, CardSection } from "../../react/Card"; import { useEffect, useRef, useState } from "preact/hooks"; @@ -33,7 +34,7 @@ export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens } { noteIds.length > 0 &&
        {!hasCollectionProperties && } - +
        } @@ -93,27 +94,35 @@ function ListNoteCard({ note, parentNote, highlightedTokens, currentLevel, expan // Reset expand state if switching to another note, or if user manually toggled expansion state. useEffect(() => setExpanded(currentLevel <= expandDepth), [ note, currentLevel, expandDepth ]); + const children = <> + {isExpanded && <> + + + + + } + + return ( -
        setExpanded(!isExpanded)} data-note-id={note.noteId} > -
        +
        setExpanded(!isExpanded)} + onClick={(e) => {setExpanded(!isExpanded); e.stopPropagation();}} />
        - - {isExpanded && <> - - - } -
        + ); } diff --git a/apps/client/src/widgets/react/Card.css b/apps/client/src/widgets/react/Card.css index d717354be1..53fd889b21 100644 --- a/apps/client/src/widgets/react/Card.css +++ b/apps/client/src/widgets/react/Card.css @@ -2,6 +2,7 @@ --card-border-radius: 8px; --card-padding: 8px 16px; --card-section-gap: 3px; + --card-nested-section-indent: 30px; display: flex; flex-direction: column; @@ -23,7 +24,7 @@ } &.tn-card-section-nested { - padding-left: calc(30px * var(--tn-card-section-nesting-level)); + padding-left: calc(8px + (var(--card-nested-section-indent) * var(--tn-card-section-nesting-level))); background-color: color-mix(in srgb, var(--card-background-color) calc(100% / (var(--tn-card-section-nesting-level) + 1)) , transparent); } From 870524f9cfb0b67a9ae677e138123ee11fcbb757 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 14 Feb 2026 02:03:29 +0000 Subject: [PATCH 014/247] chore(deps): update dependency @redocly/cli to v2.18.1 --- apps/build-docs/package.json | 2 +- pnpm-lock.yaml | 84 +++++++++++++----------------------- 2 files changed, 31 insertions(+), 55 deletions(-) diff --git a/apps/build-docs/package.json b/apps/build-docs/package.json index 99b10e5b3c..005ff1836b 100644 --- a/apps/build-docs/package.json +++ b/apps/build-docs/package.json @@ -11,7 +11,7 @@ "license": "AGPL-3.0-only", "packageManager": "pnpm@10.29.3", "devDependencies": { - "@redocly/cli": "2.18.0", + "@redocly/cli": "2.18.1", "archiver": "7.0.1", "fs-extra": "11.3.3", "react": "19.2.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4725bc60e0..993a21f49c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -156,8 +156,8 @@ importers: apps/build-docs: devDependencies: '@redocly/cli': - specifier: 2.18.0 - version: 2.18.0(@opentelemetry/api@1.9.0)(bufferutil@4.0.9)(core-js@3.46.0)(encoding@0.1.13)(utf-8-validate@6.0.5) + specifier: 2.18.1 + version: 2.18.1(@opentelemetry/api@1.9.0)(bufferutil@4.0.9)(core-js@3.46.0)(encoding@0.1.13)(utf-8-validate@6.0.5) archiver: specifier: 7.0.1 version: 7.0.1 @@ -4774,14 +4774,11 @@ packages: '@radix-ui/rect@1.1.0': resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==} - '@redocly/ajv@8.17.1': - resolution: {integrity: sha512-EDtsGZS964mf9zAUXAl9Ew16eYbeyAFWhsPr0fX6oaJxgd8rApYlPBf0joyhnUHz88WxrigyFtTaqqzXNzPgqw==} + '@redocly/ajv@8.17.4': + resolution: {integrity: sha512-BieiCML/IgP6x99HZByJSt7fJE4ipgzO7KAFss92Bs+PEI35BhY7vGIysFXLT+YmS7nHtQjZjhOQyPPEf7xGHA==} - '@redocly/ajv@8.17.2': - resolution: {integrity: sha512-rcbDZOfXAgGEJeJ30aWCVVJvxV9ooevb/m1/SFblO2qHs4cqTk178gx7T/vdslf57EA4lTofrwsq5K8rxK9g+g==} - - '@redocly/cli@2.18.0': - resolution: {integrity: sha512-LZCfASCqlHThihfXbs5OLR/ggBs+8GeMDeP6vw39eX4uyCOtSeadRGXnVlEbMqNOmXM7YITApPrWKiAoZ18uag==} + '@redocly/cli@2.18.1': + resolution: {integrity: sha512-x3OBHb3T6GM+b48hKZkyTAwT58lWyJbBFfTQbX5WQXPJMB/+2x/KhrUlbAOiGPBtkTNnVBG5iskTv7l6bs6tig==} engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'} hasBin: true @@ -4795,12 +4792,12 @@ packages: resolution: {integrity: sha512-0EbE8LRbkogtcCXU7liAyC00n9uNG9hJ+eMyHFdUsy9lB/WGqnEBgwjA9q2cyzAVcdTkQqTBBU1XePNnN3OijA==} engines: {node: '>=18.17.0', npm: '>=9.5.0'} - '@redocly/openapi-core@2.18.0': - resolution: {integrity: sha512-I6SqmxPb/Q0Wf9eu3cbWxtTsHocgW/cL1+hEmS9C05aO1BQ+a+sd5BX96ffTxv8PRpwTeCdkuhmvmfczgvD3hA==} + '@redocly/openapi-core@2.18.1': + resolution: {integrity: sha512-1fjuH85SpFyIFHcdQiGoT5uWsoErs+qJyK+2HqaqTANkNO3ONpDBS6B79Z/mYUH44+LxeTTVzbDPBEcI0ZJHhQ==} engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'} - '@redocly/respect-core@2.18.0': - resolution: {integrity: sha512-mLCXnGYjiW+fq9AB3UAMhpOPAMd/ww2L2h+lbDOtTVC9PfFnC7QZcBKN40MoEwoM0b/KKf5y8lsSzkctLIj4XQ==} + '@redocly/respect-core@2.18.1': + resolution: {integrity: sha512-o/XgvxuZZhZkugFxpICqdmgpz5oFzpmhO7v3hziHk1tc4CYtI1pG6PlTJuJv5ufGAlAMZOn93ymgl27A7x/GUA==} engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'} '@replit/codemirror-indentation-markers@6.5.3': @@ -16024,8 +16021,6 @@ snapshots: '@ckeditor/ckeditor5-core': 47.4.0 '@ckeditor/ckeditor5-upload': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-ai@47.4.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)': dependencies: @@ -16377,8 +16372,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-decoupled@47.4.0': dependencies: @@ -16388,8 +16381,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-inline@47.4.0': dependencies: @@ -16581,8 +16572,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 '@ckeditor/ckeditor5-widget': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-html-embed@47.4.0': dependencies: @@ -17000,8 +16989,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-special-characters@47.4.0': dependencies: @@ -19987,31 +19974,24 @@ snapshots: '@radix-ui/rect@1.1.0': {} - '@redocly/ajv@8.17.1': + '@redocly/ajv@8.17.4': dependencies: fast-deep-equal: 3.1.3 fast-uri: 3.1.0 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - '@redocly/ajv@8.17.2': - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - - '@redocly/cli@2.18.0(@opentelemetry/api@1.9.0)(bufferutil@4.0.9)(core-js@3.46.0)(encoding@0.1.13)(utf-8-validate@6.0.5)': + '@redocly/cli@2.18.1(@opentelemetry/api@1.9.0)(bufferutil@4.0.9)(core-js@3.46.0)(encoding@0.1.13)(utf-8-validate@6.0.5)': dependencies: '@opentelemetry/exporter-trace-otlp-http': 0.202.0(@opentelemetry/api@1.9.0) '@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-node': 2.0.1(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.34.0 - '@redocly/openapi-core': 2.18.0 - '@redocly/respect-core': 2.18.0 + '@redocly/openapi-core': 2.18.1 + '@redocly/respect-core': 2.18.1 abort-controller: 3.0.0 - ajv: '@redocly/ajv@8.17.1' - ajv-formats: 3.0.1(@redocly/ajv@8.17.1) + ajv: '@redocly/ajv@8.17.4' + ajv-formats: 3.0.1(@redocly/ajv@8.17.4) colorette: 1.4.0 cookie: 0.7.2 dotenv: 16.4.7 @@ -20048,7 +20028,7 @@ snapshots: '@redocly/openapi-core@1.34.5': dependencies: - '@redocly/ajv': 8.17.2 + '@redocly/ajv': 8.17.4 '@redocly/config': 0.22.2 colorette: 1.4.0 https-proxy-agent: 7.0.6 @@ -20060,12 +20040,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@redocly/openapi-core@2.18.0': + '@redocly/openapi-core@2.18.1': dependencies: - '@redocly/ajv': 8.17.2 + '@redocly/ajv': 8.17.4 '@redocly/config': 0.43.0 - ajv: '@redocly/ajv@8.17.2' - ajv-formats: 3.0.1(@redocly/ajv@8.17.2) + ajv: '@redocly/ajv@8.17.4' + ajv-formats: 3.0.1(@redocly/ajv@8.17.4) colorette: 1.4.0 js-levenshtein: 1.1.6 js-yaml: 4.1.1 @@ -20073,14 +20053,14 @@ snapshots: pluralize: 8.0.0 yaml-ast-parser: 0.0.43 - '@redocly/respect-core@2.18.0': + '@redocly/respect-core@2.18.1': dependencies: '@faker-js/faker': 7.6.0 '@noble/hashes': 1.8.0 - '@redocly/ajv': 8.17.1 - '@redocly/openapi-core': 2.18.0 - ajv: '@redocly/ajv@8.17.1' - better-ajv-errors: 1.2.0(@redocly/ajv@8.17.1) + '@redocly/ajv': 8.17.4 + '@redocly/openapi-core': 2.18.1 + ajv: '@redocly/ajv@8.17.4' + better-ajv-errors: 1.2.0(@redocly/ajv@8.17.4) colorette: 2.0.20 json-pointer: 0.6.2 jsonpath-rfc9535: 1.3.0 @@ -22155,13 +22135,9 @@ snapshots: optionalDependencies: ajv: 8.17.1 - ajv-formats@3.0.1(@redocly/ajv@8.17.1): + ajv-formats@3.0.1(@redocly/ajv@8.17.4): optionalDependencies: - ajv: '@redocly/ajv@8.17.1' - - ajv-formats@3.0.1(@redocly/ajv@8.17.2): - optionalDependencies: - ajv: '@redocly/ajv@8.17.2' + ajv: '@redocly/ajv@8.17.4' ajv-formats@3.0.1(ajv@8.13.0): optionalDependencies: @@ -22526,11 +22502,11 @@ snapshots: batch@0.6.1: {} - better-ajv-errors@1.2.0(@redocly/ajv@8.17.1): + better-ajv-errors@1.2.0(@redocly/ajv@8.17.4): dependencies: '@babel/code-frame': 7.27.1 '@humanwhocodes/momoa': 2.0.4 - ajv: '@redocly/ajv@8.17.1' + ajv: '@redocly/ajv@8.17.4' chalk: 4.1.2 jsonpointer: 5.0.1 leven: 3.1.0 From 8cbc15f1b0af7a8e684a948ba3f85c2db47b1cc5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 14 Feb 2026 02:04:20 +0000 Subject: [PATCH 015/247] chore(deps): update dependency electron to v40.4.1 --- apps/desktop/package.json | 2 +- apps/edit-docs/package.json | 2 +- apps/server/package.json | 2 +- pnpm-lock.yaml | 44 ++++++++++++------------------------- 4 files changed, 17 insertions(+), 33 deletions(-) diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 59d5bd37f9..2f5996944d 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -35,7 +35,7 @@ "@triliumnext/commons": "workspace:*", "@triliumnext/server": "workspace:*", "copy-webpack-plugin": "13.0.1", - "electron": "40.4.0", + "electron": "40.4.1", "@electron-forge/cli": "7.11.1", "@electron-forge/maker-deb": "7.11.1", "@electron-forge/maker-dmg": "7.11.1", diff --git a/apps/edit-docs/package.json b/apps/edit-docs/package.json index 9c8f58048b..eb443b2e94 100644 --- a/apps/edit-docs/package.json +++ b/apps/edit-docs/package.json @@ -12,7 +12,7 @@ "@triliumnext/desktop": "workspace:*", "@types/fs-extra": "11.0.4", "copy-webpack-plugin": "13.0.1", - "electron": "40.4.0", + "electron": "40.4.1", "fs-extra": "11.3.3" }, "scripts": { diff --git a/apps/server/package.json b/apps/server/package.json index 30d3370d8d..9de789b994 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -83,7 +83,7 @@ "debounce": "3.0.0", "debug": "4.4.3", "ejs": "4.0.1", - "electron": "40.4.0", + "electron": "40.4.1", "electron-debug": "4.1.0", "electron-window-state": "5.0.3", "escape-html": "1.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4725bc60e0..ca6d088399 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -392,7 +392,7 @@ importers: dependencies: '@electron/remote': specifier: 2.1.3 - version: 2.1.3(electron@40.4.0) + version: 2.1.3(electron@40.4.1) better-sqlite3: specifier: 12.6.2 version: 12.6.2 @@ -449,8 +449,8 @@ importers: specifier: 13.0.1 version: 13.0.1(webpack@5.101.3(esbuild@0.27.3)) electron: - specifier: 40.4.0 - version: 40.4.0 + specifier: 40.4.1 + version: 40.4.1 prebuild-install: specifier: 7.1.3 version: 7.1.3 @@ -505,8 +505,8 @@ importers: specifier: 13.0.1 version: 13.0.1(webpack@5.101.3(esbuild@0.27.3)) electron: - specifier: 40.4.0 - version: 40.4.0 + specifier: 40.4.1 + version: 40.4.1 fs-extra: specifier: 11.3.3 version: 11.3.3 @@ -543,7 +543,7 @@ importers: version: 7.1.2 '@electron/remote': specifier: 2.1.3 - version: 2.1.3(electron@40.4.0) + version: 2.1.3(electron@40.4.1) '@triliumnext/commons': specifier: workspace:* version: link:../../packages/commons @@ -680,8 +680,8 @@ importers: specifier: 4.0.1 version: 4.0.1 electron: - specifier: 40.4.0 - version: 40.4.0 + specifier: 40.4.1 + version: 40.4.1 electron-debug: specifier: 4.1.0 version: 4.1.0 @@ -8330,8 +8330,8 @@ packages: resolution: {integrity: sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==} engines: {node: '>=8.0.0'} - electron@40.4.0: - resolution: {integrity: sha512-31l4V7Ys4oUuXyaN/cCNnyBdDXN9RwOVOG+JhiHCf4zx5tZkHd43PKGY6KLEWpeYCxaphsuGSEjagJLfPqKj8g==} + electron@40.4.1: + resolution: {integrity: sha512-N1ZXybQZL8kYemO8vAeh9nrk4mSvqlAO8xs0QCHkXIvRnuB/7VGwEehjvQbsU5/f4bmTKpG+2GQERe/zmKpudQ==} engines: {node: '>= 12.20.55'} hasBin: true @@ -16024,8 +16024,6 @@ snapshots: '@ckeditor/ckeditor5-core': 47.4.0 '@ckeditor/ckeditor5-upload': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-ai@47.4.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)': dependencies: @@ -16172,8 +16170,6 @@ snapshots: '@ckeditor/ckeditor5-core': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-code-block@47.4.0(patch_hash=2361d8caad7d6b5bddacc3a3b4aa37dbfba260b1c1b22a450413a79c1bb1ce95)': dependencies: @@ -16366,8 +16362,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-classic@47.4.0': dependencies: @@ -16377,8 +16371,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-decoupled@47.4.0': dependencies: @@ -16388,8 +16380,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-inline@47.4.0': dependencies: @@ -16581,8 +16571,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 '@ckeditor/ckeditor5-widget': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-html-embed@47.4.0': dependencies: @@ -16912,8 +16900,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-restricted-editing@47.4.0': dependencies: @@ -17000,8 +16986,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-special-characters@47.4.0': dependencies: @@ -17804,9 +17788,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@electron/remote@2.1.3(electron@40.4.0)': + '@electron/remote@2.1.3(electron@40.4.1)': dependencies: - electron: 40.4.0 + electron: 40.4.1 '@electron/universal@2.0.2': dependencies: @@ -24356,10 +24340,10 @@ snapshots: - supports-color optional: true - electron@40.4.0: + electron@40.4.1: dependencies: '@electron/get': 2.0.3 - '@types/node': 24.10.10 + '@types/node': 24.10.13 extract-zip: 2.0.1 transitivePeerDependencies: - supports-color From bb38e806cdc6d5579faf871adc23a4445a0a30e6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 14 Feb 2026 02:05:04 +0000 Subject: [PATCH 016/247] chore(deps): update dependency typedoc to v0.28.17 --- apps/build-docs/package.json | 2 +- pnpm-lock.yaml | 34 +++++++++------------------------- 2 files changed, 10 insertions(+), 26 deletions(-) diff --git a/apps/build-docs/package.json b/apps/build-docs/package.json index 99b10e5b3c..13c2f619c2 100644 --- a/apps/build-docs/package.json +++ b/apps/build-docs/package.json @@ -16,7 +16,7 @@ "fs-extra": "11.3.3", "react": "19.2.4", "react-dom": "19.2.4", - "typedoc": "0.28.16", + "typedoc": "0.28.17", "typedoc-plugin-missing-exports": "4.1.2" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4725bc60e0..b8f8ccf9d3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -171,11 +171,11 @@ importers: specifier: 19.2.4 version: 19.2.4(react@19.2.4) typedoc: - specifier: 0.28.16 - version: 0.28.16(typescript@5.9.3) + specifier: 0.28.17 + version: 0.28.17(typescript@5.9.3) typedoc-plugin-missing-exports: specifier: 4.1.2 - version: 4.1.2(typedoc@0.28.16(typescript@5.9.3)) + version: 4.1.2(typedoc@0.28.17(typescript@5.9.3)) apps/client: dependencies: @@ -14384,8 +14384,8 @@ packages: peerDependencies: typedoc: ^0.28.1 - typedoc@0.28.16: - resolution: {integrity: sha512-x4xW77QC3i5DUFMBp0qjukOTnr/sSg+oEs86nB3LjDslvAmwe/PUGDWbe3GrIqt59oTqoXK5GRK9tAa0sYMiog==} + typedoc@0.28.17: + resolution: {integrity: sha512-ZkJ2G7mZrbxrKxinTQMjFqsCoYY6a5Luwv2GKbTnBCEgV2ihYm5CflA9JnJAwH0pZWavqfYxmDkFHPt4yx2oDQ==} engines: {node: '>= 18', pnpm: '>= 10'} hasBin: true peerDependencies: @@ -16024,8 +16024,6 @@ snapshots: '@ckeditor/ckeditor5-core': 47.4.0 '@ckeditor/ckeditor5-upload': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-ai@47.4.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)': dependencies: @@ -16172,8 +16170,6 @@ snapshots: '@ckeditor/ckeditor5-core': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-code-block@47.4.0(patch_hash=2361d8caad7d6b5bddacc3a3b4aa37dbfba260b1c1b22a450413a79c1bb1ce95)': dependencies: @@ -16366,8 +16362,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-classic@47.4.0': dependencies: @@ -16377,8 +16371,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-decoupled@47.4.0': dependencies: @@ -16388,8 +16380,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-inline@47.4.0': dependencies: @@ -16581,8 +16571,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 '@ckeditor/ckeditor5-widget': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-html-embed@47.4.0': dependencies: @@ -16912,8 +16900,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-restricted-editing@47.4.0': dependencies: @@ -17000,8 +16986,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-special-characters@47.4.0': dependencies: @@ -26065,7 +26049,7 @@ snapshots: domelementtype: 2.3.0 domhandler: 5.0.3 domutils: 3.2.2 - entities: 6.0.0 + entities: 6.0.1 htmlparser2@10.1.0: dependencies: @@ -31843,11 +31827,11 @@ snapshots: typedarray@0.0.6: {} - typedoc-plugin-missing-exports@4.1.2(typedoc@0.28.16(typescript@5.9.3)): + typedoc-plugin-missing-exports@4.1.2(typedoc@0.28.17(typescript@5.9.3)): dependencies: - typedoc: 0.28.16(typescript@5.9.3) + typedoc: 0.28.17(typescript@5.9.3) - typedoc@0.28.16(typescript@5.9.3): + typedoc@0.28.17(typescript@5.9.3): dependencies: '@gerrit0/mini-shiki': 3.17.0 lunr: 2.3.9 From 8b752878270e0886056c8f51d10b5caa054b5f3b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 14 Feb 2026 02:05:55 +0000 Subject: [PATCH 017/247] fix(deps): update dependency i18next to v25.8.7 --- apps/client/package.json | 2 +- apps/server/package.json | 2 +- apps/website/package.json | 2 +- pnpm-lock.yaml | 42 ++++++++++++--------------------------- 4 files changed, 16 insertions(+), 32 deletions(-) diff --git a/apps/client/package.json b/apps/client/package.json index 09c9b51052..d6d691a8f2 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -44,7 +44,7 @@ "draggabilly": "3.0.0", "force-graph": "1.51.1", "globals": "17.3.0", - "i18next": "25.8.6", + "i18next": "25.8.7", "i18next-http-backend": "3.0.2", "jquery": "4.0.0", "jquery.fancytree": "2.38.5", diff --git a/apps/server/package.json b/apps/server/package.json index 30d3370d8d..84f6330599 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -99,7 +99,7 @@ "html2plaintext": "2.1.4", "http-proxy-agent": "7.0.2", "https-proxy-agent": "7.0.6", - "i18next": "25.8.6", + "i18next": "25.8.7", "i18next-fs-backend": "2.6.1", "image-type": "6.0.0", "ini": "6.0.0", diff --git a/apps/website/package.json b/apps/website/package.json index 8d4728b96e..23c55aec75 100644 --- a/apps/website/package.json +++ b/apps/website/package.json @@ -9,7 +9,7 @@ "preview": "pnpm build && vite preview" }, "dependencies": { - "i18next": "25.8.6", + "i18next": "25.8.7", "i18next-http-backend": "3.0.2", "preact": "10.28.3", "preact-iso": "2.11.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4725bc60e0..600a69024c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -264,8 +264,8 @@ importers: specifier: 17.3.0 version: 17.3.0 i18next: - specifier: 25.8.6 - version: 25.8.6(typescript@5.9.3) + specifier: 25.8.7 + version: 25.8.7(typescript@5.9.3) i18next-http-backend: specifier: 3.0.2 version: 3.0.2(encoding@0.1.13) @@ -313,7 +313,7 @@ importers: version: 10.28.3 react-i18next: specifier: 16.5.4 - version: 16.5.4(i18next@25.8.6(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + version: 16.5.4(i18next@25.8.7(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) react-window: specifier: 2.2.6 version: 2.2.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -728,8 +728,8 @@ importers: specifier: 7.0.6 version: 7.0.6 i18next: - specifier: 25.8.6 - version: 25.8.6(typescript@5.9.3) + specifier: 25.8.7 + version: 25.8.7(typescript@5.9.3) i18next-fs-backend: specifier: 2.6.1 version: 2.6.1 @@ -849,8 +849,8 @@ importers: apps/website: dependencies: i18next: - specifier: 25.8.6 - version: 25.8.6(typescript@5.9.3) + specifier: 25.8.7 + version: 25.8.7(typescript@5.9.3) i18next-http-backend: specifier: 3.0.2 version: 3.0.2(encoding@0.1.13) @@ -865,7 +865,7 @@ importers: version: 6.6.5(preact@10.28.3) react-i18next: specifier: 16.5.4 - version: 16.5.4(i18next@25.8.6(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + version: 16.5.4(i18next@25.8.7(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) devDependencies: '@preact/preset-vite': specifier: 2.10.3 @@ -9629,8 +9629,8 @@ packages: i18next-http-backend@3.0.2: resolution: {integrity: sha512-PdlvPnvIp4E1sYi46Ik4tBYh/v/NbYfFFgTjkwFl0is8A18s7/bx9aXqsrOax9WUbeNS6mD2oix7Z0yGGf6m5g==} - i18next@25.8.6: - resolution: {integrity: sha512-HsS6p2yr/Vo5EPljWuBJ9OxKVFok2Q/Oa6PvFTpv2bMcDt2sQMOnKDQ7FTDDdME+3d1YULQjKj7aVSZP1bCouQ==} + i18next@25.8.7: + resolution: {integrity: sha512-ttxxc5+67S/0hhoeVdEgc1lRklZhdfcUSEPp1//uUG2NB88X3667gRsDar+ZWQFdysnOsnb32bcoMsa4mtzhkQ==} peerDependencies: typescript: ^5 peerDependenciesMeta: @@ -16024,8 +16024,6 @@ snapshots: '@ckeditor/ckeditor5-core': 47.4.0 '@ckeditor/ckeditor5-upload': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-ai@47.4.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)': dependencies: @@ -16172,8 +16170,6 @@ snapshots: '@ckeditor/ckeditor5-core': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-code-block@47.4.0(patch_hash=2361d8caad7d6b5bddacc3a3b4aa37dbfba260b1c1b22a450413a79c1bb1ce95)': dependencies: @@ -16366,8 +16362,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-classic@47.4.0': dependencies: @@ -16377,8 +16371,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-decoupled@47.4.0': dependencies: @@ -16388,8 +16380,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-inline@47.4.0': dependencies: @@ -16581,8 +16571,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 '@ckeditor/ckeditor5-widget': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-html-embed@47.4.0': dependencies: @@ -16912,8 +16900,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-restricted-editing@47.4.0': dependencies: @@ -17000,8 +16986,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-special-characters@47.4.0': dependencies: @@ -26227,7 +26211,7 @@ snapshots: transitivePeerDependencies: - encoding - i18next@25.8.6(typescript@5.9.3): + i18next@25.8.7(typescript@5.9.3): dependencies: '@babel/runtime': 7.28.4 optionalDependencies: @@ -29670,11 +29654,11 @@ snapshots: react: 19.2.4 scheduler: 0.27.0 - react-i18next@16.5.4(i18next@25.8.6(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3): + react-i18next@16.5.4(i18next@25.8.7(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3): dependencies: '@babel/runtime': 7.28.4 html-parse-stringify: 3.0.1 - i18next: 25.8.6(typescript@5.9.3) + i18next: 25.8.7(typescript@5.9.3) react: 19.2.4 use-sync-external-store: 1.6.0(react@19.2.4) optionalDependencies: From 5f16ecf02db9a28dfa65c43623cff40fdf1fc63f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 14 Feb 2026 02:06:40 +0000 Subject: [PATCH 018/247] fix(deps): update dependency react-window to v2.2.7 --- apps/client/package.json | 2 +- pnpm-lock.yaml | 26 +++++--------------------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/apps/client/package.json b/apps/client/package.json index 09c9b51052..02a2b4ce4a 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -61,7 +61,7 @@ "panzoom": "9.4.3", "preact": "10.28.3", "react-i18next": "16.5.4", - "react-window": "2.2.6", + "react-window": "2.2.7", "reveal.js": "5.2.1", "svg-pan-zoom": "3.6.2", "tabulator-tables": "6.3.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4725bc60e0..a3db490fb1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -315,8 +315,8 @@ importers: specifier: 16.5.4 version: 16.5.4(i18next@25.8.6(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) react-window: - specifier: 2.2.6 - version: 2.2.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: 2.2.7 + version: 2.2.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) reveal.js: specifier: 5.2.1 version: 5.2.1 @@ -12772,8 +12772,8 @@ packages: peerDependencies: react: ^18.0.0 || ^19.0.0 - react-window@2.2.6: - resolution: {integrity: sha512-v89O08xRdpCaEuf380B39D1C/0KgUDZA59xft6SVAjzjz/xQxSyXrgDWHymIsYI6TMrqE8WO+G0/PB9AGE8VNA==} + react-window@2.2.7: + resolution: {integrity: sha512-SH5nvfUQwGHYyriDUAOt7wfPsfG9Qxd6OdzQxl5oQ4dsSsUicqQvjV7dR+NqZ4coY0fUn3w1jnC5PwzIUWEg5w==} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 @@ -16024,8 +16024,6 @@ snapshots: '@ckeditor/ckeditor5-core': 47.4.0 '@ckeditor/ckeditor5-upload': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-ai@47.4.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)': dependencies: @@ -16172,8 +16170,6 @@ snapshots: '@ckeditor/ckeditor5-core': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-code-block@47.4.0(patch_hash=2361d8caad7d6b5bddacc3a3b4aa37dbfba260b1c1b22a450413a79c1bb1ce95)': dependencies: @@ -16366,8 +16362,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-classic@47.4.0': dependencies: @@ -16377,8 +16371,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-decoupled@47.4.0': dependencies: @@ -16388,8 +16380,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-inline@47.4.0': dependencies: @@ -16581,8 +16571,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 '@ckeditor/ckeditor5-widget': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-html-embed@47.4.0': dependencies: @@ -16912,8 +16900,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-restricted-editing@47.4.0': dependencies: @@ -17000,8 +16986,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-special-characters@47.4.0': dependencies: @@ -29746,7 +29730,7 @@ snapshots: prop-types: 15.8.1 react: 19.2.4 - react-window@2.2.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + react-window@2.2.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) From f3b37b16d5f63d8998c73372efe7abb6cb01aff5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 14 Feb 2026 02:07:20 +0000 Subject: [PATCH 019/247] chore(deps): update dependency openai to v6.22.0 --- apps/server/package.json | 2 +- pnpm-lock.yaml | 26 +++++--------------------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/apps/server/package.json b/apps/server/package.json index 30d3370d8d..ead8d102bc 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -112,7 +112,7 @@ "multer": "2.0.2", "normalize-strings": "1.1.1", "ollama": "0.6.3", - "openai": "6.21.0", + "openai": "6.22.0", "rand-token": "1.0.1", "safe-compare": "1.1.4", "sanitize-filename": "1.6.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4725bc60e0..28b41d4b99 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -767,8 +767,8 @@ importers: specifier: 0.6.3 version: 0.6.3 openai: - specifier: 6.21.0 - version: 6.21.0(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@4.1.12) + specifier: 6.22.0 + version: 6.22.0(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@4.1.12) rand-token: specifier: 1.0.1 version: 1.0.1 @@ -11609,8 +11609,8 @@ packages: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} - openai@6.21.0: - resolution: {integrity: sha512-26dQFi76dB8IiN/WKGQOV+yKKTTlRCxQjoi2WLt0kMcH8pvxVyvfdBDkld5GTl7W1qvBpwVOtFcsqktj3fBRpA==} + openai@6.22.0: + resolution: {integrity: sha512-7Yvy17F33Bi9RutWbsaYt5hJEEJ/krRPOrwan+f9aCPuMat1WVsb2VNSII5W1EksKT6fF69TG/xj4XzodK3JZw==} hasBin: true peerDependencies: ws: ^8.18.0 @@ -16024,8 +16024,6 @@ snapshots: '@ckeditor/ckeditor5-core': 47.4.0 '@ckeditor/ckeditor5-upload': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-ai@47.4.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)': dependencies: @@ -16172,8 +16170,6 @@ snapshots: '@ckeditor/ckeditor5-core': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-code-block@47.4.0(patch_hash=2361d8caad7d6b5bddacc3a3b4aa37dbfba260b1c1b22a450413a79c1bb1ce95)': dependencies: @@ -16366,8 +16362,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-classic@47.4.0': dependencies: @@ -16377,8 +16371,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-decoupled@47.4.0': dependencies: @@ -16388,8 +16380,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-inline@47.4.0': dependencies: @@ -16581,8 +16571,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 '@ckeditor/ckeditor5-widget': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-html-embed@47.4.0': dependencies: @@ -16912,8 +16900,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-restricted-editing@47.4.0': dependencies: @@ -17000,8 +16986,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-special-characters@47.4.0': dependencies: @@ -28559,7 +28543,7 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 - openai@6.21.0(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@4.1.12): + openai@6.22.0(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@4.1.12): optionalDependencies: ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@6.0.5) zod: 4.1.12 From f3094e307982576c42a345f14bc4722541dc95ad Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 14 Feb 2026 02:08:04 +0000 Subject: [PATCH 020/247] chore(deps): update dependency stylelint to v17.3.0 --- packages/ckeditor5-admonition/package.json | 2 +- packages/ckeditor5-footnotes/package.json | 2 +- .../ckeditor5-keyboard-marker/package.json | 2 +- packages/ckeditor5-math/package.json | 2 +- packages/ckeditor5-mermaid/package.json | 2 +- pnpm-lock.yaml | 101 ++++++++---------- 6 files changed, 49 insertions(+), 62 deletions(-) diff --git a/packages/ckeditor5-admonition/package.json b/packages/ckeditor5-admonition/package.json index bdd0d23c6c..dc84866966 100644 --- a/packages/ckeditor5-admonition/package.json +++ b/packages/ckeditor5-admonition/package.json @@ -33,7 +33,7 @@ "eslint-config-ckeditor5": ">=9.1.0", "http-server": "14.1.1", "lint-staged": "16.2.7", - "stylelint": "17.2.0", + "stylelint": "17.3.0", "stylelint-config-ckeditor5": ">=9.1.0", "ts-node": "10.9.2", "typescript": "5.9.3", diff --git a/packages/ckeditor5-footnotes/package.json b/packages/ckeditor5-footnotes/package.json index 137c932a1a..829ccb3ac3 100644 --- a/packages/ckeditor5-footnotes/package.json +++ b/packages/ckeditor5-footnotes/package.json @@ -34,7 +34,7 @@ "eslint-config-ckeditor5": ">=9.1.0", "http-server": "14.1.1", "lint-staged": "16.2.7", - "stylelint": "17.2.0", + "stylelint": "17.3.0", "stylelint-config-ckeditor5": ">=9.1.0", "ts-node": "10.9.2", "typescript": "5.9.3", diff --git a/packages/ckeditor5-keyboard-marker/package.json b/packages/ckeditor5-keyboard-marker/package.json index 4d8f257f08..5770bddf03 100644 --- a/packages/ckeditor5-keyboard-marker/package.json +++ b/packages/ckeditor5-keyboard-marker/package.json @@ -36,7 +36,7 @@ "eslint-config-ckeditor5": ">=9.1.0", "http-server": "14.1.1", "lint-staged": "16.2.7", - "stylelint": "17.2.0", + "stylelint": "17.3.0", "stylelint-config-ckeditor5": ">=9.1.0", "ts-node": "10.9.2", "typescript": "5.9.3", diff --git a/packages/ckeditor5-math/package.json b/packages/ckeditor5-math/package.json index daf7d52504..08535c7986 100644 --- a/packages/ckeditor5-math/package.json +++ b/packages/ckeditor5-math/package.json @@ -36,7 +36,7 @@ "eslint-config-ckeditor5": ">=9.1.0", "http-server": "14.1.1", "lint-staged": "16.2.7", - "stylelint": "17.2.0", + "stylelint": "17.3.0", "stylelint-config-ckeditor5": ">=9.1.0", "ts-node": "10.9.2", "typescript": "5.9.3", diff --git a/packages/ckeditor5-mermaid/package.json b/packages/ckeditor5-mermaid/package.json index ea1a659023..92af4b0a1e 100644 --- a/packages/ckeditor5-mermaid/package.json +++ b/packages/ckeditor5-mermaid/package.json @@ -36,7 +36,7 @@ "eslint-config-ckeditor5": ">=9.1.0", "http-server": "14.1.1", "lint-staged": "16.2.7", - "stylelint": "17.2.0", + "stylelint": "17.3.0", "stylelint-config-ckeditor5": ">=9.1.0", "ts-node": "10.9.2", "typescript": "5.9.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4725bc60e0..0745c0d3a2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -962,11 +962,11 @@ importers: specifier: 16.2.7 version: 16.2.7 stylelint: - specifier: 17.2.0 - version: 17.2.0(typescript@5.9.3) + specifier: 17.3.0 + version: 17.3.0(typescript@5.9.3) stylelint-config-ckeditor5: specifier: '>=9.1.0' - version: 13.0.0(stylelint@17.2.0(typescript@5.9.3)) + version: 13.0.0(stylelint@17.3.0(typescript@5.9.3)) ts-node: specifier: 10.9.2 version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.13)(typescript@5.9.3) @@ -1022,11 +1022,11 @@ importers: specifier: 16.2.7 version: 16.2.7 stylelint: - specifier: 17.2.0 - version: 17.2.0(typescript@5.9.3) + specifier: 17.3.0 + version: 17.3.0(typescript@5.9.3) stylelint-config-ckeditor5: specifier: '>=9.1.0' - version: 13.0.0(stylelint@17.2.0(typescript@5.9.3)) + version: 13.0.0(stylelint@17.3.0(typescript@5.9.3)) ts-node: specifier: 10.9.2 version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.13)(typescript@5.9.3) @@ -1082,11 +1082,11 @@ importers: specifier: 16.2.7 version: 16.2.7 stylelint: - specifier: 17.2.0 - version: 17.2.0(typescript@5.9.3) + specifier: 17.3.0 + version: 17.3.0(typescript@5.9.3) stylelint-config-ckeditor5: specifier: '>=9.1.0' - version: 13.0.0(stylelint@17.2.0(typescript@5.9.3)) + version: 13.0.0(stylelint@17.3.0(typescript@5.9.3)) ts-node: specifier: 10.9.2 version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.13)(typescript@5.9.3) @@ -1149,11 +1149,11 @@ importers: specifier: 16.2.7 version: 16.2.7 stylelint: - specifier: 17.2.0 - version: 17.2.0(typescript@5.9.3) + specifier: 17.3.0 + version: 17.3.0(typescript@5.9.3) stylelint-config-ckeditor5: specifier: '>=9.1.0' - version: 13.0.0(stylelint@17.2.0(typescript@5.9.3)) + version: 13.0.0(stylelint@17.3.0(typescript@5.9.3)) ts-node: specifier: 10.9.2 version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.13)(typescript@5.9.3) @@ -1216,11 +1216,11 @@ importers: specifier: 16.2.7 version: 16.2.7 stylelint: - specifier: 17.2.0 - version: 17.2.0(typescript@5.9.3) + specifier: 17.3.0 + version: 17.3.0(typescript@5.9.3) stylelint-config-ckeditor5: specifier: '>=9.1.0' - version: 13.0.0(stylelint@17.2.0(typescript@5.9.3)) + version: 13.0.0(stylelint@17.3.0(typescript@5.9.3)) ts-node: specifier: 10.9.2 version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.13)(typescript@5.9.3) @@ -2210,8 +2210,8 @@ packages: '@csstools/css-parser-algorithms': ^3.0.5 '@csstools/css-tokenizer': ^3.0.4 - '@csstools/css-calc@3.0.0': - resolution: {integrity: sha512-q4d82GTl8BIlh/dTnVsWmxnbWJeb3kiU8eUH71UxlxnS+WIaALmtzTL8gR15PkYOexMQYVk0CO4qIG93C1IvPA==} + '@csstools/css-calc@3.1.1': + resolution: {integrity: sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==} engines: {node: '>=20.19.0'} peerDependencies: '@csstools/css-parser-algorithms': ^4.0.0 @@ -2236,10 +2236,6 @@ packages: peerDependencies: '@csstools/css-tokenizer': ^4.0.0 - '@csstools/css-syntax-patches-for-csstree@1.0.25': - resolution: {integrity: sha512-g0Kw9W3vjx5BEBAF8c5Fm2NcB/Fs8jJXh85aXqwEXiL+tqtOut07TWgyaGzAAfTM+gKckrrncyeGEZPcaRgm2Q==} - engines: {node: '>=18'} - '@csstools/css-syntax-patches-for-csstree@1.0.27': resolution: {integrity: sha512-sxP33Jwg1bviSUXAV43cVYdmjt2TLnLXNqCWl9xmxHawWVjGz/kEbdkr7F9pxJNBN2Mh+dq0crgItbW6tQvyow==} @@ -13786,6 +13782,10 @@ packages: resolution: {integrity: sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==} engines: {node: '>=20'} + string-width@8.1.1: + resolution: {integrity: sha512-KpqHIdDL9KwYk22wEOg/VIqYbrnLeSApsKT/bSj6Ez7pn3CftUiLAv2Lccpq1ALcpLV9UX1Ppn92npZWu2w/aw==} + engines: {node: '>=20'} + string.prototype.matchall@4.0.12: resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} engines: {node: '>= 0.4'} @@ -13953,8 +13953,8 @@ packages: engines: {node: '>=18.12.0'} hasBin: true - stylelint@17.2.0: - resolution: {integrity: sha512-602jhMkRt6P1dSh9kEzbFIaOKY//h4D0E7u/w2WHKxmi5VAjjMqe6P8rQPJuCWdbB3apOkjOFN5kcg6qWPIZWQ==} + stylelint@17.3.0: + resolution: {integrity: sha512-1POV91lcEMhj6SLVaOeA0KlS9yattS+qq+cyWqP/nYzWco7K5jznpGH1ExngvPlTM9QF1Kjd2bmuzJu9TH2OcA==} engines: {node: '>=20.19.0'} hasBin: true @@ -16024,8 +16024,6 @@ snapshots: '@ckeditor/ckeditor5-core': 47.4.0 '@ckeditor/ckeditor5-upload': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-ai@47.4.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)': dependencies: @@ -16172,8 +16170,6 @@ snapshots: '@ckeditor/ckeditor5-core': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-code-block@47.4.0(patch_hash=2361d8caad7d6b5bddacc3a3b4aa37dbfba260b1c1b22a450413a79c1bb1ce95)': dependencies: @@ -16366,8 +16362,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-classic@47.4.0': dependencies: @@ -16377,8 +16371,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-decoupled@47.4.0': dependencies: @@ -16388,8 +16380,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-inline@47.4.0': dependencies: @@ -16581,8 +16571,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 '@ckeditor/ckeditor5-widget': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-html-embed@47.4.0': dependencies: @@ -16912,8 +16900,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-restricted-editing@47.4.0': dependencies: @@ -17000,8 +16986,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-special-characters@47.4.0': dependencies: @@ -17338,7 +17322,7 @@ snapshots: '@csstools/css-tokenizer': 3.0.4 optional: true - '@csstools/css-calc@3.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + '@csstools/css-calc@3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': dependencies: '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) '@csstools/css-tokenizer': 4.0.0 @@ -17359,8 +17343,6 @@ snapshots: dependencies: '@csstools/css-tokenizer': 4.0.0 - '@csstools/css-syntax-patches-for-csstree@1.0.25': {} - '@csstools/css-syntax-patches-for-csstree@1.0.27': {} '@csstools/css-tokenizer@3.0.4': {} @@ -20802,7 +20784,7 @@ snapshots: - supports-color - typescript - '@stylistic/stylelint-plugin@3.1.3(stylelint@17.2.0(typescript@5.9.3))': + '@stylistic/stylelint-plugin@3.1.3(stylelint@17.3.0(typescript@5.9.3))': dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 @@ -20812,7 +20794,7 @@ snapshots: postcss-selector-parser: 6.1.2 postcss-value-parser: 4.2.0 style-search: 0.1.0 - stylelint: 17.2.0(typescript@5.9.3) + stylelint: 17.3.0(typescript@5.9.3) '@swc/core-darwin-arm64@1.11.29': optional: true @@ -31025,6 +31007,11 @@ snapshots: get-east-asian-width: 1.4.0 strip-ansi: 7.1.2 + string-width@8.1.1: + dependencies: + get-east-asian-width: 1.4.0 + strip-ansi: 7.1.2 + string.prototype.matchall@4.0.12: dependencies: call-bind: 1.0.8 @@ -31175,34 +31162,34 @@ snapshots: postcss: 8.5.6 postcss-selector-parser: 7.1.1 - stylelint-config-ckeditor5@13.0.0(stylelint@17.2.0(typescript@5.9.3)): + stylelint-config-ckeditor5@13.0.0(stylelint@17.3.0(typescript@5.9.3)): dependencies: - '@stylistic/stylelint-plugin': 3.1.3(stylelint@17.2.0(typescript@5.9.3)) - stylelint: 17.2.0(typescript@5.9.3) - stylelint-config-recommended: 16.0.0(stylelint@17.2.0(typescript@5.9.3)) - stylelint-plugin-ckeditor5-rules: 13.0.0(stylelint@17.2.0(typescript@5.9.3)) + '@stylistic/stylelint-plugin': 3.1.3(stylelint@17.3.0(typescript@5.9.3)) + stylelint: 17.3.0(typescript@5.9.3) + stylelint-config-recommended: 16.0.0(stylelint@17.3.0(typescript@5.9.3)) + stylelint-plugin-ckeditor5-rules: 13.0.0(stylelint@17.3.0(typescript@5.9.3)) stylelint-config-ckeditor5@2.0.1(stylelint@16.26.1(typescript@5.0.4)): dependencies: stylelint: 16.26.1(typescript@5.0.4) stylelint-config-recommended: 3.0.0(stylelint@16.26.1(typescript@5.0.4)) - stylelint-config-recommended@16.0.0(stylelint@17.2.0(typescript@5.9.3)): + stylelint-config-recommended@16.0.0(stylelint@17.3.0(typescript@5.9.3)): dependencies: - stylelint: 17.2.0(typescript@5.9.3) + stylelint: 17.3.0(typescript@5.9.3) stylelint-config-recommended@3.0.0(stylelint@16.26.1(typescript@5.0.4)): dependencies: stylelint: 16.26.1(typescript@5.0.4) - stylelint-plugin-ckeditor5-rules@13.0.0(stylelint@17.2.0(typescript@5.9.3)): + stylelint-plugin-ckeditor5-rules@13.0.0(stylelint@17.3.0(typescript@5.9.3)): dependencies: - stylelint: 17.2.0(typescript@5.9.3) + stylelint: 17.3.0(typescript@5.9.3) stylelint@16.26.1(typescript@5.0.4): dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-syntax-patches-for-csstree': 1.0.25 + '@csstools/css-syntax-patches-for-csstree': 1.0.27 '@csstools/css-tokenizer': 3.0.4 '@csstools/media-query-list-parser': 4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1) @@ -31244,9 +31231,9 @@ snapshots: - supports-color - typescript - stylelint@17.2.0(typescript@5.9.3): + stylelint@17.3.0(typescript@5.9.3): dependencies: - '@csstools/css-calc': 3.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) '@csstools/css-syntax-patches-for-csstree': 1.0.27 '@csstools/css-tokenizer': 4.0.0 @@ -31280,7 +31267,7 @@ snapshots: postcss-safe-parser: 7.0.1(postcss@8.5.6) postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 - string-width: 8.1.0 + string-width: 8.1.1 supports-hyperlinks: 4.4.0 svg-tags: 1.0.0 table: 6.9.0 From 311b1d8a648f2a194fc3cf9579609e0311997b17 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 14 Feb 2026 02:08:43 +0000 Subject: [PATCH 021/247] fix(deps): update dependency @preact/signals to v2.8.0 --- apps/client/package.json | 2 +- pnpm-lock.yaml | 26 +++++--------------------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/apps/client/package.json b/apps/client/package.json index 09c9b51052..77ef5cb3cf 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -27,7 +27,7 @@ "@mermaid-js/layout-elk": "0.2.0", "@mind-elixir/node-menu": "5.0.1", "@popperjs/core": "2.11.8", - "@preact/signals": "2.7.1", + "@preact/signals": "2.8.0", "@triliumnext/ckeditor5": "workspace:*", "@triliumnext/codemirror": "workspace:*", "@triliumnext/commons": "workspace:*", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4725bc60e0..d64fdf93f8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -213,8 +213,8 @@ importers: specifier: 2.11.8 version: 2.11.8 '@preact/signals': - specifier: 2.7.1 - version: 2.7.1(preact@10.28.3) + specifier: 2.8.0 + version: 2.8.0(preact@10.28.3) '@triliumnext/ckeditor5': specifier: workspace:* version: link:../../packages/ckeditor5 @@ -4432,8 +4432,8 @@ packages: '@preact/signals-core@1.13.0': resolution: {integrity: sha512-slT6XeTCAbdql61GVLlGU4x7XHI7kCZV5Um5uhE4zLX4ApgiiXc0UYFvVOKq06xcovzp7p+61l68oPi563ARKg==} - '@preact/signals@2.7.1': - resolution: {integrity: sha512-mP2+wMYHqDXVKFGzjqkL6CiHj3okB8eVTTJUZBrSVGozi/XfA+zZRCEALKKZYRoSoqLyT4J6qM4lhwT9155s1Q==} + '@preact/signals@2.8.0': + resolution: {integrity: sha512-lcILM82mei8s/53n2M6uZlrDHLlgLld8Squ0PVSUL5Ae1M45uEstWfHm+wcDqp2U5I/ZYrBvCY65udFyTo5OZw==} peerDependencies: preact: 10.28.3 @@ -16024,8 +16024,6 @@ snapshots: '@ckeditor/ckeditor5-core': 47.4.0 '@ckeditor/ckeditor5-upload': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-ai@47.4.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)': dependencies: @@ -16172,8 +16170,6 @@ snapshots: '@ckeditor/ckeditor5-core': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-code-block@47.4.0(patch_hash=2361d8caad7d6b5bddacc3a3b4aa37dbfba260b1c1b22a450413a79c1bb1ce95)': dependencies: @@ -16366,8 +16362,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-classic@47.4.0': dependencies: @@ -16377,8 +16371,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-decoupled@47.4.0': dependencies: @@ -16388,8 +16380,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-editor-inline@47.4.0': dependencies: @@ -16581,8 +16571,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 '@ckeditor/ckeditor5-widget': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-html-embed@47.4.0': dependencies: @@ -16912,8 +16900,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-restricted-editing@47.4.0': dependencies: @@ -17000,8 +16986,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-special-characters@47.4.0': dependencies: @@ -19642,7 +19626,7 @@ snapshots: '@preact/signals-core@1.13.0': {} - '@preact/signals@2.7.1(preact@10.28.3)': + '@preact/signals@2.8.0(preact@10.28.3)': dependencies: '@preact/signals-core': 1.13.0 preact: 10.28.3 From f3dccc0aec8c4b50fbf696f268d5dab832609b89 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 14 Feb 2026 09:19:46 +0200 Subject: [PATCH 022/247] feat(badges/content): detect icon pack --- apps/client/src/stylesheets/theme-next-light.css | 3 ++- apps/client/src/widgets/layout/NoteBadges.css | 1 + apps/client/src/widgets/layout/NoteBadges.tsx | 15 +++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/client/src/stylesheets/theme-next-light.css b/apps/client/src/stylesheets/theme-next-light.css index 2d7862ae00..44f594d0ab 100644 --- a/apps/client/src/stylesheets/theme-next-light.css +++ b/apps/client/src/stylesheets/theme-next-light.css @@ -202,6 +202,7 @@ --badge-share-background-color: #6b6b6b; --badge-clipped-note-background-color: #2284c0; --badge-execute-background-color: #7b47af; + --badge-icon-pack-background-color: rgb(228, 163, 44); --note-icon-background-color: #4f4f4f; --note-icon-color: white; @@ -322,4 +323,4 @@ .note-split.with-hue *::selection, .quick-edit-dialog-wrapper.with-hue *::selection { --selection-background-color: hsl(var(--custom-color-hue), 60%, 90%); -} \ No newline at end of file +} diff --git a/apps/client/src/widgets/layout/NoteBadges.css b/apps/client/src/widgets/layout/NoteBadges.css index ec163da6f2..7c11c7fce6 100644 --- a/apps/client/src/widgets/layout/NoteBadges.css +++ b/apps/client/src/widgets/layout/NoteBadges.css @@ -37,6 +37,7 @@ pointer-events: none; } } + &.icon-pack-badge { --color: var(--badge-icon-pack-background-color); } min-width: 0; diff --git a/apps/client/src/widgets/layout/NoteBadges.tsx b/apps/client/src/widgets/layout/NoteBadges.tsx index b4fba9e28a..669778d71b 100644 --- a/apps/client/src/widgets/layout/NoteBadges.tsx +++ b/apps/client/src/widgets/layout/NoteBadges.tsx @@ -19,6 +19,7 @@ export default function NoteBadges() { +
        ); } @@ -147,3 +148,17 @@ export function SaveStatusBadge() { /> ); } + +function IconPackBadge() { + const { note } = useNoteContext(); + const isEnabledIconPack = useNoteLabelBoolean(note, "iconPack"); + const isDisabledIconPack = useNoteLabelBoolean(note, "disabled:iconPack"); + + return ((isEnabledIconPack || isDisabledIconPack) && + + ); +} From 7d103f8c50fafb5af87e7af96b73e0d7dcc2dab4 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 14 Feb 2026 09:37:48 +0200 Subject: [PATCH 023/247] refactor(badges/content): extract to separate file --- .../widgets/layout/ActiveContentBadges.tsx | 34 +++++++++++++++++++ apps/client/src/widgets/layout/NoteBadges.css | 5 +++ apps/client/src/widgets/layout/NoteBadges.tsx | 17 ++-------- 3 files changed, 41 insertions(+), 15 deletions(-) create mode 100644 apps/client/src/widgets/layout/ActiveContentBadges.tsx diff --git a/apps/client/src/widgets/layout/ActiveContentBadges.tsx b/apps/client/src/widgets/layout/ActiveContentBadges.tsx new file mode 100644 index 0000000000..1ffa2792c3 --- /dev/null +++ b/apps/client/src/widgets/layout/ActiveContentBadges.tsx @@ -0,0 +1,34 @@ +import { Badge } from "../react/Badge"; +import FormToggle from "../react/FormToggle"; +import { useNoteContext, useNoteLabelBoolean } from "../react/hooks"; + +export function ActiveContentBadges() { + return ( + <> + + + + ); +} + +function IconPackBadge() { + const { note } = useNoteContext(); + const [ isEnabledIconPack ] = useNoteLabelBoolean(note, "iconPack"); + const [ isDisabledIconPack ] = useNoteLabelBoolean(note, "disabled:iconPack"); + + return ((isEnabledIconPack || isDisabledIconPack) && + + ); +} + +function ActiveContentToggle() { + return ; +} diff --git a/apps/client/src/widgets/layout/NoteBadges.css b/apps/client/src/widgets/layout/NoteBadges.css index 7c11c7fce6..b2b6e18f77 100644 --- a/apps/client/src/widgets/layout/NoteBadges.css +++ b/apps/client/src/widgets/layout/NoteBadges.css @@ -46,6 +46,11 @@ text-overflow: ellipsis; min-width: 0; } + + .switch-button { + --switch-track-height: 8px; + --switch-track-width: 30px; + } } .dropdown-badge { diff --git a/apps/client/src/widgets/layout/NoteBadges.tsx b/apps/client/src/widgets/layout/NoteBadges.tsx index 669778d71b..bf484edf73 100644 --- a/apps/client/src/widgets/layout/NoteBadges.tsx +++ b/apps/client/src/widgets/layout/NoteBadges.tsx @@ -10,6 +10,7 @@ import { FormDropdownDivider, FormListItem } from "../react/FormList"; import { useGetContextData, useIsNoteReadOnly, useNoteContext, useNoteLabel, useNoteLabelBoolean } from "../react/hooks"; import { useShareState } from "../ribbon/BasicPropertiesTab"; import { useShareInfo } from "../shared_info"; +import { ActiveContentBadges } from "./ActiveContentBadges"; export default function NoteBadges() { return ( @@ -19,7 +20,7 @@ export default function NoteBadges() { - + ); } @@ -148,17 +149,3 @@ export function SaveStatusBadge() { /> ); } - -function IconPackBadge() { - const { note } = useNoteContext(); - const isEnabledIconPack = useNoteLabelBoolean(note, "iconPack"); - const isDisabledIconPack = useNoteLabelBoolean(note, "disabled:iconPack"); - - return ((isEnabledIconPack || isDisabledIconPack) && - - ); -} From a2264847b6a19f496657ab4c45f33c3b98aad349 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 14 Feb 2026 09:53:37 +0200 Subject: [PATCH 024/247] refactor(badges/content): use shared mechanism for extracting info --- .../widgets/layout/ActiveContentBadges.tsx | 60 ++++++++++++++++--- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/apps/client/src/widgets/layout/ActiveContentBadges.tsx b/apps/client/src/widgets/layout/ActiveContentBadges.tsx index 1ffa2792c3..62eb528898 100644 --- a/apps/client/src/widgets/layout/ActiveContentBadges.tsx +++ b/apps/client/src/widgets/layout/ActiveContentBadges.tsx @@ -1,22 +1,26 @@ +import { useEffect, useState } from "preact/hooks"; + +import FNote from "../../entities/fnote"; +import attributes from "../../services/attributes"; import { Badge } from "../react/Badge"; import FormToggle from "../react/FormToggle"; -import { useNoteContext, useNoteLabelBoolean } from "../react/hooks"; +import { useNoteContext, useTriliumEvent } from "../react/hooks"; export function ActiveContentBadges() { + const { note } = useNoteContext(); + const info = useActiveContentInfo(note); + console.log("Got inf ", info); + return ( <> - + {info?.type === "iconPack" && } ); } function IconPackBadge() { - const { note } = useNoteContext(); - const [ isEnabledIconPack ] = useNoteLabelBoolean(note, "iconPack"); - const [ isDisabledIconPack ] = useNoteLabelBoolean(note, "disabled:iconPack"); - - return ((isEnabledIconPack || isDisabledIconPack) && + return ( ; } + +const activeContentLabels = [ "iconPack" ] as const; + +interface ActiveContentInfo { + type: "iconPack"; +} + +function useActiveContentInfo(note: FNote | null | undefined) { + const [ info, setInfo ] = useState(null); + + function refresh() { + let type: ActiveContentInfo["type"] | null = null; + + if (!note) { + setInfo(null); + return; + } + + for (const labelToCheck of activeContentLabels ) { + if (note.hasLabel(labelToCheck)) { + type = labelToCheck; + } + } + + if (type) { + setInfo({ type }); + } else { + setInfo(null); + } + } + + // Refresh on note change. + useEffect(refresh, [ note ]); + + useTriliumEvent("entitiesReloaded", ({ loadResults }) => { + if (loadResults.getAttributeRows().some(attr => attributes.isAffecting(attr, note))) { + refresh(); + } + }); + + return info; +} From ccff210b4c9834cae4c410f740f804006ed2a8c2 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 14 Feb 2026 09:57:40 +0200 Subject: [PATCH 025/247] feat(badges/content): indicate enabled/disabled state --- .../widgets/layout/ActiveContentBadges.tsx | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/client/src/widgets/layout/ActiveContentBadges.tsx b/apps/client/src/widgets/layout/ActiveContentBadges.tsx index 62eb528898..c2eab4a68a 100644 --- a/apps/client/src/widgets/layout/ActiveContentBadges.tsx +++ b/apps/client/src/widgets/layout/ActiveContentBadges.tsx @@ -11,10 +11,10 @@ export function ActiveContentBadges() { const info = useActiveContentInfo(note); console.log("Got inf ", info); - return ( + return (info && <> - {info?.type === "iconPack" && } - + {info.type === "iconPack" && } + ); } @@ -29,11 +29,11 @@ function IconPackBadge() { ); } -function ActiveContentToggle() { - return ; } @@ -41,6 +41,7 @@ const activeContentLabels = [ "iconPack" ] as const; interface ActiveContentInfo { type: "iconPack"; + isEnabled: boolean; } function useActiveContentInfo(note: FNote | null | undefined) { @@ -48,6 +49,7 @@ function useActiveContentInfo(note: FNote | null | undefined) { function refresh() { let type: ActiveContentInfo["type"] | null = null; + let isEnabled = true; if (!note) { setInfo(null); @@ -57,11 +59,16 @@ function useActiveContentInfo(note: FNote | null | undefined) { for (const labelToCheck of activeContentLabels ) { if (note.hasLabel(labelToCheck)) { type = labelToCheck; + break; + } else if (note.hasLabel(`disabled:${labelToCheck}`)) { + type = labelToCheck; + isEnabled = false; + break; } } if (type) { - setInfo({ type }); + setInfo({ type, isEnabled }); } else { setInfo(null); } From 9b3396349e025ca2f412def8d5a25fd7d980d7ee Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 14 Feb 2026 10:30:24 +0200 Subject: [PATCH 026/247] refactor(commons): add builtin_attributes to commons --- apps/server/src/services/anonymization.ts | 10 +++++----- apps/server/src/services/attributes.ts | 20 +++++++++---------- packages/commons/src/index.ts | 1 + .../commons/src/lib}/builtin_attributes.ts | 0 4 files changed, 15 insertions(+), 16 deletions(-) rename {apps/server/src/services => packages/commons/src/lib}/builtin_attributes.ts (100%) diff --git a/apps/server/src/services/anonymization.ts b/apps/server/src/services/anonymization.ts index 6950be72d8..262251ba91 100644 --- a/apps/server/src/services/anonymization.ts +++ b/apps/server/src/services/anonymization.ts @@ -1,11 +1,11 @@ -import BUILTIN_ATTRIBUTES from "./builtin_attributes.js"; +import { AnonymizedDbResponse, BUILTIN_ATTRIBUTES, DatabaseAnonymizeResponse } from "@triliumnext/commons"; +import Database from "better-sqlite3"; import fs from "fs"; +import path from "path"; + import dataDir from "./data_dir.js"; import dateUtils from "./date_utils.js"; -import Database from "better-sqlite3"; import sql from "./sql.js"; -import path from "path"; -import { AnonymizedDbResponse, DatabaseAnonymizeResponse } from "@triliumnext/commons"; function getFullAnonymizationScript() { // we want to delete all non-builtin attributes because they can contain sensitive names and values @@ -86,7 +86,7 @@ function getExistingAnonymizedDatabases() { .readdirSync(dataDir.ANONYMIZED_DB_DIR) .filter((fileName) => fileName.includes("anonymized")) .map((fileName) => ({ - fileName: fileName, + fileName, filePath: path.resolve(dataDir.ANONYMIZED_DB_DIR, fileName) })) satisfies AnonymizedDbResponse[]; } diff --git a/apps/server/src/services/attributes.ts b/apps/server/src/services/attributes.ts index c1fec6808f..2e1a207447 100644 --- a/apps/server/src/services/attributes.ts +++ b/apps/server/src/services/attributes.ts @@ -1,13 +1,11 @@ -"use strict"; +import { type AttributeRow, BUILTIN_ATTRIBUTES } from "@triliumnext/commons"; -import searchService from "./search/services/search.js"; -import sql from "./sql.js"; import becca from "../becca/becca.js"; import BAttribute from "../becca/entities/battribute.js"; -import attributeFormatter from "./attribute_formatter.js"; -import BUILTIN_ATTRIBUTES from "./builtin_attributes.js"; import type BNote from "../becca/entities/bnote.js"; -import type { AttributeRow } from "@triliumnext/commons"; +import attributeFormatter from "./attribute_formatter.js"; +import searchService from "./search/services/search.js"; +import sql from "./sql.js"; const ATTRIBUTE_TYPES = new Set(["label", "relation"]); @@ -41,18 +39,18 @@ function getNoteWithLabel(name: string, value?: string): BNote | null { function createLabel(noteId: string, name: string, value: string = "") { return createAttribute({ - noteId: noteId, + noteId, type: "label", - name: name, - value: value + name, + value }); } function createRelation(noteId: string, name: string, targetNoteId: string) { return createAttribute({ - noteId: noteId, + noteId, type: "relation", - name: name, + name, value: targetNoteId }); } diff --git a/packages/commons/src/index.ts b/packages/commons/src/index.ts index 1ae730a563..d2e4f85d4c 100644 --- a/packages/commons/src/index.ts +++ b/packages/commons/src/index.ts @@ -13,3 +13,4 @@ export * from "./lib/attribute_names.js"; export * from "./lib/utils.js"; export * from "./lib/dayjs.js"; export * from "./lib/notes.js"; +export { default as BUILTIN_ATTRIBUTES } from "./lib/builtin_attributes.js"; diff --git a/apps/server/src/services/builtin_attributes.ts b/packages/commons/src/lib/builtin_attributes.ts similarity index 100% rename from apps/server/src/services/builtin_attributes.ts rename to packages/commons/src/lib/builtin_attributes.ts From 7be637798ff242b40a9c1ae2cd5da178d4dc43fb Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 14 Feb 2026 10:30:34 +0200 Subject: [PATCH 027/247] feat(badges/content): functional enable/disable toggle --- .../widgets/layout/ActiveContentBadges.tsx | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/apps/client/src/widgets/layout/ActiveContentBadges.tsx b/apps/client/src/widgets/layout/ActiveContentBadges.tsx index c2eab4a68a..8b0cb3744c 100644 --- a/apps/client/src/widgets/layout/ActiveContentBadges.tsx +++ b/apps/client/src/widgets/layout/ActiveContentBadges.tsx @@ -1,3 +1,4 @@ +import { BUILTIN_ATTRIBUTES } from "@triliumnext/commons"; import { useEffect, useState } from "preact/hooks"; import FNote from "../../entities/fnote"; @@ -6,15 +7,17 @@ import { Badge } from "../react/Badge"; import FormToggle from "../react/FormToggle"; import { useNoteContext, useTriliumEvent } from "../react/hooks"; +const DANGEROUS_ATTRIBUTES = BUILTIN_ATTRIBUTES.filter(a => a.isDangerous); +const activeContentLabels = [ "iconPack" ] as const; + export function ActiveContentBadges() { const { note } = useNoteContext(); const info = useActiveContentInfo(note); - console.log("Got inf ", info); - return (info && + return (note && info && <> {info.type === "iconPack" && } - + ); } @@ -29,15 +32,35 @@ function IconPackBadge() { ); } -function ActiveContentToggle({ info }: { info: ActiveContentInfo }) { +function ActiveContentToggle({ note, info }: { note: FNote, info: ActiveContentInfo }) { return info && { + const attrs = note.getOwnedAttributes() + .filter(attr => { + if (attr.isInheritable) return false; + const baseName = getNameWithoutPrefix(attr.name); + return DANGEROUS_ATTRIBUTES.some(item => item.name === baseName && item.type === attr.type); + }); + + for (const attr of attrs) { + const baseName = getNameWithoutPrefix(attr.name); + const newName = willEnable ? baseName : `disabled:${baseName}`; + if (newName === attr.name) continue; + + // We are adding and removing afterwards to avoid a flicker (because for a moment there would be no active content attribute anymore) because the operations are done in sequence and not atomically. + await attributes.addLabel(note.noteId, newName, attr.value); + await attributes.removeAttributeById(note.noteId, attr.attributeId); + } + }} />; } -const activeContentLabels = [ "iconPack" ] as const; +function getNameWithoutPrefix(name: string) { + return name.startsWith("disabled:") ? name.substring(9) : name; +} interface ActiveContentInfo { type: "iconPack"; From 46556c1c14bfbbd7d807ce1b475e2752536fc2c6 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 14 Feb 2026 10:40:19 +0200 Subject: [PATCH 028/247] chore(badges/content): make toggle more compact --- apps/client/src/translations/en/translation.json | 5 +++++ apps/client/src/widgets/layout/ActiveContentBadges.tsx | 8 +++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index f434ffeddd..48f5707563 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -2288,5 +2288,10 @@ }, "bookmark_buttons": { "bookmarks": "Bookmarks" + }, + "active_content_badges": { + "type_icon_pack": "Icon pack", + "toggle_tooltip_enable_tooltip": "Click to enable this {{type}}.", + "toggle_tooltip_disable_tooltip": "Click to disable this {{type}}." } } diff --git a/apps/client/src/widgets/layout/ActiveContentBadges.tsx b/apps/client/src/widgets/layout/ActiveContentBadges.tsx index 8b0cb3744c..6f93ada5cb 100644 --- a/apps/client/src/widgets/layout/ActiveContentBadges.tsx +++ b/apps/client/src/widgets/layout/ActiveContentBadges.tsx @@ -3,6 +3,7 @@ import { useEffect, useState } from "preact/hooks"; import FNote from "../../entities/fnote"; import attributes from "../../services/attributes"; +import { t } from "../../services/i18n"; import { Badge } from "../react/Badge"; import FormToggle from "../react/FormToggle"; import { useNoteContext, useTriliumEvent } from "../react/hooks"; @@ -27,16 +28,17 @@ function IconPackBadge() { ); } function ActiveContentToggle({ note, info }: { note: FNote, info: ActiveContentInfo }) { return info && { const attrs = note.getOwnedAttributes() .filter(attr => { From a68e82c1c89481f22fd92d99cd95a77ab0ae1062 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 14 Feb 2026 10:57:32 +0200 Subject: [PATCH 029/247] feat(badges/content): basic support for backend scripts --- .../src/translations/en/translation.json | 1 + .../widgets/layout/ActiveContentBadges.tsx | 34 +++++++++++++++---- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index 48f5707563..8717ecac23 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -2291,6 +2291,7 @@ }, "active_content_badges": { "type_icon_pack": "Icon pack", + "type_backend_script": "Backend script", "toggle_tooltip_enable_tooltip": "Click to enable this {{type}}.", "toggle_tooltip_disable_tooltip": "Click to disable this {{type}}." } diff --git a/apps/client/src/widgets/layout/ActiveContentBadges.tsx b/apps/client/src/widgets/layout/ActiveContentBadges.tsx index 6f93ada5cb..dc867d8828 100644 --- a/apps/client/src/widgets/layout/ActiveContentBadges.tsx +++ b/apps/client/src/widgets/layout/ActiveContentBadges.tsx @@ -11,34 +11,50 @@ import { useNoteContext, useTriliumEvent } from "../react/hooks"; const DANGEROUS_ATTRIBUTES = BUILTIN_ATTRIBUTES.filter(a => a.isDangerous); const activeContentLabels = [ "iconPack" ] as const; +const typeIconMappings: Record = { + iconPack: "bx bx-package", + backendScript: "bx bx-server" +}; + export function ActiveContentBadges() { const { note } = useNoteContext(); const info = useActiveContentInfo(note); return (note && info && <> - {info.type === "iconPack" && } + ); } -function IconPackBadge() { +function ActiveContentBadge({ info }: { note: FNote, info: ActiveContentInfo }) { return ( ); } +function getTranslationForType(type: ActiveContentInfo["type"]) { + switch (type) { + case "iconPack": + return t("active_content_badges.type_icon_pack"); + case "backendScript": + return t("active_content_badges.type_backend_script"); + } +} + function ActiveContentToggle({ note, info }: { note: FNote, info: ActiveContentInfo }) { + const typeTranslation = getTranslationForType(info.type); + return info && { const attrs = note.getOwnedAttributes() .filter(attr => { @@ -65,7 +81,7 @@ function getNameWithoutPrefix(name: string) { } interface ActiveContentInfo { - type: "iconPack"; + type: "iconPack" | "backendScript"; isEnabled: boolean; } @@ -81,6 +97,10 @@ function useActiveContentInfo(note: FNote | null | undefined) { return; } + if (note.type === "code" && note.mime === "application/javascript;env=backend") { + type = "backendScript"; + } + for (const labelToCheck of activeContentLabels ) { if (note.hasLabel(labelToCheck)) { type = labelToCheck; From 66ff009b72622d497ba14b03cae0575f5a8caf38 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 14 Feb 2026 11:08:30 +0200 Subject: [PATCH 030/247] feat(badges/content): option to open documentation --- .../src/translations/en/translation.json | 3 +- .../widgets/layout/ActiveContentBadges.tsx | 31 ++++++++++++++----- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index 8717ecac23..8145a74231 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -2293,6 +2293,7 @@ "type_icon_pack": "Icon pack", "type_backend_script": "Backend script", "toggle_tooltip_enable_tooltip": "Click to enable this {{type}}.", - "toggle_tooltip_disable_tooltip": "Click to disable this {{type}}." + "toggle_tooltip_disable_tooltip": "Click to disable this {{type}}.", + "menu_docs": "Open documentation" } } diff --git a/apps/client/src/widgets/layout/ActiveContentBadges.tsx b/apps/client/src/widgets/layout/ActiveContentBadges.tsx index dc867d8828..088d97cd6e 100644 --- a/apps/client/src/widgets/layout/ActiveContentBadges.tsx +++ b/apps/client/src/widgets/layout/ActiveContentBadges.tsx @@ -4,16 +4,27 @@ import { useEffect, useState } from "preact/hooks"; import FNote from "../../entities/fnote"; import attributes from "../../services/attributes"; import { t } from "../../services/i18n"; -import { Badge } from "../react/Badge"; +import { openInAppHelpFromUrl } from "../../services/utils"; +import { Badge, BadgeWithDropdown } from "../react/Badge"; +import { FormListItem } from "../react/FormList"; import FormToggle from "../react/FormToggle"; import { useNoteContext, useTriliumEvent } from "../react/hooks"; const DANGEROUS_ATTRIBUTES = BUILTIN_ATTRIBUTES.filter(a => a.isDangerous); const activeContentLabels = [ "iconPack" ] as const; -const typeIconMappings: Record = { - iconPack: "bx bx-package", - backendScript: "bx bx-server" +const typeMappings: Record = { + iconPack: { + icon: "bx bx-package", + helpPage: "g1mlRoU8CsqC" + }, + backendScript: { + icon: "bx bx-server", + helpPage: "SPirpZypehBG" + } }; export function ActiveContentBadges() { @@ -29,12 +40,18 @@ export function ActiveContentBadges() { } function ActiveContentBadge({ info }: { note: FNote, info: ActiveContentInfo }) { + const { icon, helpPage } = typeMappings[info.type]; return ( - + > + openInAppHelpFromUrl(helpPage)} + >{t("active_content_badges.menu_docs")} + ); } From a739d2856357476b80edb7aa0aa8f4f5eb561b6c Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 14 Feb 2026 11:12:39 +0200 Subject: [PATCH 031/247] feat(badges/content): option to open API docs --- .../widgets/layout/ActiveContentBadges.tsx | 22 ++++++++++++++----- .../src/widgets/ribbon/NoteActionsCustom.tsx | 10 --------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/apps/client/src/widgets/layout/ActiveContentBadges.tsx b/apps/client/src/widgets/layout/ActiveContentBadges.tsx index 088d97cd6e..daa787b927 100644 --- a/apps/client/src/widgets/layout/ActiveContentBadges.tsx +++ b/apps/client/src/widgets/layout/ActiveContentBadges.tsx @@ -5,7 +5,7 @@ import FNote from "../../entities/fnote"; import attributes from "../../services/attributes"; import { t } from "../../services/i18n"; import { openInAppHelpFromUrl } from "../../services/utils"; -import { Badge, BadgeWithDropdown } from "../react/Badge"; +import { BadgeWithDropdown } from "../react/Badge"; import { FormListItem } from "../react/FormList"; import FormToggle from "../react/FormToggle"; import { useNoteContext, useTriliumEvent } from "../react/hooks"; @@ -16,14 +16,21 @@ const activeContentLabels = [ "iconPack" ] as const; const typeMappings: Record = { iconPack: { icon: "bx bx-package", - helpPage: "g1mlRoU8CsqC" + helpPage: "g1mlRoU8CsqC", }, backendScript: { icon: "bx bx-server", - helpPage: "SPirpZypehBG" + helpPage: "SPirpZypehBG", + apiDocsPage: "MEtfsqa5VwNi" + }, + frontendScript: { + icon: "bx bx-window", + helpPage: "yIhgI5H7A2Sm", + apiDocsPage: "Q2z6av6JZVWm" } }; @@ -40,7 +47,7 @@ export function ActiveContentBadges() { } function ActiveContentBadge({ info }: { note: FNote, info: ActiveContentInfo }) { - const { icon, helpPage } = typeMappings[info.type]; + const { icon, helpPage, apiDocsPage } = typeMappings[info.type]; return ( openInAppHelpFromUrl(helpPage)} >{t("active_content_badges.menu_docs")} + + {apiDocsPage && openInAppHelpFromUrl(apiDocsPage)} + >{t("code_buttons.trilium_api_docs_button_title")}} ); } @@ -98,7 +110,7 @@ function getNameWithoutPrefix(name: string) { } interface ActiveContentInfo { - type: "iconPack" | "backendScript"; + type: "iconPack" | "backendScript" | "frontendScript"; isEnabled: boolean; } diff --git a/apps/client/src/widgets/ribbon/NoteActionsCustom.tsx b/apps/client/src/widgets/ribbon/NoteActionsCustom.tsx index 2864e50eaf..482cd1a693 100644 --- a/apps/client/src/widgets/ribbon/NoteActionsCustom.tsx +++ b/apps/client/src/widgets/ribbon/NoteActionsCustom.tsx @@ -70,7 +70,6 @@ export default function NoteActionsCustom(props: NoteActionsCustomProps) { > - @@ -230,15 +229,6 @@ function SaveToNoteButton({ note, noteMime }: NoteActionsCustomInnerProps) { />; } -function OpenTriliumApiDocsButton({ noteMime }: NoteActionsCustomInnerProps) { - const isEnabled = noteMime.startsWith("application/javascript;env="); - return isEnabled && openInAppHelpFromUrl(noteMime.endsWith("frontend") ? "Q2z6av6JZVWm" : "MEtfsqa5VwNi")} - />; -} - function InAppHelpButton({ note }: NoteActionsCustomInnerProps) { const helpUrl = getHelpUrlForNote(note); const isEnabled = !!helpUrl; From ef75de63fe0f47c199d699c8c65a7d112eed4237 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 14 Feb 2026 11:15:08 +0200 Subject: [PATCH 032/247] feat(badges/content): option to execute now --- .../src/translations/en/translation.json | 3 ++- .../widgets/layout/ActiveContentBadges.tsx | 21 +++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index 8145a74231..c8ded0fbb4 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -2294,6 +2294,7 @@ "type_backend_script": "Backend script", "toggle_tooltip_enable_tooltip": "Click to enable this {{type}}.", "toggle_tooltip_disable_tooltip": "Click to disable this {{type}}.", - "menu_docs": "Open documentation" + "menu_docs": "Open documentation", + "menu_execute_now": "Execute script now" } } diff --git a/apps/client/src/widgets/layout/ActiveContentBadges.tsx b/apps/client/src/widgets/layout/ActiveContentBadges.tsx index daa787b927..936c6da7a6 100644 --- a/apps/client/src/widgets/layout/ActiveContentBadges.tsx +++ b/apps/client/src/widgets/layout/ActiveContentBadges.tsx @@ -6,7 +6,7 @@ import attributes from "../../services/attributes"; import { t } from "../../services/i18n"; import { openInAppHelpFromUrl } from "../../services/utils"; import { BadgeWithDropdown } from "../react/Badge"; -import { FormListItem } from "../react/FormList"; +import { FormDropdownDivider, FormListItem } from "../react/FormList"; import FormToggle from "../react/FormToggle"; import { useNoteContext, useTriliumEvent } from "../react/hooks"; @@ -17,6 +17,7 @@ const typeMappings: Record = { iconPack: { icon: "bx bx-package", @@ -25,12 +26,14 @@ const typeMappings: Record + {isExecutable && ( + <> + {t("active_content_badges.menu_execute_now")} + + + )} + openInAppHelpFromUrl(helpPage)} From bd1f0909a24df62bfcd4ff39d932f27a3fb98bcc Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 14 Feb 2026 11:30:05 +0200 Subject: [PATCH 033/247] feat(badges/content): configurable backend run options --- .../src/translations/en/translation.json | 7 ++- .../widgets/layout/ActiveContentBadges.tsx | 51 +++++++++++++++++-- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index c8ded0fbb4..cc468ff597 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -2295,6 +2295,11 @@ "toggle_tooltip_enable_tooltip": "Click to enable this {{type}}.", "toggle_tooltip_disable_tooltip": "Click to disable this {{type}}.", "menu_docs": "Open documentation", - "menu_execute_now": "Execute script now" + "menu_execute_now": "Execute script now", + "menu_run": "Run automatically", + "menu_run_disabled": "Manually", + "menu_run_backend_startup": "When the backend starts up", + "menu_run_hourly": "Hourly", + "menu_run_daily": "Daily" } } diff --git a/apps/client/src/widgets/layout/ActiveContentBadges.tsx b/apps/client/src/widgets/layout/ActiveContentBadges.tsx index 936c6da7a6..a0b3af16c7 100644 --- a/apps/client/src/widgets/layout/ActiveContentBadges.tsx +++ b/apps/client/src/widgets/layout/ActiveContentBadges.tsx @@ -1,4 +1,5 @@ import { BUILTIN_ATTRIBUTES } from "@triliumnext/commons"; +import { note } from "mermaid/dist/rendering-util/rendering-elements/shapes/note.js"; import { useEffect, useState } from "preact/hooks"; import FNote from "../../entities/fnote"; @@ -6,9 +7,9 @@ import attributes from "../../services/attributes"; import { t } from "../../services/i18n"; import { openInAppHelpFromUrl } from "../../services/utils"; import { BadgeWithDropdown } from "../react/Badge"; -import { FormDropdownDivider, FormListItem } from "../react/FormList"; +import { FormDropdownDivider, FormDropdownSubmenu, FormListItem } from "../react/FormList"; import FormToggle from "../react/FormToggle"; -import { useNoteContext, useTriliumEvent } from "../react/hooks"; +import { useNoteContext, useNoteLabel, useTriliumEvent, useTriliumOption } from "../react/hooks"; const DANGEROUS_ATTRIBUTES = BUILTIN_ATTRIBUTES.filter(a => a.isDangerous); const activeContentLabels = [ "iconPack" ] as const; @@ -49,7 +50,7 @@ export function ActiveContentBadges() { ); } -function ActiveContentBadge({ info }: { note: FNote, info: ActiveContentInfo }) { +function ActiveContentBadge({ info, note }: { note: FNote, info: ActiveContentInfo }) { const { icon, helpPage, apiDocsPage, isExecutable } = typeMappings[info.type]; return ( {t("active_content_badges.menu_execute_now")} + )} @@ -80,6 +82,49 @@ function ActiveContentBadge({ info }: { note: FNote, info: ActiveContentInfo }) ); } +function ScriptRunOptions({ note }: { note: FNote }) { + const [ run, setRun ] = useNoteLabel(note, "run"); + + const options: { + title: string; + value: string | null; + type: "backendScript" | "frontendScript"; + }[] = [ + { + title: t("active_content_badges.menu_run_disabled"), + value: null, + type: "backendScript" + }, + { + title: t("active_content_badges.menu_run_backend_startup"), + value: "backendStartup", + type: "backendScript" + }, + { + title: t("active_content_badges.menu_run_daily"), + value: "daily", + type: "backendScript" + }, + { + title: t("active_content_badges.menu_run_hourly"), + value: "hourly", + type: "backendScript" + }, + ]; + + return ( + + {options.map(({ title, value }) => ( + setRun(value)} + checked={run ? run === value : value === null } + >{title} + ))} + + ); +} + function getTranslationForType(type: ActiveContentInfo["type"]) { switch (type) { case "iconPack": From 2d34cdef5efde8db7c96d03ff62110d56b575784 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 14 Feb 2026 11:37:20 +0200 Subject: [PATCH 034/247] feat(badges/content): integrate options for frontend script --- .../src/translations/en/translation.json | 5 +++- .../widgets/layout/ActiveContentBadges.tsx | 26 ++++++++++++++----- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index cc468ff597..d2fdb2f4b9 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -2292,6 +2292,7 @@ "active_content_badges": { "type_icon_pack": "Icon pack", "type_backend_script": "Backend script", + "type_frontend_script": "Frontend script", "toggle_tooltip_enable_tooltip": "Click to enable this {{type}}.", "toggle_tooltip_disable_tooltip": "Click to disable this {{type}}.", "menu_docs": "Open documentation", @@ -2300,6 +2301,8 @@ "menu_run_disabled": "Manually", "menu_run_backend_startup": "When the backend starts up", "menu_run_hourly": "Hourly", - "menu_run_daily": "Daily" + "menu_run_daily": "Daily", + "menu_run_frontend_startup": "When the desktop frontend starts up", + "menu_run_mobile_startup": "When the mobile frontend starts up" } } diff --git a/apps/client/src/widgets/layout/ActiveContentBadges.tsx b/apps/client/src/widgets/layout/ActiveContentBadges.tsx index a0b3af16c7..4d00cbca26 100644 --- a/apps/client/src/widgets/layout/ActiveContentBadges.tsx +++ b/apps/client/src/widgets/layout/ActiveContentBadges.tsx @@ -64,7 +64,7 @@ function ActiveContentBadge({ info, note }: { note: FNote, info: ActiveContentIn icon="bx bx-play" triggerCommand="runActiveNote" >{t("active_content_badges.menu_execute_now")} - + )} @@ -82,18 +82,18 @@ function ActiveContentBadge({ info, note }: { note: FNote, info: ActiveContentIn ); } -function ScriptRunOptions({ note }: { note: FNote }) { +function ScriptRunOptions({ info, note }: { note: FNote, info: ActiveContentInfo }) { const [ run, setRun ] = useNoteLabel(note, "run"); const options: { title: string; value: string | null; - type: "backendScript" | "frontendScript"; - }[] = [ + type: "both" | "backendScript" | "frontendScript"; + }[] = ([ { title: t("active_content_badges.menu_run_disabled"), value: null, - type: "backendScript" + type: "both" }, { title: t("active_content_badges.menu_run_backend_startup"), @@ -110,7 +110,17 @@ function ScriptRunOptions({ note }: { note: FNote }) { value: "hourly", type: "backendScript" }, - ]; + { + title: t("active_content_badges.menu_run_frontend_startup"), + value: "frontendStartup", + type: "frontendScript" + }, + { + title: t("active_content_badges.menu_run_mobile_startup"), + value: "mobileStartup", + type: "frontendScript" + } + ] as const).filter(option => option.type === "both" || option.type === info.type); return ( @@ -131,6 +141,8 @@ function getTranslationForType(type: ActiveContentInfo["type"]) { return t("active_content_badges.type_icon_pack"); case "backendScript": return t("active_content_badges.type_backend_script"); + case "frontendScript": + return t("active_content_badges.type_frontend_script"); } } @@ -186,6 +198,8 @@ function useActiveContentInfo(note: FNote | null | undefined) { if (note.type === "code" && note.mime === "application/javascript;env=backend") { type = "backendScript"; + } else if (note.type === "code" && note.mime === "application/javascript;env=frontend") { + type = "frontendScript"; } for (const labelToCheck of activeContentLabels ) { From 3107bc88400851a5427e5d1deadb05ce82fb4289 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 14 Feb 2026 11:47:42 +0200 Subject: [PATCH 035/247] feat(badges/content): add toggle for widget --- .../src/translations/en/translation.json | 3 ++- .../src/widgets/layout/ActiveContentBadges.tsx | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index d2fdb2f4b9..5e6bba615a 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -2303,6 +2303,7 @@ "menu_run_hourly": "Hourly", "menu_run_daily": "Daily", "menu_run_frontend_startup": "When the desktop frontend starts up", - "menu_run_mobile_startup": "When the mobile frontend starts up" + "menu_run_mobile_startup": "When the mobile frontend starts up", + "menu_toggle_widget": "Widget" } } diff --git a/apps/client/src/widgets/layout/ActiveContentBadges.tsx b/apps/client/src/widgets/layout/ActiveContentBadges.tsx index 4d00cbca26..64ef118181 100644 --- a/apps/client/src/widgets/layout/ActiveContentBadges.tsx +++ b/apps/client/src/widgets/layout/ActiveContentBadges.tsx @@ -7,9 +7,9 @@ import attributes from "../../services/attributes"; import { t } from "../../services/i18n"; import { openInAppHelpFromUrl } from "../../services/utils"; import { BadgeWithDropdown } from "../react/Badge"; -import { FormDropdownDivider, FormDropdownSubmenu, FormListItem } from "../react/FormList"; +import { FormDropdownDivider, FormDropdownSubmenu, FormListItem, FormListToggleableItem } from "../react/FormList"; import FormToggle from "../react/FormToggle"; -import { useNoteContext, useNoteLabel, useTriliumEvent, useTriliumOption } from "../react/hooks"; +import { useNoteContext, useNoteLabel, useNoteLabelBoolean, useTriliumEvent, useTriliumOption } from "../react/hooks"; const DANGEROUS_ATTRIBUTES = BUILTIN_ATTRIBUTES.filter(a => a.isDangerous); const activeContentLabels = [ "iconPack" ] as const; @@ -65,6 +65,7 @@ function ActiveContentBadge({ info, note }: { note: FNote, info: ActiveContentIn triggerCommand="runActiveNote" >{t("active_content_badges.menu_execute_now")} + {info.type === "frontendScript" && } )} @@ -135,6 +136,19 @@ function ScriptRunOptions({ info, note }: { note: FNote, info: ActiveContentInfo ); } +function WidgetSwitcher({ note }: { note: FNote }) { + const [ widget, setWidget ] = useNoteLabelBoolean(note, "widget"); + + return ( + setWidget(newValue)} + /> + ); +} + function getTranslationForType(type: ActiveContentInfo["type"]) { switch (type) { case "iconPack": From 7a3e7fccec08c9abe48381cc705beefa8f0d068b Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 14 Feb 2026 11:54:27 +0200 Subject: [PATCH 036/247] feat(badges/content): handle widgets as separate content type --- .../src/translations/en/translation.json | 4 ++- .../widgets/layout/ActiveContentBadges.tsx | 35 ++++++++++++------- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index 5e6bba615a..2ced551e90 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -2293,6 +2293,7 @@ "type_icon_pack": "Icon pack", "type_backend_script": "Backend script", "type_frontend_script": "Frontend script", + "type_widget": "Widget", "toggle_tooltip_enable_tooltip": "Click to enable this {{type}}.", "toggle_tooltip_disable_tooltip": "Click to disable this {{type}}.", "menu_docs": "Open documentation", @@ -2304,6 +2305,7 @@ "menu_run_daily": "Daily", "menu_run_frontend_startup": "When the desktop frontend starts up", "menu_run_mobile_startup": "When the mobile frontend starts up", - "menu_toggle_widget": "Widget" + "menu_change_to_widget": "Change to widget", + "menu_change_to_frontend_script": "Change to frontend script" } } diff --git a/apps/client/src/widgets/layout/ActiveContentBadges.tsx b/apps/client/src/widgets/layout/ActiveContentBadges.tsx index 64ef118181..70190fa855 100644 --- a/apps/client/src/widgets/layout/ActiveContentBadges.tsx +++ b/apps/client/src/widgets/layout/ActiveContentBadges.tsx @@ -1,5 +1,4 @@ import { BUILTIN_ATTRIBUTES } from "@triliumnext/commons"; -import { note } from "mermaid/dist/rendering-util/rendering-elements/shapes/note.js"; import { useEffect, useState } from "preact/hooks"; import FNote from "../../entities/fnote"; @@ -7,12 +6,12 @@ import attributes from "../../services/attributes"; import { t } from "../../services/i18n"; import { openInAppHelpFromUrl } from "../../services/utils"; import { BadgeWithDropdown } from "../react/Badge"; -import { FormDropdownDivider, FormDropdownSubmenu, FormListItem, FormListToggleableItem } from "../react/FormList"; +import { FormDropdownDivider, FormDropdownSubmenu, FormListItem } from "../react/FormList"; import FormToggle from "../react/FormToggle"; -import { useNoteContext, useNoteLabel, useNoteLabelBoolean, useTriliumEvent, useTriliumOption } from "../react/hooks"; +import { useNoteContext, useNoteLabel, useNoteLabelBoolean, useTriliumEvent } from "../react/hooks"; const DANGEROUS_ATTRIBUTES = BUILTIN_ATTRIBUTES.filter(a => a.isDangerous); -const activeContentLabels = [ "iconPack" ] as const; +const activeContentLabels = [ "iconPack", "widget" ] as const; const typeMappings: Record{t("active_content_badges.menu_execute_now")} - {info.type === "frontendScript" && } + + + )} + + {(info.type === "frontendScript" || info.type === "widget") && ( + <> + )} @@ -140,12 +149,12 @@ function WidgetSwitcher({ note }: { note: FNote }) { const [ widget, setWidget ] = useNoteLabelBoolean(note, "widget"); return ( - setWidget(newValue)} - /> + setWidget(!widget)} + > + {widget ? t("active_content_badges.menu_change_to_frontend_script") : t("active_content_badges.menu_change_to_widget")} + ); } @@ -157,6 +166,8 @@ function getTranslationForType(type: ActiveContentInfo["type"]) { return t("active_content_badges.type_backend_script"); case "frontendScript": return t("active_content_badges.type_frontend_script"); + case "widget": + return t("active_content_badges.type_widget"); } } @@ -194,7 +205,7 @@ function getNameWithoutPrefix(name: string) { } interface ActiveContentInfo { - type: "iconPack" | "backendScript" | "frontendScript"; + type: "iconPack" | "backendScript" | "frontendScript" | "widget"; isEnabled: boolean; } From 866d3110da1d170b4554c35d060a0235896b74dd Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 14 Feb 2026 12:05:24 +0200 Subject: [PATCH 037/247] feat(badges/content): add badge for custom CSS --- apps/client/src/translations/en/translation.json | 1 + .../src/widgets/layout/ActiveContentBadges.tsx | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index 2ced551e90..317c64bd1c 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -2294,6 +2294,7 @@ "type_backend_script": "Backend script", "type_frontend_script": "Frontend script", "type_widget": "Widget", + "type_app_css": "Custom CSS", "toggle_tooltip_enable_tooltip": "Click to enable this {{type}}.", "toggle_tooltip_disable_tooltip": "Click to disable this {{type}}.", "menu_docs": "Open documentation", diff --git a/apps/client/src/widgets/layout/ActiveContentBadges.tsx b/apps/client/src/widgets/layout/ActiveContentBadges.tsx index 70190fa855..ae5dc4ca0f 100644 --- a/apps/client/src/widgets/layout/ActiveContentBadges.tsx +++ b/apps/client/src/widgets/layout/ActiveContentBadges.tsx @@ -10,8 +10,8 @@ import { FormDropdownDivider, FormDropdownSubmenu, FormListItem } from "../react import FormToggle from "../react/FormToggle"; import { useNoteContext, useNoteLabel, useNoteLabelBoolean, useTriliumEvent } from "../react/hooks"; -const DANGEROUS_ATTRIBUTES = BUILTIN_ATTRIBUTES.filter(a => a.isDangerous); -const activeContentLabels = [ "iconPack", "widget" ] as const; +const DANGEROUS_ATTRIBUTES = BUILTIN_ATTRIBUTES.filter(a => a.isDangerous || a.name === "appCss"); +const activeContentLabels = [ "iconPack", "widget", "appCss" ] as const; const typeMappings: Record Date: Fri, 13 Feb 2026 10:58:46 +0100 Subject: [PATCH 038/247] Translated using Weblate (Irish) Currently translated at 100.0% (1777 of 1777 strings) Translation: Trilium Notes/Client Translate-URL: https://hosted.weblate.org/projects/trilium/client/ga/ --- apps/client/src/translations/ga/translation.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/client/src/translations/ga/translation.json b/apps/client/src/translations/ga/translation.json index 19029219d9..2f00a54ce6 100644 --- a/apps/client/src/translations/ga/translation.json +++ b/apps/client/src/translations/ga/translation.json @@ -1590,7 +1590,8 @@ "description": "Cur síos", "reload_app": "Athlódáil an aip chun na hathruithe a chur i bhfeidhm", "set_all_to_default": "Socraigh gach aicearra go dtí an réamhshocrú", - "confirm_reset": "An bhfuil tú cinnte gur mhaith leat na haicearraí méarchláir go léir a athshocrú go dtí an rogha réamhshocraithe?" + "confirm_reset": "An bhfuil tú cinnte gur mhaith leat na haicearraí méarchláir go léir a athshocrú go dtí an rogha réamhshocraithe?", + "no_results": "Níor aimsíodh aon aicearraí a mheaitseálann '{{filter}}'" }, "spellcheck": { "title": "Seiceáil Litrithe", @@ -1808,7 +1809,9 @@ "print_report_collection_content_many": "Níorbh fhéidir {{count}} nótaí sa bhailiúchán a phriontáil mar nach dtacaítear leo nó mar go bhfuil siad faoi chosaint.", "print_report_collection_content_other": "Níorbh fhéidir {{count}} nótaí sa bhailiúchán a phriontáil mar nach dtacaítear leo nó mar go bhfuil siad faoi chosaint.", "print_report_collection_details_button": "Féach sonraí", - "print_report_collection_details_ignored_notes": "Nótaí neamhairdithe" + "print_report_collection_details_ignored_notes": "Nótaí neamhairdithe", + "print_report_error_title": "Theip ar phriontáil", + "print_report_stack_trace": "Rian cruachta" }, "note_title": { "placeholder": "clóscríobh teideal an nóta anseo...", From 740b02952f86c5a6beff60707769a14ba0527b2f Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 14 Feb 2026 12:22:27 +0200 Subject: [PATCH 039/247] feat(badges/content): disable toggle when not necessary --- apps/client/src/entities/fnote.ts | 4 ++ .../widgets/layout/ActiveContentBadges.tsx | 37 ++++++++++++++----- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/apps/client/src/entities/fnote.ts b/apps/client/src/entities/fnote.ts index f161d7adb1..fbe9493128 100644 --- a/apps/client/src/entities/fnote.ts +++ b/apps/client/src/entities/fnote.ts @@ -700,6 +700,10 @@ export default class FNote { return this.hasAttribute(LABEL, name); } + hasLabelOrDisabled(name: string) { + return this.hasLabel(name) || this.hasLabel(`disabled:${name}`); + } + /** * @param name - label name * @returns true if label exists (including inherited) and does not have "false" value. diff --git a/apps/client/src/widgets/layout/ActiveContentBadges.tsx b/apps/client/src/widgets/layout/ActiveContentBadges.tsx index ae5dc4ca0f..35160eee8d 100644 --- a/apps/client/src/widgets/layout/ActiveContentBadges.tsx +++ b/apps/client/src/widgets/layout/ActiveContentBadges.tsx @@ -51,8 +51,8 @@ export function ActiveContentBadges() { return (note && info && <> + {info.canToggleEnabled && } - ); } @@ -151,15 +151,23 @@ function ScriptRunOptions({ info, note }: { note: FNote, info: ActiveContentInfo function WidgetSwitcher({ note }: { note: FNote }) { const [ widget, setWidget ] = useNoteLabelBoolean(note, "widget"); + const [ disabledWidget, setDisabledWidget ] = useNoteLabelBoolean(note, "disabled:widget"); - return ( - { + setWidget(false); + setDisabledWidget(false); + }} + >{t("active_content_badges.menu_change_to_frontend_script")} + : setWidget(!widget)} - > - {widget ? t("active_content_badges.menu_change_to_frontend_script") : t("active_content_badges.menu_change_to_widget")} - - ); + onClick={() => { + setWidget(true); + }} + >{t("active_content_badges.menu_change_to_widget")}; + } function getTranslationForType(type: ActiveContentInfo["type"]) { @@ -213,6 +221,7 @@ function getNameWithoutPrefix(name: string) { interface ActiveContentInfo { type: "iconPack" | "backendScript" | "frontendScript" | "widget" | "appCss"; isEnabled: boolean; + canToggleEnabled: boolean; } function useActiveContentInfo(note: FNote | null | undefined) { @@ -221,6 +230,7 @@ function useActiveContentInfo(note: FNote | null | undefined) { function refresh() { let type: ActiveContentInfo["type"] | null = null; let isEnabled = true; + let canToggleEnabled = false; if (!note) { setInfo(null); @@ -229,8 +239,17 @@ function useActiveContentInfo(note: FNote | null | undefined) { if (note.type === "code" && note.mime === "application/javascript;env=backend") { type = "backendScript"; + for (const backendLabel of [ "run", "customRequestHandler", "customResourceProvider" ]) { + isEnabled ||= note.hasLabel(backendLabel); + + if (!canToggleEnabled && note.hasLabelOrDisabled(backendLabel)) { + canToggleEnabled = true; + } + } } else if (note.type === "code" && note.mime === "application/javascript;env=frontend") { type = "frontendScript"; + isEnabled = note.hasLabel("widget") || note.hasLabel("run"); + canToggleEnabled = note.hasLabelOrDisabled("widget") || note.hasLabelOrDisabled("run"); } for (const labelToCheck of activeContentLabels ) { @@ -245,7 +264,7 @@ function useActiveContentInfo(note: FNote | null | undefined) { } if (type) { - setInfo({ type, isEnabled }); + setInfo({ type, isEnabled, canToggleEnabled }); } else { setInfo(null); } From 50dcd3ba443f30284c1fabd0fd964040c5d0dbbb Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 14 Feb 2026 12:30:43 +0200 Subject: [PATCH 040/247] feat(badges/content): add support for render note --- .../src/translations/en/translation.json | 1 + .../widgets/layout/ActiveContentBadges.tsx | 30 ++++++++++++++----- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index 317c64bd1c..2f78d6a341 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -2295,6 +2295,7 @@ "type_frontend_script": "Frontend script", "type_widget": "Widget", "type_app_css": "Custom CSS", + "type_render_note": "Render note", "toggle_tooltip_enable_tooltip": "Click to enable this {{type}}.", "toggle_tooltip_disable_tooltip": "Click to disable this {{type}}.", "menu_docs": "Open documentation", diff --git a/apps/client/src/widgets/layout/ActiveContentBadges.tsx b/apps/client/src/widgets/layout/ActiveContentBadges.tsx index 35160eee8d..d39ab75f36 100644 --- a/apps/client/src/widgets/layout/ActiveContentBadges.tsx +++ b/apps/client/src/widgets/layout/ActiveContentBadges.tsx @@ -13,6 +13,12 @@ import { useNoteContext, useNoteLabel, useNoteLabelBoolean, useTriliumEvent } fr const DANGEROUS_ATTRIBUTES = BUILTIN_ATTRIBUTES.filter(a => a.isDangerous || a.name === "appCss"); const activeContentLabels = [ "iconPack", "widget", "appCss" ] as const; +interface ActiveContentInfo { + type: "iconPack" | "backendScript" | "frontendScript" | "widget" | "appCss" | "renderNote"; + isEnabled: boolean; + canToggleEnabled: boolean; +} + const typeMappings: Record(null); @@ -237,7 +247,11 @@ function useActiveContentInfo(note: FNote | null | undefined) { return; } - if (note.type === "code" && note.mime === "application/javascript;env=backend") { + if (note.type === "render") { + type = "renderNote"; + isEnabled = note.hasRelation("renderNote"); + canToggleEnabled = note.hasRelation("renderNote") || note.hasRelation("disabled:renderNote"); + } else if (note.type === "code" && note.mime === "application/javascript;env=backend") { type = "backendScript"; for (const backendLabel of [ "run", "customRequestHandler", "customResourceProvider" ]) { isEnabled ||= note.hasLabel(backendLabel); From 5a2b04adba376c8212ff0a517adcd683a4e59625 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 14 Feb 2026 12:35:06 +0200 Subject: [PATCH 041/247] feat(badges/content): add support for web view --- apps/client/src/translations/en/translation.json | 1 + .../src/widgets/layout/ActiveContentBadges.tsx | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index 2f78d6a341..ea5fda411a 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -2296,6 +2296,7 @@ "type_widget": "Widget", "type_app_css": "Custom CSS", "type_render_note": "Render note", + "type_web_view": "Web view", "toggle_tooltip_enable_tooltip": "Click to enable this {{type}}.", "toggle_tooltip_disable_tooltip": "Click to disable this {{type}}.", "menu_docs": "Open documentation", diff --git a/apps/client/src/widgets/layout/ActiveContentBadges.tsx b/apps/client/src/widgets/layout/ActiveContentBadges.tsx index d39ab75f36..644ad7c49e 100644 --- a/apps/client/src/widgets/layout/ActiveContentBadges.tsx +++ b/apps/client/src/widgets/layout/ActiveContentBadges.tsx @@ -14,7 +14,7 @@ const DANGEROUS_ATTRIBUTES = BUILTIN_ATTRIBUTES.filter(a => a.isDangerous || a.n const activeContentLabels = [ "iconPack", "widget", "appCss" ] as const; interface ActiveContentInfo { - type: "iconPack" | "backendScript" | "frontendScript" | "widget" | "appCss" | "renderNote"; + type: "iconPack" | "backendScript" | "frontendScript" | "widget" | "appCss" | "renderNote" | "webView"; isEnabled: boolean; canToggleEnabled: boolean; } @@ -52,6 +52,10 @@ const typeMappings: Record Date: Sat, 14 Feb 2026 12:41:41 +0200 Subject: [PATCH 042/247] feat(badges/content): improve color support --- apps/client/src/stylesheets/theme-next-dark.css | 7 ++++--- apps/client/src/stylesheets/theme-next-light.css | 2 +- apps/client/src/widgets/layout/ActiveContentBadges.tsx | 3 ++- apps/client/src/widgets/layout/NoteBadges.css | 5 ++++- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/client/src/stylesheets/theme-next-dark.css b/apps/client/src/stylesheets/theme-next-dark.css index f8fb305726..cf88b7f2d2 100644 --- a/apps/client/src/stylesheets/theme-next-dark.css +++ b/apps/client/src/stylesheets/theme-next-dark.css @@ -210,6 +210,7 @@ --badge-share-background-color: #4d4d4d; --badge-clipped-note-background-color: #295773; --badge-execute-background-color: #604180; + --badge-active-content-background-color: rgb(12, 68, 70); --note-icon-background-color: #444444; --note-icon-color: #d4d4d4; @@ -238,9 +239,9 @@ --bottom-panel-background-color: #11111180; --bottom-panel-title-bar-background-color: #3F3F3F80; - + --status-bar-border-color: var(--main-border-color); - + --scrollbar-thumb-color: #fdfdfd5c; --scrollbar-thumb-hover-color: #ffffff7d; --scrollbar-background-color: transparent; @@ -351,4 +352,4 @@ body .todo-list input[type="checkbox"]:not(:checked):before { .note-split.with-hue *::selection, .quick-edit-dialog-wrapper.with-hue *::selection { --selection-background-color: hsl(var(--custom-color-hue), 49.2%, 35%); -} \ No newline at end of file +} diff --git a/apps/client/src/stylesheets/theme-next-light.css b/apps/client/src/stylesheets/theme-next-light.css index 44f594d0ab..00678c6ae9 100644 --- a/apps/client/src/stylesheets/theme-next-light.css +++ b/apps/client/src/stylesheets/theme-next-light.css @@ -202,7 +202,7 @@ --badge-share-background-color: #6b6b6b; --badge-clipped-note-background-color: #2284c0; --badge-execute-background-color: #7b47af; - --badge-icon-pack-background-color: rgb(228, 163, 44); + --badge-active-content-background-color: rgb(27, 164, 168); --note-icon-background-color: #4f4f4f; --note-icon-color: white; diff --git a/apps/client/src/widgets/layout/ActiveContentBadges.tsx b/apps/client/src/widgets/layout/ActiveContentBadges.tsx index 644ad7c49e..ff94f19f04 100644 --- a/apps/client/src/widgets/layout/ActiveContentBadges.tsx +++ b/apps/client/src/widgets/layout/ActiveContentBadges.tsx @@ -1,4 +1,5 @@ import { BUILTIN_ATTRIBUTES } from "@triliumnext/commons"; +import clsx from "clsx"; import { useEffect, useState } from "preact/hooks"; import FNote from "../../entities/fnote"; @@ -75,7 +76,7 @@ function ActiveContentBadge({ info, note }: { note: FNote, info: ActiveContentIn const { icon, helpPage, apiDocsPage, isExecutable } = typeMappings[info.type]; return ( diff --git a/apps/client/src/widgets/layout/NoteBadges.css b/apps/client/src/widgets/layout/NoteBadges.css index b2b6e18f77..013963adb4 100644 --- a/apps/client/src/widgets/layout/NoteBadges.css +++ b/apps/client/src/widgets/layout/NoteBadges.css @@ -37,7 +37,10 @@ pointer-events: none; } } - &.icon-pack-badge { --color: var(--badge-icon-pack-background-color); } + &.active-content-badge { --color: var(--badge-active-content-background-color); } + &.active-content-badge.disabled { + opacity: 0.5; + } min-width: 0; From 2ef4eb7eaee9281e1319438241ecf379ef3fa320 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 14 Feb 2026 12:43:40 +0200 Subject: [PATCH 043/247] chore(client): fix type errors --- packages/commons/src/lib/attribute_names.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/commons/src/lib/attribute_names.ts b/packages/commons/src/lib/attribute_names.ts index b524b409f0..31997489ce 100644 --- a/packages/commons/src/lib/attribute_names.ts +++ b/packages/commons/src/lib/attribute_names.ts @@ -22,6 +22,11 @@ type Labels = { pageUrl: string; dateNote: string; + // Scripting + run: string; + widget: boolean; + "disabled:widget": boolean; + // Tree specific subtreeHidden: boolean; From fe4a11c5adf01fc37a7a53a87c50d54c67c72fb7 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sat, 14 Feb 2026 16:22:13 +0200 Subject: [PATCH 044/247] client/list view: improve appearance --- .../collections/legacy/ListOrGridView.css | 119 +++++++++++++----- .../collections/legacy/ListOrGridView.tsx | 44 ++++--- apps/client/src/widgets/react/Card.css | 2 +- apps/client/src/widgets/react/Card.tsx | 12 +- 4 files changed, 125 insertions(+), 52 deletions(-) diff --git a/apps/client/src/widgets/collections/legacy/ListOrGridView.css b/apps/client/src/widgets/collections/legacy/ListOrGridView.css index ef609c1d0d..d393c2496b 100644 --- a/apps/client/src/widgets/collections/legacy/ListOrGridView.css +++ b/apps/client/src/widgets/collections/legacy/ListOrGridView.css @@ -100,50 +100,111 @@ overflow: auto; } -.note-expander { - font-size: x-large; - cursor: pointer; - opacity: .65; -} - .note-list-pager { text-align: center; } -.note-list.list-view .note-path { - margin-left: 0.5em; - vertical-align: middle; - opacity: 0.5; +@keyframes note-preview-show { + from { + opacity: 0; + } to { + opacity: 1; + } } -:root .list-view-card { +.nested-note-list { --card-nested-section-indent: 40px; -} -.note-list h5 { - display: flex; - align-items: center; - font-size: 1em; - margin: 0; + h5 { + display: flex; + align-items: center; + font-size: 1em; + font-weight: normal; + margin: 0; - .tn-icon { - color: var(--left-pane-icon-color); - margin-inline-end: 8px; - font-size: 1.2em; + .note-expander { + font-size: x-large; + cursor: pointer; + opacity: .65; + margin-inline-end: 4px; + } + + .tn-icon { + color: var(--left-pane-icon-color); + margin-inline-end: 8px; + font-size: 1.2em; + } + + .note-book-title { + color: inherit; + font-weight: normal; + } + + .note-path { + margin-left: 0.5em; + vertical-align: middle; + opacity: 0.5; + order: -1; + } + + .note-list-attributes { + flex-grow: 1; + text-align: right; + font-size: .75em; + opacity: .75; + } } - .note-book-title { - color: inherit; - } + .note-book-content { + --background: rgba(0, 0, 0, .2); + outline: 1px solid var(--background); + border-radius: 8px; + background-color: var(--background); + overflow: hidden; + user-select: text; + animation: note-preview-show .25s ease-out; + will-change: opacity; - .note-list-attributes { - flex-grow: 1; - text-align: right; - font-size: .75em; - opacity: .75; + > .rendered-content > *:last-child { + margin-bottom: 0; + } + + &.type-text { + padding: 8px 24px; + + .ck-content > *:last-child { + margin-bottom: 0; + } + } + + &.type-protectedSession { + padding: 20px; + } + + &.type-image { + padding: 0; + } + + &.type-pdf { + iframe { + height: 50vh; + } + + .file-footer { + padding: 8px; + } + } + + &.type-webView { + display: flex; + flex-direction: column; + justify-content: center; + min-height: 50vh; + } } } + .note-content-preview:has(.note-book-content:empty) { display: none; } diff --git a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx index 6bf77c644f..a1bbd6916d 100644 --- a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx +++ b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx @@ -15,6 +15,7 @@ import NoteLink from "../../react/NoteLink"; import { ViewModeProps } from "../interface"; import { Pager, usePagination } from "../Pagination"; import { filterChildNotes, useFilteredNoteIds } from "./utils"; +import { JSX } from "preact/jsx-runtime"; export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens }: ViewModeProps<{}>) { const expandDepth = useExpansionDepth(note); @@ -34,7 +35,7 @@ export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens } { noteIds.length > 0 &&
        {!hasCollectionProperties && } - + {pageNotes?.map(childNote => ( setExpanded(currentLevel <= expandDepth), [ note, currentLevel, expandDepth ]); - const children = <> - {isExpanded && <> + let subSections: JSX.Element | undefined = undefined; + if (isExpanded) { + subSections = <> - + - - } - + + + } + return ( setExpanded(!isExpanded)} data-note-id={note.noteId} >
        - {setExpanded(!isExpanded); e.stopPropagation();}} - /> - + - +
        @@ -198,7 +209,8 @@ export function NoteContent({ note, trim, noChildrenList, highlightedTokens, inc }); }, [ note, highlightedTokens ]); - return
        ; + return
        +
        ; } function NoteChildren({ note, parentNote, highlightedTokens, currentLevel, expandDepth, includeArchived }: { diff --git a/apps/client/src/widgets/react/Card.css b/apps/client/src/widgets/react/Card.css index 53fd889b21..4a5b53f82a 100644 --- a/apps/client/src/widgets/react/Card.css +++ b/apps/client/src/widgets/react/Card.css @@ -24,7 +24,7 @@ } &.tn-card-section-nested { - padding-left: calc(8px + (var(--card-nested-section-indent) * var(--tn-card-section-nesting-level))); + padding-left: calc(var(--card-nested-section-indent) * var(--tn-card-section-nesting-level)); background-color: color-mix(in srgb, var(--card-background-color) calc(100% / (var(--tn-card-section-nesting-level) + 1)) , transparent); } diff --git a/apps/client/src/widgets/react/Card.tsx b/apps/client/src/widgets/react/Card.tsx index 34eea094af..c717ee5433 100644 --- a/apps/client/src/widgets/react/Card.tsx +++ b/apps/client/src/widgets/react/Card.tsx @@ -27,16 +27,16 @@ export function CardSection(props: {children: ComponentChildren} & CardSectionPr const nestingLevel = (parentContext && parentContext.nestingLevel + 1) ?? 0; return <> -
        0, - "tn-action": props?.hasAction} - ], props.className)} - style={"--tn-card-section-nesting-level: " + nestingLevel} - onClick={() => {props.onAction?.()}}> + "tn-action": props.hasAction + })} + style={{"--tn-card-section-nesting-level": nestingLevel}} + onClick={props.onAction}> {props.children}
        - {props?.childrenVisible && + {props.childrenVisible && {props.subSections} From 9c13f36ca03058e3d22331f935c4cda2472d192d Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sat, 14 Feb 2026 16:39:20 +0200 Subject: [PATCH 045/247] client/list view: show the contents of a note only after its rendering completes --- .../src/widgets/collections/legacy/ListOrGridView.css | 5 +++++ .../src/widgets/collections/legacy/ListOrGridView.tsx | 10 ++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/client/src/widgets/collections/legacy/ListOrGridView.css b/apps/client/src/widgets/collections/legacy/ListOrGridView.css index d393c2496b..d4596afe88 100644 --- a/apps/client/src/widgets/collections/legacy/ListOrGridView.css +++ b/apps/client/src/widgets/collections/legacy/ListOrGridView.css @@ -156,6 +156,7 @@ } .note-book-content { + display: none; --background: rgba(0, 0, 0, .2); outline: 1px solid var(--background); border-radius: 8px; @@ -165,6 +166,10 @@ animation: note-preview-show .25s ease-out; will-change: opacity; + &.note-book-content-ready { + display: block; + } + > .rendered-content > *:last-child { margin-bottom: 0; } diff --git a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx index a1bbd6916d..3a3b2c9974 100644 --- a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx +++ b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx @@ -16,6 +16,7 @@ import { ViewModeProps } from "../interface"; import { Pager, usePagination } from "../Pagination"; import { filterChildNotes, useFilteredNoteIds } from "./utils"; import { JSX } from "preact/jsx-runtime"; +import { clsx } from "clsx"; export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens }: ViewModeProps<{}>) { const expandDepth = useExpansionDepth(note); @@ -185,6 +186,9 @@ export function NoteContent({ note, trim, noChildrenList, highlightedTokens, inc const contentRef = useRef(null); const highlightSearch = useImperativeSearchHighlighlighting(highlightedTokens); + const [ready, setReady] = useState(false); + const [noteType, setNoteType] = useState("none"); + useEffect(() => { content_renderer.getRenderedContent(note, { trim, @@ -199,17 +203,19 @@ export function NoteContent({ note, trim, noChildrenList, highlightedTokens, inc } else { contentRef.current.replaceChildren(); } - contentRef.current.classList.add(`type-${type}`); highlightSearch(contentRef.current); + setNoteType(type); + setReady(true); }) .catch(e => { console.warn(`Caught error while rendering note '${note.noteId}' of type '${note.type}'`); console.error(e); contentRef.current?.replaceChildren(t("collections.rendering_error")); + setReady(true); }); }, [ note, highlightedTokens ]); - return
        + return
        ; } From 09436f8d6522547963c19734a1c73e44fa47c337 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Sat, 14 Feb 2026 20:52:26 +0100 Subject: [PATCH 046/247] Update translation files Updated by "Cleanup translation files" add-on in Weblate. Translation: Trilium Notes/README Translate-URL: https://hosted.weblate.org/projects/trilium/readme/ --- docs/README-el.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README-el.md b/docs/README-el.md index 19e5b0cb81..f031c0d960 100644 --- a/docs/README-el.md +++ b/docs/README-el.md @@ -135,8 +135,8 @@ script)](./README-ZH_TW.md) | [English](../README.md) | [French](./README-fr.md) εύκολη αποθήκευση περιεχομένου ιστού * Προσαρμόσιμο UI (κουμπιά πλαϊνής γραμμής, γραφικά στοιχεία που ορίζονται από το χρήστη,...) -* [Metrics](https://docs.triliumnotes.org/user-guide/advanced-usage/metrics), - along with a Grafana Dashboard. +* [Μετρικές](https://docs.triliumnotes.org/user-guide/advanced-usage/metrics), + μαζί με ένα Grafana Dashboard. ✨ Ρίξτε μια ματιά στους ακόλουθους πόρους/κοινότητες τρίτων για περισσότερες δυνατότητες που σχετίζονται με το TriliumNext: From 645279c8fab3c6ac9fce0c9bd5193d117cfb60d4 Mon Sep 17 00:00:00 2001 From: AggelosPnS Date: Sat, 14 Feb 2026 15:17:00 +0100 Subject: [PATCH 047/247] Translated using Weblate (Greek) Currently translated at 2.7% (49 of 1777 strings) Translation: Trilium Notes/Client Translate-URL: https://hosted.weblate.org/projects/trilium/client/el/ --- .../client/src/translations/el/translation.json | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/client/src/translations/el/translation.json b/apps/client/src/translations/el/translation.json index 2155123a67..7512b9e705 100644 --- a/apps/client/src/translations/el/translation.json +++ b/apps/client/src/translations/el/translation.json @@ -53,6 +53,21 @@ "prefix": "Πρόθεμα: ", "save": "Αποθήκευση", "branch_prefix_saved": "Το πρόθεμα κλάδου αποθηκεύτηκε.", - "branch_prefix_saved_multiple": "Το πρόθεμα κλάδου αποθηκεύτηκε για {{count}} κλάδους." + "branch_prefix_saved_multiple": "Το πρόθεμα κλάδου αποθηκεύτηκε για {{count}} κλάδους.", + "affected_branches": "Επηρεαζόμενοι κλάδοι ({{count}}):" + }, + "bulk_actions": { + "bulk_actions": "Μαζικές ενέργειες", + "affected_notes": "Επηρεαζόμενες σημειώσεις", + "include_descendants": "Συμπερίληψη απογόνων των επιλεγμένων σημειώσεων", + "available_actions": "Διαθέσιμες ενέργειες", + "chosen_actions": "Επιλεγμένες ενέργειες", + "execute_bulk_actions": "Εκτέλεση μαζικών ενεργειών", + "bulk_actions_executed": "Οι μαζικές ενέργειες εκτελέστηκαν επιτυχώς.", + "none_yet": "Καμία ακόμη… προσθέστε μια ενέργεια επιλέγοντας μία από τις διαθέσιμες παραπάνω.", + "labels": "Ετικέτες", + "relations": "Συσχετίσεις", + "notes": "Σημειώσεις", + "other": "Λοιπά" } } From f290317acc2177fbfbc58eb048edf269e0dc0740 Mon Sep 17 00:00:00 2001 From: AggelosPnS Date: Sat, 14 Feb 2026 15:17:36 +0100 Subject: [PATCH 048/247] Translated using Weblate (Greek) Currently translated at 12.3% (48 of 389 strings) Translation: Trilium Notes/Server Translate-URL: https://hosted.weblate.org/projects/trilium/server/el/ --- .../server/src/assets/translations/el/server.json | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/apps/server/src/assets/translations/el/server.json b/apps/server/src/assets/translations/el/server.json index df49cb7e4b..2a2d4cc829 100644 --- a/apps/server/src/assets/translations/el/server.json +++ b/apps/server/src/assets/translations/el/server.json @@ -34,6 +34,19 @@ "duplicate-subtree": "Αντιγραφή υποδέντρου", "tabs-and-windows": "Καρτέλες & Παράθυρα", "open-new-tab": "Άνοιγμα νέας καρτέλας", - "close-active-tab": "Κλείσιμο ενεργής καρτέλας" + "close-active-tab": "Κλείσιμο ενεργής καρτέλας", + "reopen-last-tab": "Επαναφορά τελευταίας κλειστής καρτέλας", + "activate-next-tab": "Ενεργοποίηση καρτέλας στα δεξιά", + "activate-previous-tab": "Ενεργοποίηση καρτέλας στα αριστερά", + "open-new-window": "Άνοιγμα νέου κενού παραθύρου", + "toggle-tray": "Εμφάνιση/Απόκρυψη εφαρμογής από το system tray", + "first-tab": "Ενεργοποίηση πρώτης καρτέλας στη λίστα", + "second-tab": "Ενεργοποίηση της δεύτερης καρτέλας στη λίστα", + "third-tab": "Ενεργοποίηση της τρίτης καρτέλας στη λίστα", + "fourth-tab": "Ενεργοποίηση της τέταρτης καρτέλας στη λίστα", + "fifth-tab": "Ενεργοποίηση της πέμπτης καρτέλας στη λίστα", + "sixth-tab": "Ενεργοποίηση της έκτης καρτέλας στη λίστα", + "seventh-tab": "Ενεργοποίηση της έβδομης καρτέλας στη λίστα", + "eight-tab": "Ενεργοποίηση της όγδοης καρτέλας στη λίστα" } } From a6cbde88bbfa4b6430ec99c0f092122797d8bac2 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sun, 15 Feb 2026 01:57:10 +0200 Subject: [PATCH 049/247] client/list view: add an alternate style for search results --- .../collections/legacy/ListOrGridView.css | 42 +++++++++++++++++++ .../collections/legacy/ListOrGridView.tsx | 6 +-- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/apps/client/src/widgets/collections/legacy/ListOrGridView.css b/apps/client/src/widgets/collections/legacy/ListOrGridView.css index d4596afe88..6685025383 100644 --- a/apps/client/src/widgets/collections/legacy/ListOrGridView.css +++ b/apps/client/src/widgets/collections/legacy/ListOrGridView.css @@ -209,6 +209,48 @@ } } +.nested-note-list.search-results { + span.tn-icon + span > span { + display: flex; + flex-direction: column-reverse; + align-items: flex-start; + } + + small { + line-height: .85em; + } + + .note-path { + margin-left: 0; + font-size: .85em; + line-height: .85em; + font-weight: 500; + letter-spacing: .5pt; + } + + .tn-icon { + display: flex; + justify-content: center; + align-items: center; + margin-inline-end: 12px; + background: rgb(88, 88, 88); + border-radius: 50%; + width: 1.75em; + height: 1.75em; + font-size: 1.2em; + } + + .note-book-title { + --link-hover-background: transparent; + } + + .ck-find-result { + background: transparent; + color: var(--quick-search-result-highlight-color); + font-weight: 600; + text-decoration: underline; + } +} .note-content-preview:has(.note-book-content:empty) { display: none; diff --git a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx index 3a3b2c9974..1eba122f9b 100644 --- a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx +++ b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx @@ -36,7 +36,7 @@ export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens } { noteIds.length > 0 &&
        {!hasCollectionProperties && } - + {pageNotes?.map(childNote => ( setExpanded(!isExpanded)} data-note-id={note.noteId} >
        - + setExpanded(!isExpanded)}/> Date: Sun, 15 Feb 2026 02:26:23 +0200 Subject: [PATCH 050/247] client/list view: add a menu button for list items --- .../src/widgets/collections/legacy/ListOrGridView.css | 4 ++++ .../src/widgets/collections/legacy/ListOrGridView.tsx | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/apps/client/src/widgets/collections/legacy/ListOrGridView.css b/apps/client/src/widgets/collections/legacy/ListOrGridView.css index 6685025383..018db0a6c7 100644 --- a/apps/client/src/widgets/collections/legacy/ListOrGridView.css +++ b/apps/client/src/widgets/collections/legacy/ListOrGridView.css @@ -153,6 +153,10 @@ font-size: .75em; opacity: .75; } + + .nested-note-list-item-menu { + margin-inline-start: 8px; + } } .note-book-content { diff --git a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx index 1eba122f9b..be244cbbe7 100644 --- a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx +++ b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx @@ -17,6 +17,8 @@ import { Pager, usePagination } from "../Pagination"; import { filterChildNotes, useFilteredNoteIds } from "./utils"; import { JSX } from "preact/jsx-runtime"; import { clsx } from "clsx"; +import ActionButton from "../../react/ActionButton"; +import linkContextMenuService from "../../../menus/link_context_menu"; export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens }: ViewModeProps<{}>) { const expandDepth = useExpansionDepth(note); @@ -133,6 +135,10 @@ function ListNoteCard({ note, parentNote, highlightedTokens, currentLevel, expan showNotePath={parentNote.type === "search"} highlightedTokens={highlightedTokens} /> + {linkContextMenuService.openContextMenu(notePath, e); e.stopPropagation()}} + />
        ); From 3774ea37683aed52e9e64229bfb9a9c5c06173cf Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sun, 15 Feb 2026 02:28:52 +0200 Subject: [PATCH 051/247] style/list view: tweak --- apps/client/src/widgets/collections/legacy/ListOrGridView.css | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/client/src/widgets/collections/legacy/ListOrGridView.css b/apps/client/src/widgets/collections/legacy/ListOrGridView.css index 018db0a6c7..e1d55a8680 100644 --- a/apps/client/src/widgets/collections/legacy/ListOrGridView.css +++ b/apps/client/src/widgets/collections/legacy/ListOrGridView.css @@ -234,6 +234,7 @@ .tn-icon { display: flex; + flex-shrink: 0; justify-content: center; align-items: center; margin-inline-end: 12px; From 15e569dcea32449a79c1d15cdd27724d8f5ba8e2 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 15 Feb 2026 11:32:27 +0200 Subject: [PATCH 052/247] chore(client): address requested changes --- apps/client/src/entities/fnote.ts | 5 +++++ .../src/widgets/layout/ActiveContentBadges.tsx | 12 ++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/client/src/entities/fnote.ts b/apps/client/src/entities/fnote.ts index fbe9493128..2b515f2412 100644 --- a/apps/client/src/entities/fnote.ts +++ b/apps/client/src/entities/fnote.ts @@ -700,6 +700,11 @@ export default class FNote { return this.hasAttribute(LABEL, name); } + /** + * Returns `true` if the note has a label with the given name (same as {@link hasOwnedLabel}), or it has a label with the `disabled:` prefix (for example due to a safe import). + * @param name the name of the label to look for. + * @returns `true` if the label exists, or its version with the `disabled:` prefix. + */ hasLabelOrDisabled(name: string) { return this.hasLabel(name) || this.hasLabel(`disabled:${name}`); } diff --git a/apps/client/src/widgets/layout/ActiveContentBadges.tsx b/apps/client/src/widgets/layout/ActiveContentBadges.tsx index ff94f19f04..80b37ec291 100644 --- a/apps/client/src/widgets/layout/ActiveContentBadges.tsx +++ b/apps/client/src/widgets/layout/ActiveContentBadges.tsx @@ -76,7 +76,7 @@ function ActiveContentBadge({ info, note }: { note: FNote, info: ActiveContentIn const { icon, helpPage, apiDocsPage, isExecutable } = typeMappings[info.type]; return ( @@ -200,7 +200,7 @@ function getTranslationForType(type: ActiveContentInfo["type"]) { case "renderNote": return t("active_content_badges.type_render_note"); case "webView": - return t("note_types.web-view"); + return t("active_content_badges.type_web_view"); } } @@ -210,8 +210,8 @@ function ActiveContentToggle({ note, info }: { note: FNote, info: ActiveContentI return info && { const attrs = note.getOwnedAttributes() .filter(attr => { @@ -227,7 +227,7 @@ function ActiveContentToggle({ note, info }: { note: FNote, info: ActiveContentI // We are adding and removing afterwards to avoid a flicker (because for a moment there would be no active content attribute anymore) because the operations are done in sequence and not atomically. if (attr.type === "label") { - await attributes.addLabel(note.noteId, newName, attr.value); + await attributes.setLabel(note.noteId, newName, attr.value); } else { await attributes.setRelation(note.noteId, newName, attr.value); } @@ -246,7 +246,7 @@ function useActiveContentInfo(note: FNote | null | undefined) { function refresh() { let type: ActiveContentInfo["type"] | null = null; - let isEnabled = true; + let isEnabled = false; let canToggleEnabled = false; if (!note) { From 1588c8103c5a05793cf97e43ac12caea7271bc18 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 15 Feb 2026 12:32:41 +0200 Subject: [PATCH 053/247] docs(user): improve documentation on scripts & active content --- .../doc_notes/en/User Guide/!!!meta.json | 2 +- .../Active content.html | 126 ++++++++ .../Themes/Icon Packs.html | 7 +- .../User Guide/Note Types/Render Note.html | 45 +-- .../User Guide/Scripting/Backend scripts.html | 29 ++ .../Scripting/Backend scripts/Events.html | 258 ++++++++-------- .../User Guide/Scripting/Frontend Basics.html | 153 +++++----- .../Frontend Basics/Custom Widgets.html | 161 +++++----- .../Frontend Basics/Launch Bar Widgets.html | 26 +- .../Developer Guide/Documentation.md | 2 +- docs/User Guide/!!!meta.json | 280 +++++++++++++++++- .../Active content.md | 33 +++ .../User Guide/Note Types/Render Note.md | 10 +- .../User Guide/Scripting/Backend scripts.md | 24 ++ .../Scripting/Backend scripts/Events.md | 2 +- .../User Guide/Scripting/Frontend Basics.md | 63 ++-- .../Frontend Basics/Custom Widgets.md | 24 +- .../Frontend Basics/Launch Bar Widgets.md | 6 +- 18 files changed, 865 insertions(+), 386 deletions(-) create mode 100644 apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Active content.html create mode 100644 apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Backend scripts.html create mode 100644 docs/User Guide/User Guide/Basic Concepts and Features/Active content.md create mode 100644 docs/User Guide/User Guide/Scripting/Backend scripts.md diff --git a/apps/server/src/assets/doc_notes/en/User Guide/!!!meta.json b/apps/server/src/assets/doc_notes/en/User Guide/!!!meta.json index b828947f2c..498d3a4aa5 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/!!!meta.json +++ b/apps/server/src/assets/doc_notes/en/User Guide/!!!meta.json @@ -1 +1 @@ -[{"id":"_help_BOCnjTMBCoxW","title":"Feature Highlights","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Feature Highlights"},{"name":"iconClass","value":"bx bx-star","type":"label"}]},{"id":"_help_Otzi9La2YAUX","title":"Installation & Setup","type":"book","attributes":[{"name":"iconClass","value":"bx bx-cog","type":"label"}],"children":[{"id":"_help_poXkQfguuA0U","title":"Desktop Installation","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Desktop Installation"},{"name":"iconClass","value":"bx bx-desktop","type":"label"}],"children":[{"id":"_help_nRqcgfTb97uV","title":"Using the desktop application as a server","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Desktop Installation/Using the desktop application "},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_Rp0q8bSP6Ayl","title":"System Requirements","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Desktop Installation/System Requirements"},{"name":"iconClass","value":"bx bx-chip","type":"label"}]},{"id":"_help_Un4wj2Mak2Ky","title":"Nix flake","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Desktop Installation/Nix flake"},{"name":"iconClass","value":"bx bxl-tux","type":"label"}]}]},{"id":"_help_WOcw2SLH6tbX","title":"Server Installation","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation"},{"name":"iconClass","value":"bx bx-server","type":"label"}],"children":[{"id":"_help_Dgg7bR3b6K9j","title":"1. Installing the server","type":"book","attributes":[{"name":"iconClass","value":"bx bx-folder","type":"label"}],"children":[{"id":"_help_3tW6mORuTHnB","title":"Packaged version for Linux","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Packaged version for Linux"},{"name":"iconClass","value":"bx bxl-tux","type":"label"}]},{"id":"_help_rWX5eY045zbE","title":"Using Docker","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Using Docker"},{"name":"iconClass","value":"bx bxl-docker","type":"label"}]},{"id":"_help_moVgBcoxE3EK","title":"On NixOS","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/On NixOS"},{"name":"iconClass","value":"bx bxl-tux","type":"label"}]},{"id":"_help_J1Bb6lVlwU5T","title":"Manually","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Manually"},{"name":"iconClass","value":"bx bx-code-alt","type":"label"}]},{"id":"_help_DCmT6e7clMoP","title":"Using Kubernetes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Using Kubernetes"},{"name":"iconClass","value":"bx bxl-kubernetes","type":"label"}]},{"id":"_help_klCWNks3ReaQ","title":"Multiple server instances","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Multiple server instances"},{"name":"iconClass","value":"bx bxs-user-account","type":"label"}]}]},{"id":"_help_vcjrb3VVYPZI","title":"2. Reverse proxy","type":"book","attributes":[{"name":"iconClass","value":"bx bx-folder","type":"label"}],"children":[{"id":"_help_ud6MShXL4WpO","title":"Nginx","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/2. Reverse proxy/Nginx"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_fDLvzOx29Pfg","title":"Apache using Docker","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/2. Reverse proxy/Apache using Docker"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_LLzSMXACKhUs","title":"Trusted proxy","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/2. Reverse proxy/Trusted proxy"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_5ERVJb9s4FRD","title":"Traefik","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/2. Reverse proxy/Traefik"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_l2VkvOwUNfZj","title":"HTTPS (TLS)","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/HTTPS (TLS)"},{"name":"iconClass","value":"bx bx-lock-alt","type":"label"}]},{"id":"_help_0hzsNCP31IAB","title":"Authentication","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/Authentication"},{"name":"iconClass","value":"bx bx-user","type":"label"}]},{"id":"_help_7DAiwaf8Z7Rz","title":"Multi-Factor Authentication","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/Multi-Factor Authentication"},{"name":"iconClass","value":"bx bx-stopwatch","type":"label"}]},{"id":"_help_Un4wj2Mak2Ky","title":"Nix flake","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/Nix flake.clone"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_yeEaYqosGLSh","title":"Third-party cloud hosting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/Third-party cloud hosting"},{"name":"iconClass","value":"bx bx-cloud","type":"label"}]},{"id":"_help_iGTnKjubbXkA","title":"System Requirements","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/System Requirements"},{"name":"iconClass","value":"bx bx-chip","type":"label"}]}]},{"id":"_help_cbkrhQjrkKrh","title":"Synchronization","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Synchronization"},{"name":"iconClass","value":"bx bx-sync","type":"label"}]},{"id":"_help_RDslemsQ6gCp","title":"Mobile Frontend","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Mobile Frontend"},{"name":"iconClass","value":"bx bx-mobile-alt","type":"label"}]},{"id":"_help_MtPxeAWVAzMg","title":"Web Clipper","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Web Clipper"},{"name":"iconClass","value":"bx bx-paperclip","type":"label"}]},{"id":"_help_n1lujUxCwipy","title":"Upgrading TriliumNext","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Upgrading TriliumNext"},{"name":"iconClass","value":"bx bx-up-arrow-alt","type":"label"}]},{"id":"_help_ODY7qQn5m2FT","title":"Backup","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Backup"},{"name":"iconClass","value":"bx bx-hdd","type":"label"}]},{"id":"_help_tAassRL4RSQL","title":"Data directory","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Data directory"},{"name":"iconClass","value":"bx bx-folder-open","type":"label"}]}]},{"id":"_help_gh7bpGYxajRS","title":"Basic Concepts and Features","type":"book","attributes":[{"name":"iconClass","value":"bx bx-help-circle","type":"label"}],"children":[{"id":"_help_Vc8PjrjAGuOp","title":"UI Elements","type":"book","attributes":[{"name":"iconClass","value":"bx bx-window-alt","type":"label"}],"children":[{"id":"_help_x0JgW8UqGXvq","title":"Vertical and horizontal layout","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Vertical and horizontal layout"},{"name":"iconClass","value":"bx bxs-layout","type":"label"}]},{"id":"_help_x3i7MxGccDuM","title":"Global menu","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Global menu"},{"name":"iconClass","value":"bx bx-menu","type":"label"}]},{"id":"_help_oPVyFC7WL2Lp","title":"Note Tree","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree"},{"name":"iconClass","value":"bx bxs-tree-alt","type":"label"}],"children":[{"id":"_help_YtSN43OrfzaA","title":"Note tree contextual menu","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Note tree contextual menu"},{"name":"iconClass","value":"bx bx-menu","type":"label"}]},{"id":"_help_yTjUdsOi4CIE","title":"Multiple selection","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Multiple selection"},{"name":"iconClass","value":"bx bx-list-plus","type":"label"}]},{"id":"_help_DvdZhoQZY9Yd","title":"Keyboard shortcuts","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Keyboard shortcuts"},{"name":"iconClass","value":"bx bxs-keyboard","type":"label"}]},{"id":"_help_wyaGBBQrl4i3","title":"Hiding the subtree","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Hiding the subtree"},{"name":"iconClass","value":"bx bx-hide","type":"label"}]}]},{"id":"_help_BlN9DFI679QC","title":"Ribbon","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Ribbon"},{"name":"iconClass","value":"bx bx-dots-horizontal","type":"label"}]},{"id":"_help_3seOhtN8uLIY","title":"Tabs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Tabs"},{"name":"iconClass","value":"bx bx-dock-top","type":"label"}]},{"id":"_help_xYmIYSP6wE3F","title":"Launch Bar","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Launch Bar"},{"name":"iconClass","value":"bx bx-sidebar","type":"label"}]},{"id":"_help_8YBEPzcpUgxw","title":"Note buttons","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note buttons"},{"name":"iconClass","value":"bx bx-dots-vertical-rounded","type":"label"}]},{"id":"_help_4TIF1oA4VQRO","title":"Options","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Options"},{"name":"iconClass","value":"bx bx-cog","type":"label"}]},{"id":"_help_luNhaphA37EO","title":"Split View","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Split View"},{"name":"iconClass","value":"bx bx-dock-right","type":"label"}]},{"id":"_help_XpOYSgsLkTJy","title":"Floating buttons","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Floating buttons"},{"name":"iconClass","value":"bx bx-rectangle","type":"label"}]},{"id":"_help_RnaPdbciOfeq","title":"Right Sidebar","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Right Sidebar"},{"name":"iconClass","value":"bx bxs-dock-right","type":"label"}]},{"id":"_help_r5JGHN99bVKn","title":"Recent Changes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Recent Changes"},{"name":"iconClass","value":"bx bx-history","type":"label"}]},{"id":"_help_ny318J39E5Z0","title":"Zoom","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Zoom"},{"name":"iconClass","value":"bx bx-zoom-in","type":"label"}]},{"id":"_help_lgKX7r3aL30x","title":"Note Tooltip","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tooltip"},{"name":"iconClass","value":"bx bx-message-detail","type":"label"}]},{"id":"_help_IjZS7iK5EXtb","title":"New Layout","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/New Layout"},{"name":"iconClass","value":"bx bx-layout","type":"label"}],"children":[{"id":"_help_I6p2a06hdnL6","title":"Breadcrumb","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/New Layout/Breadcrumb"},{"name":"iconClass","value":"bx bx-chevron-right","type":"label"}]},{"id":"_help_AlJ73vBCjWDw","title":"Status bar","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/New Layout/Status bar"},{"name":"iconClass","value":"bx bx-dock-bottom","type":"label"}]}]}]},{"id":"_help_BFs8mudNFgCS","title":"Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes"},{"name":"iconClass","value":"bx bx-notepad","type":"label"}],"children":[{"id":"_help_p9kXRFAkwN4o","title":"Note Icons","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Note Icons"},{"name":"iconClass","value":"bx bxs-grid","type":"label"}]},{"id":"_help_0vhv7lsOLy82","title":"Attachments","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Attachments"},{"name":"iconClass","value":"bx bx-paperclip","type":"label"}]},{"id":"_help_IakOLONlIfGI","title":"Cloning Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Cloning Notes"},{"name":"iconClass","value":"bx bx-duplicate","type":"label"}],"children":[{"id":"_help_TBwsyfadTA18","title":"Branch prefix","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Cloning Notes/Branch prefix"},{"name":"iconClass","value":"bx bx-rename","type":"label"}]}]},{"id":"_help_bwg0e8ewQMak","title":"Protected Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Protected Notes"},{"name":"iconClass","value":"bx bx-lock-alt","type":"label"}]},{"id":"_help_MKmLg5x6xkor","title":"Archived Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Archived Notes"},{"name":"iconClass","value":"bx bx-box","type":"label"}]},{"id":"_help_vZWERwf8U3nx","title":"Note Revisions","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Note Revisions"},{"name":"iconClass","value":"bx bx-history","type":"label"}]},{"id":"_help_aGlEvb9hyDhS","title":"Sorting Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Sorting Notes"},{"name":"iconClass","value":"bx bx-sort-up","type":"label"}]},{"id":"_help_NRnIZmSMc5sj","title":"Printing & Exporting as PDF","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF"},{"name":"iconClass","value":"bx bx-printer","type":"label"}]},{"id":"_help_CoFPLs3dRlXc","title":"Read-Only Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Read-Only Notes"},{"name":"iconClass","value":"bx bx-edit-alt","type":"label"}]},{"id":"_help_0ESUbbAxVnoK","title":"Note List","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Note List"},{"name":"iconClass","value":"bx bxs-grid","type":"label"}]}]},{"id":"_help_wArbEsdSae6g","title":"Navigation","type":"book","attributes":[{"name":"iconClass","value":"bx bx-navigation","type":"label"}],"children":[{"id":"_help_kBrnXNG3Hplm","title":"Tree Concepts","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Tree Concepts"},{"name":"iconClass","value":"bx bx-pyramid","type":"label"}]},{"id":"_help_MMiBEQljMQh2","title":"Note Navigation","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Note Navigation"},{"name":"iconClass","value":"bx bxs-navigation","type":"label"}]},{"id":"_help_Ms1nauBra7gq","title":"Quick search","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Quick search"},{"name":"iconClass","value":"bx bx-search-alt-2","type":"label"}]},{"id":"_help_F1r9QtzQLZqm","title":"Jump to...","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Jump to"},{"name":"iconClass","value":"bx bx-send","type":"label"}]},{"id":"_help_eIg8jdvaoNNd","title":"Search","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Search"},{"name":"iconClass","value":"bx bx-search-alt-2","type":"label"}]},{"id":"_help_u3YFHC9tQlpm","title":"Bookmarks","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Bookmarks"},{"name":"iconClass","value":"bx bx-bookmarks","type":"label"}]},{"id":"_help_OR8WJ7Iz9K4U","title":"Note Hoisting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Note Hoisting"},{"name":"iconClass","value":"bx bxs-chevrons-up","type":"label"}]},{"id":"_help_ZjLYv08Rp3qC","title":"Quick edit","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Quick edit"},{"name":"iconClass","value":"bx bx-edit","type":"label"}]},{"id":"_help_9sRHySam5fXb","title":"Workspaces","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Workspaces"},{"name":"iconClass","value":"bx bx-door-open","type":"label"}]},{"id":"_help_xWtq5NUHOwql","title":"Similar Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Similar Notes"},{"name":"iconClass","value":"bx bx-bar-chart","type":"label"}]},{"id":"_help_McngOG2jbUWX","title":"Search in note","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Search in note"},{"name":"iconClass","value":"bx bx-search-alt-2","type":"label"}]}]},{"id":"_help_A9Oc6YKKc65v","title":"Keyboard Shortcuts","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Keyboard Shortcuts"},{"name":"iconClass","value":"bx bxs-keyboard","type":"label"}]},{"id":"_help_Wy267RK4M69c","title":"Themes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Themes"},{"name":"iconClass","value":"bx bx-palette","type":"label"}],"children":[{"id":"_help_VbjZvtUek0Ln","title":"Theme Gallery","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Themes/Theme Gallery"},{"name":"iconClass","value":"bx bx-book-reader","type":"label"}]},{"id":"_help_gOKqSJgXLcIj","title":"Icon Packs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Themes/Icon Packs"},{"name":"iconClass","value":"bx bx-package","type":"label"}]}]},{"id":"_help_mHbBMPDPkVV5","title":"Import & Export","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Import & Export"},{"name":"iconClass","value":"bx bx-import","type":"label"}],"children":[{"id":"_help_Oau6X9rCuegd","title":"Markdown","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Import & Export/Markdown"},{"name":"iconClass","value":"bx bxl-markdown","type":"label"}],"children":[{"id":"_help_rJ9grSgoExl9","title":"Supported syntax","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Import & Export/Markdown/Supported syntax"},{"name":"iconClass","value":"bx bx-code-alt","type":"label"}]}]},{"id":"_help_syuSEKf2rUGr","title":"Evernote","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Import & Export/Evernote"},{"name":"iconClass","value":"bx bx-window-open","type":"label"}],"children":[{"id":"_help_dj3j8dG4th4l","title":"Process internal links by title","type":"doc","attributes":[{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_GnhlmrATVqcH","title":"OneNote","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Import & Export/OneNote"},{"name":"iconClass","value":"bx bx-window-open","type":"label"}]}]},{"id":"_help_rC3pL2aptaRE","title":"Zen mode","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Zen mode"},{"name":"iconClass","value":"bx bxs-yin-yang","type":"label"}]}]},{"id":"_help_s3YCWHBfmYuM","title":"Quick Start","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Quick Start"},{"name":"iconClass","value":"bx bx-run","type":"label"}]},{"id":"_help_i6dbnitykE5D","title":"FAQ","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/FAQ"},{"name":"iconClass","value":"bx bx-question-mark","type":"label"}]},{"id":"_help_KSZ04uQ2D1St","title":"Note Types","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types"},{"name":"iconClass","value":"bx bx-edit","type":"label"}],"children":[{"id":"_help_iPIMuisry3hd","title":"Text","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text"},{"name":"iconClass","value":"bx bx-note","type":"label"}],"children":[{"id":"_help_NwBbFdNZ9h7O","title":"Block quotes & admonitions","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Block quotes & admonitions"},{"name":"iconClass","value":"bx bx-info-circle","type":"label"}]},{"id":"_help_oSuaNgyyKnhu","title":"Bookmarks","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Bookmarks"},{"name":"iconClass","value":"bx bx-bookmark","type":"label"}]},{"id":"_help_veGu4faJErEM","title":"Content language & Right-to-left support","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Content language & Right-to-le"},{"name":"iconClass","value":"bx bx-align-right","type":"label"}]},{"id":"_help_2x0ZAX9ePtzV","title":"Cut to subnote","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Cut to subnote"},{"name":"iconClass","value":"bx bx-cut","type":"label"}]},{"id":"_help_UYuUB1ZekNQU","title":"Developer-specific formatting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Developer-specific formatting"},{"name":"iconClass","value":"bx bx-code-alt","type":"label"}],"children":[{"id":"_help_QxEyIjRBizuC","title":"Code blocks","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Developer-specific formatting/Code blocks"},{"name":"iconClass","value":"bx bx-code","type":"label"}]}]},{"id":"_help_AgjCISero73a","title":"Footnotes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Footnotes"},{"name":"iconClass","value":"bx bx-bracket","type":"label"}]},{"id":"_help_nRhnJkTT8cPs","title":"Formatting toolbar","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Formatting toolbar"},{"name":"iconClass","value":"bx bx-text","type":"label"}]},{"id":"_help_Gr6xFaF6ioJ5","title":"General formatting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/General formatting"},{"name":"iconClass","value":"bx bx-bold","type":"label"}]},{"id":"_help_AxshuNRegLAv","title":"Highlights list","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Highlights list"},{"name":"iconClass","value":"bx bx-highlight","type":"label"}]},{"id":"_help_mT0HEkOsz6i1","title":"Images","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Images"},{"name":"iconClass","value":"bx bx-image-alt","type":"label"}],"children":[{"id":"_help_0Ofbk1aSuVRu","title":"Image references","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Images/Image references"},{"name":"iconClass","value":"bx bxs-file-image","type":"label"}]}]},{"id":"_help_nBAXQFj20hS1","title":"Include Note","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Include Note"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_CohkqWQC1iBv","title":"Insert buttons","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Insert buttons"},{"name":"iconClass","value":"bx bx-plus","type":"label"}]},{"id":"_help_oiVPnW8QfnvS","title":"Keyboard shortcuts","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Keyboard shortcuts"},{"name":"iconClass","value":"bx bxs-keyboard","type":"label"}]},{"id":"_help_QEAPj01N5f7w","title":"Links","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Links"},{"name":"iconClass","value":"bx bx-link-alt","type":"label"}],"children":[{"id":"_help_3IDVtesTQ8ds","title":"External links","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Links/External links"},{"name":"iconClass","value":"bx bx-link-external","type":"label"}]},{"id":"_help_hrZ1D00cLbal","title":"Internal (reference) links","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Links/Internal (reference) links"},{"name":"iconClass","value":"bx bx-link","type":"label"}]}]},{"id":"_help_S6Xx8QIWTV66","title":"Lists","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Lists"},{"name":"iconClass","value":"bx bx-list-ul","type":"label"}]},{"id":"_help_QrtTYPmdd1qq","title":"Markdown-like formatting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Markdown-like formatting"},{"name":"iconClass","value":"bx bxl-markdown","type":"label"}]},{"id":"_help_YfYAtQBcfo5V","title":"Math Equations","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Math Equations"},{"name":"iconClass","value":"bx bx-math","type":"label"}]},{"id":"_help_dEHYtoWWi8ct","title":"Other features","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Other features"},{"name":"iconClass","value":"bx bxs-grid","type":"label"}]},{"id":"_help_gLt3vA97tMcp","title":"Premium features","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Premium features"},{"name":"iconClass","value":"bx bx-star","type":"label"}],"children":[{"id":"_help_ZlN4nump6EbW","title":"Slash Commands","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Premium features/Slash Commands"},{"name":"iconClass","value":"bx bx-menu","type":"label"}]},{"id":"_help_pwc194wlRzcH","title":"Text Snippets","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Premium features/Text Snippets"},{"name":"iconClass","value":"bx bx-align-left","type":"label"}]},{"id":"_help_5wZallV2Qo1t","title":"Format Painter","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Premium features/Format Painter"},{"name":"iconClass","value":"bx bxs-paint-roll","type":"label"}]}]},{"id":"_help_BFvAtE74rbP6","title":"Table of contents","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Table of contents"},{"name":"iconClass","value":"bx bx-heading","type":"label"}]},{"id":"_help_NdowYOC1GFKS","title":"Tables","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Tables"},{"name":"iconClass","value":"bx bx-table","type":"label"}]}]},{"id":"_help_6f9hih2hXXZk","title":"Code","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Code"},{"name":"iconClass","value":"bx bx-code","type":"label"}]},{"id":"_help_m523cpzocqaD","title":"Saved Search","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Saved Search"},{"name":"iconClass","value":"bx bx-file-find","type":"label"}]},{"id":"_help_iRwzGnHPzonm","title":"Relation Map","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Relation Map"},{"name":"iconClass","value":"bx bxs-network-chart","type":"label"}]},{"id":"_help_bdUJEHsAPYQR","title":"Note Map","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Note Map"},{"name":"iconClass","value":"bx bxs-network-chart","type":"label"}]},{"id":"_help_HcABDtFCkbFN","title":"Render Note","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Render Note"},{"name":"iconClass","value":"bx bx-extension","type":"label"}]},{"id":"_help_s1aBHPd79XYj","title":"Mermaid Diagrams","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Mermaid Diagrams"},{"name":"iconClass","value":"bx bx-selection","type":"label"}],"children":[{"id":"_help_RH6yLjjWJHof","title":"ELK layout","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Mermaid Diagrams/ELK layout"},{"name":"iconClass","value":"bx bxs-network-chart","type":"label"}]},{"id":"_help_WWgeUaBb7UfC","title":"Syntax reference","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://mermaid.js.org/intro/syntax-reference.html"},{"name":"iconClass","value":"bx bx-file","type":"label"}],"enforceAttributes":true}]},{"id":"_help_grjYqerjn243","title":"Canvas","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Canvas"},{"name":"iconClass","value":"bx bx-pen","type":"label"}]},{"id":"_help_1vHRoWCEjj0L","title":"Web View","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Web View"},{"name":"iconClass","value":"bx bx-globe-alt","type":"label"}]},{"id":"_help_gBbsAeiuUxI5","title":"Mind Map","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Mind Map"},{"name":"iconClass","value":"bx bx-sitemap","type":"label"}]},{"id":"_help_W8vYD3Q1zjCR","title":"File","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/File"},{"name":"iconClass","value":"bx bx-file-blank","type":"label"}],"children":[{"id":"_help_XJGJrpu7F9sh","title":"PDFs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/File/PDFs"},{"name":"iconClass","value":"bx bxs-file-pdf","type":"label"}]}]}]},{"id":"_help_GTwFsgaA0lCt","title":"Collections","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections"},{"name":"iconClass","value":"bx bx-book","type":"label"}],"children":[{"id":"_help_xWbu3jpNWapp","title":"Calendar","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Calendar"},{"name":"iconClass","value":"bx bx-calendar","type":"label"}]},{"id":"_help_2FvYrpmOXm29","title":"Table","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Table"},{"name":"iconClass","value":"bx bx-table","type":"label"}]},{"id":"_help_CtBQqbwXDx1w","title":"Kanban Board","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Kanban Board"},{"name":"iconClass","value":"bx bx-columns","type":"label"}]},{"id":"_help_81SGnPGMk7Xc","title":"Geo Map","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Geo Map"},{"name":"iconClass","value":"bx bx-map-alt","type":"label"}]},{"id":"_help_zP3PMqaG71Ct","title":"Presentation","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Presentation"},{"name":"iconClass","value":"bx bx-slideshow","type":"label"}]},{"id":"_help_8QqnMzx393bx","title":"Grid View","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Grid View"},{"name":"iconClass","value":"bx bxs-grid","type":"label"}]},{"id":"_help_mULW0Q3VojwY","title":"List View","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/List View"},{"name":"iconClass","value":"bx bx-list-ul","type":"label"}]}]},{"id":"_help_BgmBlOIl72jZ","title":"Troubleshooting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting"},{"name":"iconClass","value":"bx bx-bug","type":"label"}],"children":[{"id":"_help_wy8So3yZZlH9","title":"Reporting issues","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Reporting issues"},{"name":"iconClass","value":"bx bx-bug-alt","type":"label"}]},{"id":"_help_x59R8J8KV5Bp","title":"Anonymized Database","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Anonymized Database"},{"name":"iconClass","value":"bx bx-low-vision","type":"label"}]},{"id":"_help_qzNzp9LYQyPT","title":"Error logs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Error logs"},{"name":"iconClass","value":"bx bx-comment-error","type":"label"}],"children":[{"id":"_help_bnyigUA2UK7s","title":"Backend (server) logs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Error logs/Backend (server) logs"},{"name":"iconClass","value":"bx bx-server","type":"label"}]},{"id":"_help_9yEHzMyFirZR","title":"Frontend logs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Error logs/Frontend logs"},{"name":"iconClass","value":"bx bx-window-alt","type":"label"}]}]},{"id":"_help_vdlYGAcpXAgc","title":"Synchronization fails with 504 Gateway Timeout","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Synchronization fails with 504"},{"name":"iconClass","value":"bx bx-error","type":"label"}]},{"id":"_help_s8alTXmpFR61","title":"Refreshing the application","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Refreshing the application"},{"name":"iconClass","value":"bx bx-refresh","type":"label"}]}]},{"id":"_help_pKK96zzmvBGf","title":"Theme development","type":"book","attributes":[{"name":"iconClass","value":"bx bx-palette","type":"label"}],"children":[{"id":"_help_7NfNr5pZpVKV","title":"Creating a custom theme","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Theme development/Creating a custom theme"},{"name":"iconClass","value":"bx bxs-color","type":"label"}]},{"id":"_help_WFGzWeUK6arS","title":"Customize the Next theme","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Theme development/Customize the Next theme"},{"name":"iconClass","value":"bx bx-news","type":"label"}]},{"id":"_help_WN5z4M8ASACJ","title":"Reference","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Theme development/Reference"},{"name":"iconClass","value":"bx bx-book-open","type":"label"}]},{"id":"_help_AlhDUqhENtH7","title":"Custom app-wide CSS","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Theme development/Custom app-wide CSS"},{"name":"iconClass","value":"bx bxs-file-css","type":"label"}]},{"id":"_help_g1mlRoU8CsqC","title":"Creating an icon pack","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Theme development/Creating an icon pack"},{"name":"iconClass","value":"bx bx-package","type":"label"}]}]},{"id":"_help_tC7s2alapj8V","title":"Advanced Usage","type":"book","attributes":[{"name":"iconClass","value":"bx bx-rocket","type":"label"}],"children":[{"id":"_help_zEY4DaJG4YT5","title":"Attributes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Attributes"},{"name":"iconClass","value":"bx bx-list-check","type":"label"}],"children":[{"id":"_help_HI6GBBIduIgv","title":"Labels","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Attributes/Labels"},{"name":"iconClass","value":"bx bx-hash","type":"label"}]},{"id":"_help_Cq5X6iKQop6R","title":"Relations","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Attributes/Relations"},{"name":"iconClass","value":"bx bx-transfer","type":"label"}]},{"id":"_help_bwZpz2ajCEwO","title":"Attribute Inheritance","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Attributes/Attribute Inheritance"},{"name":"iconClass","value":"bx bx-list-plus","type":"label"}]},{"id":"_help_OFXdgB2nNk1F","title":"Promoted Attributes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Attributes/Promoted Attributes"},{"name":"iconClass","value":"bx bx-table","type":"label"}]}]},{"id":"_help_KC1HB96bqqHX","title":"Templates","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Templates"},{"name":"iconClass","value":"bx bx-copy","type":"label"}]},{"id":"_help_BCkXAVs63Ttv","title":"Note Map (Link map, Tree map)","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Note Map (Link map, Tree map)"},{"name":"iconClass","value":"bx bxs-network-chart","type":"label"}]},{"id":"_help_R9pX4DGra2Vt","title":"Sharing","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Sharing"},{"name":"iconClass","value":"bx bx-share-alt","type":"label"}],"children":[{"id":"_help_Qjt68inQ2bRj","title":"Serving directly the content of a note","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Sharing/Serving directly the content o"},{"name":"iconClass","value":"bx bx-code","type":"label"}]},{"id":"_help_ycBFjKrrwE9p","title":"Exporting static HTML for web publishing","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Sharing/Exporting static HTML for web "},{"name":"iconClass","value":"bx bxs-file-html","type":"label"}]},{"id":"_help_sLIJ6f1dkJYW","title":"Reverse proxy configuration","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Sharing/Reverse proxy configuration"},{"name":"iconClass","value":"bx bx-world","type":"label"}]}]},{"id":"_help_5668rwcirq1t","title":"Advanced Showcases","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Advanced Showcases"},{"name":"iconClass","value":"bx bxs-component","type":"label"}],"children":[{"id":"_help_l0tKav7yLHGF","title":"Day Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Advanced Showcases/Day Notes"},{"name":"iconClass","value":"bx bx-calendar","type":"label"}]},{"id":"_help_R7abl2fc6Mxi","title":"Weight Tracker","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Advanced Showcases/Weight Tracker"},{"name":"iconClass","value":"bx bx-line-chart","type":"label"}]},{"id":"_help_xYjQUYhpbUEW","title":"Task Manager","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Advanced Showcases/Task Manager"},{"name":"iconClass","value":"bx bx-calendar-check","type":"label"}]}]},{"id":"_help_J5Ex1ZrMbyJ6","title":"Custom Request Handler","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Custom Request Handler"},{"name":"iconClass","value":"bx bx-globe","type":"label"}]},{"id":"_help_d3fAXQ2diepH","title":"Custom Resource Providers","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Custom Resource Providers"},{"name":"iconClass","value":"bx bxs-file-plus","type":"label"}]},{"id":"_help_pgxEVkzLl1OP","title":"ETAPI (REST API)","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/ETAPI (REST API)"},{"name":"iconClass","value":"bx bx-extension","type":"label"}],"children":[{"id":"_help_9qPsTWBorUhQ","title":"API Reference","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://docs.triliumnotes.org/rest-api/etapi/"},{"name":"iconClass","value":"bx bx-file","type":"label"}],"enforceAttributes":true}]},{"id":"_help_47ZrP6FNuoG8","title":"Default Note Title","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Default Note Title"},{"name":"iconClass","value":"bx bx-edit-alt","type":"label"}]},{"id":"_help_wX4HbRucYSDD","title":"Database","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Database"},{"name":"iconClass","value":"bx bx-data","type":"label"}],"children":[{"id":"_help_oyIAJ9PvvwHX","title":"Manually altering the database","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Database/Manually altering the database"},{"name":"iconClass","value":"bx bxs-edit","type":"label"}],"children":[{"id":"_help_YKWqdJhzi2VY","title":"SQL Console","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Database/Manually altering the database/SQL Console"},{"name":"iconClass","value":"bx bx-data","type":"label"}]}]},{"id":"_help_6tZeKvSHEUiB","title":"Demo Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Database/Demo Notes"},{"name":"iconClass","value":"bx bx-package","type":"label"}]}]},{"id":"_help_Gzjqa934BdH4","title":"Configuration (config.ini or environment variables)","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Configuration (config.ini or e"},{"name":"iconClass","value":"bx bx-cog","type":"label"}],"children":[{"id":"_help_c5xB8m4g2IY6","title":"Trilium instance","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Configuration (config.ini or environment variables)/Trilium instance"},{"name":"iconClass","value":"bx bx-windows","type":"label"}]},{"id":"_help_LWtBjFej3wX3","title":"Cross-Origin Resource Sharing (CORS)","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Configuration (config.ini or environment variables)/Cross-Origin Resource Sharing "},{"name":"iconClass","value":"bx bx-lock","type":"label"}]}]},{"id":"_help_ivYnonVFBxbQ","title":"Bulk Actions","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Bulk Actions"},{"name":"iconClass","value":"bx bx-list-plus","type":"label"}]},{"id":"_help_4FahAwuGTAwC","title":"Note source","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Note source"},{"name":"iconClass","value":"bx bx-code","type":"label"}]},{"id":"_help_1YeN2MzFUluU","title":"Technologies used","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Technologies used"},{"name":"iconClass","value":"bx bx-pyramid","type":"label"}],"children":[{"id":"_help_MI26XDLSAlCD","title":"CKEditor","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Technologies used/CKEditor"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_N4IDkixaDG9C","title":"MindElixir","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Technologies used/MindElixir"},{"name":"iconClass","value":"bx bx-sitemap","type":"label"}]},{"id":"_help_H0mM1lTxF9JI","title":"Excalidraw","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Technologies used/Excalidraw"},{"name":"iconClass","value":"bx bx-pen","type":"label"}]},{"id":"_help_MQHyy2dIFgxS","title":"Leaflet","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Technologies used/Leaflet"},{"name":"iconClass","value":"bx bx-map-alt","type":"label"}]}]},{"id":"_help_m1lbrzyKDaRB","title":"Note ID","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Note ID"},{"name":"iconClass","value":"bx bx-hash","type":"label"}]},{"id":"_help_0vTSyvhPTAOz","title":"Internal API","type":"book","attributes":[{"name":"iconClass","value":"bx bxs-component","type":"label"}],"children":[{"id":"_help_z8O2VG4ZZJD7","title":"API Reference","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://docs.triliumnotes.org/rest-api/internal/"},{"name":"iconClass","value":"bx bx-file","type":"label"}],"enforceAttributes":true}]},{"id":"_help_2mUhVmZK8RF3","title":"Hidden Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Hidden Notes"},{"name":"iconClass","value":"bx bx-hide","type":"label"}]},{"id":"_help_uYF7pmepw27K","title":"Metrics","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Metrics"},{"name":"iconClass","value":"bx bxs-data","type":"label"}],"children":[{"id":"_help_bOP3TB56fL1V","title":"grafana-dashboard.json","type":"doc","attributes":[{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_64ZTlUPgEPtW","title":"Safe mode","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Safe mode"},{"name":"iconClass","value":"bx bxs-virus-block","type":"label"}]},{"id":"_help_HAIOFBoYIIdO","title":"Nightly release","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Nightly release"},{"name":"iconClass","value":"bx bx-moon","type":"label"}]},{"id":"_help_ZmT9ln8XJX2o","title":"Read-only database","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Read-only database"},{"name":"iconClass","value":"bx bx-book-reader","type":"label"}]}]},{"id":"_help_GBBMSlVSOIGP","title":"AI","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/AI"},{"name":"iconClass","value":"bx bx-bot","type":"label"}],"children":[{"id":"_help_WkM7gsEUyCXs","title":"Providers","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/AI/Providers"},{"name":"iconClass","value":"bx bx-select-multiple","type":"label"}],"children":[{"id":"_help_7EdTxPADv95W","title":"Ollama","type":"book","attributes":[{"name":"iconClass","value":"bx bx-message-dots","type":"label"}],"children":[{"id":"_help_vvUCN7FDkq7G","title":"Installing Ollama","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/AI/Providers/Ollama/Installing Ollama"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_ZavFigBX9AwP","title":"OpenAI","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/AI/Providers/OpenAI"},{"name":"iconClass","value":"bx bx-message-dots","type":"label"}]},{"id":"_help_e0lkirXEiSNc","title":"Anthropic","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/AI/Providers/Anthropic"},{"name":"iconClass","value":"bx bx-message-dots","type":"label"}]}]}]},{"id":"_help_CdNpE2pqjmI6","title":"Scripting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting"},{"name":"iconClass","value":"bx bxs-file-js","type":"label"}],"children":[{"id":"_help_yIhgI5H7A2Sm","title":"Frontend Basics","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics"},{"name":"iconClass","value":"bx bx-window","type":"label"}],"children":[{"id":"_help_MgibgPcfeuGz","title":"Custom Widgets","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets"},{"name":"iconClass","value":"bx bxs-widget","type":"label"}],"children":[{"id":"_help_SynTBQiBsdYJ","title":"Widget Basics","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Widget Basics"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_GhurYZjh8e1V","title":"Note context aware widget","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Note context aware widget"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_M8IppdwVHSjG","title":"Right pane widget","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Right pane widget"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_YNxAqkI5Kg1M","title":"Word count widget","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Word count widget"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_VqGQnnPGnqAU","title":"CSS","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/CSS"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_gMkgcLJ6jBkg","title":"Troubleshooting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Troubleshooting"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_es8OU2GuguFU","title":"Examples","type":"book","attributes":[{"name":"iconClass","value":"bx bx-code-alt","type":"label"}],"children":[{"id":"_help_TjLYAo3JMO8X","title":"\"New Task\" launcher button","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Examples/New Task launcher button"},{"name":"iconClass","value":"bx bx-task","type":"label"}]},{"id":"_help_7kZPMD0uFwkH","title":"Downloading responses from Google Forms","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Examples/Downloading responses from Goo"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_DL92EjAaXT26","title":"Using promoted attributes to configure scripts","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Examples/Using promoted attributes to c"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_4Gn3psZKsfSm","title":"Launch Bar Widgets","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Launch Bar Widgets"},{"name":"iconClass","value":"bx bx-dock-left","type":"label"}],"children":[{"id":"_help_IPArqVfDQ4We","title":"Note Title Widget","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Launch Bar Widgets/Note Title Widget"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_gcI7RPbaNSh3","title":"Analog Watch","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Launch Bar Widgets/Analog Watch"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_KLsqhjaqh1QW","title":"Preact","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Preact"},{"name":"iconClass","value":"bx bxl-react","type":"label"}],"children":[{"id":"_help_Bqde6BvPo05g","title":"Component libraries","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Preact/Component libraries"},{"name":"iconClass","value":"bx bxs-component","type":"label"}]},{"id":"_help_ykYtbM9k3a7B","title":"Hooks","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Preact/Hooks"},{"name":"iconClass","value":"bx bx-question-mark","type":"label"}]},{"id":"_help_Sg9GrCtyftZf","title":"CSS","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Preact/CSS"},{"name":"iconClass","value":"bx bxs-file-css","type":"label"}]},{"id":"_help_RSssb9S3xgSr","title":"Built-in components","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Preact/Built-in components"},{"name":"iconClass","value":"bx bxs-component","type":"label"}],"children":[{"id":"_help_i9B4IW7b6V6z","title":"Widget showcase","type":"doc","attributes":[{"name":"iconClass","value":"bx bx-file","type":"label"}]}]}]}]},{"id":"_help_SPirpZypehBG","title":"Backend scripts","type":"book","attributes":[{"name":"iconClass","value":"bx bx-server","type":"label"}],"children":[{"id":"_help_fZ2IGYFXjkEy","title":"Server-side imports","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Backend scripts/Server-side imports"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_GPERMystNGTB","title":"Events","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Backend scripts/Events"},{"name":"iconClass","value":"bx bx-rss","type":"label"}]}]},{"id":"_help_wqXwKJl6VpNk","title":"Common concepts","type":"book","attributes":[{"name":"iconClass","value":"bx bxl-nodejs","type":"label"}],"children":[{"id":"_help_hA834UaHhSNn","title":"Script bundles","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Common concepts/Script bundles"},{"name":"iconClass","value":"bx bx-package","type":"label"}]}]},{"id":"_help_GLks18SNjxmC","title":"Script API","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Script API"},{"name":"iconClass","value":"bx bx-code-curly","type":"label"}],"children":[{"id":"_help_Q2z6av6JZVWm","title":"Frontend API","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://docs.triliumnotes.org/script-api/frontend"},{"name":"iconClass","value":"bx bx-folder","type":"label"}],"enforceAttributes":true,"children":[{"id":"_help_habiZ3HU8Kw8","title":"FNote","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://docs.triliumnotes.org/script-api/frontend/interfaces/FNote.html"},{"name":"iconClass","value":"bx bx-file","type":"label"}],"enforceAttributes":true}]},{"id":"_help_MEtfsqa5VwNi","title":"Backend API","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://docs.triliumnotes.org/script-api/backend"},{"name":"iconClass","value":"bx bx-file","type":"label"}],"enforceAttributes":true},{"id":"_help_ApVHZ8JY5ofC","title":"Day.js","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Script API/Day.js"},{"name":"iconClass","value":"bx bx-calendar","type":"label"}]}]},{"id":"_help_vElnKeDNPSVl","title":"Logging","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Logging"},{"name":"iconClass","value":"bx bx-terminal","type":"label"}]},{"id":"_help_cNpC0ITcfX0N","title":"Breaking changes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Breaking changes"},{"name":"iconClass","value":"bx bx-up-arrow-alt","type":"label"}]}]},{"id":"_help_Fm0j45KqyHpU","title":"Miscellaneous","type":"book","attributes":[{"name":"iconClass","value":"bx bx-info-circle","type":"label"}],"children":[{"id":"_help_WFbFXrgnDyyU","title":"Privacy Policy","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Miscellaneous/Privacy Policy"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_NcsmUYZRWEW4","title":"Patterns of personal knowledge","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Miscellaneous/Patterns of personal knowledge"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]}] \ No newline at end of file +[{"id":"_help_BOCnjTMBCoxW","title":"Feature Highlights","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Feature Highlights"},{"name":"iconClass","value":"bx bx-star","type":"label"}]},{"id":"_help_Otzi9La2YAUX","title":"Installation & Setup","type":"book","attributes":[{"name":"iconClass","value":"bx bx-cog","type":"label"}],"children":[{"id":"_help_poXkQfguuA0U","title":"Desktop Installation","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Desktop Installation"},{"name":"iconClass","value":"bx bx-desktop","type":"label"}],"children":[{"id":"_help_nRqcgfTb97uV","title":"Using the desktop application as a server","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Desktop Installation/Using the desktop application "},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_Rp0q8bSP6Ayl","title":"System Requirements","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Desktop Installation/System Requirements"},{"name":"iconClass","value":"bx bx-chip","type":"label"}]},{"id":"_help_Un4wj2Mak2Ky","title":"Nix flake","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Desktop Installation/Nix flake"},{"name":"iconClass","value":"bx bxl-tux","type":"label"}]}]},{"id":"_help_WOcw2SLH6tbX","title":"Server Installation","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation"},{"name":"iconClass","value":"bx bx-server","type":"label"}],"children":[{"id":"_help_Dgg7bR3b6K9j","title":"1. Installing the server","type":"book","attributes":[{"name":"iconClass","value":"bx bx-folder","type":"label"}],"children":[{"id":"_help_3tW6mORuTHnB","title":"Packaged version for Linux","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Packaged version for Linux"},{"name":"iconClass","value":"bx bxl-tux","type":"label"}]},{"id":"_help_rWX5eY045zbE","title":"Using Docker","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Using Docker"},{"name":"iconClass","value":"bx bxl-docker","type":"label"}]},{"id":"_help_moVgBcoxE3EK","title":"On NixOS","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/On NixOS"},{"name":"iconClass","value":"bx bxl-tux","type":"label"}]},{"id":"_help_J1Bb6lVlwU5T","title":"Manually","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Manually"},{"name":"iconClass","value":"bx bx-code-alt","type":"label"}]},{"id":"_help_DCmT6e7clMoP","title":"Using Kubernetes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Using Kubernetes"},{"name":"iconClass","value":"bx bxl-kubernetes","type":"label"}]},{"id":"_help_klCWNks3ReaQ","title":"Multiple server instances","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/1. Installing the server/Multiple server instances"},{"name":"iconClass","value":"bx bxs-user-account","type":"label"}]}]},{"id":"_help_vcjrb3VVYPZI","title":"2. Reverse proxy","type":"book","attributes":[{"name":"iconClass","value":"bx bx-folder","type":"label"}],"children":[{"id":"_help_ud6MShXL4WpO","title":"Nginx","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/2. Reverse proxy/Nginx"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_fDLvzOx29Pfg","title":"Apache using Docker","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/2. Reverse proxy/Apache using Docker"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_LLzSMXACKhUs","title":"Trusted proxy","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/2. Reverse proxy/Trusted proxy"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_5ERVJb9s4FRD","title":"Traefik","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/2. Reverse proxy/Traefik"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_l2VkvOwUNfZj","title":"HTTPS (TLS)","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/HTTPS (TLS)"},{"name":"iconClass","value":"bx bx-lock-alt","type":"label"}]},{"id":"_help_0hzsNCP31IAB","title":"Authentication","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/Authentication"},{"name":"iconClass","value":"bx bx-user","type":"label"}]},{"id":"_help_7DAiwaf8Z7Rz","title":"Multi-Factor Authentication","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/Multi-Factor Authentication"},{"name":"iconClass","value":"bx bx-stopwatch","type":"label"}]},{"id":"_help_Un4wj2Mak2Ky","title":"Nix flake","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/Nix flake.clone"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_yeEaYqosGLSh","title":"Third-party cloud hosting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/Third-party cloud hosting"},{"name":"iconClass","value":"bx bx-cloud","type":"label"}]},{"id":"_help_iGTnKjubbXkA","title":"System Requirements","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Server Installation/System Requirements"},{"name":"iconClass","value":"bx bx-chip","type":"label"}]}]},{"id":"_help_cbkrhQjrkKrh","title":"Synchronization","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Synchronization"},{"name":"iconClass","value":"bx bx-sync","type":"label"}]},{"id":"_help_RDslemsQ6gCp","title":"Mobile Frontend","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Mobile Frontend"},{"name":"iconClass","value":"bx bx-mobile-alt","type":"label"}]},{"id":"_help_MtPxeAWVAzMg","title":"Web Clipper","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Web Clipper"},{"name":"iconClass","value":"bx bx-paperclip","type":"label"}]},{"id":"_help_n1lujUxCwipy","title":"Upgrading TriliumNext","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Upgrading TriliumNext"},{"name":"iconClass","value":"bx bx-up-arrow-alt","type":"label"}]},{"id":"_help_ODY7qQn5m2FT","title":"Backup","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Backup"},{"name":"iconClass","value":"bx bx-hdd","type":"label"}]},{"id":"_help_tAassRL4RSQL","title":"Data directory","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Installation & Setup/Data directory"},{"name":"iconClass","value":"bx bx-folder-open","type":"label"}]}]},{"id":"_help_gh7bpGYxajRS","title":"Basic Concepts and Features","type":"book","attributes":[{"name":"iconClass","value":"bx bx-help-circle","type":"label"}],"children":[{"id":"_help_Vc8PjrjAGuOp","title":"UI Elements","type":"book","attributes":[{"name":"iconClass","value":"bx bx-window-alt","type":"label"}],"children":[{"id":"_help_x0JgW8UqGXvq","title":"Vertical and horizontal layout","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Vertical and horizontal layout"},{"name":"iconClass","value":"bx bxs-layout","type":"label"}]},{"id":"_help_x3i7MxGccDuM","title":"Global menu","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Global menu"},{"name":"iconClass","value":"bx bx-menu","type":"label"}]},{"id":"_help_oPVyFC7WL2Lp","title":"Note Tree","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree"},{"name":"iconClass","value":"bx bxs-tree-alt","type":"label"}],"children":[{"id":"_help_YtSN43OrfzaA","title":"Note tree contextual menu","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Note tree contextual menu"},{"name":"iconClass","value":"bx bx-menu","type":"label"}]},{"id":"_help_yTjUdsOi4CIE","title":"Multiple selection","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Multiple selection"},{"name":"iconClass","value":"bx bx-list-plus","type":"label"}]},{"id":"_help_DvdZhoQZY9Yd","title":"Keyboard shortcuts","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Keyboard shortcuts"},{"name":"iconClass","value":"bx bxs-keyboard","type":"label"}]},{"id":"_help_wyaGBBQrl4i3","title":"Hiding the subtree","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tree/Hiding the subtree"},{"name":"iconClass","value":"bx bx-hide","type":"label"}]}]},{"id":"_help_BlN9DFI679QC","title":"Ribbon","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Ribbon"},{"name":"iconClass","value":"bx bx-dots-horizontal","type":"label"}]},{"id":"_help_3seOhtN8uLIY","title":"Tabs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Tabs"},{"name":"iconClass","value":"bx bx-dock-top","type":"label"}]},{"id":"_help_xYmIYSP6wE3F","title":"Launch Bar","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Launch Bar"},{"name":"iconClass","value":"bx bx-sidebar","type":"label"}]},{"id":"_help_8YBEPzcpUgxw","title":"Note buttons","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note buttons"},{"name":"iconClass","value":"bx bx-dots-vertical-rounded","type":"label"}]},{"id":"_help_4TIF1oA4VQRO","title":"Options","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Options"},{"name":"iconClass","value":"bx bx-cog","type":"label"}]},{"id":"_help_luNhaphA37EO","title":"Split View","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Split View"},{"name":"iconClass","value":"bx bx-dock-right","type":"label"}]},{"id":"_help_XpOYSgsLkTJy","title":"Floating buttons","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Floating buttons"},{"name":"iconClass","value":"bx bx-rectangle","type":"label"}]},{"id":"_help_RnaPdbciOfeq","title":"Right Sidebar","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Right Sidebar"},{"name":"iconClass","value":"bx bxs-dock-right","type":"label"}]},{"id":"_help_r5JGHN99bVKn","title":"Recent Changes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Recent Changes"},{"name":"iconClass","value":"bx bx-history","type":"label"}]},{"id":"_help_ny318J39E5Z0","title":"Zoom","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Zoom"},{"name":"iconClass","value":"bx bx-zoom-in","type":"label"}]},{"id":"_help_lgKX7r3aL30x","title":"Note Tooltip","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/Note Tooltip"},{"name":"iconClass","value":"bx bx-message-detail","type":"label"}]},{"id":"_help_IjZS7iK5EXtb","title":"New Layout","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/New Layout"},{"name":"iconClass","value":"bx bx-layout","type":"label"}],"children":[{"id":"_help_I6p2a06hdnL6","title":"Breadcrumb","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/New Layout/Breadcrumb"},{"name":"iconClass","value":"bx bx-chevron-right","type":"label"}]},{"id":"_help_AlJ73vBCjWDw","title":"Status bar","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/UI Elements/New Layout/Status bar"},{"name":"iconClass","value":"bx bx-dock-bottom","type":"label"}]}]}]},{"id":"_help_BFs8mudNFgCS","title":"Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes"},{"name":"iconClass","value":"bx bx-notepad","type":"label"}],"children":[{"id":"_help_p9kXRFAkwN4o","title":"Note Icons","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Note Icons"},{"name":"iconClass","value":"bx bxs-grid","type":"label"}]},{"id":"_help_0vhv7lsOLy82","title":"Attachments","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Attachments"},{"name":"iconClass","value":"bx bx-paperclip","type":"label"}]},{"id":"_help_IakOLONlIfGI","title":"Cloning Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Cloning Notes"},{"name":"iconClass","value":"bx bx-duplicate","type":"label"}],"children":[{"id":"_help_TBwsyfadTA18","title":"Branch prefix","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Cloning Notes/Branch prefix"},{"name":"iconClass","value":"bx bx-rename","type":"label"}]}]},{"id":"_help_bwg0e8ewQMak","title":"Protected Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Protected Notes"},{"name":"iconClass","value":"bx bx-lock-alt","type":"label"}]},{"id":"_help_MKmLg5x6xkor","title":"Archived Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Archived Notes"},{"name":"iconClass","value":"bx bx-box","type":"label"}]},{"id":"_help_vZWERwf8U3nx","title":"Note Revisions","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Note Revisions"},{"name":"iconClass","value":"bx bx-history","type":"label"}]},{"id":"_help_aGlEvb9hyDhS","title":"Sorting Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Sorting Notes"},{"name":"iconClass","value":"bx bx-sort-up","type":"label"}]},{"id":"_help_NRnIZmSMc5sj","title":"Printing & Exporting as PDF","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Printing & Exporting as PDF"},{"name":"iconClass","value":"bx bx-printer","type":"label"}]},{"id":"_help_CoFPLs3dRlXc","title":"Read-Only Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Read-Only Notes"},{"name":"iconClass","value":"bx bx-edit-alt","type":"label"}]},{"id":"_help_0ESUbbAxVnoK","title":"Note List","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Notes/Note List"},{"name":"iconClass","value":"bx bxs-grid","type":"label"}]}]},{"id":"_help_wArbEsdSae6g","title":"Navigation","type":"book","attributes":[{"name":"iconClass","value":"bx bx-navigation","type":"label"}],"children":[{"id":"_help_kBrnXNG3Hplm","title":"Tree Concepts","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Tree Concepts"},{"name":"iconClass","value":"bx bx-pyramid","type":"label"}]},{"id":"_help_MMiBEQljMQh2","title":"Note Navigation","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Note Navigation"},{"name":"iconClass","value":"bx bxs-navigation","type":"label"}]},{"id":"_help_Ms1nauBra7gq","title":"Quick search","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Quick search"},{"name":"iconClass","value":"bx bx-search-alt-2","type":"label"}]},{"id":"_help_F1r9QtzQLZqm","title":"Jump to...","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Jump to"},{"name":"iconClass","value":"bx bx-send","type":"label"}]},{"id":"_help_eIg8jdvaoNNd","title":"Search","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Search"},{"name":"iconClass","value":"bx bx-search-alt-2","type":"label"}]},{"id":"_help_u3YFHC9tQlpm","title":"Bookmarks","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Bookmarks"},{"name":"iconClass","value":"bx bx-bookmarks","type":"label"}]},{"id":"_help_OR8WJ7Iz9K4U","title":"Note Hoisting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Note Hoisting"},{"name":"iconClass","value":"bx bxs-chevrons-up","type":"label"}]},{"id":"_help_ZjLYv08Rp3qC","title":"Quick edit","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Quick edit"},{"name":"iconClass","value":"bx bx-edit","type":"label"}]},{"id":"_help_9sRHySam5fXb","title":"Workspaces","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Workspaces"},{"name":"iconClass","value":"bx bx-door-open","type":"label"}]},{"id":"_help_xWtq5NUHOwql","title":"Similar Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Similar Notes"},{"name":"iconClass","value":"bx bx-bar-chart","type":"label"}]},{"id":"_help_McngOG2jbUWX","title":"Search in note","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Navigation/Search in note"},{"name":"iconClass","value":"bx bx-search-alt-2","type":"label"}]}]},{"id":"_help_A9Oc6YKKc65v","title":"Keyboard Shortcuts","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Keyboard Shortcuts"},{"name":"iconClass","value":"bx bxs-keyboard","type":"label"}]},{"id":"_help_Wy267RK4M69c","title":"Themes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Themes"},{"name":"iconClass","value":"bx bx-palette","type":"label"}],"children":[{"id":"_help_VbjZvtUek0Ln","title":"Theme Gallery","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Themes/Theme Gallery"},{"name":"iconClass","value":"bx bx-book-reader","type":"label"}]},{"id":"_help_gOKqSJgXLcIj","title":"Icon Packs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Themes/Icon Packs"},{"name":"iconClass","value":"bx bx-package","type":"label"}]}]},{"id":"_help_mHbBMPDPkVV5","title":"Import & Export","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Import & Export"},{"name":"iconClass","value":"bx bx-import","type":"label"}],"children":[{"id":"_help_Oau6X9rCuegd","title":"Markdown","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Import & Export/Markdown"},{"name":"iconClass","value":"bx bxl-markdown","type":"label"}],"children":[{"id":"_help_rJ9grSgoExl9","title":"Supported syntax","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Import & Export/Markdown/Supported syntax"},{"name":"iconClass","value":"bx bx-code-alt","type":"label"}]}]},{"id":"_help_syuSEKf2rUGr","title":"Evernote","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Import & Export/Evernote"},{"name":"iconClass","value":"bx bx-window-open","type":"label"}],"children":[{"id":"_help_dj3j8dG4th4l","title":"Process internal links by title","type":"doc","attributes":[{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_GnhlmrATVqcH","title":"OneNote","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Import & Export/OneNote"},{"name":"iconClass","value":"bx bx-window-open","type":"label"}]}]},{"id":"_help_rC3pL2aptaRE","title":"Zen mode","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Zen mode"},{"name":"iconClass","value":"bx bxs-yin-yang","type":"label"}]},{"id":"_help_YzMcWlCVeW09","title":"Active content","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Basic Concepts and Features/Active content"},{"name":"iconClass","value":"bx bxs-widget","type":"label"}]}]},{"id":"_help_s3YCWHBfmYuM","title":"Quick Start","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Quick Start"},{"name":"iconClass","value":"bx bx-run","type":"label"}]},{"id":"_help_i6dbnitykE5D","title":"FAQ","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/FAQ"},{"name":"iconClass","value":"bx bx-question-mark","type":"label"}]},{"id":"_help_KSZ04uQ2D1St","title":"Note Types","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types"},{"name":"iconClass","value":"bx bx-edit","type":"label"}],"children":[{"id":"_help_iPIMuisry3hd","title":"Text","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text"},{"name":"iconClass","value":"bx bx-note","type":"label"}],"children":[{"id":"_help_NwBbFdNZ9h7O","title":"Block quotes & admonitions","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Block quotes & admonitions"},{"name":"iconClass","value":"bx bx-info-circle","type":"label"}]},{"id":"_help_oSuaNgyyKnhu","title":"Bookmarks","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Bookmarks"},{"name":"iconClass","value":"bx bx-bookmark","type":"label"}]},{"id":"_help_veGu4faJErEM","title":"Content language & Right-to-left support","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Content language & Right-to-le"},{"name":"iconClass","value":"bx bx-align-right","type":"label"}]},{"id":"_help_2x0ZAX9ePtzV","title":"Cut to subnote","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Cut to subnote"},{"name":"iconClass","value":"bx bx-cut","type":"label"}]},{"id":"_help_UYuUB1ZekNQU","title":"Developer-specific formatting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Developer-specific formatting"},{"name":"iconClass","value":"bx bx-code-alt","type":"label"}],"children":[{"id":"_help_QxEyIjRBizuC","title":"Code blocks","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Developer-specific formatting/Code blocks"},{"name":"iconClass","value":"bx bx-code","type":"label"}]}]},{"id":"_help_AgjCISero73a","title":"Footnotes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Footnotes"},{"name":"iconClass","value":"bx bx-bracket","type":"label"}]},{"id":"_help_nRhnJkTT8cPs","title":"Formatting toolbar","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Formatting toolbar"},{"name":"iconClass","value":"bx bx-text","type":"label"}]},{"id":"_help_Gr6xFaF6ioJ5","title":"General formatting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/General formatting"},{"name":"iconClass","value":"bx bx-bold","type":"label"}]},{"id":"_help_AxshuNRegLAv","title":"Highlights list","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Highlights list"},{"name":"iconClass","value":"bx bx-highlight","type":"label"}]},{"id":"_help_mT0HEkOsz6i1","title":"Images","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Images"},{"name":"iconClass","value":"bx bx-image-alt","type":"label"}],"children":[{"id":"_help_0Ofbk1aSuVRu","title":"Image references","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Images/Image references"},{"name":"iconClass","value":"bx bxs-file-image","type":"label"}]}]},{"id":"_help_nBAXQFj20hS1","title":"Include Note","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Include Note"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_CohkqWQC1iBv","title":"Insert buttons","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Insert buttons"},{"name":"iconClass","value":"bx bx-plus","type":"label"}]},{"id":"_help_oiVPnW8QfnvS","title":"Keyboard shortcuts","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Keyboard shortcuts"},{"name":"iconClass","value":"bx bxs-keyboard","type":"label"}]},{"id":"_help_QEAPj01N5f7w","title":"Links","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Links"},{"name":"iconClass","value":"bx bx-link-alt","type":"label"}],"children":[{"id":"_help_3IDVtesTQ8ds","title":"External links","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Links/External links"},{"name":"iconClass","value":"bx bx-link-external","type":"label"}]},{"id":"_help_hrZ1D00cLbal","title":"Internal (reference) links","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Links/Internal (reference) links"},{"name":"iconClass","value":"bx bx-link","type":"label"}]}]},{"id":"_help_S6Xx8QIWTV66","title":"Lists","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Lists"},{"name":"iconClass","value":"bx bx-list-ul","type":"label"}]},{"id":"_help_QrtTYPmdd1qq","title":"Markdown-like formatting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Markdown-like formatting"},{"name":"iconClass","value":"bx bxl-markdown","type":"label"}]},{"id":"_help_YfYAtQBcfo5V","title":"Math Equations","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Math Equations"},{"name":"iconClass","value":"bx bx-math","type":"label"}]},{"id":"_help_dEHYtoWWi8ct","title":"Other features","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Other features"},{"name":"iconClass","value":"bx bxs-grid","type":"label"}]},{"id":"_help_gLt3vA97tMcp","title":"Premium features","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Premium features"},{"name":"iconClass","value":"bx bx-star","type":"label"}],"children":[{"id":"_help_ZlN4nump6EbW","title":"Slash Commands","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Premium features/Slash Commands"},{"name":"iconClass","value":"bx bx-menu","type":"label"}]},{"id":"_help_pwc194wlRzcH","title":"Text Snippets","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Premium features/Text Snippets"},{"name":"iconClass","value":"bx bx-align-left","type":"label"}]},{"id":"_help_5wZallV2Qo1t","title":"Format Painter","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Premium features/Format Painter"},{"name":"iconClass","value":"bx bxs-paint-roll","type":"label"}]}]},{"id":"_help_BFvAtE74rbP6","title":"Table of contents","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Table of contents"},{"name":"iconClass","value":"bx bx-heading","type":"label"}]},{"id":"_help_NdowYOC1GFKS","title":"Tables","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Text/Tables"},{"name":"iconClass","value":"bx bx-table","type":"label"}]}]},{"id":"_help_6f9hih2hXXZk","title":"Code","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Code"},{"name":"iconClass","value":"bx bx-code","type":"label"}]},{"id":"_help_m523cpzocqaD","title":"Saved Search","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Saved Search"},{"name":"iconClass","value":"bx bx-file-find","type":"label"}]},{"id":"_help_iRwzGnHPzonm","title":"Relation Map","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Relation Map"},{"name":"iconClass","value":"bx bxs-network-chart","type":"label"}]},{"id":"_help_bdUJEHsAPYQR","title":"Note Map","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Note Map"},{"name":"iconClass","value":"bx bxs-network-chart","type":"label"}]},{"id":"_help_HcABDtFCkbFN","title":"Render Note","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Render Note"},{"name":"iconClass","value":"bx bx-extension","type":"label"}]},{"id":"_help_s1aBHPd79XYj","title":"Mermaid Diagrams","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Mermaid Diagrams"},{"name":"iconClass","value":"bx bx-selection","type":"label"}],"children":[{"id":"_help_RH6yLjjWJHof","title":"ELK layout","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Mermaid Diagrams/ELK layout"},{"name":"iconClass","value":"bx bxs-network-chart","type":"label"}]},{"id":"_help_WWgeUaBb7UfC","title":"Syntax reference","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://mermaid.js.org/intro/syntax-reference.html"},{"name":"iconClass","value":"bx bx-file","type":"label"}],"enforceAttributes":true}]},{"id":"_help_grjYqerjn243","title":"Canvas","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Canvas"},{"name":"iconClass","value":"bx bx-pen","type":"label"}]},{"id":"_help_1vHRoWCEjj0L","title":"Web View","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Web View"},{"name":"iconClass","value":"bx bx-globe-alt","type":"label"}]},{"id":"_help_gBbsAeiuUxI5","title":"Mind Map","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/Mind Map"},{"name":"iconClass","value":"bx bx-sitemap","type":"label"}]},{"id":"_help_W8vYD3Q1zjCR","title":"File","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/File"},{"name":"iconClass","value":"bx bx-file-blank","type":"label"}],"children":[{"id":"_help_XJGJrpu7F9sh","title":"PDFs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Note Types/File/PDFs"},{"name":"iconClass","value":"bx bxs-file-pdf","type":"label"}]}]}]},{"id":"_help_GTwFsgaA0lCt","title":"Collections","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections"},{"name":"iconClass","value":"bx bx-book","type":"label"}],"children":[{"id":"_help_xWbu3jpNWapp","title":"Calendar","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Calendar"},{"name":"iconClass","value":"bx bx-calendar","type":"label"}]},{"id":"_help_2FvYrpmOXm29","title":"Table","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Table"},{"name":"iconClass","value":"bx bx-table","type":"label"}]},{"id":"_help_CtBQqbwXDx1w","title":"Kanban Board","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Kanban Board"},{"name":"iconClass","value":"bx bx-columns","type":"label"}]},{"id":"_help_81SGnPGMk7Xc","title":"Geo Map","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Geo Map"},{"name":"iconClass","value":"bx bx-map-alt","type":"label"}]},{"id":"_help_zP3PMqaG71Ct","title":"Presentation","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Presentation"},{"name":"iconClass","value":"bx bx-slideshow","type":"label"}]},{"id":"_help_8QqnMzx393bx","title":"Grid View","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/Grid View"},{"name":"iconClass","value":"bx bxs-grid","type":"label"}]},{"id":"_help_mULW0Q3VojwY","title":"List View","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Collections/List View"},{"name":"iconClass","value":"bx bx-list-ul","type":"label"}]}]},{"id":"_help_BgmBlOIl72jZ","title":"Troubleshooting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting"},{"name":"iconClass","value":"bx bx-bug","type":"label"}],"children":[{"id":"_help_wy8So3yZZlH9","title":"Reporting issues","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Reporting issues"},{"name":"iconClass","value":"bx bx-bug-alt","type":"label"}]},{"id":"_help_x59R8J8KV5Bp","title":"Anonymized Database","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Anonymized Database"},{"name":"iconClass","value":"bx bx-low-vision","type":"label"}]},{"id":"_help_qzNzp9LYQyPT","title":"Error logs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Error logs"},{"name":"iconClass","value":"bx bx-comment-error","type":"label"}],"children":[{"id":"_help_bnyigUA2UK7s","title":"Backend (server) logs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Error logs/Backend (server) logs"},{"name":"iconClass","value":"bx bx-server","type":"label"}]},{"id":"_help_9yEHzMyFirZR","title":"Frontend logs","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Error logs/Frontend logs"},{"name":"iconClass","value":"bx bx-window-alt","type":"label"}]}]},{"id":"_help_vdlYGAcpXAgc","title":"Synchronization fails with 504 Gateway Timeout","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Synchronization fails with 504"},{"name":"iconClass","value":"bx bx-error","type":"label"}]},{"id":"_help_s8alTXmpFR61","title":"Refreshing the application","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Troubleshooting/Refreshing the application"},{"name":"iconClass","value":"bx bx-refresh","type":"label"}]}]},{"id":"_help_pKK96zzmvBGf","title":"Theme development","type":"book","attributes":[{"name":"iconClass","value":"bx bx-palette","type":"label"}],"children":[{"id":"_help_7NfNr5pZpVKV","title":"Creating a custom theme","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Theme development/Creating a custom theme"},{"name":"iconClass","value":"bx bxs-color","type":"label"}]},{"id":"_help_WFGzWeUK6arS","title":"Customize the Next theme","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Theme development/Customize the Next theme"},{"name":"iconClass","value":"bx bx-news","type":"label"}]},{"id":"_help_WN5z4M8ASACJ","title":"Reference","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Theme development/Reference"},{"name":"iconClass","value":"bx bx-book-open","type":"label"}]},{"id":"_help_AlhDUqhENtH7","title":"Custom app-wide CSS","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Theme development/Custom app-wide CSS"},{"name":"iconClass","value":"bx bxs-file-css","type":"label"}]},{"id":"_help_g1mlRoU8CsqC","title":"Creating an icon pack","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Theme development/Creating an icon pack"},{"name":"iconClass","value":"bx bx-package","type":"label"}]}]},{"id":"_help_tC7s2alapj8V","title":"Advanced Usage","type":"book","attributes":[{"name":"iconClass","value":"bx bx-rocket","type":"label"}],"children":[{"id":"_help_zEY4DaJG4YT5","title":"Attributes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Attributes"},{"name":"iconClass","value":"bx bx-list-check","type":"label"}],"children":[{"id":"_help_HI6GBBIduIgv","title":"Labels","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Attributes/Labels"},{"name":"iconClass","value":"bx bx-hash","type":"label"}]},{"id":"_help_Cq5X6iKQop6R","title":"Relations","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Attributes/Relations"},{"name":"iconClass","value":"bx bx-transfer","type":"label"}]},{"id":"_help_bwZpz2ajCEwO","title":"Attribute Inheritance","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Attributes/Attribute Inheritance"},{"name":"iconClass","value":"bx bx-list-plus","type":"label"}]},{"id":"_help_OFXdgB2nNk1F","title":"Promoted Attributes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Attributes/Promoted Attributes"},{"name":"iconClass","value":"bx bx-table","type":"label"}]}]},{"id":"_help_KC1HB96bqqHX","title":"Templates","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Templates"},{"name":"iconClass","value":"bx bx-copy","type":"label"}]},{"id":"_help_BCkXAVs63Ttv","title":"Note Map (Link map, Tree map)","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Note Map (Link map, Tree map)"},{"name":"iconClass","value":"bx bxs-network-chart","type":"label"}]},{"id":"_help_R9pX4DGra2Vt","title":"Sharing","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Sharing"},{"name":"iconClass","value":"bx bx-share-alt","type":"label"}],"children":[{"id":"_help_Qjt68inQ2bRj","title":"Serving directly the content of a note","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Sharing/Serving directly the content o"},{"name":"iconClass","value":"bx bx-code","type":"label"}]},{"id":"_help_ycBFjKrrwE9p","title":"Exporting static HTML for web publishing","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Sharing/Exporting static HTML for web "},{"name":"iconClass","value":"bx bxs-file-html","type":"label"}]},{"id":"_help_sLIJ6f1dkJYW","title":"Reverse proxy configuration","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Sharing/Reverse proxy configuration"},{"name":"iconClass","value":"bx bx-world","type":"label"}]}]},{"id":"_help_5668rwcirq1t","title":"Advanced Showcases","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Advanced Showcases"},{"name":"iconClass","value":"bx bxs-component","type":"label"}],"children":[{"id":"_help_l0tKav7yLHGF","title":"Day Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Advanced Showcases/Day Notes"},{"name":"iconClass","value":"bx bx-calendar","type":"label"}]},{"id":"_help_R7abl2fc6Mxi","title":"Weight Tracker","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Advanced Showcases/Weight Tracker"},{"name":"iconClass","value":"bx bx-line-chart","type":"label"}]},{"id":"_help_xYjQUYhpbUEW","title":"Task Manager","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Advanced Showcases/Task Manager"},{"name":"iconClass","value":"bx bx-calendar-check","type":"label"}]}]},{"id":"_help_J5Ex1ZrMbyJ6","title":"Custom Request Handler","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Custom Request Handler"},{"name":"iconClass","value":"bx bx-globe","type":"label"}]},{"id":"_help_d3fAXQ2diepH","title":"Custom Resource Providers","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Custom Resource Providers"},{"name":"iconClass","value":"bx bxs-file-plus","type":"label"}]},{"id":"_help_pgxEVkzLl1OP","title":"ETAPI (REST API)","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/ETAPI (REST API)"},{"name":"iconClass","value":"bx bx-extension","type":"label"}],"children":[{"id":"_help_9qPsTWBorUhQ","title":"API Reference","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://docs.triliumnotes.org/rest-api/etapi/"},{"name":"iconClass","value":"bx bx-file","type":"label"}],"enforceAttributes":true}]},{"id":"_help_47ZrP6FNuoG8","title":"Default Note Title","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Default Note Title"},{"name":"iconClass","value":"bx bx-edit-alt","type":"label"}]},{"id":"_help_wX4HbRucYSDD","title":"Database","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Database"},{"name":"iconClass","value":"bx bx-data","type":"label"}],"children":[{"id":"_help_oyIAJ9PvvwHX","title":"Manually altering the database","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Database/Manually altering the database"},{"name":"iconClass","value":"bx bxs-edit","type":"label"}],"children":[{"id":"_help_YKWqdJhzi2VY","title":"SQL Console","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Database/Manually altering the database/SQL Console"},{"name":"iconClass","value":"bx bx-data","type":"label"}]}]},{"id":"_help_6tZeKvSHEUiB","title":"Demo Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Database/Demo Notes"},{"name":"iconClass","value":"bx bx-package","type":"label"}]}]},{"id":"_help_Gzjqa934BdH4","title":"Configuration (config.ini or environment variables)","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Configuration (config.ini or e"},{"name":"iconClass","value":"bx bx-cog","type":"label"}],"children":[{"id":"_help_c5xB8m4g2IY6","title":"Trilium instance","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Configuration (config.ini or environment variables)/Trilium instance"},{"name":"iconClass","value":"bx bx-windows","type":"label"}]},{"id":"_help_LWtBjFej3wX3","title":"Cross-Origin Resource Sharing (CORS)","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Configuration (config.ini or environment variables)/Cross-Origin Resource Sharing "},{"name":"iconClass","value":"bx bx-lock","type":"label"}]}]},{"id":"_help_ivYnonVFBxbQ","title":"Bulk Actions","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Bulk Actions"},{"name":"iconClass","value":"bx bx-list-plus","type":"label"}]},{"id":"_help_4FahAwuGTAwC","title":"Note source","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Note source"},{"name":"iconClass","value":"bx bx-code","type":"label"}]},{"id":"_help_1YeN2MzFUluU","title":"Technologies used","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Technologies used"},{"name":"iconClass","value":"bx bx-pyramid","type":"label"}],"children":[{"id":"_help_MI26XDLSAlCD","title":"CKEditor","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Technologies used/CKEditor"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_N4IDkixaDG9C","title":"MindElixir","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Technologies used/MindElixir"},{"name":"iconClass","value":"bx bx-sitemap","type":"label"}]},{"id":"_help_H0mM1lTxF9JI","title":"Excalidraw","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Technologies used/Excalidraw"},{"name":"iconClass","value":"bx bx-pen","type":"label"}]},{"id":"_help_MQHyy2dIFgxS","title":"Leaflet","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Technologies used/Leaflet"},{"name":"iconClass","value":"bx bx-map-alt","type":"label"}]}]},{"id":"_help_m1lbrzyKDaRB","title":"Note ID","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Note ID"},{"name":"iconClass","value":"bx bx-hash","type":"label"}]},{"id":"_help_0vTSyvhPTAOz","title":"Internal API","type":"book","attributes":[{"name":"iconClass","value":"bx bxs-component","type":"label"}],"children":[{"id":"_help_z8O2VG4ZZJD7","title":"API Reference","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://docs.triliumnotes.org/rest-api/internal/"},{"name":"iconClass","value":"bx bx-file","type":"label"}],"enforceAttributes":true}]},{"id":"_help_2mUhVmZK8RF3","title":"Hidden Notes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Hidden Notes"},{"name":"iconClass","value":"bx bx-hide","type":"label"}]},{"id":"_help_uYF7pmepw27K","title":"Metrics","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Metrics"},{"name":"iconClass","value":"bx bxs-data","type":"label"}],"children":[{"id":"_help_bOP3TB56fL1V","title":"grafana-dashboard.json","type":"doc","attributes":[{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_64ZTlUPgEPtW","title":"Safe mode","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Safe mode"},{"name":"iconClass","value":"bx bxs-virus-block","type":"label"}]},{"id":"_help_HAIOFBoYIIdO","title":"Nightly release","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Nightly release"},{"name":"iconClass","value":"bx bx-moon","type":"label"}]},{"id":"_help_ZmT9ln8XJX2o","title":"Read-only database","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Advanced Usage/Read-only database"},{"name":"iconClass","value":"bx bx-book-reader","type":"label"}]}]},{"id":"_help_GBBMSlVSOIGP","title":"AI","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/AI"},{"name":"iconClass","value":"bx bx-bot","type":"label"}],"children":[{"id":"_help_WkM7gsEUyCXs","title":"Providers","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/AI/Providers"},{"name":"iconClass","value":"bx bx-select-multiple","type":"label"}],"children":[{"id":"_help_7EdTxPADv95W","title":"Ollama","type":"book","attributes":[{"name":"iconClass","value":"bx bx-message-dots","type":"label"}],"children":[{"id":"_help_vvUCN7FDkq7G","title":"Installing Ollama","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/AI/Providers/Ollama/Installing Ollama"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_ZavFigBX9AwP","title":"OpenAI","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/AI/Providers/OpenAI"},{"name":"iconClass","value":"bx bx-message-dots","type":"label"}]},{"id":"_help_e0lkirXEiSNc","title":"Anthropic","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/AI/Providers/Anthropic"},{"name":"iconClass","value":"bx bx-message-dots","type":"label"}]}]}]},{"id":"_help_CdNpE2pqjmI6","title":"Scripting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting"},{"name":"iconClass","value":"bx bxs-file-js","type":"label"}],"children":[{"id":"_help_yIhgI5H7A2Sm","title":"Frontend Basics","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics"},{"name":"iconClass","value":"bx bx-window","type":"label"}],"children":[{"id":"_help_MgibgPcfeuGz","title":"Custom Widgets","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets"},{"name":"iconClass","value":"bx bxs-widget","type":"label"}],"children":[{"id":"_help_SynTBQiBsdYJ","title":"Widget Basics","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Widget Basics"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_GhurYZjh8e1V","title":"Note context aware widget","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Note context aware widget"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_M8IppdwVHSjG","title":"Right pane widget","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Right pane widget"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_YNxAqkI5Kg1M","title":"Word count widget","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Word count widget"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_VqGQnnPGnqAU","title":"CSS","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/CSS"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_gMkgcLJ6jBkg","title":"Troubleshooting","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Troubleshooting"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_es8OU2GuguFU","title":"Examples","type":"book","attributes":[{"name":"iconClass","value":"bx bx-code-alt","type":"label"}],"children":[{"id":"_help_TjLYAo3JMO8X","title":"\"New Task\" launcher button","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Examples/New Task launcher button"},{"name":"iconClass","value":"bx bx-task","type":"label"}]},{"id":"_help_7kZPMD0uFwkH","title":"Downloading responses from Google Forms","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Examples/Downloading responses from Goo"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_DL92EjAaXT26","title":"Using promoted attributes to configure scripts","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Examples/Using promoted attributes to c"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_4Gn3psZKsfSm","title":"Launch Bar Widgets","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Launch Bar Widgets"},{"name":"iconClass","value":"bx bx-dock-left","type":"label"}],"children":[{"id":"_help_IPArqVfDQ4We","title":"Note Title Widget","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Launch Bar Widgets/Note Title Widget"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_gcI7RPbaNSh3","title":"Analog Watch","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Launch Bar Widgets/Analog Watch"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]},{"id":"_help_KLsqhjaqh1QW","title":"Preact","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Preact"},{"name":"iconClass","value":"bx bxl-react","type":"label"}],"children":[{"id":"_help_Bqde6BvPo05g","title":"Component libraries","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Preact/Component libraries"},{"name":"iconClass","value":"bx bxs-component","type":"label"}]},{"id":"_help_ykYtbM9k3a7B","title":"Hooks","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Preact/Hooks"},{"name":"iconClass","value":"bx bx-question-mark","type":"label"}]},{"id":"_help_Sg9GrCtyftZf","title":"CSS","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Preact/CSS"},{"name":"iconClass","value":"bx bxs-file-css","type":"label"}]},{"id":"_help_RSssb9S3xgSr","title":"Built-in components","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Frontend Basics/Preact/Built-in components"},{"name":"iconClass","value":"bx bxs-component","type":"label"}],"children":[{"id":"_help_i9B4IW7b6V6z","title":"Widget showcase","type":"doc","attributes":[{"name":"iconClass","value":"bx bx-file","type":"label"}]}]}]}]},{"id":"_help_SPirpZypehBG","title":"Backend scripts","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Backend scripts"},{"name":"iconClass","value":"bx bx-server","type":"label"}],"children":[{"id":"_help_fZ2IGYFXjkEy","title":"Server-side imports","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Backend scripts/Server-side imports"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_GPERMystNGTB","title":"Events","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Backend scripts/Events"},{"name":"iconClass","value":"bx bx-rss","type":"label"}]}]},{"id":"_help_wqXwKJl6VpNk","title":"Common concepts","type":"book","attributes":[{"name":"iconClass","value":"bx bxl-nodejs","type":"label"}],"children":[{"id":"_help_hA834UaHhSNn","title":"Script bundles","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Common concepts/Script bundles"},{"name":"iconClass","value":"bx bx-package","type":"label"}]}]},{"id":"_help_GLks18SNjxmC","title":"Script API","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Script API"},{"name":"iconClass","value":"bx bx-code-curly","type":"label"}],"children":[{"id":"_help_Q2z6av6JZVWm","title":"Frontend API","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://docs.triliumnotes.org/script-api/frontend"},{"name":"iconClass","value":"bx bx-folder","type":"label"}],"enforceAttributes":true,"children":[{"id":"_help_habiZ3HU8Kw8","title":"FNote","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://docs.triliumnotes.org/script-api/frontend/interfaces/FNote.html"},{"name":"iconClass","value":"bx bx-file","type":"label"}],"enforceAttributes":true}]},{"id":"_help_MEtfsqa5VwNi","title":"Backend API","type":"webView","attributes":[{"type":"label","name":"webViewSrc","value":"https://docs.triliumnotes.org/script-api/backend"},{"name":"iconClass","value":"bx bx-file","type":"label"}],"enforceAttributes":true},{"id":"_help_ApVHZ8JY5ofC","title":"Day.js","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Script API/Day.js"},{"name":"iconClass","value":"bx bx-calendar","type":"label"}]}]},{"id":"_help_vElnKeDNPSVl","title":"Logging","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Logging"},{"name":"iconClass","value":"bx bx-terminal","type":"label"}]},{"id":"_help_cNpC0ITcfX0N","title":"Breaking changes","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Scripting/Breaking changes"},{"name":"iconClass","value":"bx bx-up-arrow-alt","type":"label"}]}]},{"id":"_help_Fm0j45KqyHpU","title":"Miscellaneous","type":"book","attributes":[{"name":"iconClass","value":"bx bx-info-circle","type":"label"}],"children":[{"id":"_help_WFbFXrgnDyyU","title":"Privacy Policy","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Miscellaneous/Privacy Policy"},{"name":"iconClass","value":"bx bx-file","type":"label"}]},{"id":"_help_NcsmUYZRWEW4","title":"Patterns of personal knowledge","type":"doc","attributes":[{"type":"label","name":"docName","value":"User Guide/User Guide/Miscellaneous/Patterns of personal knowledge"},{"name":"iconClass","value":"bx bx-file","type":"label"}]}]}] \ No newline at end of file diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Active content.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Active content.html new file mode 100644 index 0000000000..f45db3c93d --- /dev/null +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Active content.html @@ -0,0 +1,126 @@ +

        Active content is a generic name for powerful features in Trilium, + these range from customizing the UI to advanced scripting that can alter + your notes or even your PC.

        +

        Safe import

        +

        Active content problem of safety, especially when this active content + comes from a third-party such as if it is downloaded from a website and + then imported into Trilium.

        +

        When importing .zip + archives into Trilium, safe mode is active by default which will + try to prevent untrusted code from executing. For example, a custom widget needs + the #widget label in + order to function; safe import works by renaming that label to #disabled:widget.

        +

        Safe mode

        +

        Sometimes active content can cause issues with the UI or the server, preventing + it from functioning properly. Safe mode allows + starting Trilium in such a way that active content is not loaded by default + at start-up, allowing the user to fix the problematic scripts or widgets.

        +

        Types of active content

        +

        These are the types of active content in Trilium, along with a few examples + of what untrusted content of that type could cause:

        +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        NameDisabled on a safe import + DescriptionPotential risks of untrusted code
        Front-end scripts + YesAllow running arbitrary code on the client (UI) of Trilium, which can + alter the user interface.A malicious script can execute server-side code, access un-encrypted notes + or change their contents.
        Custom Widgets + YesCan add new UI features to Trilium, for example by adding a new section + in the Right Sidebar.The UI can be altered in such a way that it can be used to extract sensitive + information or it can simply cause the application to crash.
        Backend scripts + YesCan run custom code on the server of Trilium (Node.js environment), with + full access to the notes and the database.Has access to all the unencrypted notes, but with full access to the database + it can completely destroy the data. It also has access to execute other + applications or alter the files and folders on the server).
        Web View + YesDisplays a website inside a note.Can point to a phishing website which can collect the data (for example + on a log in page).
        Render Note + YesRenders custom content inside a note, such as a dashboard or a new editor + that is not officially supported by Trilium.Can affect the UI similar to front-end scripts or custom widgets since + the scripts are not completely encapsulated, or they can act similar to + a web view where they can collect data entered by the user.
        Custom app-wide CSS + NoCan alter the layout and style of the UI using CSS, applied regardless + of theme.Generally less problematic than the rest of active content, but a badly + written CSS can affect the layout of the application, requiring the use + of Safe mode to + be able to use the application.
        Custom themes + NoCan change the style of the entire UI.Similar to custom app-wide CSS.
        Icon Packs + NoIntroduces new icons that can be used for notes.Generally are more contained and less prone to cause issues, but they + can cause performance issues (for example if the icon pack has millions + of icons in it).
        +
        +

        Active content badge

        +

        Starting with v0.102.0, on the New Layout a + badge will be displayed near the note title, indicating that an active + content is detected. Clicking the badge will reveal a menu with various + options related to that content type, for example to open the documentation + or to configure the execution of scripts.

        +

        For some active content types, such as backend scripts with custom triggering + conditions a toggle button will appear. This makes it possible to easily + disable scripts or widgets, but also to re-enable them if an import was + made with safe mode active.

        +

         

        \ No newline at end of file diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Themes/Icon Packs.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Themes/Icon Packs.html index 243bc06cd4..190a1f070c 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Themes/Icon Packs.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Themes/Icon Packs.html @@ -29,10 +29,9 @@
      • Ideally, create a dedicated spot in your note tree where to place the icon packs.
      • Right click the note where to put it and select Import into note.
      • -
      • Uncheck Safe import.
      • -
      • Select Import.
      • -
      • Refresh the application.
      • +
      • Uncheck Safe import.
      • +
      • Select Import.
      • +
      • Refresh the application.