/** * Svelte 5 rune-based theme store. * Applies all 26 --ctp-* CSS vars to document.documentElement instantly. * Persists selection via settings RPC. * * Usage: * import { themeStore } from './theme-store.svelte'; * themeStore.setTheme('tokyo-night'); * await themeStore.initTheme(rpc); */ import { applyCssVars, THEME_LIST, type ThemeId } from "./themes.ts"; const SETTING_KEY = "theme"; const DEFAULT_THEME: ThemeId = "mocha"; // ── Minimal RPC interface ───────────────────────────────────────────────────── // Avoids importing the full Electroview class — just the subset we need. interface SettingsRpc { request: { "settings.get"(p: { key: string }): Promise<{ value: string | null }>; "settings.set"(p: { key: string; value: string }): Promise<{ ok: boolean }>; }; } // ── Helpers ─────────────────────────────────────────────────────────────────── function isValidThemeId(id: string): id is ThemeId { return THEME_LIST.some((t) => t.id === id); } // ── Store ───────────────────────────────────────────────────────────────────── function createThemeStore() { let currentThemeId = $state(DEFAULT_THEME); let rpc: SettingsRpc | null = null; /** Apply CSS vars immediately — synchronous, no flash. */ function applyToDocument(id: ThemeId): void { applyCssVars(id); currentThemeId = id; } /** * Change the active theme. * Applies CSS vars immediately and persists asynchronously. */ function setTheme(id: ThemeId): void { applyToDocument(id); if (rpc) { rpc.request["settings.set"]({ key: SETTING_KEY, value: id }).catch((err) => { console.error("[theme-store] Failed to persist theme:", err); }); } } /** * Load persisted theme from settings on startup. * Call once in App.svelte onMount. */ async function initTheme(rpcInstance: SettingsRpc): Promise { rpc = rpcInstance; try { const result = await rpc.request["settings.get"]({ key: SETTING_KEY }); const saved = result.value; if (saved && isValidThemeId(saved)) { applyToDocument(saved); } else { // Apply default to ensure vars are set even when nothing was persisted. applyToDocument(DEFAULT_THEME); } } catch (err) { console.error("[theme-store] Failed to load theme from settings:", err); applyToDocument(DEFAULT_THEME); } } return { get currentTheme() { return currentThemeId; }, setTheme, initTheme, }; } export const themeStore = createThemeStore();