import { useSyncExternalStore } from "react"; // 本机界面偏好(设置 → 界面):只影响当前浏览器,存 localStorage;读写失败(隐私模式、禁用存储)时用默认值。 export type UiPrefs = { /** 技术信息(ID、hash、token、耗时、原始字段、内部状态码)默认展开 */ techInfoExpanded: boolean; }; const KEY = "umt.ui-prefs"; const DEFAULTS: UiPrefs = { techInfoExpanded: false }; const listeners = new Set<() => void>(); let cache: UiPrefs | null = null; function read(): UiPrefs { if (cache) return cache; let v: UiPrefs = DEFAULTS; try { const raw = typeof localStorage === "undefined" ? null : localStorage.getItem(KEY); if (raw) v = { ...DEFAULTS, ...(JSON.parse(raw) as Partial) }; } catch { v = DEFAULTS; } cache = v; return v; } export function setUiPref(key: K, value: UiPrefs[K]) { cache = { ...read(), [key]: value }; try { localStorage.setItem(KEY, JSON.stringify(cache)); } catch { // 存不下就只在本次会话生效 } for (const l of listeners) l(); } function subscribe(l: () => void) { listeners.add(l); const onStorage = (e: StorageEvent) => { if (e.key !== KEY) return; cache = null; l(); }; if (typeof window !== "undefined") window.addEventListener("storage", onStorage); return () => { listeners.delete(l); if (typeof window !== "undefined") window.removeEventListener("storage", onStorage); }; } export function useUiPrefs(): UiPrefs { return useSyncExternalStore(subscribe, read, () => DEFAULTS); } /** 本地记住的折叠状态(计划页分组等):key → 是否展开;读写失败时返回 null */ export function readCollapseState(key: string): Record | null { try { const raw = localStorage.getItem(key); return raw ? (JSON.parse(raw) as Record) : null; } catch { return null; } } export function writeCollapseState(key: string, v: Record) { try { localStorage.setItem(key, JSON.stringify(v)); } catch { // 忽略 } }