import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode } from "react"; import { Moon, Sun } from "lucide-react"; import { useI18n } from "./i18n"; export type Theme = "light" | "dark"; const storageKey = "telesrv.admin.theme"; type ThemeContextValue = { theme: Theme; setTheme: (theme: Theme) => void; toggleTheme: () => void; }; const ThemeContext = createContext(null); export function applyTheme(theme: Theme) { document.documentElement.setAttribute("data-theme", theme); document.documentElement.style.colorScheme = theme; } export function ThemeProvider({ children }: { children: ReactNode }) { const [theme, setThemeState] = useState(() => initialTheme()); useEffect(() => { applyTheme(theme); try { localStorage.setItem(storageKey, theme); } catch { // Theme persistence is best-effort. } }, [theme]); // Follow the OS preference until the user makes an explicit choice. useEffect(() => { if (!window.matchMedia) { return; } const media = window.matchMedia("(prefers-color-scheme: dark)"); const onChange = (event: MediaQueryListEvent) => { let stored: string | null = null; try { stored = localStorage.getItem(storageKey); } catch { stored = null; } if (stored !== "light" && stored !== "dark") { setThemeState(event.matches ? "dark" : "light"); } }; media.addEventListener("change", onChange); return () => media.removeEventListener("change", onChange); }, []); const setTheme = useCallback((next: Theme) => setThemeState(next), []); const toggleTheme = useCallback(() => setThemeState((current) => (current === "dark" ? "light" : "dark")), []); const value = useMemo(() => ({ theme, setTheme, toggleTheme }), [theme, setTheme, toggleTheme]); return {children}; } export function useTheme(): ThemeContextValue { const value = useContext(ThemeContext); if (!value) { throw new Error("useTheme must be used inside ThemeProvider"); } return value; } export function ThemeSwitch() { const { theme, toggleTheme } = useTheme(); const { t } = useI18n(); const nextIsDark = theme === "light"; const label = t(nextIsDark ? "theme.switchToDark" : "theme.switchToLight"); return ( ); } function initialTheme(): Theme { try { const stored = localStorage.getItem(storageKey); if (stored === "light" || stored === "dark") { return stored; } } catch { // Storage is optional. } try { if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) { return "dark"; } } catch { // matchMedia can be unavailable in unusual embedded contexts. } return "light"; }