Import source: web/src/lib/ui
Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
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<UIState | null>(null);
|
||||
|
||||
export function UIProvider({ children }: { children: ReactNode }) {
|
||||
const [lang, setLang] = useState<Lang>(
|
||||
() => (localStorage.getItem("dash.lang") as Lang) || "en",
|
||||
);
|
||||
const [mode, setMode] = useState<ViewMode>(
|
||||
() => (localStorage.getItem("dash.mode") as ViewMode) || "internal",
|
||||
);
|
||||
const [window, setWindow] = useState<Window>("24h");
|
||||
const [theme, setTheme] = useState<Theme>(
|
||||
() => (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<UIState>(
|
||||
() => ({
|
||||
lang,
|
||||
dir,
|
||||
mode,
|
||||
window,
|
||||
theme,
|
||||
reduced,
|
||||
t: STRINGS[lang],
|
||||
setLang,
|
||||
setMode,
|
||||
setWindow,
|
||||
setTheme,
|
||||
}),
|
||||
[lang, dir, mode, window, theme, reduced],
|
||||
);
|
||||
|
||||
return <UIContext.Provider value={value}>{children}</UIContext.Provider>;
|
||||
}
|
||||
|
||||
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<string, string> = {
|
||||
up: "var(--color-up)",
|
||||
degraded: "var(--color-warn)",
|
||||
down: "var(--color-down)",
|
||||
unknown: "var(--color-idle)",
|
||||
};
|
||||
Reference in New Issue
Block a user