From 2bf9030e7479ad8b49bb3149d4b8ea94af2789e4 Mon Sep 17 00:00:00 2001 From: Zain Date: Fri, 20 Mar 2026 16:57:39 +0800 Subject: [PATCH] docs(spec): add preview panel option a design --- ...026-03-20-preview-panel-option-a-design.md | 244 ++++++++++++++++++ 1 file changed, 244 insertions(+) create mode 100644 docs/superpowers/specs/2026-03-20-preview-panel-option-a-design.md diff --git a/docs/superpowers/specs/2026-03-20-preview-panel-option-a-design.md b/docs/superpowers/specs/2026-03-20-preview-panel-option-a-design.md new file mode 100644 index 0000000..ff38415 --- /dev/null +++ b/docs/superpowers/specs/2026-03-20-preview-panel-option-a-design.md @@ -0,0 +1,244 @@ +# 预览面板 Option A 设计 + +## 背景 +当前预览面板已经具备以下能力: + +- 统计预览项数量、冲突数量与执行状态。 +- 按状态高亮冲突、失败、成功、待执行项目。 +- 在长列表场景下使用虚拟列表优化渲染性能。 + +但当前实现仍有一个明显的确认断点:用户在预览区只能看到**新文件名**,无法直接看到对应的**旧文件名**。这会导致用户在执行前需要依赖记忆完成确认,尤其在以下场景下体验较差: + +1. 文件名格式相近,只靠新名称无法分辨来源。 +2. 剧集提取、正则替换等规则会对多个文件同时生效,用户需要确认映射是否正确。 +3. 冲突和失败项虽然有状态提示,但用户无法第一时间知道“是哪一个原文件会出问题”。 + +与 `docs/renamer.js` 的对比中,这也是最容易被用户感知到的交互差距。因此本次选择采用 **Option A:在不改变整体三栏布局的前提下,为每条预览项补充“旧名 -> 新名”对照信息**。 + +## 目标 + +- 在不重做整体布局的前提下,补齐预览项的“旧名 -> 新名”映射展示。 +- 保持当前三栏布局与信息密度,不引入更重的审阅台模型。 +- 让冲突项、失败项的可理解性提升,不需要用户额外点开详情或回到文件列表反查。 +- 尽量复用现有 `PreviewItem` 数据结构和 `virtual-preview-list` 渲染链路,降低改动面。 + +## 非目标 + +- 不在本次改动中引入单条操作按钮,例如“排除”“仅重试此项”“从此项填充剧名”等。 +- 不将预览区改造成完整的“变更审阅中心”。 +- 不调整当前执行流程、冲突检测流程或批量执行引擎。 +- 不新增新的规则类型或剧集提取逻辑。 + +## 方案对比 + +### 方案 A:双行映射预览(采用) +- 每条预览项显示: + - 第一行:旧文件名 + 当前状态 + - 第二行:新文件名 + 方向箭头 + - 第三行:仅在必要时显示补充说明,例如冲突原因、失败原因或提取结果提示 + +**优点** +- 最大收益来自补足确认链路,而不是重做布局。 +- 可以直接复用当前的 `PreviewItem.file.name` 与 `PreviewItem.newName`。 +- 改动集中在展示层,风险较低。 +- 与现有三栏布局兼容,不会显著压缩左右两栏可用空间。 + +**缺点** +- 单条项目高度会增加,列表可视密度略低于当前实现。 +- 视觉表达力不如更重的“审阅台”方案。 + +### 方案 B:变更审阅视图 +- 每条项目除旧名、新名外,还显式展示规则来源、风险标签、操作建议。 + +**优点** +- 表达力更强,后续可自然承接单条操作入口。 + +**缺点** +- 单项高度更大,长列表滚动负担更高。 +- 需要重新设计预览面板层级,超出本轮“低风险优化”的目标。 + +**采用方案:A。** + +## 交互设计 + +### 1. 面板整体结构 +保留当前右侧预览面板结构: + +1. 标题区 +2. 统计区 +3. 列表区 + +不改变面板层级,只调整列表项视觉结构。 + +### 2. 预览项结构 +每条预览项调整为三层信息: + +#### 第一层:旧文件名 +- 使用较弱的视觉层级展示原文件名。 +- 文本颜色弱于新文件名,但仍需足够可读。 +- 右侧保留状态标签,例如: + - `成功` + - `待执行` + - `冲突` + - `失败` + +#### 第二层:新文件名 +- 使用较强视觉层级展示新文件名。 +- 保持当前预览区域的主阅读焦点。 +- 可在最右侧加入轻量箭头,强调“从旧名映射到新名”。 + +#### 第三层:补充信息 +- 仅在需要时展示,避免噪声。 +- 建议场景: + - 剧集提取成功时:显示提取结果摘要,如 `剧集提取 / 季号 01 / 集号 003` + - 冲突时:显示“与现有文件名重复” + - 失败时:显示可读性更强的原因文案,而不是裸错误码 + +### 3. 状态表达 +保留当前背景色与左侧强调边的状态表达方式: + +- `success`:浅绿色背景 +- `warning/conflict`:浅橙色背景 +- `error`:浅红色背景 +- `pending`:中性背景 + +但状态标签需要从“附属角标”升级为“与旧名同行的信息”,这样用户先看到旧文件,再看到它当前是否有风险。 + +### 4. 长文件名处理 +- 旧文件名与新文件名均保留单行截断。 +- `title` 保持完整名称悬浮提示。 +- 对失败原因仍使用一行或两行受控显示,避免把列表高度拉得过长。 + +### 5. 空状态与加载状态 +沿用当前空状态和 loading 状态,不做额外改动。 + +## 架构与组件设计 + +### 涉及组件 + +- `[src/content/components/preview-panel.ts](/Users/lhly/chromeex/cloud-drive-renamer/src/content/components/preview-panel.ts)` +- `[src/content/components/virtual-preview-list.ts](/Users/lhly/chromeex/cloud-drive-renamer/src/content/components/virtual-preview-list.ts)` +- `[src/types/file-selector.ts](/Users/lhly/chromeex/cloud-drive-renamer/src/types/file-selector.ts)` +- `[src/locales/zh_CN.json](/Users/lhly/chromeex/cloud-drive-renamer/src/locales/zh_CN.json)` +- `[src/locales/zh_TW.json](/Users/lhly/chromeex/cloud-drive-renamer/src/locales/zh_TW.json)` +- `[src/locales/en.json](/Users/lhly/chromeex/cloud-drive-renamer/src/locales/en.json)` + +### 数据结构 +本方案优先不修改 `PreviewItem` 结构,因为现有数据已足够: + +- `item.file.name`:旧文件名 +- `item.newName`:新文件名 +- `item.conflict`:是否冲突 +- `item.done`:是否成功 +- `item.error`:失败原因 + +如需增加更友好的说明文案,优先在展示层通过状态推导生成,不新增持久化字段。 + +### 渲染职责 + +#### `preview-panel` +- 继续负责统计区与外层容器。 +- 不承担单项结构逻辑,避免组件职责继续膨胀。 + +#### `virtual-preview-list` +- 负责预览项的双行映射展示。 +- 继续承担虚拟滚动切换逻辑。 +- 负责把原始状态值转换成最终的显示块结构。 + +## 文案设计 + +### 推荐新增文案键 + +- `preview_old_name` +- `preview_new_name` +- `preview_mapping_arrow` +- `preview_conflict_reason_existing_name` +- `preview_extract_summary` +- `preview_failed_reason_prefix` + +如果实现时认为标签文本过多,也可以不引入“旧名/新名”显式标题,而仅通过层级和箭头表达映射关系,以减少视觉拥挤。 + +### 错误文案策略 +当前失败项可能直接显示错误码,例如 `extract_episode_not_found`。在本方案中建议: + +- UI 层优先转成面向用户的可读文案; +- 保留原始错误码作为 `title` 或调试信息; +- 避免在主列表里直接暴露生硬内部标识。 + +## 数据流 + +### 现有流程 +1. `file-selector-panel` 根据规则生成 `previewList` +2. `preview-panel` 接收 `items` +3. `virtual-preview-list` 渲染每个 `PreviewItem` + +### 方案 A 调整后 +数据流保持不变,仅增强最后一步渲染: + +1. `file-selector-panel` 无需新增字段 +2. `preview-panel` 无需新增协议 +3. `virtual-preview-list` 从 `item.file.name` 和 `item.newName` 生成双行映射视图 + +这意味着本次改动主要是视图层优化,而非状态管理或执行流程改造。 + +## 风险与权衡 + +### 1. 列表可视密度下降 +双行结构会使单项高度增加。考虑到预览区已经支持虚拟列表,这个问题可接受,但需要控制补充信息的默认展示长度。 + +### 2. 样式复杂度提升 +当前预览项样式较简单,双行结构会增加样式层级。需要确保: + +- 状态色仍然清晰; +- 旧名不会抢走新名焦点; +- 不引入与现有主题变量冲突的新颜色体系。 + +### 3. 国际化文案膨胀 +若补充标签过多,会增加 i18n 维护成本。实现时应优先使用结构和层级表达含义,而不是堆更多标题文本。 + +## 测试设计 + +### 1. 组件渲染测试 +针对 `virtual-preview-list` 增加测试,验证: + +- 成功项会同时展示旧名和新名。 +- 冲突项会显示冲突状态和冲突说明。 +- 失败项会显示失败状态和失败说明。 +- `showStatus = false/true` 时状态展示符合预期。 + +### 2. 截断与 title 测试 +验证长文件名情况下: + +- 旧名、新名都不会撑破布局; +- 完整名称仍能通过 `title` 获取。 + +### 3. 视觉回归检查 +建议补一个组件级快照或 Playwright 截图验证,至少覆盖: + +- 普通项 +- 成功项 +- 冲突项 +- 失败项 + +### 4. 虚拟列表兼容性 +确认增加双行结构后,虚拟列表的初始化与刷新逻辑不受影响,尤其是超过 200 条项目时的滚动与渲染稳定性。 + +## 实施建议 + +### 第一阶段 +- 仅修改 `virtual-preview-list` 渲染结构和样式。 +- 保持 `preview-panel` 统计区不变。 +- 保持数据结构不变。 + +### 第二阶段(可选) +- 视实际效果决定是否在补充信息中加入更友好的失败原因翻译。 +- 若用户反馈仍希望进一步增强,可再演进到更强的审阅视图,而不是一次性做重。 + +## 结论 +Option A 是一次典型的“高感知、低侵入”优化: + +- 它不解决所有预览场景问题; +- 但它能直接补足当前最明显的确认断点; +- 且几乎不需要改动执行逻辑、状态管理和数据结构。 + +因此本次建议按 **展示层局部升级** 的方式推进,先把“旧名 -> 新名”的确认能力补齐,再根据真实反馈决定是否继续向更重的审阅模型演进。