From a436fa61e50686d52e2abbe68d4698f3b436e867 Mon Sep 17 00:00:00 2001 From: Saravana Achu Mac Date: Tue, 5 May 2026 22:23:06 -0700 Subject: [PATCH] fix(web): tolerate unavailable theme storage --- web/src/components/theme/ThemeProvider.tsx | 32 ++++++++++++++++++---- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/web/src/components/theme/ThemeProvider.tsx b/web/src/components/theme/ThemeProvider.tsx index fbfbaba..c64897a 100644 --- a/web/src/components/theme/ThemeProvider.tsx +++ b/web/src/components/theme/ThemeProvider.tsx @@ -19,10 +19,33 @@ function applyTheme(theme: Theme) { root.dataset.theme = theme; } +function readStoredTheme(): Theme | null { + if (typeof window === 'undefined') return null; + try { + const storage = window.localStorage; + if (typeof storage?.getItem !== 'function') return null; + const stored = storage.getItem(STORAGE_KEY); + return stored === 'light' || stored === 'dark' ? stored : null; + } catch { + return null; + } +} + +function writeStoredTheme(theme: Theme) { + try { + const storage = window.localStorage; + if (typeof storage?.setItem === 'function') { + storage.setItem(STORAGE_KEY, theme); + } + } catch { + // Theme persistence is best-effort; restricted storage should not break UI. + } +} + function resolveInitialTheme(): Theme { if (typeof window === 'undefined') return 'light'; - const stored = window.localStorage.getItem(STORAGE_KEY); - if (stored === 'light' || stored === 'dark') return stored; + const stored = readStoredTheme(); + if (stored) return stored; return window.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; } @@ -31,15 +54,14 @@ export function ThemeProvider({ children }: { children: ReactNode }) { useEffect(() => { applyTheme(theme); - window.localStorage.setItem(STORAGE_KEY, theme); + writeStoredTheme(theme); }, [theme]); useEffect(() => { const media = window.matchMedia?.('(prefers-color-scheme: dark)'); if (!media) return; const handleChange = () => { - const stored = window.localStorage.getItem(STORAGE_KEY); - if (stored === 'light' || stored === 'dark') return; + if (readStoredTheme()) return; setThemeState(media.matches ? 'dark' : 'light'); }; media.addEventListener?.('change', handleChange);