diff --git a/src/modules/lesson-preparation/hooks/expanded-slice.ts b/src/modules/lesson-preparation/hooks/expanded-slice.ts new file mode 100644 index 0000000..f4e7e25 --- /dev/null +++ b/src/modules/lesson-preparation/hooks/expanded-slice.ts @@ -0,0 +1,56 @@ +import type { StateCreator } from "zustand"; +import type { EditorState } from "./use-lesson-plan-editor"; + +export interface ExpandedSlice { + /** 已展开到正文流的节点 ID */ + expandedNodeIds: string[]; + /** v3 迁移过来的失效锚点提示(按 planId 记录是否已 dismiss) */ + legacyAnchorDismissed: Record; + toggleExpand: (nodeId: string) => void; + setExpanded: (nodeIds: string[]) => void; + isExpanded: (nodeId: string) => boolean; + dismissLegacyAnchor: (planId: string) => void; + /** 同步 doc.expandedNodeIds(保存/加载时调用) */ + syncFromDoc: (expandedNodeIds: string[]) => void; +} + +export const createExpandedSlice: StateCreator< + EditorState, + [], + [], + ExpandedSlice +> = (set, get) => ({ + expandedNodeIds: [], + legacyAnchorDismissed: {}, + + toggleExpand: (nodeId) => { + get().pushHistory(); + set((s) => { + const isExp = s.expandedNodeIds.includes(nodeId); + const next = isExp + ? s.expandedNodeIds.filter((id) => id !== nodeId) + : [...s.expandedNodeIds, nodeId]; + // 同步到 doc + return { + expandedNodeIds: next, + doc: { ...s.doc, expandedNodeIds: next }, + isDirty: true, + }; + }); + }, + + setExpanded: (nodeIds) => + set((s) => ({ + expandedNodeIds: nodeIds, + doc: { ...s.doc, expandedNodeIds: nodeIds }, + })), + + isExpanded: (nodeId) => get().expandedNodeIds.includes(nodeId), + + dismissLegacyAnchor: (planId) => + set((s) => ({ + legacyAnchorDismissed: { ...s.legacyAnchorDismissed, [planId]: true }, + })), + + syncFromDoc: (expandedNodeIds) => set({ expandedNodeIds }), +});