diff --git a/docs/superpowers/specs/2026-08-31-close-preview-tab-on-middle-click-design.md b/docs/superpowers/specs/2026-08-31-close-preview-tab-on-middle-click-design.md new file mode 100644 index 00000000..b07f6f58 --- /dev/null +++ b/docs/superpowers/specs/2026-08-31-close-preview-tab-on-middle-click-design.md @@ -0,0 +1,141 @@ +# 预览标签页「中键按下关闭」需求与设计 + +- 日期:2026-08-31 +- 状态:需求澄清完成,已实现 +- 分类:Bounded(前端单点改动,复用现有关闭链路) +- 决策轮次:经两轮澄清,最终决策见下(第二轮推翻第一轮的 mousedown/开关选择) + +## 1. 背景与动机 + +ACECode 桌面端的「工作区」里,文档、浏览器、变更等预览内容以**标签页(preview tab)**形式呈现在预览面板(PreviewDetailsPanel)的标签条上。当前关闭一个标签页只有两种方式: + +1. 点击标签右侧的小 ✕ 关闭按钮; +2. 右键标签 → 上下文菜单(关闭 / 关闭其他 / 关闭右侧 / 关闭全部)。 + +用户希望增加一种更快的关闭手势:**把鼠标指针移到某个标签页上,按下鼠标滚轮(中键 / middle button)即关闭该标签页**——与 Chrome、VS Code 的中键关页行为一致。中键无需瞄准小 ✕,能显著提升多标签浏览时的关闭效率。 + +## 2. 目标 + +在工作区的预览面板标签条上,支持「中键按下即关闭对应标签页」,并满足以下约束: + +- 仅在预览面板标签(文档 / 浏览器 / 变更类)生效; +- 遇到有未保存草稿的文档标签时,走现有的「确认 / 保存后关闭」流程,不静默丢失内容; +- 功能默认开启,**不提供设置开关**(对齐 VS Code / Chrome / 终端模拟器默认行为); +- 改动集中在前端,不重写已有的纯函数关闭逻辑。 + +## 3. 范围 + +### In Scope + +- 预览面板标签条上的四类标签: + - `FILE`(文档) + - `BROWSER`(浏览器) + - `SESSION_CHANGES`(会话变更) + - `GIT_CHANGES`(git 变更) +- 中键(鼠标滚轮按下,`button === 1`)在标签元素上的关闭手势,通过 `auxclick` 事件触发。 +- 中键 `mousedown` 时的自动滚动光标抑制(`preventDefault`)。 + +### Out of Scope + +- 顶部会话标签、侧边栏等非预览面板的标签条(本期不做)。 +- 滚轮「滚动」手势(上下滚动触发关闭)或「长按滚轮」——本期只做「按下」即关。 +- 非预览区域的全局中键行为(如中键在新标签打开链接)。 +- 设置开关:明确不做,功能始终开启。 + +## 4. 功能需求(FR) + +- **FR-1** 当鼠标指针位于某个预览标签页元素上,且按下中键(`event.button === 1`)并在抬起后产生 `auxclick` 事件时,关闭该标签页。 +- **FR-2** 中键关闭必须复用现有的关闭入口 `onCloseTab`(ChatView 中即 `closePreview`),从而自动继承其「未保存草稿 → 弹确认框」逻辑。 +- **FR-3** 中键 `mousedown` 时调用 `event.preventDefault()`,阻止浏览器默认的中键「自动滚动」四向箭头光标出现(该抑制仅挡默认行为,不影响后续 `auxclick` 派发)。 +- **FR-4** 功能始终开启,不提供设置开关。 +- **FR-5** 关闭行为无额外视觉动画,与点击 ✕ 一致(标签从列表瞬间移除)。 + +## 5. 设计与实现要点 + +### 5.1 改动文件 + +唯一改动文件:`web/src/components/PreviewDetailsPanel.jsx` + +标签条渲染位于该组件的 `tabs.map(...)` 内,每个标签是一个 +`