import { createContext, useContext, useEffect, useState, FC, ReactNode } from 'react'; type Theme = 'light' | 'dark' | 'system'; interface ThemeContextType { theme: Theme; setTheme: (theme: Theme) => void; resolvedTheme: 'light' | 'dark'; } const ThemeContext = createContext(undefined); const STORAGE_KEY = 'hackathon-theme'; function getSystemTheme(): 'light' | 'dark' { if (typeof window !== 'undefined') { return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; } return 'light'; } interface ThemeProviderProps { children: ReactNode; defaultTheme?: Theme; } export const ThemeProvider: FC = ({ children, defaultTheme = 'system' }) => { const [theme, setThemeState] = useState(() => { if (typeof window !== 'undefined') { const stored = localStorage.getItem(STORAGE_KEY) as Theme | null; return stored || defaultTheme; } return defaultTheme; }); const [resolvedTheme, setResolvedTheme] = useState<'light' | 'dark'>(() => { if (theme === 'system') { return getSystemTheme(); } return theme; }); const setTheme = (newTheme: Theme) => { setThemeState(newTheme); localStorage.setItem(STORAGE_KEY, newTheme); }; useEffect(() => { const root = document.documentElement; // Calculate the resolved theme const resolved = theme === 'system' ? getSystemTheme() : theme; setResolvedTheme(resolved); // Apply dark class to root if (resolved === 'dark') { root.classList.add('dark'); } else { root.classList.remove('dark'); } }, [theme]); // Listen for system theme changes useEffect(() => { if (theme !== 'system') return; const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); const handleChange = (e: MediaQueryListEvent) => { const newTheme = e.matches ? 'dark' : 'light'; setResolvedTheme(newTheme); const root = document.documentElement; if (newTheme === 'dark') { root.classList.add('dark'); } else { root.classList.remove('dark'); } }; mediaQuery.addEventListener('change', handleChange); return () => mediaQuery.removeEventListener('change', handleChange); }, [theme]); return ( {children} ); }; export function useTheme() { const context = useContext(ThemeContext); if (context === undefined) { throw new Error('useTheme must be used within a ThemeProvider'); } return context; } export default ThemeProvider;