haixunMaster/components/theme-provider.tsx

61 lines
1.4 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import {
createContext,
useCallback,
useContext,
useEffect,
useState,
type ReactNode,
} from "react";
import {
DEFAULT_THEME,
type ThemeMode,
persistTheme,
readStoredTheme,
} from "@/lib/theme";
interface ThemeContextValue {
theme: ThemeMode;
setTheme: (mode: ThemeMode) => void;
toggleTheme: () => void;
}
const ThemeContext = createContext<ThemeContextValue | null>(null);
export function ThemeProvider({ children }: { children: ReactNode }) {
// 首屏必須與 SSR 一致DEFAULT_THEMElocalStorage 在 useEffect 讀取,避免 hydration mismatch。
const [theme, setThemeState] = useState<ThemeMode>(DEFAULT_THEME);
useEffect(() => {
const stored = readStoredTheme();
if (stored) setThemeState(stored);
}, []);
const setTheme = useCallback((mode: ThemeMode) => {
setThemeState(mode);
persistTheme(mode);
}, []);
const toggleTheme = useCallback(() => {
setThemeState((prev) => {
const next = prev === "dark" ? "light" : "dark";
persistTheme(next);
return next;
});
}, []);
return (
<ThemeContext.Provider value={{ theme, setTheme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
const ctx = useContext(ThemeContext);
if (!ctx) {
throw new Error("useTheme must be used within ThemeProvider");
}
return ctx;
}