1+ import React , { createContext , useState , useContext , ReactNode , useEffect } from 'react' ;
2+
3+ // Define the shape of our context state
4+ interface ThemeContextType {
5+ theme : 'light' | 'dark' ;
6+ toggleTheme : ( ) => void ;
7+ }
8+
9+ // Create the context
10+ const ThemeContext = createContext < ThemeContextType | undefined > ( undefined ) ;
11+
12+ // Define props for the provider
13+ interface ThemeProviderProps {
14+ children : ReactNode ;
15+ }
16+
17+ export const ThemeProvider : React . FC < ThemeProviderProps > = ( { children } ) => {
18+ // Initialize state from local storage or default to 'light'
19+ const [ theme , setTheme ] = useState < 'light' | 'dark' > ( ( ) => {
20+ const storedTheme = localStorage . getItem ( 'theme' ) ;
21+ return ( storedTheme === 'dark' || storedTheme === 'light' ) ? storedTheme : 'light' ;
22+ } ) ;
23+
24+ // Use useEffect to update the body class and local storage when the theme changes
25+ useEffect ( ( ) => {
26+ document . body . className = theme ;
27+ localStorage . setItem ( 'theme' , theme ) ;
28+ } , [ theme ] ) ;
29+
30+ const toggleTheme = ( ) => {
31+ setTheme ( currentTheme => ( currentTheme === 'light' ? 'dark' : 'light' ) ) ;
32+ } ;
33+
34+ return (
35+ < ThemeContext . Provider value = { { theme, toggleTheme } } >
36+ { children }
37+ </ ThemeContext . Provider >
38+ ) ;
39+ } ;
40+
41+ // Custom hook to use the theme context
42+ export const useTheme = ( ) => {
43+ const context = useContext ( ThemeContext ) ;
44+ if ( context === undefined ) {
45+ throw new Error ( 'useTheme must be used within a ThemeProvider' ) ;
46+ }
47+ return context ;
48+ } ;
0 commit comments