import { createContext, useContext, useEffect, useMemo, useState, type ReactNode, } from "react"; import { useReducedMotion } from "motion/react"; import { STRINGS, type Lang } from "./i18n"; export type ViewMode = "internal" | "public"; export type Window = "24h" | "7d"; export type Theme = "dark" | "light"; interface UIState { lang: Lang; dir: "ltr" | "rtl"; mode: ViewMode; window: Window; theme: Theme; reduced: boolean; t: (typeof STRINGS)["en"]; setLang: (l: Lang) => void; setMode: (m: ViewMode) => void; setWindow: (w: Window) => void; setTheme: (t: Theme) => void; } const UIContext = createContext(null); export function UIProvider({ children }: { children: ReactNode }) { const [lang, setLang] = useState( () => (localStorage.getItem("dash.lang") as Lang) || "en", ); const [mode, setMode] = useState( () => (localStorage.getItem("dash.mode") as ViewMode) || "internal", ); const [window, setWindow] = useState("24h"); const [theme, setTheme] = useState( () => (localStorage.getItem("dash.theme") as Theme) || "dark", ); const reduced = useReducedMotion() ?? false; const dir = lang === "fa" ? "rtl" : "ltr"; useEffect(() => { document.documentElement.dir = dir; document.documentElement.lang = lang; localStorage.setItem("dash.lang", lang); }, [lang, dir]); useEffect(() => { document.documentElement.dataset.theme = theme; localStorage.setItem("dash.theme", theme); }, [theme]); useEffect(() => { localStorage.setItem("dash.mode", mode); }, [mode]); const value = useMemo( () => ({ lang, dir, mode, window, theme, reduced, t: STRINGS[lang], setLang, setMode, setWindow, setTheme, }), [lang, dir, mode, window, theme, reduced], ); return {children}; } export function useUI(): UIState { const ctx = useContext(UIContext); if (!ctx) throw new Error("useUI outside UIProvider"); return ctx; } /** Spring presets — physical, interruptible; inert under reduced motion. */ export const springs = { arc: { type: "spring", stiffness: 48, damping: 16, mass: 1.2 } as const, snappy: { type: "spring", stiffness: 360, damping: 28 } as const, gentle: { type: "spring", stiffness: 120, damping: 22 } as const, layout: { type: "spring", stiffness: 230, damping: 26 } as const, }; export const STATE_COLOR: Record = { up: "var(--color-up)", degraded: "var(--color-warn)", down: "var(--color-down)", unknown: "var(--color-idle)", };