記住主題/模式/面板偏好,重開頁面自動還原
摘要: 與 claude-office 同步:深色模式、LIVE 模式與面板收合狀態 存入 localStorage,載入時自動套用。 根本原因: 偏好只存在記憶體 state,重整即重置。 影響: 使用者偏好跨重整保留;localStorage 不可用時安全降級。 修法: 同步 office-store.ts(loadPref/savePref)與 App.tsx(開機套用 mode)。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+3
-2
@@ -2,8 +2,8 @@ import { useEffect } from "react";
|
|||||||
import { FloorPlan } from "./components/FloorPlan";
|
import { FloorPlan } from "./components/FloorPlan";
|
||||||
import { HeaderBar } from "./components/HeaderBar";
|
import { HeaderBar } from "./components/HeaderBar";
|
||||||
import { SidePanel } from "./components/SidePanel";
|
import { SidePanel } from "./components/SidePanel";
|
||||||
import { startRuntime } from "./sim/runtime";
|
import { setMode, startRuntime } from "./sim/runtime";
|
||||||
import { useOfficeStore } from "./store/office-store";
|
import { loadPreferredMode, useOfficeStore } from "./store/office-store";
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const theme = useOfficeStore((s) => s.theme);
|
const theme = useOfficeStore((s) => s.theme);
|
||||||
@@ -11,6 +11,7 @@ export default function App() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
startRuntime();
|
startRuntime();
|
||||||
|
if (loadPreferredMode() === "live") setMode("live");
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -71,25 +71,60 @@ interface OfficeState {
|
|||||||
|
|
||||||
let eventSeq = 0;
|
let eventSeq = 0;
|
||||||
|
|
||||||
|
/* UI preferences persisted across reloads. */
|
||||||
|
function loadPref(key: string): string | null {
|
||||||
|
try {
|
||||||
|
return localStorage.getItem(key);
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function savePref(key: string, value: string) {
|
||||||
|
try {
|
||||||
|
localStorage.setItem(key, value);
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const savedTheme = loadPref("office-theme");
|
||||||
|
const savedPanel = loadPref("office-panel");
|
||||||
|
|
||||||
|
/** Read the preferred data source ("live" | "sim"); the runtime applies it on boot. */
|
||||||
|
export function loadPreferredMode(): "sim" | "live" {
|
||||||
|
return loadPref("office-mode") === "live" ? "live" : "sim";
|
||||||
|
}
|
||||||
|
|
||||||
export const useOfficeStore = create<OfficeState>()((set, get) => ({
|
export const useOfficeStore = create<OfficeState>()((set, get) => ({
|
||||||
agents: new Map(),
|
agents: new Map(),
|
||||||
links: [],
|
links: [],
|
||||||
meetings: [],
|
meetings: [],
|
||||||
events: [],
|
events: [],
|
||||||
selectedAgentId: null,
|
selectedAgentId: null,
|
||||||
theme: "light",
|
theme: savedTheme === "dark" ? "dark" : "light",
|
||||||
paused: false,
|
paused: false,
|
||||||
speed: 1,
|
speed: 1,
|
||||||
mode: "sim",
|
mode: "sim",
|
||||||
panelOpen: true,
|
panelOpen: savedPanel !== "0",
|
||||||
clock: 0,
|
clock: 0,
|
||||||
|
|
||||||
selectAgent: (id) => set({ selectedAgentId: id }),
|
selectAgent: (id) => set({ selectedAgentId: id }),
|
||||||
setTheme: (t) => set({ theme: t }),
|
setTheme: (t) => {
|
||||||
|
savePref("office-theme", t);
|
||||||
|
set({ theme: t });
|
||||||
|
},
|
||||||
setPaused: (p) => set({ paused: p }),
|
setPaused: (p) => set({ paused: p }),
|
||||||
setSpeed: (s) => set({ speed: s }),
|
setSpeed: (s) => set({ speed: s }),
|
||||||
setMode: (m) => set({ mode: m }),
|
setMode: (m) => {
|
||||||
togglePanel: () => set((state) => ({ panelOpen: !state.panelOpen })),
|
savePref("office-mode", m);
|
||||||
|
set({ mode: m });
|
||||||
|
},
|
||||||
|
togglePanel: () =>
|
||||||
|
set((state) => {
|
||||||
|
savePref("office-panel", state.panelOpen ? "0" : "1");
|
||||||
|
return { panelOpen: !state.panelOpen };
|
||||||
|
}),
|
||||||
clearWorld: () =>
|
clearWorld: () =>
|
||||||
set({ agents: new Map(), links: [], meetings: [], events: [], selectedAgentId: null }),
|
set({ agents: new Map(), links: [], meetings: [], events: [], selectedAgentId: null }),
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user