'use client'; import React, { createContext, useContext, useEffect, useState } from 'react'; export type Theme = 'dark' | 'light' | 'system'; export type EffectiveTheme = 'dark' | 'light'; interface ThemeContextValue { theme: Theme; setTheme: (theme: Theme) => void; effectiveTheme: EffectiveTheme; } const ThemeContext = createContext(undefined); const STORAGE_KEY = 'aiready-theme'; function getSystemTheme(): EffectiveTheme { if (typeof window === 'undefined') return 'light'; return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; } function getStoredTheme(): Theme { if (typeof window === 'undefined') return 'system'; try { const stored = localStorage.getItem(STORAGE_KEY); if (stored === 'dark' || stored === 'light' || stored === 'system') { return stored; } } catch { // localStorage not available } return 'system'; } interface ThemeProviderProps { children: React.ReactNode; defaultTheme?: Theme; storageKey?: string; } export function ThemeProvider({ children, defaultTheme = 'system', storageKey = STORAGE_KEY, }: ThemeProviderProps) { const [theme, setThemeState] = useState(defaultTheme); const [effectiveTheme, setEffectiveTheme] = useState('light'); const [mounted, setMounted] = useState(false); // Initialize theme from storage on mount useEffect(() => { const storedTheme = getStoredTheme(); setThemeState(storedTheme); setMounted(true); }, []); // Update effective theme when theme or system preference changes useEffect(() => { if (!mounted) return; const updateEffectiveTheme = () => { if (theme === 'system') { setEffectiveTheme(getSystemTheme()); } else { setEffectiveTheme(theme); } }; updateEffectiveTheme(); // Listen for system theme changes const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); const handleChange = () => { if (theme === 'system') { setEffectiveTheme(getSystemTheme()); } }; mediaQuery.addEventListener('change', handleChange); return () => mediaQuery.removeEventListener('change', handleChange); }, [theme, mounted]); // Apply theme class to document useEffect(() => { if (!mounted) return; const root = document.documentElement; root.classList.remove('light', 'dark'); root.classList.add(effectiveTheme); }, [effectiveTheme, mounted]); const setTheme = (newTheme: Theme) => { setThemeState(newTheme); try { localStorage.setItem(storageKey, newTheme); } catch { // localStorage not available } }; // Prevent hydration mismatch if (!mounted) { return ( {}, effectiveTheme: 'light', }} > {children} ); } return ( {children} ); } export function useTheme(): ThemeContextValue { const context = useContext(ThemeContext); if (context === undefined) { throw new Error('useTheme must be used within a ThemeProvider'); } return context; }