import { createContext, useContext, useEffect, useMemo, useState } from 'react'; type ThemePreference = 'light' | 'dark' | 'system'; type ResolvedTheme = 'light' | 'dark'; interface ThemeContextType { theme: ThemePreference; resolvedTheme: ResolvedTheme; setTheme: (theme: ThemePreference) => void; } const getSystemTheme = (): ResolvedTheme => window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; const ThemeContext = createContext(undefined); export function ThemeProvider({ children }: { children: React.ReactNode }) { const [theme, setTheme] = useState(() => { const stored = localStorage.getItem('theme'); if (stored === 'dark' || stored === 'light' || stored === 'system') { return stored; } return 'system'; }); const [systemTheme, setSystemTheme] = useState(getSystemTheme); useEffect(() => { const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); const onChange = (event: MediaQueryListEvent) => { setSystemTheme(event.matches ? 'dark' : 'light'); }; mediaQuery.addEventListener('change', onChange); return () => mediaQuery.removeEventListener('change', onChange); }, []); const resolvedTheme = useMemo( () => (theme === 'system' ? systemTheme : theme), [systemTheme, theme], ); useEffect(() => { const root = window.document.documentElement; root.classList.remove('light', 'dark'); root.classList.add(resolvedTheme); localStorage.setItem('theme', theme); }, [resolvedTheme, theme]); return ( {children} ); } export function useTheme() { const ctx = useContext(ThemeContext); if (!ctx) { throw new Error('useTheme must be used within ThemeProvider'); } return ctx; }