nanobot/webui/src/hooks/useTheme.ts

49 lines
1.3 KiB
TypeScript

import { useCallback, useEffect, useState } from "react";
type Theme = "light" | "dark";
const STORAGE_KEY = "nanobot-webui.theme";
function readStored(): Theme | null {
try {
const v = localStorage.getItem(STORAGE_KEY);
return v === "light" || v === "dark" ? v : null;
} catch {
return null;
}
}
function applyTheme(theme: Theme): void {
const root = document.documentElement;
if (theme === "dark") root.classList.add("dark");
else root.classList.remove("dark");
}
export function useTheme(): { theme: Theme; toggle: () => void; setTheme: (t: Theme) => void } {
const [theme, setThemeState] = useState<Theme>(() => {
const stored = readStored();
if (stored) return stored;
if (typeof window !== "undefined" && window.matchMedia) {
return window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
}
return "light";
});
useEffect(() => {
applyTheme(theme);
try {
localStorage.setItem(STORAGE_KEY, theme);
} catch {
// ignore
}
}, [theme]);
const setTheme = useCallback((t: Theme) => setThemeState(t), []);
const toggle = useCallback(
() => setThemeState((t) => (t === "dark" ? "light" : "dark")),
[],
);
return { theme, toggle, setTheme };
}