| import { createContext, useContext, useEffect, useState, type ReactNode } from "react"; |
|
|
| type Theme = "light" | "dark"; |
|
|
| interface ThemeCtx { |
| theme: Theme; |
| toggle: () => void; |
| } |
|
|
| const Ctx = createContext<ThemeCtx | null>(null); |
|
|
| function initialTheme(): Theme { |
| const stored = localStorage.getItem("theme"); |
| if (stored === "light" || stored === "dark") return stored; |
| return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; |
| } |
|
|
| export function ThemeProvider({ children }: { children: ReactNode }) { |
| const [theme, setTheme] = useState<Theme>(initialTheme); |
|
|
| useEffect(() => { |
| const root = document.documentElement; |
| root.classList.toggle("dark", theme === "dark"); |
| localStorage.setItem("theme", theme); |
| }, [theme]); |
|
|
| const toggle = () => setTheme((t) => (t === "dark" ? "light" : "dark")); |
|
|
| return <Ctx.Provider value={{ theme, toggle }}>{children}</Ctx.Provider>; |
| } |
|
|
| export function useTheme() { |
| const ctx = useContext(Ctx); |
| if (!ctx) throw new Error("useTheme must be used within ThemeProvider"); |
| return ctx; |
| } |
|
|