import React, { createContext, useContext, useEffect, useMemo, useState } from 'react'; export type Appearance = 'light' | 'dark' | 'system'; type AppearanceContextValue = { appearance: Appearance; resolved: 'light' | 'dark'; updateAppearance: (mode: Appearance) => void; }; const AppearanceContext = createContext({ appearance: 'system', resolved: 'light', updateAppearance: () => {}, }); function resolveTheme(mode: Appearance): 'light' | 'dark' { if (mode === 'dark') return 'dark'; if (mode === 'light') return 'light'; return window.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; } function applyDocumentClass(theme: 'light' | 'dark') { if (theme === 'dark') { document.documentElement.classList.add('dark'); } else { document.documentElement.classList.remove('dark'); } } export function AppearanceProvider({ children }: { children: React.ReactNode }) { const [appearance, setAppearance] = useState(() => { const stored = localStorage.getItem('theme') as Appearance | null; return stored ?? 'system'; }); const [resolved, setResolved] = useState<'light' | 'dark'>(() => resolveTheme(appearance)); useEffect(() => { const nextResolved = resolveTheme(appearance); setResolved(nextResolved); applyDocumentClass(nextResolved); if (appearance === 'system') { const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); const listener = () => { const resolvedTheme = mediaQuery.matches ? 'dark' : 'light'; setResolved(resolvedTheme); applyDocumentClass(resolvedTheme); }; mediaQuery.addEventListener('change', listener); return () => mediaQuery.removeEventListener('change', listener); } return undefined; }, [appearance]); const updateAppearance = (mode: Appearance) => { setAppearance(mode); localStorage.setItem('theme', mode); }; const value = useMemo( () => ({ appearance, resolved, updateAppearance, }), [appearance, resolved] ); return React.createElement(AppearanceContext.Provider, { value }, children); } export function useAppearance(): AppearanceContextValue { return useContext(AppearanceContext); } export function initializeTheme() { const stored = localStorage.getItem('theme') as Appearance | null; const mode = stored ?? 'system'; const resolved = resolveTheme(mode); applyDocumentClass(resolved); }