# 4-2 [done] Sidebar / 页面树 / 文件树 产品交互合同 v1 > 更新时间:2026-04-17 > > 关联文档: > - `/mnt/Data1T/mnote/design/04-tree-domain/done/4-sidebar-pagetree-filetree-rust-web-rebuild-v1.md` > - `/mnt/Data1T/mnote/design/old/04-tree-domain/process/4-1-sidebar-pagetree-filetree-product-gap-analysis-v1.md` > - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/reference/1-tree-first-graph-kernel-v1.md` ## 1. 文档目的 这份文档不是继续讨论“是否要做 Rust tree shell”。 这份文档要冻结的是: - 页面树对标 Wolai / Notion 的最小产品交互合同 - 文件树对标 VS Code Explorer 的最小产品交互合同 - 当前旧树已经具备的能力基线 - 新 Rust tree shell 必须补齐的能力矩阵 - 后续 `projection / command / row model / selection model / focus model / keyboard / DnD / context menu` 的最低验收口径 也就是说,这份文档是下一阶段多人并行推进时的共同合同,而不是描述性分析。 --- ## 2. 基本原则 - 页面树 / 文件树都不是事实源,它们都只是 `tree-first graph kernel` 的 projection。 - Sidebar 是壳,不是树真相。 - 新实现不能以“能显示树结构”作为完成标准,而要以“不比旧交互与 UI 差”作为最低标准。 - 文件树与页面树允许在 UI 上不同,但必须共享同一套 projection 与 command 主骨架。 - 所有新增能力都应优先落到可测试的 `row model / selection model / focus model / keyboard / DnD` 层,而不是先堆散落 UI 事件。 --- ## 3. 页面树合同 ### 3.1 对标目标 - 功能对标:Wolai / Notion 页面树 - 视觉与节奏对标:轻量、低干扰、hover 才显动作、不是调试面板 ### 3.2 页面树必须具备的最低能力 - 稳定的页面层级展开 / 折叠 - 当前页高亮与祖先自动展开 - 行级 hover 动作区 - 新建子页面 - 重命名 - 页面移动 - 上下文菜单入口 - 焦点与键盘导航 - 基础拖拽排序 - 搜索过滤后仍保持树层级可理解 ### 3.3 页面树必须保留的旧能力基线 - 右键菜单不是只有重命名/删除,而应保留工作区级高频动作入口 - 页面树不能退化成纯按钮列表 - 大树场景不能因切流而失去稳定滚动体验 - 主树 consumer 不能重新持有第二套结构真相 --- ## 4. 文件树合同 ### 4.1 对标目标 - 功能对标:VS Code Explorer - 视觉密度对标:资源管理器,而不是文档树换皮 ### 4.2 文件树必须具备的最低能力 - 文件树专用 row model - 页面、`index.md`、附件、mindmap 文件夹、导图子附件的复合资源层级 - 单选 - 多选 - Shift 范围选 - 右键菜单入口 - 双击打开资源 - 基础键盘导航 - 目录拖拽骨架 - 外部文件拖入上传骨架 - 资源图标语义 - 资源类型菜单分支 ### 4.3 文件树必须保留的旧能力基线 - 不能退化成“页面树加附件列表” - 不能丢掉多选与范围选 - 不能丢掉资产级操作入口 - 不能丢掉内部拖拽/复制与外部文件拖入的扩展空间 - mindmap 相关资源不能被拍平成普通附件列表 --- ## 5. 统一协议合同 ### 5.1 Projection 合同 所有树 consumer 必须能明确声明自己消费哪一种 projection: - `sidebar_tree` - `page_tree` - `file_tree` 最小字段基线: - `row_id` - `node_id` - `parent_node_id` - `node_type` - `projection_kind` - `depth` - `position` - `title` - `capabilities` - `resource_meta` 文件树扩展字段: - `resource_kind` - `asset_kind` - `icon_hint` - `expandable` - `expanded_by_default` ### 5.2 Command 合同 命令面至少要为后续产品交互预留稳定口径: - `tree.node.create` - `tree.node.rename` - `tree.subtree.move` - `tree.node.archive` - `tree.node.restore` - `tree.asset.attach` - `tree.asset.detach` ### 5.3 本地 UI 状态合同 以下状态不应回流为结构真相,只能留在 UI 本地状态层: - `expanded` - `selected` - `hover` - `focus` - `dragging` - `drop target` --- ## 6. 状态骨架合同 ### 6.1 row model 必须单独存在,不能散落在 renderer 中。 最低要求: - 页面树与文件树都能从 projection 映射到稳定 row model - row model 可以独立测试 - row model 不再重新定义结构真相 ### 6.2 selection model 最低要求: - 单选 - 多选 - Shift 范围选 - 右键选中 - 可见行变化后的选择归一化 ### 6.3 focus model 最低要求: - 当前焦点行稳定可追踪 - 焦点与选中不完全等价 - 页面树与文件树都能共享焦点层定义 ### 6.4 keyboard 最低要求: - 上下导航 - 左右展开/折叠 - Enter 打开 - 文件树预留 copy / paste / delete 的按键入口 ### 6.5 DnD 最低要求: - 页面树支持基础排序/移动 - 文件树支持目录拖放骨架 - 文件树支持外部文件拖入的扩展点 - 非法投放校验必须可测试 ### 6.6 context menu 最低要求: - 页面树与文件树都有统一的 context menu 入口模型 - 菜单本身可按资源类型分支 - shell 与宿主之间要有稳定动作协议,而不是只靠壳内 `prompt/alert` --- ## 7. 当前判定 截至 2026-04-28 final DOM shell 收口后: - `page_tree`:默认主路径已进入 `rust_wasm_dom_shell_host + dom_wasm`,展开/折叠、当前页高亮、祖先展开、行级动作、重命名、移动、上下文菜单、键盘与基础拖拽均由 Rust runtime contract 驱动或回放。 - `picker`:轻量选择器已复用同一 renderer state family,键盘高亮、Enter 选中、根节点与排除项逻辑已进入默认 DOM host。 - `file_tree`:默认主路径已进入 `rust_wasm_dom_shell_host + dom_wasm`,页面、`index.md`、附件、`mindmap` 文件夹、资源图标、单选/多选/范围选、右键、双击打开、内部拖放与外部文件拖入均保留。 本合同的产品交互最低门槛已由 `4-11` 与 `4-18` 收口;剩余 `normalizedMove` fallback、`document.snapshot.saved` 独立事件、`tree.node.embed pageReference` 等属于后续 Page Aggregate / runtime 深层收口,不再阻塞本文。 - `filetree` 模式闭环已由 Rust projection、runtime state family、preflight 与默认 DOM host 共同承接。 - 页面树 / 文件树正式交互合同已固定,并由 `task112/task113` smoke 与组件/Rust 测试覆盖。 - row model / selection model / focus model / keyboard / DnD / context menu 骨架已进入 renderer state family 与 runtime facade。 --- ## 8. 完成判定 只有同时满足下面几条,才可以宣称“新树不比旧交互与 UI 差”: - 页面树满足本合同第 3 节最低能力 - 文件树满足本合同第 4 节最低能力 - projection / command 合同不再漂移 - `row model / selection model / focus model / keyboard / DnD / context menu` 有独立实现与测试 - filetree 不再依赖协议裂缝或壳内临时拼装来维持主路径