Spaces:
Paused
Paused
| /** | |
| * Theme Context | |
| * Manages light/dark theme with localStorage persistence | |
| */ | |
| import { createContext, useContext, useEffect, useState, type ReactNode } from 'react'; | |
| import type { Theme } from '@/types'; | |
| interface ThemeContextValue { | |
| theme: Theme; | |
| toggleTheme: () => void; | |
| setTheme: (theme: Theme) => void; | |
| } | |
| const ThemeContext = createContext<ThemeContextValue | null>(null); | |
| const STORAGE_KEY = 'theme'; | |
| export function ThemeProvider({ children }: { children: ReactNode }) { | |
| const [theme, setThemeState] = useState<Theme>(() => { | |
| // Check localStorage first | |
| const stored = localStorage.getItem(STORAGE_KEY) as Theme | null; | |
| if (stored === 'light' || stored === 'dark') return stored; | |
| // Check system preference | |
| if (window.matchMedia('(prefers-color-scheme: light)').matches) { | |
| return 'light'; | |
| } | |
| return 'dark'; | |
| }); | |
| useEffect(() => { | |
| // Apply theme to document | |
| document.documentElement.setAttribute('data-theme', theme); | |
| localStorage.setItem(STORAGE_KEY, theme); | |
| }, [theme]); | |
| const toggleTheme = () => { | |
| setThemeState(prev => prev === 'dark' ? 'light' : 'dark'); | |
| }; | |
| const setTheme = (newTheme: Theme) => { | |
| setThemeState(newTheme); | |
| }; | |
| return ( | |
| <ThemeContext.Provider value={{ theme, toggleTheme, setTheme }}> | |
| {children} | |
| </ThemeContext.Provider> | |
| ); | |
| } | |
| export function useTheme(): ThemeContextValue { | |
| const context = useContext(ThemeContext); | |
| if (!context) { | |
| throw new Error('useTheme must be used within a ThemeProvider'); | |
| } | |
| return context; | |
| } | |