First Commit
ci / go (push) Waiting to run
ci / go-db (agent) (push) Waiting to run
ci / go-db (config) (push) Waiting to run
ci / go-db (db) (push) Waiting to run
ci / go-db (evidence) (push) Waiting to run
ci / go-db (llmrec) (push) Waiting to run
ci / go-db (server) (push) Waiting to run
web / web (push) Waiting to run
docs / links (push) Canceled after 0s
detections / detections (push) Canceled after 0s

This commit is contained in:
dela
2026-10-09 08:38:16 +08:00
commit 0335d572de
756 changed files with 201663 additions and 0 deletions
@@ -0,0 +1,120 @@
"use client";
import { createContext, useContext, useEffect, useRef, useState } from "react";
import { type StoreApi, useStore } from "zustand";
import { type FontKey, fontRegistry } from "@/lib/fonts/registry";
import {
CONTENT_LAYOUT_VALUES,
NAVBAR_STYLE_VALUES,
SIDEBAR_COLLAPSIBLE_VALUES,
SIDEBAR_VARIANT_VALUES,
} from "@/lib/preferences/layout";
import { THEME_MODE_VALUES, THEME_PRESET_VALUES } from "@/lib/preferences/theme";
import { applyThemeMode, subscribeToSystemTheme } from "@/lib/preferences/theme-utils";
import { createPreferencesStore, type PreferencesState } from "./preferences-store";
const PreferencesStoreContext = createContext<StoreApi<PreferencesState> | null>(null);
const FONT_VALUES = Object.keys(fontRegistry) as FontKey[];
function getSafeValue<T extends string>(raw: string | null, allowed: readonly T[]): T | undefined {
if (!raw) return undefined;
return allowed.includes(raw as T) ? (raw as T) : undefined;
}
function readDomState(): Partial<PreferencesState> {
const root = document.documentElement;
const themeModeAttr = getSafeValue(root.getAttribute("data-theme-mode"), THEME_MODE_VALUES);
const resolvedMode = root.classList.contains("dark") ? "dark" : "light";
return {
themeMode: themeModeAttr ?? resolvedMode,
resolvedThemeMode: resolvedMode,
themePreset: getSafeValue(root.getAttribute("data-theme-preset"), THEME_PRESET_VALUES),
font: getSafeValue(root.getAttribute("data-font"), FONT_VALUES),
contentLayout: getSafeValue(root.getAttribute("data-content-layout"), CONTENT_LAYOUT_VALUES),
navbarStyle: getSafeValue(root.getAttribute("data-navbar-style"), NAVBAR_STYLE_VALUES),
sidebarVariant: getSafeValue(root.getAttribute("data-sidebar-variant"), SIDEBAR_VARIANT_VALUES),
sidebarCollapsible: getSafeValue(root.getAttribute("data-sidebar-collapsible"), SIDEBAR_COLLAPSIBLE_VALUES),
};
}
export const PreferencesStoreProvider = ({
children,
themeMode,
themePreset,
font,
contentLayout,
navbarStyle,
}: {
children: React.ReactNode;
themeMode: PreferencesState["themeMode"];
themePreset: PreferencesState["themePreset"];
font: PreferencesState["font"];
contentLayout: PreferencesState["contentLayout"];
navbarStyle: PreferencesState["navbarStyle"];
}) => {
const [store] = useState<StoreApi<PreferencesState>>(() =>
createPreferencesStore({
themeMode,
themePreset,
font,
contentLayout,
navbarStyle,
}),
);
const domSnapshotRef = useRef<Partial<PreferencesState> | null>(null);
useEffect(() => {
const domState = readDomState();
domSnapshotRef.current = domState;
store.setState((prev) => ({
...prev,
...domState,
isSynced: true,
}));
}, [store]);
useEffect(() => {
let unsubscribeMedia: (() => void) | undefined;
const applyFromMode = (mode: PreferencesState["themeMode"]) => {
unsubscribeMedia?.();
const resolved = applyThemeMode(mode);
store.setState((prev) => ({ ...prev, resolvedThemeMode: resolved }));
if (mode === "system") {
unsubscribeMedia = subscribeToSystemTheme(() => {
const next = applyThemeMode("system");
store.setState((prev) => ({ ...prev, resolvedThemeMode: next }));
});
}
};
const startMode = domSnapshotRef.current?.themeMode ?? store.getState().themeMode;
applyFromMode(startMode);
const unsubscribeStore = store.subscribe((s, p) => {
if (s.themeMode !== p.themeMode) applyFromMode(s.themeMode);
});
return () => {
unsubscribeMedia?.();
unsubscribeStore();
};
}, [store]);
return <PreferencesStoreContext.Provider value={store}>{children}</PreferencesStoreContext.Provider>;
};
export const usePreferencesStore = <T,>(selector: (state: PreferencesState) => T): T => {
const store = useContext(PreferencesStoreContext);
if (!store) throw new Error("Missing PreferencesStoreProvider");
return useStore(store, selector);
};
@@ -0,0 +1,49 @@
import { createStore } from "zustand/vanilla";
import type { FontKey } from "@/lib/fonts/registry";
import type { ContentLayout, NavbarStyle, SidebarCollapsible, SidebarVariant } from "@/lib/preferences/layout";
import { PREFERENCE_DEFAULTS } from "@/lib/preferences/preferences-config";
import type { ResolvedThemeMode, ThemeMode, ThemePreset } from "@/lib/preferences/theme";
export type PreferencesState = {
themeMode: ThemeMode;
resolvedThemeMode: ResolvedThemeMode;
themePreset: ThemePreset;
font: FontKey;
contentLayout: ContentLayout;
navbarStyle: NavbarStyle;
sidebarVariant: SidebarVariant;
sidebarCollapsible: SidebarCollapsible;
setThemeMode: (mode: ThemeMode) => void;
setResolvedThemeMode: (mode: ResolvedThemeMode) => void;
setThemePreset: (preset: ThemePreset) => void;
setFont: (font: FontKey) => void;
setContentLayout: (layout: ContentLayout) => void;
setNavbarStyle: (style: NavbarStyle) => void;
setSidebarVariant: (variant: SidebarVariant) => void;
setSidebarCollapsible: (mode: SidebarCollapsible) => void;
isSynced: boolean;
setIsSynced: (val: boolean) => void;
};
export const createPreferencesStore = (init?: Partial<PreferencesState>) =>
createStore<PreferencesState>()((set) => ({
themeMode: init?.themeMode ?? PREFERENCE_DEFAULTS.theme_mode,
resolvedThemeMode: init?.resolvedThemeMode ?? "light",
themePreset: init?.themePreset ?? PREFERENCE_DEFAULTS.theme_preset,
font: init?.font ?? PREFERENCE_DEFAULTS.font,
contentLayout: init?.contentLayout ?? PREFERENCE_DEFAULTS.content_layout,
navbarStyle: init?.navbarStyle ?? PREFERENCE_DEFAULTS.navbar_style,
sidebarVariant: init?.sidebarVariant ?? PREFERENCE_DEFAULTS.sidebar_variant,
sidebarCollapsible: init?.sidebarCollapsible ?? PREFERENCE_DEFAULTS.sidebar_collapsible,
setThemeMode: (mode) => set({ themeMode: mode }),
setResolvedThemeMode: (mode) => set({ resolvedThemeMode: mode }),
setThemePreset: (preset) => set({ themePreset: preset }),
setFont: (font) => set({ font }),
setContentLayout: (layout) => set({ contentLayout: layout }),
setNavbarStyle: (style) => set({ navbarStyle: style }),
setSidebarVariant: (variant) => set({ sidebarVariant: variant }),
setSidebarCollapsible: (mode) => set({ sidebarCollapsible: mode }),
isSynced: init?.isSynced ?? false,
setIsSynced: (val) => set({ isSynced: val }),
}));