1+ "use client"
2+
3+ import React , { createContext , useContext , useState , useEffect } from 'react'
4+
5+ export type Theme = 'light' | 'dark'
6+
7+ interface ThemeContextType {
8+ theme : Theme
9+ toggleTheme : ( ) => void
10+ setTheme : ( theme : Theme ) => void
11+ mounted : boolean
12+ }
13+
14+ const ThemeContext = createContext < ThemeContextType | undefined > ( undefined )
15+
16+ interface ThemeProviderProps {
17+ children : React . ReactNode
18+ }
19+
20+ export function ThemeProvider ( { children } : ThemeProviderProps ) {
21+ const [ theme , setThemeState ] = useState < Theme > ( 'light' )
22+ const [ mounted , setMounted ] = useState ( false )
23+
24+ // Initialize theme on mount
25+ useEffect ( ( ) => {
26+ setMounted ( true )
27+
28+ // Check for stored theme preference or default to system preference
29+ const stored = localStorage . getItem ( 'theme' ) as Theme | null
30+ if ( stored && ( stored === 'light' || stored === 'dark' ) ) {
31+ setThemeState ( stored )
32+ applyTheme ( stored )
33+ } else {
34+ // Check system preference
35+ const prefersDark = window . matchMedia ( '(prefers-color-scheme: dark)' ) . matches
36+ const systemTheme : Theme = prefersDark ? 'dark' : 'light'
37+ setThemeState ( systemTheme )
38+ applyTheme ( systemTheme )
39+ }
40+ } , [ ] )
41+
42+ const applyTheme = ( newTheme : Theme ) => {
43+ const root = document . documentElement
44+ if ( newTheme === 'dark' ) {
45+ root . classList . add ( 'dark' )
46+ } else {
47+ root . classList . remove ( 'dark' )
48+ }
49+ }
50+
51+ const toggleTheme = ( ) => {
52+ if ( ! mounted ) return
53+
54+ const newTheme : Theme = theme === 'light' ? 'dark' : 'light'
55+ setThemeState ( newTheme )
56+ localStorage . setItem ( 'theme' , newTheme )
57+ applyTheme ( newTheme )
58+ }
59+
60+ const setTheme = ( newTheme : Theme ) => {
61+ if ( ! mounted ) return
62+
63+ setThemeState ( newTheme )
64+ localStorage . setItem ( 'theme' , newTheme )
65+ applyTheme ( newTheme )
66+ }
67+
68+ const value : ThemeContextType = {
69+ theme,
70+ toggleTheme,
71+ setTheme,
72+ mounted,
73+ }
74+
75+ return (
76+ < ThemeContext . Provider value = { value } >
77+ { children }
78+ </ ThemeContext . Provider >
79+ )
80+ }
81+
82+ export function useThemeContext ( ) : ThemeContextType {
83+ const context = useContext ( ThemeContext )
84+ if ( context === undefined ) {
85+ throw new Error ( 'useThemeContext must be used within a ThemeProvider' )
86+ }
87+ return context
88+ }
0 commit comments