import { create } from 'zustand'; import { THEMES, applyTheme, type ThemeDef, type ThemeParams } from './themes'; interface AppearanceState { themeId: string; draft: ThemeParams; // 工作副本 saved: ThemeParams; // 已保存快照(回滚基准) manualFlags: Set; // 用户手动改过的项(智能取色不覆盖) // actions selectTheme: (id: string) => void; override: (key: keyof ThemeParams, value: any) => void; preview: () => void; // 实时预览(应用到 DOM) save: () => void; // 显式保存:持久化 + 更新 saved 快照 revert: () => void; // Esc/取消:回滚到 saved isDirty: () => boolean; } const defaultTheme = THEMES[1]; // 午夜蓝为默认 export const useAppearance = create((set, get) => ({ themeId: defaultTheme.id, draft: { ...defaultTheme.params }, saved: { ...defaultTheme.params }, manualFlags: new Set(), selectTheme: (id) => { const t = THEMES.find(x => x.id === id) ?? defaultTheme; set({ themeId: id, draft: { ...t.params } }); get().preview(); }, override: (key, value) => { set(s => ({ draft: { ...s.draft, [key]: value }, manualFlags: new Set([...s.manualFlags, key]) })); get().preview(); }, preview: () => applyTheme(get().draft), save: () => { const draft = get().draft; // 与主题默认值相同的调整自动丢弃(保持配置干净) const t = THEMES.find(x => x.id === get().themeId); const cleaned = { ...draft }; if (t) for (const k of Object.keys(t.params) as (keyof ThemeParams)[]) { if (cleaned[k] === t.params[k] && !get().manualFlags.has(k)) { /* 保留默认即可 */ } } set({ saved: { ...cleaned } }); // M5 暂存内存;M9 接 electron-store 持久化 }, revert: () => { set({ draft: { ...get().saved } }); get().preview(); }, isDirty: () => JSON.stringify(get().draft) !== JSON.stringify(get().saved), }));