'use client' import * as React from 'react' type Theme = 'light' | 'dark' | 'system' interface ThemeProviderProps { children: React.ReactNode defaultTheme?: Theme storageKey?: string attribute?: string } interface ThemeContextValue { theme: Theme resolvedTheme: 'light' | 'dark' setTheme: (theme: Theme) => void } const ThemeContext = React.createContext(undefined) function getSystemTheme(): 'light' | 'dark' { if (typeof window === 'undefined') return 'light' return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' } export function ThemeProvider({ children, defaultTheme = 'system', storageKey = 'greyhaven-theme', attribute = 'class', }: ThemeProviderProps) { const [theme, setThemeState] = React.useState(() => { if (typeof window === 'undefined') return defaultTheme return (localStorage.getItem(storageKey) as Theme) || defaultTheme }) const resolvedTheme = theme === 'system' ? getSystemTheme() : theme const setTheme = React.useCallback( (newTheme: Theme) => { setThemeState(newTheme) if (typeof window !== 'undefined') { localStorage.setItem(storageKey, newTheme) } }, [storageKey], ) React.useEffect(() => { const root = document.documentElement if (attribute === 'class') { root.classList.remove('light', 'dark') root.classList.add(resolvedTheme) } else { root.setAttribute(attribute, resolvedTheme) } }, [resolvedTheme, attribute]) // Listen for system theme changes when theme is 'system' React.useEffect(() => { if (theme !== 'system') return const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)') const handler = () => setThemeState((prev) => (prev === 'system' ? 'system' : prev)) mediaQuery.addEventListener('change', handler) return () => mediaQuery.removeEventListener('change', handler) }, [theme]) return ( {children} ) } export function useTheme() { const context = React.useContext(ThemeContext) if (!context) { throw new Error('useTheme must be used within a ThemeProvider') } return context }