# 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 简化 body；KMind/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 node，readonly 下仍可使用。
- [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、minimap；count 可保留或按 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 actions，root 节点 `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 6：chrome hide/click restore。
5. Task 7-9：右侧详细设置栏与持久化。
6. Task 10：navigator 图标化。
7. Task 11：context menu。
8. Task 12：视觉主题与连线对齐。
9. Task 13-14：smoke 与回归。

每次实现完成后，至少保存对应截图，再勾选节点。

## 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。
