From 002a5d16eba8fe85afe477816b1f568c120e799b Mon Sep 17 00:00:00 2001 From: Abhishek S Lal Date: Thu, 1 Jan 2026 23:55:06 +0530 Subject: [PATCH] refactor: improve theme handling in ThemeProvider for better responsiveness to system preferences (#6606) * refactor: improve theme handling in ThemeProvider for better responsiveness to system preferences - Introduced helper functions to determine effective theme and apply it to the root element. - Updated theme application logic to respond to system theme changes more efficiently. - Simplified theme computation to avoid race conditions by directly using storedTheme. * fix: update displayedTheme initialization in ThemeProvider to use storedTheme for consistency --- .../bruno-app/src/providers/Theme/index.js | 50 ++++++++++--------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/packages/bruno-app/src/providers/Theme/index.js b/packages/bruno-app/src/providers/Theme/index.js index fcd79404c..06b6b7597 100644 --- a/packages/bruno-app/src/providers/Theme/index.js +++ b/packages/bruno-app/src/providers/Theme/index.js @@ -10,42 +10,46 @@ import { ThemeProvider as SCThemeProvider } from 'styled-components'; const validator = new Validator(); +// Helper: Get effective theme ('light' or 'dark') based on storedTheme +const getEffectiveTheme = (storedTheme) => { + if (storedTheme === 'system') { + return window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark'; + } + return storedTheme; +}; + +// Helper: Apply theme class to root element +const applyThemeToRoot = (theme) => { + const root = window.document.documentElement; + root.classList.remove('light', 'dark'); + root.classList.add(theme); +}; + export const ThemeContext = createContext(); export const ThemeProvider = (props) => { - const isBrowserThemeLight = window.matchMedia('(prefers-color-scheme: light)').matches; - const [displayedTheme, setDisplayedTheme] = useState(isBrowserThemeLight ? 'light' : 'dark'); const [storedTheme, setStoredTheme] = useLocalStorage('bruno.theme', 'system'); + const [displayedTheme, setDisplayedTheme] = useState(() => getEffectiveTheme(storedTheme)); const [themeVariantLight, setThemeVariantLight] = useLocalStorage('bruno.themeVariantLight', 'light'); const [themeVariantDark, setThemeVariantDark] = useLocalStorage('bruno.themeVariantDark', 'dark'); - const toggleHtml = () => { - const html = document.querySelector('html'); - if (html) { - html.classList.toggle('dark'); - } - }; + // Listen for system theme changes (only affects 'system' mode) useEffect(() => { const mediaQuery = window.matchMedia('(prefers-color-scheme: light)'); const handleChange = (e) => { if (storedTheme !== 'system') return; - setDisplayedTheme(e.matches ? 'light' : 'dark'); - toggleHtml(); + const newTheme = e.matches ? 'light' : 'dark'; + setDisplayedTheme(newTheme); + applyThemeToRoot(newTheme); }; mediaQuery.addEventListener('change', handleChange); return () => mediaQuery.removeEventListener('change', handleChange); }, [storedTheme]); + // Apply theme when storedTheme changes useEffect(() => { - const root = window.document.documentElement; - root.classList.remove('light', 'dark'); - if (storedTheme === 'system') { - const isBrowserThemeLight = window.matchMedia('(prefers-color-scheme: light)').matches; - setDisplayedTheme(isBrowserThemeLight ? 'light' : 'dark'); - root.classList.add(isBrowserThemeLight ? 'light' : 'dark'); - } else { - setDisplayedTheme(storedTheme); - root.classList.add(storedTheme); - } + const effectiveTheme = getEffectiveTheme(storedTheme); + setDisplayedTheme(effectiveTheme); + applyThemeToRoot(effectiveTheme); if (window.ipcRenderer) { window.ipcRenderer.send('renderer:theme-change', storedTheme); @@ -55,9 +59,9 @@ export const ThemeProvider = (props) => { // storedTheme can have 3 values: 'light', 'dark', 'system' // displayedTheme can have 2 values: 'light', 'dark' - // Get the appropriate variant based on the current display mode + // Compute theme object directly from storedTheme to avoid race conditions const theme = useMemo(() => { - const isLightMode = displayedTheme === 'light'; + const isLightMode = getEffectiveTheme(storedTheme) === 'light'; const variantName = isLightMode ? themeVariantLight : themeVariantDark; const fallbackTheme = isLightMode ? themes.light : themes.dark; const fallbackName = isLightMode ? 'light' : 'dark'; @@ -88,7 +92,7 @@ export const ThemeProvider = (props) => { } return selectedTheme; - }, [displayedTheme, themeVariantLight, themeVariantDark]); + }, [storedTheme, themeVariantLight, themeVariantDark]); const value = { theme,