From 247f16baa5633b27590b1677cbe7783525d084ee Mon Sep 17 00:00:00 2001 From: avi Date: Tue, 18 Aug 2026 17:15:10 -0500 Subject: [PATCH] Add a built-in Light theme Replaces the old Default theme (which followed the OS color scheme) with a fixed warm, writing-focused Light theme: off-white editor surface, charcoal text, subtle warm-gray borders, and a restrained deep teal-green accent. The selector now offers Light and Neonflux. Old saves storing "default" are migrated to "light" in both the renderer and the main process, and the e2e scenario now covers Light + Neonflux application, light/dark checks, theme round-trips, and content preservation. --- src/main/index.ts | 9 +++-- src/renderer/index.html | 2 +- src/renderer/theme.ts | 21 +++++++---- src/renderer/themes.css | 74 +++++++++++++------------------------- tests/selftest-scenario.js | 72 ++++++++++++++++++++++++++++--------- 5 files changed, 103 insertions(+), 75 deletions(-) diff --git a/src/main/index.ts b/src/main/index.ts index be581c9..d44aa0a 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -432,10 +432,13 @@ ipcMain.handle("folio:getClipboardText", () => { }); // Theme preference. Stored as a plain string so future themes can be added -// without touching the main process. -ipcMain.handle("folio:getTheme", () => getSetting("theme", "default")); +// without touching the main process. "default" from older builds maps to +// "light" in the renderer, so it is normalized here too. +ipcMain.handle("folio:getTheme", () => getSetting("theme", "light")); ipcMain.handle("folio:setTheme", (_e, id: unknown) => { - setSetting("theme", typeof id === "string" && id ? id : "default"); + const theme = + typeof id === "string" && id && id !== "default" ? id : "light"; + setSetting("theme", theme); return { ok: true }; }); diff --git a/src/renderer/index.html b/src/renderer/index.html index fe9137f..9fa1c80 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -30,7 +30,7 @@
diff --git a/src/renderer/theme.ts b/src/renderer/theme.ts index e0afdd0..d1162e6 100644 --- a/src/renderer/theme.ts +++ b/src/renderer/theme.ts @@ -6,28 +6,37 @@ export interface ThemeApi { setTheme: (id: string) => Promise; } -function selector(): HTMLSelectElement { +export function selector(): HTMLSelectElement { return document.getElementById("themeSelect") as HTMLSelectElement; } +// Older builds stored the theme as "default"; that now maps to the Light +// theme, which replaced it as Folio's default light appearance. +const LIGHT = "light"; + +function normalizeTheme(id: unknown): string { + if (typeof id !== "string" || !id || id === "default") return LIGHT; + return id; +} + export function applyTheme(id: string): void { - const theme = typeof id === "string" && id ? id : "default"; + const theme = normalizeTheme(id); document.documentElement.setAttribute("data-theme", theme); const sel = selector(); if (sel && sel.value !== theme) sel.value = theme; } export function currentTheme(): string { - return document.documentElement.getAttribute("data-theme") || "default"; + return normalizeTheme(document.documentElement.getAttribute("data-theme")); } // Load the saved theme and wire the selector. Unknown stored values fall back -// to Default (the :root base), so adding a theme later is safe for old saves. +// to Light (the :root base), so adding a theme later is safe for old saves. export async function initTheme(api: ThemeApi): Promise { - let saved = "default"; + let saved = LIGHT; try { const value = await api.getTheme(); - if (typeof value === "string" && value) saved = value; + if (typeof value === "string" && value) saved = normalizeTheme(value); } catch { // keep the default on any IPC failure } diff --git a/src/renderer/themes.css b/src/renderer/themes.css index a5528ac..e1499a2 100644 --- a/src/renderer/themes.css +++ b/src/renderer/themes.css @@ -4,9 +4,8 @@ just a block of variable values — adding one means dropping a `:root[data-theme="..."]` block here plus an