From b7ed23268806069815c68731af9484c5d1276783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20Andr=C3=A9?= Date: Mon, 23 Mar 2026 10:11:13 +0100 Subject: [PATCH] refactor(ui): reuse storage cache for bootstrap config --- packages/ui/src/lib/storage.ts | 33 +++++++++++ .../ui/src/lib/ui-bootstrap-cache-sync.tsx | 20 ------- packages/ui/src/lib/ui-bootstrap-cache.ts | 59 ------------------- packages/ui/src/main.tsx | 14 +++-- 4 files changed, 41 insertions(+), 85 deletions(-) delete mode 100644 packages/ui/src/lib/ui-bootstrap-cache-sync.tsx delete mode 100644 packages/ui/src/lib/ui-bootstrap-cache.ts diff --git a/packages/ui/src/lib/storage.ts b/packages/ui/src/lib/storage.ts index 4616bc94..569c4e0e 100644 --- a/packages/ui/src/lib/storage.ts +++ b/packages/ui/src/lib/storage.ts @@ -4,6 +4,7 @@ import { serverEvents } from "./server-events" import { getLogger } from "./logger" const log = getLogger("actions") +const UI_CONFIG_CACHE_KEY = "codenomad:config-owner:ui" export type OwnerBucket = Record @@ -57,6 +58,23 @@ export class ServerStorage { }) } + readCachedConfigOwner(owner: string): OwnerBucket | undefined { + if (owner !== "ui" || typeof window === "undefined" || !window.localStorage) { + return undefined + } + + try { + const raw = window.localStorage.getItem(UI_CONFIG_CACHE_KEY) + if (!raw) { + return undefined + } + const parsed = JSON.parse(raw) as OwnerBucket + return parsed && typeof parsed === "object" ? parsed : undefined + } catch { + return undefined + } + } + async loadConfigOwner(owner: string): Promise { const cached = this.configOwnerCache.get(owner) if (cached) return cached @@ -218,6 +236,9 @@ export class ServerStorage { return } cache.set(owner, value) + if (kind === "config" && owner === "ui") { + this.persistUiConfigCache(value) + } const bucket = listeners.get(owner) if (!bucket) return for (const listener of bucket) { @@ -225,6 +246,18 @@ export class ServerStorage { } } + private persistUiConfigCache(value: OwnerBucket) { + if (typeof window === "undefined" || !window.localStorage) { + return + } + + try { + window.localStorage.setItem(UI_CONFIG_CACHE_KEY, JSON.stringify(value)) + } catch { + /* noop */ + } + } + private normalizeInstanceData(data?: InstanceData | null): InstanceData { const source = data ?? DEFAULT_INSTANCE_DATA const messageHistory = Array.isArray(source.messageHistory) ? [...source.messageHistory] : [] diff --git a/packages/ui/src/lib/ui-bootstrap-cache-sync.tsx b/packages/ui/src/lib/ui-bootstrap-cache-sync.tsx deleted file mode 100644 index 00abf91b..00000000 --- a/packages/ui/src/lib/ui-bootstrap-cache-sync.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { createEffect } from "solid-js" -import { useConfig } from "../stores/preferences" -import { writeUiBootstrapCache } from "./ui-bootstrap-cache" - -export function UiBootstrapCacheSync() { - const { isLoaded, preferences, themePreference } = useConfig() - - createEffect(() => { - if (!isLoaded()) { - return - } - - writeUiBootstrapCache({ - theme: themePreference(), - locale: preferences().locale ?? null, - }) - }) - - return null -} diff --git a/packages/ui/src/lib/ui-bootstrap-cache.ts b/packages/ui/src/lib/ui-bootstrap-cache.ts deleted file mode 100644 index 173803a8..00000000 --- a/packages/ui/src/lib/ui-bootstrap-cache.ts +++ /dev/null @@ -1,59 +0,0 @@ -export type UiBootstrapTheme = "light" | "dark" | "system" - -export interface UiBootstrapCacheSnapshot { - theme?: UiBootstrapTheme | null - locale?: string | null -} - -const UI_BOOTSTRAP_CACHE_KEY = "codenomad:ui-bootstrap" - -export function readUiBootstrapCache(): UiBootstrapCacheSnapshot { - if (typeof window === "undefined" || typeof window.localStorage === "undefined") { - return {} - } - - try { - const raw = window.localStorage.getItem(UI_BOOTSTRAP_CACHE_KEY) - if (!raw) { - return {} - } - - const parsed = JSON.parse(raw) as UiBootstrapCacheSnapshot - if (!parsed || typeof parsed !== "object") { - return {} - } - - return { - theme: - parsed.theme === "light" || parsed.theme === "dark" || parsed.theme === "system" - ? parsed.theme - : undefined, - locale: typeof parsed.locale === "string" ? parsed.locale : undefined, - } - } catch { - return {} - } -} - -export function writeUiBootstrapCache(snapshot: UiBootstrapCacheSnapshot) { - if (typeof window === "undefined" || typeof window.localStorage === "undefined") { - return - } - - try { - const previous = readUiBootstrapCache() - const next: UiBootstrapCacheSnapshot = { - theme: snapshot.theme === undefined ? previous.theme : snapshot.theme ?? undefined, - locale: snapshot.locale === undefined ? previous.locale : snapshot.locale ?? undefined, - } - - if (!next.theme && !next.locale) { - window.localStorage.removeItem(UI_BOOTSTRAP_CACHE_KEY) - return - } - - window.localStorage.setItem(UI_BOOTSTRAP_CACHE_KEY, JSON.stringify(next)) - } catch { - /* noop */ - } -} diff --git a/packages/ui/src/main.tsx b/packages/ui/src/main.tsx index 648ff782..9fd7c153 100644 --- a/packages/ui/src/main.tsx +++ b/packages/ui/src/main.tsx @@ -5,8 +5,7 @@ import { ConfigProvider } from "./stores/preferences" import { InstanceConfigProvider } from "./stores/instance-config" import { runtimeEnv } from "./lib/runtime-env" import { I18nProvider, preloadLocaleMessages } from "./lib/i18n" -import { readUiBootstrapCache } from "./lib/ui-bootstrap-cache" -import { UiBootstrapCacheSync } from "./lib/ui-bootstrap-cache-sync" +import { storage } from "./lib/storage" import "./index.css" import "@git-diff-view/solid/styles/diff-view-pure.css" @@ -30,8 +29,12 @@ async function bootstrap() { // (and then refine once persisted config loads). document.documentElement.removeAttribute("data-theme") - const bootstrapCache = readUiBootstrapCache() - const theme = bootstrapCache.theme ?? "system" + const cachedUiConfig = storage.readCachedConfigOwner("ui") + const theme = + cachedUiConfig?.theme === "light" || cachedUiConfig?.theme === "dark" || cachedUiConfig?.theme === "system" + ? cachedUiConfig.theme + : "system" + const locale = typeof cachedUiConfig?.settings?.locale === "string" ? cachedUiConfig.settings.locale : undefined if (theme === "system") { document.documentElement.removeAttribute("data-theme") @@ -39,13 +42,12 @@ async function bootstrap() { document.documentElement.setAttribute("data-theme", theme) } - await preloadLocaleMessages(bootstrapCache.locale) + await preloadLocaleMessages(locale) } render( () => ( -