From 7aa95292b620fb06a279fa448e3eeae276c2caef Mon Sep 17 00:00:00 2001 From: Maksim Kostromin Date: Sat, 24 Oct 2026 23:34:45 -0400 Subject: [PATCH] fix(settings): tolerate blocked localStorage The settings initializer called localStorage.getItem outside its try and the settings effect called setItem with no guard. When storage is blocked (privacy settings, sandboxed frame) getItem throws and the app never renders; a full quota made setItem throw inside the effect, skipping the theme class. Both calls are now inside try/catch. --- src/main.tsx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main.tsx b/src/main.tsx index 8b0c7b8..9210965 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1043,13 +1043,12 @@ const App: React.FC = () => { // ------------------------------------------------------------------------- const [settings, setSettings] = useState(() => { if (typeof window !== 'undefined') { - const saved = localStorage.getItem(LOCALSTORAGE_SETTINGS_KEY); - if (saved) { - try { - return sanitizeSettings(JSON.parse(saved)); - } catch { - /* ignore */ - } + // getItem itself throws when storage is blocked (privacy settings, sandboxed frame) + try { + const saved = localStorage.getItem(LOCALSTORAGE_SETTINGS_KEY); + if (saved) return sanitizeSettings(JSON.parse(saved)); + } catch { + /* ignore */ } } return DEFAULT_SETTINGS; @@ -1216,7 +1215,10 @@ const App: React.FC = () => { // --- Theme & settings cache sync --- useEffect(() => { - localStorage.setItem(LOCALSTORAGE_SETTINGS_KEY, JSON.stringify(settings)); + // Blocked storage or a full quota must not stop the theme from applying + try { localStorage.setItem(LOCALSTORAGE_SETTINGS_KEY, JSON.stringify(settings)); } catch (err) { + console.warn('[Settings] Failed to persist settings to localStorage:', err); + } if (settings.theme === 'dark') document.documentElement.classList.add('dark'); else document.documentElement.classList.remove('dark'); }, [settings]);