Files
mnote/design/06-mindmap/done/6-mindmap-phase6-kmind-parity-detail-checklist-v1.md
T
lix-2026 96e03645f7 chore: 收口 review 执行清单与 runtime 验证
- 补齐 design/10-review 执行清单、验收标准与相关设计治理记录

- 迁移已完成的 tree、mindmap、runtime fallback、AI kernel 等设计和缺陷条目

- 推进 Rust Web runtime、tree/sidebar、page aggregate、mindmap 与 OnlyOffice 路由侧验证支撑

- 增加 task177-task180 smoke/audit 脚本及前端相关测试覆盖
2026-05-14 05:52:08 +08:00

476 lines
31 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 6 [done] Mindmap Phase 6 KMind/simple-mind-map Parity Detail Checklist v1
> 日期:2026-05-11
>
> 当前阶段:Phase 6 `leptos-mindmap` 已完成真实 `simple-mind-map` runtime + Leptos/Rust floating overlay shell 的第一轮收口;本 checklist 是后续细节优化入口。
>
> 执行规则:每完成一个节点,必须基于代码、测试、截图或人工复核证据勾选对应项。未验证的实现不得勾选。
## 0. 目标与结论
**目标:**把当前 mindmap shell 从“可运行的 Leptos/Rust 浮动 UI 壳”推进到接近 KMind 与 simple-mind-map 官方编辑器的工作台体验。
当前不需要改变 Phase 6 的大方向:
```text
Rust kernel truth
-> mindmap.simple_mind_map_scene.v1
-> leptos-tiptap NodeView
-> simple-mind-map runtime
-> Leptos/Rust floating UI shell
-> command bridge / compatPayload.patch
```
本轮要修正的是 UI 与交互细节,而不是回退到以下路线:
- 不直接嵌入完整 Vue `lx-doc/mind-map` 应用。
- 不恢复旧 React `MindmapBlock.tsx` 为 3000 文档页默认主链。
- 不启动 Rust-native renderer 重写。
- 不把 `simple-mind-map` runtime data 保存为 canonical truth。
- 不把 TypeScript NodeView 扩写成长期 toolbar/sidebar/navigator UI 框架;长期 UI shell 继续归到 Leptos/Rust。
## 1. 本次取证结论
### 1.1 当前实现差距
已对照:
- 当前实现截图:`/mnt/Data1T/mnote/tmp/image copy 80.png`
- KMind 目标截图:`/mnt/Data1T/mnote/tmp/image copy 81.png`
- 隐藏 chrome 目标截图:`/mnt/Data1T/mnote/tmp/image copy 82.png`
- 右侧详细设置栏目标截图:`/mnt/Data1T/mnote/tmp/image copy 83.png`
当前主要差距:
- Toolbar 当前视觉上仍是三行:`rust/spikes/leptos-tiptap-spike/src/lib.rs``.mnote-mindmap-command-toolbar``.mnote-mindmap-toolbar-primary` 都允许 `flex-wrap: wrap`,并且每个分组都带文字分组名,导致不可能稳定保持 KMind/simple-mind-map 的单行工具组。
- Toolbar 当前没有真正的 `更多` 溢出模型。lx-doc `Toolbar.vue` 通过测量工具栏宽度,把可见按钮放入 `horizontalList`,把溢出按钮放入 `verticalList`,这比单纯 CSS 横向滚动更接近目标。
- 当前没有完整全屏状态。lx-doc `Fullscreen.vue` 同时提供“全屏查看”和“全屏编辑”,并在 fullscreen change 后调用 `mindMap.resize()`
- 当前没有“鼠标移出后隐藏 chrome,鼠标移入不自动恢复,点击才恢复”的状态机。KMind changelog 明确提到 floating toolbar 会在特定场景自动隐藏,并推荐结合 Zen mode 获得更大的编辑视图。
- 当前右侧栏只是窄 tab + 148px 简化 bodyKMind/simple-mind-map 是“右侧触发条 + 可隐藏把手 + 约 300px 详细抽屉”,结构面板中有布局卡片,设置项密度明显更高。
- 当前 navigator 是文字按钮和常驻搜索输入框;目标是底部右侧图标工具条,搜索按需展开,全屏、小地图、只读、缩放、鼠标行为、设置等是同一条浮动控件。
### 1.2 参考实现证据
- `design/05-editor-mainline/reference-code/lx-doc/mind-map/src/pages/Edit/components/Toolbar.vue`
- `computeToolbarShow()` 根据宽度计算单行 `horizontalList``verticalList`
- `showMoreBtn` 显示 `更多` popover。
- `design/05-editor-mainline/reference-code/lx-doc/mind-map/src/pages/Edit/components/ToolbarNodeBtnList.vue`
- 记录 toolbar action、禁用状态、active node 规则和 runtime command。
- `design/05-editor-mainline/reference-code/lx-doc/mind-map/src/pages/Edit/components/SidebarTrigger.vue`
- 右侧触发条有 `show` 状态和 `toggleShowBtn` 隐藏把手。
- 激活 panel 后容器从 `right: 0` 推到 `right: 305px`
- `design/05-editor-mainline/reference-code/lx-doc/mind-map/src/pages/Edit/components/NavigatorToolbar.vue`
- 底部 navigator 是图标工具条,不是常驻表单。
- 包含回根、搜索、鼠标行为、小地图、只读、全屏、缩放、暗色、源码、演示等入口。
- `design/05-editor-mainline/reference-code/lx-doc/mind-map/src/pages/Edit/components/Fullscreen.vue`
- 区分 `fullscreenShow``fullscreenEdit`
- `design/05-editor-mainline/reference-code/lx-doc/mind-map/src/config/zh.js`
- `sidebarTriggerList` 包含 `nodeStyle/baseStyle/theme/structure/outline/shortcutKey`
- `design/05-editor-mainline/reference-code/kmind-plugin/README_en_US.md`
- 明确提到 desktop floating toolbar、Zen mode、自动隐藏 UI、全局配置。
- [x] 已完成当前实现、截图和参考代码的首轮取证。
## 2. 文件职责边界
### 2.1 主要运行代码
- `rust/spikes/leptos-tiptap-spike/src/lib.rs`
- 当前 Leptos/Rust shell、CSS、mount/unmount、toolbar/sidebar/navigator 渲染集中在此。
- 下一阶段应优先把 mindmap shell 拆出到专门模块,避免 `lib.rs` 继续膨胀。
- `wolai-frontend/src/lib/mindmap/mindmap-ui-schema.ts`
- 当前 action、toolbar group、sidebar panel、navigator item、context menu 的 schema 来源。
- 下一阶段需要扩展为可表达单行 toolbar、溢出、全屏、chrome visibility、详细 panel controls 的中立 schema。
- `wolai-frontend/src/lib/mindmap/mindmap-action-map.ts`
- UI action 到 runtime/local/kernel/compat 的映射。
- 下一阶段需要补全 `fullscreen``toggleChrome``toggleSidebar``toggleSearch``setScale``setMouseBehavior` 等 local view action。
- `wolai-frontend/src/lib/mindmap/mindmap-ui-state.ts`
- 当前只覆盖 active node、readonly、capability、disabled state。
- 下一阶段需要补 chrome visibility、fullscreen、sidebar open、search open、toolbar overflow、navigator active state。
- `wolai-frontend/src/lib/mindmap/simple-mind-map-bridge.ts`
- 当前 runtime bridge。
- 下一阶段需要确保 fullscreen/resize、search、minimap、scale input、sidebar style 写入都能通过 bridge 安全触达 runtime。
- `wolai-frontend/src/lib/mindmap/leptos-mindmap-adapter.ts`
- projection/command endpoint 与 adapter 初始化。
- 下一阶段继续保持薄桥接,不承载 UI 细节。
- `scripts/task166-mindmap-phase6-block-smoke.js`
- 当前 Phase 6 smoke。
- 下一阶段建议新增或扩展为 KMind parity smoke,保存对齐截图证据。
### 2.2 建议新增/拆分文件
- Create: `rust/spikes/leptos-tiptap-spike/src/mindmap_shell.rs`
- Leptos/Rust shell 组件、状态结构、事件派发。
- Create: `rust/spikes/leptos-tiptap-spike/src/mindmap_shell_style.rs` 或保留同模块内常量
- 如果现有 CSS 继续增长,单独收口 mindmap shell 样式字符串。
- Create: `scripts/task167-mindmap-kmind-parity-smoke.js`
- 专门覆盖 toolbar 单行、全屏、chrome hide、右侧抽屉、截图对比。
- Output: `tmp/task167-mindmap-kmind-parity-smoke/*.png`
- 保存每个视觉验收节点截图。
## 3. 状态模型先行
后续 UI 不应继续靠 CSS 和零散按钮状态拼凑。先把 shell state 定义清楚。
### Task 1: 扩展 Mindmap Shell State Contract
**Files:**
- Modify: `wolai-frontend/src/lib/mindmap/mindmap-ui-schema.ts`
- Modify: `wolai-frontend/src/lib/mindmap/mindmap-ui-state.ts`
- Modify: `wolai-frontend/src/lib/mindmap/mindmap-ui-state.test.ts`
- Modify/Create: `rust/spikes/leptos-tiptap-spike/src/mindmap_shell.rs`
- [x] 定义 `MindmapChromeVisibilityState`
- `visible`
- `hiddenByPointerLeave`
- `hiddenByToggle`
- `hiddenByFullscreen`
- [x] 定义 `MindmapToolbarOverflowState`
- `availableWidth`
- `visibleActionIds`
- `overflowActionIds`
- `moreOpen`
- [x] 定义 `MindmapFullscreenState`
- `mode: "none" | "canvas" | "page"`
- `isFullscreen`
- `target: "mindmap-root" | "document-body"`
- [x] 定义 `MindmapSidebarState`
- `triggerVisible`
- `panelOpen`
- `activePanelId`
- `drawerWidth`
- `collapsedByToggle`
- [x] 定义 `MindmapNavigatorState`
- `searchOpen`
- `minimapOpen`
- `readonly`
- `zoomPercent`
- `mouseBehavior`
- [x] TS 单测覆盖:鼠标移出后为 `hiddenByPointerLeave`;再次 mouseenter 不恢复;点击画布或点击显式恢复按钮才回到 `visible`
- [x] TS 单测覆盖:sidebar toggle 隐藏触发条后,不会清空 `activePanelId`;再次显示后保留最近面板。
- [x] Rust/Leptos shell options 能接收上述 state,并向 DOM 输出稳定 `data-*` 标记,供 smoke 断言。
- [x] 验证:`cd /mnt/Data1T/mnote/wolai-frontend && pnpm test -- mindmap-ui-state`
- 2026-05-11 通过:`mindmap-ui-state.test.ts` 6 项通过;同时复核 `npm run typecheck``npm run build``cargo check``node scripts/build-leptos-tiptap-island.js` 均通过。
## 4. 单行 Toolbar 与更多菜单
目标:对齐 `/mnt/Data1T/mnote/tmp/image copy 81.png` 与 lx-doc `Toolbar.vue`,主 toolbar 只占一行;溢出进入 `更多` 菜单;不要回到当前 `/mnt/Data1T/mnote/tmp/image copy 80.png` 的三行状态。
### Task 2: 设计单行 Toolbar Schema
**Files:**
- Modify: `wolai-frontend/src/lib/mindmap/mindmap-ui-schema.ts`
- Modify: `wolai-frontend/src/lib/mindmap/mindmap-ui-schema.test.ts`
- [x] 为 toolbar action 增加 `iconKey``shortLabel``longLabel``priority``overflowGroup`
- [x] 移除默认渲染中强依赖的分组文字标签;分组仅作为视觉分隔线和溢出归类,不占据单行宽度。
- [x] 把 import/export/historyRecord 规划为右侧独立 toolbar cluster,避免和节点编辑按钮互相挤压。
- [x] 增加 `more` 虚拟 action,只有存在 `overflowActionIds` 时显示。
- [x] 单测断言默认 toolbar 主按钮顺序与 lx-doc/KMind 对齐:undo、redo、editNode、insertSiblingAfter、deleteNode、insertChild、tag、hyperlink、note、image、icon、summary、associativeLine、formula、more。
- [x] 单测断言 action id 不重复,且每个可见 action 都能映射到 action map。
- [x] 验证:`cd /mnt/Data1T/mnote/wolai-frontend && pnpm test -- mindmap-ui-schema mindmap-action-map`
- 2026-05-11 通过:`mindmap-ui-schema.test.ts` 11 项通过;同轮 `mindmap-action-map.test.ts` 4 项通过。
### Task 3: 实现 Leptos 单行 Toolbar Layout
**Files:**
- Modify/Create: `rust/spikes/leptos-tiptap-spike/src/mindmap_shell.rs`
- Modify: `rust/spikes/leptos-tiptap-spike/src/lib.rs`
- Modify: `scripts/task167-mindmap-kmind-parity-smoke.js`
- [x] Toolbar CSS 改为单行:`flex-wrap: nowrap`,固定按钮宽高,禁用 group 内换行。
- [x] 顶部 toolbar 分为左/中/右 cluster:主编辑工具、导入导出/历史、更多。
- [x]`ResizeObserver` 或等价测量机制计算可见按钮与溢出按钮;窄宽度下不允许撑成第二行。
- [x] `更多` 点击后打开浮层菜单,菜单内纵向列出溢出 action。
- [x] `更多` 菜单失焦、点击菜单项或按 Escape 后关闭。
- [x] 按钮视觉从“英文 icon 名 + 中文文字”修正为图标主导、短文字辅助;不得把 `palette/sliders/layout` 这类内部 icon key 作为可见正文。
- [x] Smoke 断言 toolbar 高度不超过 72px`toolbarRows <= 1` 或等价 DOM 断言通过。
- [x] Screenshot`tmp/task167-mindmap-kmind-parity-smoke/01-toolbar-single-row.png`,肉眼能看到 toolbar 单行而不是三行。
- [x] 验证:`cd /mnt/Data1T/mnote/design/05-editor-mainline/reference-code/leptos-tiptap/tiptap && npm run typecheck && npm run build`
- [x] 验证:`cd /mnt/Data1T/mnote/wolai-frontend && node scripts/build-leptos-tiptap-island.js`
- [x] 验证:`cd /mnt/Data1T/mnote && node scripts/task167-mindmap-kmind-parity-smoke.js --stage toolbar`
- 2026-05-11 通过:桌面 toolbar `height=56``toolbarRows=1`;窄宽度 toolbar `height=56``toolbarRows=1`,并产生 `overflowActions`Escape 后 `moreOpen=false``toolbarRows=1`
## 5. 全屏与大画布模式
目标:至少提供 KMind/simple-mind-map 级别的全屏按钮与状态。优先做 block/canvas fullscreen,随后再补 page fullscreen。
### Task 4: 增加 Fullscreen Action Contract
**Files:**
- Modify: `wolai-frontend/src/lib/mindmap/mindmap-ui-schema.ts`
- Modify: `wolai-frontend/src/lib/mindmap/mindmap-action-map.ts`
- Modify: `wolai-frontend/src/lib/mindmap/mindmap-ui-state.ts`
- Modify: `wolai-frontend/src/lib/mindmap/mindmap-action-map.test.ts`
- [x] 新增 action`fullscreenCanvas`,对应 lx-doc 的“全屏查看”。
- [x] 新增 action`fullscreenPage`,对应 lx-doc 的“全屏编辑”,第一阶段先作为 schema/action contract 保留。
- [x] 新增 action`exitFullscreen`
- [x] `fullscreenCanvas/fullscreenPage/exitFullscreen` 均标记为 `localView`,不得产生 kernel command。
- [x] `Fullscreen API` 不可用时,action disabled,并在 UI 有稳定 `data-disabled-reason="fullscreen-unavailable"`
- [x] 单测覆盖 fullscreen action 不依赖 active nodereadonly 下仍可使用。
- [x] 验证:`cd /mnt/Data1T/mnote/wolai-frontend && pnpm test -- mindmap-action-map mindmap-ui-state`
- 2026-05-11 通过:`mindmap-action-map.test.ts` 新增 fullscreen localView 合同与 readonly 断言;`mindmap-ui-state.test.ts` 断言 readonly/无 active node 下 fullscreen 仍可用。
### Task 5: 实现全屏按钮与 resize
**Files:**
- Modify/Create: `rust/spikes/leptos-tiptap-spike/src/mindmap_shell.rs`
- Modify: `rust/spikes/leptos-tiptap-spike/src/lib.rs`
- Modify: `wolai-frontend/src/lib/mindmap/simple-mind-map-bridge.ts`
- Modify: `scripts/task167-mindmap-kmind-parity-smoke.js`
- [x] 底部 navigator 增加全屏图标按钮,默认显示 canvas fullscreen。
- [x] 点击后对 `data-testid="mnote-mindmap-editor-root"` 或等价 canvas root 调用 Fullscreen API。
- [x] 监听 `fullscreenchange`,退出时同步 shell state。
- [x] fullscreen change 后调用 `mindMap.resize()` 或 bridge 暴露的 resize 方法,并居中或保持当前 view transform。
- [x] 全屏时保持 toolbar/sidebar/navigator 浮动在画布上;不出现文档页滚动条错位。
- [x] 全屏模式下 Escape 退出后,toolbar/sidebar/navigator 状态恢复到进入前状态。
- [x] Smoke 断言点击全屏后 `document.fullscreenElement` 为 mindmap root 或其包含节点。
- [x] Screenshot`tmp/task167-mindmap-kmind-parity-smoke/02-fullscreen-canvas.png`
- [x] 验证:`cd /mnt/Data1T/mnote && node scripts/task167-mindmap-kmind-parity-smoke.js --stage fullscreen`
- 2026-05-11 通过:`fullscreenElementIsRoot=true``shellFullscreenActive=true`Escape 退出后 `document.fullscreenElement === null``shellFullscreenActive=false`
## 6. 鼠标移出隐藏 Chrome,点击恢复
目标:对齐 `/mnt/Data1T/mnote/tmp/image copy 82.png`。鼠标移出后隐藏 toolbar/sidebar/navigator 等菜单;鼠标重新移入不自动恢复;用户点击画布或显式按钮才恢复。
### Task 6: 实现 Chrome Visibility State Machine
**Files:**
- Modify/Create: `rust/spikes/leptos-tiptap-spike/src/mindmap_shell.rs`
- Modify: `rust/spikes/leptos-tiptap-spike/src/lib.rs`
- Modify: `scripts/task167-mindmap-kmind-parity-smoke.js`
- [x] 在 mindmap root 上监听 pointer enter/leave/click,不依赖 document 全局 hover。
- [x] pointer leave root 后进入 `hiddenByPointerLeave`,隐藏 toolbar、sidebar drawer、sidebar trigger、navigator、minimapcount 可保留或按 KMind 目标隐藏,需在 smoke 固定判定。
- [x] pointer enter root 不改变 `hiddenByPointerLeave`
- [x] 点击画布空白区或节点后恢复 `visible`
- [x] 点击恢复后不触发误插入、不改变 active node,除非点击目标本身就是节点选择。
- [x] 打开 `更多` 菜单或右侧 drawer 时,pointer leave 先关闭弹层,再隐藏 chrome,避免残留孤立菜单。
- [x] fullscreen 模式与 hidden state 组合时,退出 fullscreen 不强制显示 chrome,除非进入 fullscreen 前是 visible。
- [x] Smoke 操作:移动鼠标到 root 外 -> 断言 toolbar/sidebar/navigator hidden;移动回 root -> 仍 hidden;点击 root -> visible。
- [x] Screenshot`tmp/task167-mindmap-kmind-parity-smoke/03-chrome-hidden-after-leave.png`
- [x] Screenshot`tmp/task167-mindmap-kmind-parity-smoke/04-chrome-restored-after-click.png`
- [x] 验证:`cd /mnt/Data1T/mnote && node scripts/task167-mindmap-kmind-parity-smoke.js --stage chrome-hide`
- 2026-05-11 通过:`sceneChromeVisibility/shellChromeVisibility``visible -> hiddenByPointerLeave -> hiddenByPointerLeave -> visible`toolbar/sidebar/navigator 与截图状态一致。
- 2026-05-11 补充通过:`fullscreen` stage 已覆盖 `visible -> enter fullscreen -> exit -> visible``hiddenByPointerLeave -> enter fullscreen -> exit -> hiddenByPointerLeave`,退出 fullscreen 不再强制显示 chrome。
## 7. 右侧详细设置栏与隐藏把手
目标:对齐 `/mnt/Data1T/mnote/tmp/image copy 83.png`。右侧不只是简化 tab,而是完整 panel drawer;触发条可以隐藏;隐藏后有把手可恢复。
### Task 7: 扩展 Sidebar Schema 到详细控件
**Files:**
- Modify: `wolai-frontend/src/lib/mindmap/mindmap-ui-schema.ts`
- Modify: `wolai-frontend/src/lib/mindmap/mindmap-action-map.ts`
- Modify: `wolai-frontend/src/lib/mindmap/mindmap-ui-schema.test.ts`
- Modify: `wolai-frontend/src/lib/mindmap/mindmap-action-map.test.ts`
- [x] Sidebar panel 增加 `kind``nodeStyle``baseStyle``theme``structure``outline``shortcutKey``settings`
- [x] Sidebar option 增加控件类型:`button``swatch``segmented``slider``numberInput``select``layoutCard``treeItem``toggle`
- [x] `structure` panel 定义布局卡片:逻辑结构图、思维导图、组织结构图、目录组织图、时间轴、鱼骨图。
- [x] `theme` panel 定义主题卡片,至少包含 classic、classic4/KMind-like、simple、dark 入口。
- [x] `nodeStyle` panel 定义节点填充、文字颜色、字号、加粗、斜体、形状、边框、线条颜色、线条宽度。
- [x] `baseStyle` panel 定义连线风格、曲线/直线、彩虹线条、背景、节点间距、概要样式。
- [x] `outline` panel 从 projection/runtime 派生树,不允许成为第二套树真相。
- [x] `settings``shortcutKey` panel 第一阶段可显示只读内容,但需要在 schema 中有位置。
- [x] 单测覆盖:每个 sidebar option 要么有 actionId,要么是只读控件;可写控件必须有 compat path 或 kernel command 映射。
- [x] 验证:`cd /mnt/Data1T/mnote/wolai-frontend && pnpm test -- mindmap-ui-schema mindmap-action-map`
- 2026-05-11 通过:`mindmap-ui-schema.test.ts` 13 项通过;同轮 `mindmap-action-map.test.ts` 5 项通过。
### Task 8: 实现右侧 Trigger、Drawer、隐藏把手
**Files:**
- Modify/Create: `rust/spikes/leptos-tiptap-spike/src/mindmap_shell.rs`
- Modify: `rust/spikes/leptos-tiptap-spike/src/lib.rs`
- Modify: `scripts/task167-mindmap-kmind-parity-smoke.js`
- [x] 右侧 trigger 宽度对齐 KMind/simple-mind-map:约 60px,图标在上、文字在下。
- [x] trigger active 状态使用蓝色强调条或蓝色文字,不再用整块按钮边框作为主要视觉。
- [x] drawer 打开时宽度约 300px,右侧固定,覆盖画布,不挤压 runtime。
- [x] drawer 顶部包含 panel 标题和关闭按钮。
- [x] trigger 左侧或 drawer 边缘提供隐藏把手,点击后隐藏整个 trigger。
- [x] 隐藏后保留一个小把手;鼠标移入不自动展开,点击把手才恢复。
- [x] 点击 active trigger:若 drawer 已打开同一 panel,则关闭 drawer;若点击不同 panel,则切换 drawer 内容。
- [x] 结构 panel 的布局卡片使用稳定尺寸,不能因文字或 hover 导致布局跳动。
- [x] 右侧 drawer 打开时,底部 navigator 与 drawer 不重叠;必要时 navigator 向左避让或保持在 drawer 左侧。
- [x] Smoke 断言:打开 `structure` panel 后可见标题“结构”,可见至少 6 个布局卡片,存在关闭按钮和隐藏把手。
- [x] Screenshot`tmp/task167-mindmap-kmind-parity-smoke/05-sidebar-structure-drawer.png`
- [x] Screenshot`tmp/task167-mindmap-kmind-parity-smoke/06-sidebar-hidden-handle.png`
- [x] 验证:`cd /mnt/Data1T/mnote && node scripts/task167-mindmap-kmind-parity-smoke.js --stage sidebar`
- 2026-05-11 通过:`drawerWidth=300``title=结构``structureCardCount=6`close/hide/restore 均通过。
### Task 9: 打通右侧设置到 Runtime/Kernel/Compat
**Files:**
- Modify: `wolai-frontend/src/lib/mindmap/mindmap-action-map.ts`
- Modify: `wolai-frontend/src/lib/mindmap/simple-mind-map-bridge.ts`
- Modify: `wolai-frontend/src/lib/mindmap/leptos-mindmap-adapter.ts`
- Modify: `wolai-frontend/src/lib/mindmap/mindmap-command-diff.ts`
- Modify: `scripts/task167-mindmap-kmind-parity-smoke.js`
- [x] `setLayout` 走 kernel command,并刷新 adapter projection。
- [x] `setTheme` 走 kernel command,并刷新 adapter projection。
- [x] 节点样式类 action 先走 runtime 预览,再以 `compatPayload.patch` 保存样式字段。
- [x] 基础样式类 action 先走 runtime config/themeConfig,再以 `compatPayload.patch` 保存无法语义化字段。
- [x] option 点击失败时显示 `command_failed` 或等价错误层,不能只改变 UI 本地状态。
- [x] Smoke 点击结构卡片后 reload,断言 projection layout 保持。
- [x] Smoke 点击主题卡片后 reload,断言 theme 保持。
- [x] Smoke 点击节点样式后 reload,断言 compatPayload patch 可见或节点样式保留。
- [x] 验证:`cd /mnt/Data1T/mnote/wolai-frontend && pnpm test -- mindmap-action-map simple-mind-map-bridge`
- [x] 验证:`cd /mnt/Data1T/mnote && node scripts/task167-mindmap-kmind-parity-smoke.js --stage sidebar-actions`
- 2026-05-11 通过:`sidebarActions.beforeReload/afterReload` 均为 `layout=mindMap``theme=dark``rootFillColor=#dbeafe`;同时修正 metadata-only 本地 `put` 误分流,统一回到 `mindmap.command.apply -> mnote-web server-side apply -> mindmaps.put` 主链。
## 8. 底部 Navigator 图标化与 MiniMap/Search
目标:对齐 KMind/simple-mind-map 底部右侧工具条。搜索不应长期占用输入框宽度;全屏、只读、小地图、缩放应统一成 icon/action。
### Task 10: Navigator Schema 与 UI 重排
**Files:**
- Modify: `wolai-frontend/src/lib/mindmap/mindmap-ui-schema.ts`
- Modify/Create: `rust/spikes/leptos-tiptap-spike/src/mindmap_shell.rs`
- Modify: `scripts/task167-mindmap-kmind-parity-smoke.js`
- [x] Navigator item 改为图标按钮为主:回根、搜索、小地图、只读/编辑、全屏、缩小、缩放值、放大、设置。
- [x] 搜索默认只显示图标;点击后展开输入框;再次点击或 Escape 收起。
- [x] 缩放值允许输入百分比;非法输入恢复上一次有效值。
- [x] 小地图打开后显示在 navigator 上方或右下安全位置,不遮挡 drawer。
- [x] 只读状态显示明确 active 状态,并同步 `mindMap.setMode("readonly" | "edit")`
- [x] Count 固定在左下角,文本保持简短:`字数 17``节点 4`
- [x] Smoke 断言默认 navigator 没有常驻搜索输入框;点击搜索后输入框出现。
- [x] Screenshot`tmp/task167-mindmap-kmind-parity-smoke/07-navigator-icons.png`
- [x] Screenshot`tmp/task167-mindmap-kmind-parity-smoke/08-search-expanded.png`
- [x] 验证:`cd /mnt/Data1T/mnote && node scripts/task167-mindmap-kmind-parity-smoke.js --stage navigator`
- 2026-05-11 通过:默认 `searchOpen=false`、无常驻输入框;展开搜索后截图已保存;最终 `minimapOpen=true``readonly=true`、非法缩放输入恢复为 `100%`
## 9. Context Menu 与快捷键基础对齐
目标:当前右键菜单已有第一阶段能力,但要对齐 KMind/simple-mind-map 的禁用状态、显示位置和隐藏行为。
### Task 11: Context Menu Parity
**Files:**
- Modify: `wolai-frontend/src/lib/mindmap/mindmap-ui-schema.ts`
- Modify: `wolai-frontend/src/lib/mindmap/mindmap-action-map.ts`
- Modify/Create: `rust/spikes/leptos-tiptap-spike/src/mindmap_shell.rs`
- Modify: `scripts/task167-mindmap-kmind-parity-smoke.js`
- [x] 区分节点右键菜单与画布右键菜单。
- [x] 节点菜单包含插入子节点、插入同级、删除、展开/收起、概要、关联线、复制文本。
- [x] 画布菜单包含回根、适应画布、搜索、只读切换、显示菜单。
- [x] root/generalization 等特殊节点禁用不适用 action。
- [x] 右键菜单打开时 pointer leave 不立即隐藏 chrome;点击菜单项、Escape、点击画布空白后关闭。
- [x] 菜单位置不能超出 mindmap root 边界。
- [x] Smoke 断言节点右键菜单与画布右键菜单的 action 列表不同。
- [x] Screenshot`tmp/task167-mindmap-kmind-parity-smoke/09-node-context-menu.png`
- [x] 验证:`cd /mnt/Data1T/mnote && node scripts/task167-mindmap-kmind-parity-smoke.js --stage context-menu`
- 2026-05-11 通过:节点菜单仅包含 node actionsroot 节点 `insertSiblingAfter/deleteNode` 为 disabled;画布菜单为 `centerRoot/fitView/search/readonly/showMenu`pointer leave 后菜单与 chrome 保持可见,Escape 后关闭。
## 10. KMind 视觉基线
目标:不要只实现功能按钮,要让默认观感接近 KMind/simple-mind-map 工作台。
### Task 12: 默认 Theme/Layout 视觉对齐
**Files:**
- Modify: `rust/crates/bridge-runtime/src/lib.rs`
- Modify: `wolai-frontend/src/lib/mindmap/simple-mind-map-bridge.ts`
- Modify: `wolai-frontend/src/lib/mindmap/mindmap-projection.ts`
- Modify: `scripts/task167-mindmap-kmind-parity-smoke.js`
- [x] 默认 root 节点使用红色/橙红色背景、白色粗体文字,接近 KMind 截图。
- [x] 默认二级节点使用蓝色背景、白色文字。
- [x] 分支主题使用蓝色文字,概要括号线使用红色或主题强调色。
- [x] 默认 layout 选择与 KMind 截图一致的右向逻辑结构。
- [x] 连线位置不再错位;节点中心线、概要括号线和子节点垂直中心对齐。
- [x] Smoke 读取 canvas/svg 或截图像素,确认节点和连线非空、可见、位置不重叠。
- [x] Screenshot`tmp/task167-mindmap-kmind-parity-smoke/10-kmind-theme-baseline.png`
- [x] 验证:`cd /mnt/Data1T/mnote && node scripts/task167-mindmap-kmind-parity-smoke.js --stage theme`
- 2026-05-11 通过:runtime 默认 `layout=logicalStructure``theme=default``themeConfig` 生效为 root 红底白字、二级蓝底白字、分支蓝字、红色概要线;smoke 读取到 `nodeCount=5``pathCount=9``overlaps=0`
## 11. 验证体系
### Task 13: 新增 KMind Parity Smoke
**Files:**
- Create: `scripts/task167-mindmap-kmind-parity-smoke.js`
- Output: `tmp/task167-mindmap-kmind-parity-smoke/result.json`
- Output: `tmp/task167-mindmap-kmind-parity-smoke/*.png`
- [x] 启动前检查 `http://127.0.0.1:3000/` 可用,不强制重启已存在服务。
- [x] 使用默认测试账号登录。
- [x] 新建或打开临时文档,插入 mindmap block。
- [x] 断言 `simple-mind-map` runtime 存在,canvas rect 非零。
- [x] 断言 Leptos/Rust shell 来源为 `data-ui-shell-source="leptos-rust-shell"`
- [x] 断言 toolbar 单行。
- [x] 断言 fullscreen 按钮存在并可进入/退出。
- [x] 断言 pointer leave 隐藏 chrome、pointer enter 不恢复、click 恢复。
- [x] 断言右侧 drawer 可打开、关闭、隐藏 trigger、点击把手恢复。
- [x] 断言 navigator 搜索按需展开,小地图可打开。
- [x] 断言 reload 后 layout/theme/view/compat patch 不丢。
- [x] 输出 `result.json`,至少包含 `ok``baseUrl``documentId``mindmapId``toolbarRows``fullscreenOk``chromeHideOk``sidebarDrawerOk``navigatorOk``screenshots`
- [x] 验证:`cd /mnt/Data1T/mnote && node scripts/task167-mindmap-kmind-parity-smoke.js`
- 2026-05-11 通过:默认执行 `all` stage`result.json` 输出 `ok/baseUrl/documentId/mindmapId/toolbarRows/fullscreenOk/chromeHideOk/sidebarDrawerOk/navigatorOk/contextMenuOk/themeOk/reloadOk/screenshots`,截图 01-10 全量生成。
### Task 14: 回归现有 Phase 6 Smoke
**Files:**
- Modify: `scripts/task166-mindmap-phase6-block-smoke.js` only if needed
- [x] `task167` 新增后,`task166` 继续保持 runtime/projection/command/reload 基础验证,不与视觉 parity 重复过多。
- [x] `task166` 不因 toolbar 单行、drawer、fullscreen 变化而误判旧 testid 缺失。
- [x] `task166``task167` 输出目录分离。
- [x] 验证:`cd /mnt/Data1T/mnote && node scripts/task166-mindmap-phase6-block-smoke.js`
- 2026-05-11 通过:`task166` 保持基础链路验证,兼容 navigator 搜索折叠与 zoom 输入框;`result.json` 输出在 `tmp/task166-mindmap-phase6-block-smoke/`,与 `task167` 分离。
## 12. 执行顺序建议
建议按以下顺序执行,避免先做 CSS 后返工状态模型:
1. Task 1:状态模型。
2. Task 2-3:单行 toolbar 与更多菜单。
3. Task 4-5:全屏。
4. Task 6chrome hide/click restore。
5. Task 7-9:右侧详细设置栏与持久化。
6. Task 10navigator 图标化。
7. Task 11context menu。
8. Task 12:视觉主题与连线对齐。
9. Task 13-14smoke 与回归。
每次实现完成后,至少保存对应截图,再勾选节点。
## 13. 阶段验收标准
本 checklist 视为完成时,必须同时满足:
- [x] `/mnt/Data1T/mnote/tmp/task167-mindmap-kmind-parity-smoke/01-toolbar-single-row.png` 显示单行 toolbar。
- [x] `/mnt/Data1T/mnote/tmp/task167-mindmap-kmind-parity-smoke/02-fullscreen-canvas.png` 显示全屏画布与浮动 chrome。
- [x] `/mnt/Data1T/mnote/tmp/task167-mindmap-kmind-parity-smoke/03-chrome-hidden-after-leave.png` 显示鼠标移出后的隐藏状态。
- [x] `/mnt/Data1T/mnote/tmp/task167-mindmap-kmind-parity-smoke/05-sidebar-structure-drawer.png` 显示详细右侧结构面板。
- [x] `/mnt/Data1T/mnote/tmp/task167-mindmap-kmind-parity-smoke/07-navigator-icons.png` 显示图标化底部 navigator。
- [x] `node scripts/task166-mindmap-phase6-block-smoke.js` 通过。
- [x] `node scripts/task167-mindmap-kmind-parity-smoke.js` 通过。
- [x] `pnpm test -- mindmap-ui-schema mindmap-action-map mindmap-ui-state simple-mind-map-bridge` 通过。
- [x] `npm run typecheck && npm run build``design/05-editor-mainline/reference-code/leptos-tiptap/tiptap` 通过。
- [x] Rust `page.body.save` 主链保存 `mindmap` block 后,`/api/documents/content` 读回仍为 `type: "mindmap"`,不再退化成 `paragraph`
- 2026-05-12 通过:新增 `cargo test -p core-protocol preserves_mindmap_paragraph_placeholder``cargo test -p core-protocol tiptap_mindmap_placeholder_round_trip_preserves_mindmap_attrs``cargo test -p bridge-runtime documents_save_command_plan_preserves_mindmap_placeholder`;同时在真实 `http://127.0.0.1:3000` 上手工验证 `content[0].type === "mindmap"``pageSubtree.subtree.nodes[1].metadata.blockType === "mindmap"`
- [x] `GET /documents/{documentId}?workspaceId=...` 对有效导图文档返回 HTML 页面壳,而不是 `documents.content.get 未返回文档内容` 的错误 JSON。
- 2026-05-12 通过:在前台 `mnote-web` 实例上重新创建临时导图文档后复测,返回 `200 text/html; charset=utf-8`,首屏 HTML 正常包含 document shell。
- [x] 3000 文档页默认主链仍为 Leptos/Rust shell,不加载旧 React mindmap 主链。
## 14. 明确延期项
以下能力可参考 KMind,但不进入本 checklist 的完成条件:
- 多根节点。
- MOC 模式。
- 思源块预览、镜像块、PDF 标注跳转。
- Freemind/XMind 全量导入导出。
- 主题设计器与主题分享。
- 完整快捷键自定义配置。
- 演示模式。
- Rust-native renderer。