ThemeContext.tsx 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. import { createContext, useContext, useEffect, useState, type ReactNode } from 'react';
  2. type Theme = 'light' | 'dark';
  3. interface ThemeContextType {
  4. theme: Theme;
  5. toggleTheme: () => void;
  6. setTheme: (theme: Theme) => void;
  7. }
  8. const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
  9. export function ThemeProvider({ children }: { children: ReactNode }) {
  10. const [theme, setThemeState] = useState<Theme>(() => {
  11. const stored = localStorage.getItem('theme') as Theme | null;
  12. if (stored) return stored;
  13. // Default to dark theme
  14. return 'dark';
  15. });
  16. useEffect(() => {
  17. const root = document.documentElement;
  18. if (theme === 'dark') {
  19. root.classList.add('dark');
  20. } else {
  21. root.classList.remove('dark');
  22. }
  23. localStorage.setItem('theme', theme);
  24. }, [theme]);
  25. const toggleTheme = () => {
  26. setThemeState((prev) => (prev === 'dark' ? 'light' : 'dark'));
  27. };
  28. const setTheme = (newTheme: Theme) => {
  29. setThemeState(newTheme);
  30. };
  31. return (
  32. <ThemeContext.Provider value={{ theme, toggleTheme, setTheme }}>
  33. {children}
  34. </ThemeContext.Provider>
  35. );
  36. }
  37. export function useTheme() {
  38. const context = useContext(ThemeContext);
  39. if (!context) {
  40. throw new Error('useTheme must be used within a ThemeProvider');
  41. }
  42. return context;
  43. }