diff --git a/src/controller.ts b/src/controller.ts index 9e384d7..be5c088 100644 --- a/src/controller.ts +++ b/src/controller.ts @@ -24,6 +24,7 @@ import type { DropTarget } from './page/dnd' import type { BlockEditorDef, BlockInfo, InlineSession } from './registry' import { createStore } from './store' import type { Store } from './store' +import { readPersist, writePersist } from './persist' export interface Block extends BlockInfo { depth: number @@ -123,7 +124,7 @@ export class Controller { canRedo: false, busy: 0, toast: null, - rail: false, + rail: readPersist('cms-onpage.rail', false), dev: false, assistant: false, inline: null, @@ -155,6 +156,12 @@ export class Controller { this.reloadImpl = opts.reload ?? (() => this.softReload()) } + /** Left panel open state, remembered across reloads. */ + setRail(open: boolean): void { + writePersist('cms-onpage.rail', open) + this.store.set({ rail: open }) + } + // --- lifecycle ---------------------------------------------------------- start(): void { diff --git a/src/persist.ts b/src/persist.ts new file mode 100644 index 0000000..12c17c1 --- /dev/null +++ b/src/persist.ts @@ -0,0 +1,21 @@ +// Remembering small UI preferences across reloads (rail open, section +// collapsed). Editors reload the page constantly to preview; losing the +// panel state every time is the papercut this removes. All access is +// guarded: private mode, sandboxed iframes and some embeds throw. +export function readPersist(key: string, fallback: T): T { + try { + const raw = localStorage.getItem(key) + if (raw === null) return fallback + return (typeof fallback === 'boolean' ? raw === 'true' : JSON.parse(raw)) as T + } catch { + return fallback + } +} + +export function writePersist(key: string, value: unknown): void { + try { + localStorage.setItem(key, typeof value === 'string' ? value : JSON.stringify(value)) + } catch { + // preferences are best-effort + } +} diff --git a/src/ui/Assistant.tsx b/src/ui/Assistant.tsx index 5fd2ca2..b6bb2e3 100644 --- a/src/ui/Assistant.tsx +++ b/src/ui/Assistant.tsx @@ -69,6 +69,7 @@ function ProposalCard({ p, status, onResolve }: { p: Proposal; status: ProposalS export function Assistant() { const ctrl = useCtrl() const open = useEditorState((s) => s.assistant) + const devOpen = useEditorState((s) => s.dev) const selected = useEditorState((s) => s.selected) useEditorState((s) => s.labelsVersion) const store = conversationsFor(ctrl) @@ -140,7 +141,7 @@ export function Assistant() { const starters = scope.rootId ? BLOCK_STARTERS : PAGE_STARTERS return ( -