'use client'; import { createContext, useContext, useEffect, useState, ReactNode } from 'react'; type Theme = 'light' | 'dark' | 'system'; interface ThemeContextType { theme: Theme; setTheme: (theme: Theme) => void; resolvedTheme: 'light' | 'dark'; } const ThemeContext = createContext(undefined); export function ThemeProvider({ children }: { children: ReactNode }) { const [theme, setThemeState] = useState('system'); const [resolvedTheme, setResolvedTheme] = useState<'light' | 'dark'>('light'); const [mounted, setMounted] = useState(false); useEffect(() => { setMounted(true); const stored = localStorage.getItem('theme') as Theme | null; if (stored) { setThemeState(stored); } }, []); useEffect(() => { if (!mounted) return; const root = document.documentElement; const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; const effectiveTheme = theme === 'system' ? systemTheme : theme; // Add transition disable class root.classList.add('disable-transitions'); // Update theme if (effectiveTheme === 'dark') { root.classList.add('dark'); } else { root.classList.remove('dark'); } setResolvedTheme(effectiveTheme); // Re-enable transitions after a frame requestAnimationFrame(() => { root.classList.remove('disable-transitions'); }); }, [theme, mounted]); const setTheme = (newTheme: Theme) => { setThemeState(newTheme); localStorage.setItem('theme', newTheme); }; if (!mounted) { return <>{children}; } return ( {children} ); } export function useTheme() { const context = useContext(ThemeContext); if (!context) { // Return a default context for SSR or when outside provider return { theme: 'system' as Theme, setTheme: () => {}, resolvedTheme: 'light' as 'light' | 'dark', }; } return context; }