File size: 1,153 Bytes
557ab38 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | /**
* Theme hook — persists user choice in localStorage, respects prefers-color-scheme
* on first visit, and reflects the current theme as data-theme on <html>.
* The initial paint happens in index.html to avoid a flash.
*/
import { useCallback, useEffect, useState } from "react";
export type Theme = "light" | "dark";
const STORAGE_KEY = "theme";
function getInitial(): Theme {
if (typeof window === "undefined") return "light";
const stored = window.localStorage.getItem(STORAGE_KEY) as Theme | null;
if (stored === "light" || stored === "dark") return stored;
const dark = window.matchMedia("(prefers-color-scheme: dark)").matches;
return dark ? "dark" : "light";
}
export function useTheme() {
const [theme, setThemeState] = useState<Theme>(getInitial);
useEffect(() => {
document.documentElement.setAttribute("data-theme", theme);
window.localStorage.setItem(STORAGE_KEY, theme);
}, [theme]);
const setTheme = useCallback((t: Theme) => setThemeState(t), []);
const toggle = useCallback(
() => setThemeState((t) => (t === "dark" ? "light" : "dark")),
[]
);
return { theme, setTheme, toggle };
}
|