39 lines
1.0 KiB
TypeScript
39 lines
1.0 KiB
TypeScript
import { createContext, useContext, useEffect, useState, type ReactNode } from 'react'
|
|
|
|
export type ThemeMode = 'dark' | 'light'
|
|
|
|
interface ThemeCtx {
|
|
theme: ThemeMode
|
|
toggle: () => void
|
|
setTheme: (t: ThemeMode) => void
|
|
}
|
|
|
|
const Ctx = createContext<ThemeCtx>({ theme: 'dark', toggle: () => {}, setTheme: () => {} })
|
|
|
|
const STORAGE_KEY = 'esn_theme'
|
|
|
|
function applyTheme(t: ThemeMode) {
|
|
document.documentElement.setAttribute('data-theme', t)
|
|
}
|
|
|
|
export function ThemeProvider({ children }: { children: ReactNode }) {
|
|
const [theme, setThemeState] = useState<ThemeMode>(() => {
|
|
const saved = localStorage.getItem(STORAGE_KEY)
|
|
return saved === 'light' ? 'light' : 'dark'
|
|
})
|
|
|
|
useEffect(() => {
|
|
applyTheme(theme)
|
|
localStorage.setItem(STORAGE_KEY, theme)
|
|
}, [theme])
|
|
|
|
const setTheme = (t: ThemeMode) => setThemeState(t)
|
|
const toggle = () => setThemeState(prev => (prev === 'dark' ? 'light' : 'dark'))
|
|
|
|
return <Ctx.Provider value={{ theme, toggle, setTheme }}>{children}</Ctx.Provider>
|
|
}
|
|
|
|
export function useTheme() {
|
|
return useContext(Ctx)
|
|
}
|