|
|
|
|
|
"use client"; |
|
|
|
|
|
import { createContext, useContext, useEffect, useState, ReactNode } from 'react'; |
|
|
|
|
|
type Theme = 'light' | 'dark'; |
|
|
|
|
|
interface ThemeProviderProps { |
|
|
children: ReactNode; |
|
|
defaultTheme?: Theme; |
|
|
storageKey?: string; |
|
|
} |
|
|
|
|
|
interface ThemeProviderState { |
|
|
theme: Theme; |
|
|
setTheme: (theme: Theme) => void; |
|
|
} |
|
|
|
|
|
const initialState: ThemeProviderState = { |
|
|
theme: 'light', |
|
|
setTheme: () => null, |
|
|
}; |
|
|
|
|
|
const ThemeProviderContext = createContext<ThemeProviderState>(initialState); |
|
|
|
|
|
export function ThemeProvider({ |
|
|
children, |
|
|
defaultTheme = 'light', |
|
|
storageKey = 'anita-deploy-ui-theme', // Specific storage key |
|
|
}: ThemeProviderProps) { |
|
|
const [theme, setTheme] = useState<Theme>(() => { |
|
|
if (typeof window !== 'undefined') { |
|
|
const storedTheme = localStorage.getItem(storageKey) as Theme | null; |
|
|
if (storedTheme && (storedTheme === 'light' || storedTheme === 'dark')) { |
|
|
return storedTheme; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
return defaultTheme === 'dark' ? 'dark' : 'light'; |
|
|
}); |
|
|
|
|
|
useEffect(() => { |
|
|
if (typeof window === 'undefined') return; |
|
|
|
|
|
const root = window.document.documentElement; |
|
|
root.classList.remove('light', 'dark'); |
|
|
root.classList.add(theme); |
|
|
localStorage.setItem(storageKey, theme); |
|
|
}, [theme, storageKey]); |
|
|
|
|
|
const value = { |
|
|
theme, |
|
|
setTheme: (newTheme: Theme) => { |
|
|
setTheme(newTheme); |
|
|
}, |
|
|
}; |
|
|
|
|
|
return ( |
|
|
<ThemeProviderContext.Provider value={value}> |
|
|
{children} |
|
|
</ThemeProviderContext.Provider> |
|
|
); |
|
|
} |
|
|
|
|
|
export const useTheme = () => { |
|
|
const context = useContext(ThemeProviderContext); |
|
|
if (context === undefined) { |
|
|
throw new Error('useTheme must be used within a ThemeProvider'); |
|
|
} |
|
|
return context; |
|
|
}; |
|
|
|