From ebbb8b396c83c48082aa09bfe38e9805e7c59d5c Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Thu, 26 Mar 2026 21:58:28 +0200 Subject: [PATCH] fix(standalone): unable to switch themes --- .../src/lightweight/browser_routes.ts | 2 -- apps/server/src/routes/index.ts | 28 +-------------- .../src/services/bootstrap_utils.ts | 35 +++++++++++++++++-- 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/apps/client-standalone/src/lightweight/browser_routes.ts b/apps/client-standalone/src/lightweight/browser_routes.ts index 4901640a95..b014bc729b 100644 --- a/apps/client-standalone/src/lightweight/browser_routes.ts +++ b/apps/client-standalone/src/lightweight/browser_routes.ts @@ -245,8 +245,6 @@ function bootstrapRoute(): BootstrapDefinition { ...getSharedBootstrapItems(assetPath, isDbInitialized), isDev: import.meta.env.DEV, isStandalone: true, - themeCssUrl: false as const, - themeUseNextAsBase: "next" as const, isMainWindow: true, isElectron: false, hasNativeTitleBar: false, diff --git a/apps/server/src/routes/index.ts b/apps/server/src/routes/index.ts index a3428c5d2e..65d4b3160d 100644 --- a/apps/server/src/routes/index.ts +++ b/apps/server/src/routes/index.ts @@ -46,12 +46,10 @@ export function bootstrap(req: Request, res: Response) { hasBackgroundEffects: isElectron && (isWindows11 || isMac), isMainWindow: true, appCssNoteIds: [], - themeCssUrl: false as const } satisfies BootstrapDefinition); return; } - const options = optionService.getOptionMap(); const csrfToken = generateCsrfToken(req, res, { overwrite: false, @@ -59,8 +57,7 @@ export function bootstrap(req: Request, res: Response) { }); log.info(`CSRF token generation: ${csrfToken ? "Successful" : "Failed"}`); - const theme = options.theme; - const themeNote = attributeService.getNoteWithLabel("appTheme", theme); + const options = optionService.getOptionMap(); const nativeTitleBarVisible = options.nativeTitleBarVisible === "true"; const iconPacks = iconPackService.getIconPacks(); @@ -68,8 +65,6 @@ export function bootstrap(req: Request, res: Response) { ...commonItems, dbInitialized: true, csrfToken, - themeCssUrl: getThemeCssUrl(theme, themeNote), - themeUseNextAsBase: themeNote?.getAttributeValue("label", "appThemeBase") as "next" | "next-light" | "next-dark", platform: process.platform, hasNativeTitleBar: isElectron && nativeTitleBarVisible, hasBackgroundEffects: options.backgroundEffects === "true" @@ -122,24 +117,3 @@ function getView(req: Request): View { return "desktop"; } - -function getThemeCssUrl(theme: string, themeNote: BNote | null) { - if (theme === "auto") { - return `${assetPath}/stylesheets/theme.css`; - } else if (theme === "light") { - // light theme is always loaded as baseline - return false; - } else if (theme === "dark") { - return `${assetPath}/stylesheets/theme-dark.css`; - } else if (theme === "next") { - return `${assetPath}/stylesheets/theme-next.css`; - } else if (theme === "next-light") { - return `${assetPath}/stylesheets/theme-next-light.css`; - } else if (theme === "next-dark") { - return `${assetPath}/stylesheets/theme-next-dark.css`; - } else if (!process.env.TRILIUM_SAFE_MODE && themeNote) { - return `api/notes/download/${themeNote.noteId}`; - } - // baseline light theme - return false; -} diff --git a/packages/trilium-core/src/services/bootstrap_utils.ts b/packages/trilium-core/src/services/bootstrap_utils.ts index 6ea765554c..5970226ab9 100644 --- a/packages/trilium-core/src/services/bootstrap_utils.ts +++ b/packages/trilium-core/src/services/bootstrap_utils.ts @@ -2,9 +2,10 @@ import { BootstrapDefinition } from "@triliumnext/commons"; import { getSql } from "./sql"; import protected_session from "./protected_session"; import { generateCss, generateIconRegistry, getIconPacks, MIME_TO_EXTENSION_MAPPINGS } from "./icon_packs"; -import options from "./options"; +import optionService from "./options"; import { getCurrentLocale } from "./i18n"; import attributes from "./attributes"; +import BNote from "../becca/entities/bnote"; export default function getSharedBootstrapItems(assetPath: string, dbInitialized: boolean) { const sql = getSql(); @@ -23,6 +24,7 @@ export default function getSharedBootstrapItems(assetPath: string, dbInitialized ...getIconConfig(assetPath) }; + // Setup not yet finished. if (!dbInitialized) { return { ...commonItems, @@ -31,13 +33,19 @@ export default function getSharedBootstrapItems(assetPath: string, dbInitialized }; } + // Database initialized. + const options = optionService.getOptionMap(); + const theme = options.theme; + const themeNote = attributes.getNoteWithLabel("appTheme", theme); return { ...commonItems, - headingStyle: options.getOption("headingStyle") as "plain" | "underline" | "markdown", - layoutOrientation: options.getOption("layoutOrientation") as "vertical" | "horizontal", + headingStyle: options.headingStyle as "plain" | "underline" | "markdown", + layoutOrientation: options.layoutOrientation as "vertical" | "horizontal", maxEntityChangeIdAtLoad: sql.getValue("SELECT COALESCE(MAX(id), 0) FROM entity_changes"), maxEntityChangeSyncIdAtLoad: sql.getValue("SELECT COALESCE(MAX(id), 0) FROM entity_changes WHERE isSynced = 1"), isProtectedSessionAvailable: protected_session.isProtectedSessionAvailable(), + themeCssUrl: getThemeCssUrl(theme, commonItems.assetPath, themeNote), + themeUseNextAsBase: themeNote?.getAttributeValue("label", "appThemeBase") as "next" | "next-light" | "next-dark", } } @@ -58,3 +66,24 @@ export function getIconConfig(assetPath: string): Pick note.noteId); } + +function getThemeCssUrl(theme: string, assetPath: string, themeNote: BNote | null) { + if (theme === "auto") { + return `${assetPath}/stylesheets/theme.css`; + } else if (theme === "light") { + // light theme is always loaded as baseline + return false; + } else if (theme === "dark") { + return `${assetPath}/stylesheets/theme-dark.css`; + } else if (theme === "next") { + return `${assetPath}/stylesheets/theme-next.css`; + } else if (theme === "next-light") { + return `${assetPath}/stylesheets/theme-next-light.css`; + } else if (theme === "next-dark") { + return `${assetPath}/stylesheets/theme-next-dark.css`; + } else if (!process.env.TRILIUM_SAFE_MODE && themeNote) { + return `api/notes/download/${themeNote.noteId}`; + } + // baseline light theme + return false; +}