From 988dc37b64c18214278e450cf15e3e8399cc0bdf Mon Sep 17 00:00:00 2001 From: Kyle Pope Date: Thu, 12 Mar 2026 20:02:13 +0800 Subject: [PATCH] Fix accent color flash on refresh by eliminating CSS/JS race Guard useTheme effect to skip when settings are undefined, preventing it from overwriting the inline script's cached color with cyan defaults. Move CSS accent var defaults from index.css :root into the index.html inline script so they are always set synchronously before paint. Co-Authored-By: Claude Opus 4.6 --- frontend/index.html | 10 ++++++++-- frontend/src/hooks/useTheme.ts | 11 +++++++---- frontend/src/index.css | 7 +++---- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index 52bf6d2..b5c9d6f 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -9,18 +9,24 @@ UMBRA diff --git a/frontend/src/hooks/useTheme.ts b/frontend/src/hooks/useTheme.ts index 250075b..e3445ce 100644 --- a/frontend/src/hooks/useTheme.ts +++ b/frontend/src/hooks/useTheme.ts @@ -15,10 +15,13 @@ const ACCENT_PRESETS: Record = { export function useTheme() { const { settings } = useSettings(); - // Ensure localStorage always has an accent color (even default cyan) - // so the inline script in index.html can prevent flashes on every load + // Only apply accent color once settings have loaded from the API. + // The inline script in index.html handles the initial paint from localStorage cache. + // Firing this effect with settings=undefined would overwrite the cache with cyan. useEffect(() => { - const colorName = settings?.accent_color || 'cyan'; + if (!settings) return; + + const colorName = settings.accent_color || 'cyan'; const preset = ACCENT_PRESETS[colorName]; if (!preset) return; @@ -31,7 +34,7 @@ export function useTheme() { try { localStorage.setItem('umbra-accent-color', JSON.stringify({ h, s, l })); } catch {} - }, [settings?.accent_color]); + }, [settings]); return { accentColor: settings?.accent_color || 'cyan', diff --git a/frontend/src/index.css b/frontend/src/index.css index 83ce23f..6b58c1a 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -26,10 +26,9 @@ --ring: var(--accent-h) var(--accent-s) var(--accent-l); --radius: 0.5rem; - /* Default accent: cyan */ - --accent-h: 187; - --accent-s: 85.7%; - --accent-l: 53.3%; + /* Accent vars are set by the inline script in index.html (from localStorage + cache or cyan fallback). No CSS defaults here — they would race with the + inline script and cause a flash of wrong color on refresh. */ /* Transitions */ --transition-fast: 150ms;