Skip to content

Issue 139

clean edited this page Oct 1, 2026 · 1 revision

Issue #139:弹窗系统 UI 落地

背景

弹窗系统 UI 规范 与设计稿已在 Issue #118 中完成,但产品仍直接使用 antd Modal、Popconfirm 与 modal.confirm,各处的层级、按钮文案、焦点与动效都不一致。本 Issue 把规范接入产品,并保留全部业务功能。

目标与范围

  • 按设计稿逐项核对覆盖情况,包括 F01–F13、D01–D10、I01–I05、P01–P06、L01–L05、反馈中心 F01–F03 和 M01/M02 编排时间轴。
  • 统一令牌、Geist 字体、双层外壳、间距、按钮与遮罩。
  • 风险分级 L0 / L1 / L2,危险确认展示「将放弃 / 将保留」清单,单对象操作改为带预检的气泡确认。
  • 适配深浅主题和 ≤560px 窄窗口,统一进入 / 退出动效与减少动效,规范键盘与焦点行为。
  • 不在范围内:后端接口、数据迁移,以及设计稿中展示但后端未提供的数据(见差异)。

方案与取舍

  1. 不引入新组件库。 App.tsx 通过 ConfigProvider 设置全局令牌(--ease-*、--t-*、--tone-*)。AluneModal 用 modalRender 渲染双层外壳 .a-dlg-shell[data-level],样式集中在 dialogs.css。
  2. 用 useAluneConfirm() 替换 modal.confirm。 内容可以带状态,并通过 AluneConfirmControl 控制确认按钮是否可用(分支名冲突即采用这种方式)。
  3. 风险分级:
    • L0:蓝色主按钮,↵ 提交。
    • L1:柔和红色,聚焦主操作。
    • L2:实心红色,role="alertdialog",聚焦取消,禁用 ↵,须勾选「我了解…」才能执行。强制推送还须输入当前分支名。
    • 按钮写明后果,不再使用「确定」。
  4. AlunePopconfirm 统一 P01–P06。 safe / warning / danger 三种语气,打开时聚焦对应控件,Esc 关闭后焦点回到触发元素。移除仓库登记的两个入口合用 RemoveRepositoryConfirm。
  5. 浮层菜单无遮罩。 推送菜单的危险项「强制推送(含租约)…」用省略号提示后面还有一步确认(D03)。
  6. 反馈中心保留原生 <dialog> 与 popover="manual"。 错误逐条显示并带「1 / N」计数,托盘收件箱改为从托盘升起的浮层。打开收件箱不关闭全屏 Diff。
  7. 动效: 进入 alune-dlg-rise 360ms 弹簧,退出 alune-dlg-leave 160ms。data-reduced-motion 开启时只保留 120ms 淡入淡出。≤560px 使用 alune-dlg-sheet 底部抽屉,按钮 44px、纵向排列,并留出安全区。
  8. 防回退: dialog-guard 单测限制 antd Modal / Popconfirm / modal.confirm 只能经封装使用,并禁止弹窗内字段自行处理 ↵。打开本地仓库的路径预检是唯一例外。

覆盖清单

设计稿 产品位置 状态
F01–F13 表单 连接、本地仓库、扫描、分支、名称冲突、储藏、远程、作者、上游、Worktree、令牌、模型、合并 PR/MR 已接入,部分细节见差异
D01–D10 危险确认 放弃所有更改、删除新增文件、强制推送、删除 Worktree、删除令牌 / 模型、代理离开、忽略目录、暂存、关闭 PR/MR 已接入
I01–I05 信息弹窗 改动目录、令牌关联、储藏差异、版本更新、布局设置 已接入;I04 / I05 的组件已迁移,产品中暂无入口
P01–P06 气泡确认 删除分支、合并分支、删除储藏、丢弃单个文件、移除仓库登记、删除连接 已接入
L01–L05 浮层菜单 切换分支、工作区导航、关联 Worktree、通知、推送菜单 / 标签页菜单 已接入;L01 / L03 只调整了间距与宽度
反馈中心 F01–F03 错误详情、仓库说明、托盘与收件箱 已接入
M01 / M02 遮罩 → 外壳 → 头 / 体 / 尾,360ms / 160ms 已接入

与设计稿的差异

后端没有提供的数据,未凭空展示:

  • F03 没有扫描进度,另加了「↵ 扫描」提示。
  • F10 没有「浏览」按钮和基准 SHA。
  • I02 没有「本机 / SSH」标记。
  • I04 没有发布日期,错误标题沿用通用文案。
  • P01 没有「已合并」预检,P02 没有提交数,P03 没有文件数。
  • L04 通知没有时间戳。
  • D04 没有未提交改动预检。

保留产品现有的文案和行为:

  • F01 没有「测试连接」按钮和密码显隐切换。
  • F04 不生成哈希,也不自动把空格替换为短横线。
  • F06 写作「未跟踪项」。
  • F08 作者说明写明 git config --local。
  • F12 / D06 的眉标写作「AI 服务商」。
  • F13 标记为「可合并 / 暂不可合并」。
  • D07 只列出产品实际有的代理字段。

有意的取舍:

  • D05 / D06 没有 L1 标签。
  • D10 使用自定义勾选框。
  • I03 没有 400 行折叠。
  • P02 的提示放在正文中;P01 靠近右边缘时向上翻转。
  • L01 / L03 只调整了间距和宽度,没有加地球图标、aria-current、⌘N,也没有 Worktree 的「未提交 / 锁定」行。
  • L02 多了第 4 项「帮助」。
  • 标签页菜单原本就带计数。
  • LayoutSettings 与 UpdatePanel 的弹窗已迁移,但产品中暂无打开入口。

测试:

  • 设计稿要求 Playwright,这里改用现有的 Electron 冒烟 dialogs-smoke.cjs,在真实渲染进程中验证。

验收标准

  • 全部 antd Modal / Popconfirm / modal.confirm 都经 AluneModal / AlunePopconfirm / useAluneConfirm 使用(dialog-guard 单测)。
  • L0 / L1 / L2 的按钮颜色、默认焦点、↵ 行为与勾选确认符合规范;强制推送须输入分支名。
  • 危险确认展示「将放弃 / 将保留」清单;气泡确认只用于单个对象。
  • 浮层菜单无遮罩;反馈中心逐条显示错误并带「1 / N」,托盘收件箱为浮层。
  • 深浅主题、≤560px 底部抽屉、长内容、加载和错误状态有截图。
  • Esc、焦点约束与恢复、↵ 禁用、360ms / 160ms 动效、减少动效和 390px 底部抽屉:已写入桌面冒烟 dialogs-smoke.cjs,但尚未跑通。它排在反馈冒烟之后,而反馈冒烟开头有一处原有的 document.hasFocus() 等待:本人使用其他应用时,macOS 不允许 Electron 抢占焦点,套件在这一步停止。需在窗口保持前台时复跑。
  • 核心流程回归:npm test -w web 200 项,桌面单元 45 项,冒烟通过至历史视图。

验证记录

环境:macOS 15.5 arm64,Node.js 25.5.0,npm 11.8.0,Electron 44.2.0;截图使用 Ego/Chromium 1280×860 @2x 与 390×760,演示仓库 discard-demo。

检查 结果
npx tsc -p apps/web --noEmit 通过
npm test -w web 200 项通过
npm run build -w web 通过
npm run desktop:build 通过
npm run desktop:test 单元 45 项通过;冒烟在反馈冒烟开头的焦点等待处停止(见验收标准)

截图

表单(F04),深色与浅色:

新建分支表单,深色 新建分支表单,浅色

输入错误(名称已存在)、加载与 Git 失败:

分支名称已存在,浅色 正在创建,取消按钮禁用 反馈中心显示 Git 操作未完成

L2 放弃所有更改(D01),深色与浅色:

放弃所有更改,深色 放弃所有更改,浅色

气泡确认,含长分支名(P01–P03):

删除分支,深色 合并分支,深色 合并分支,浅色 删除储藏,浅色

浮层菜单(L02、L05、标签页菜单):

工作区导航,深色 推送菜单,深色 标签页菜单,浅色

390px 窄窗口,工作区与 L2 底部抽屉:

390px 工作区 390px 放弃所有更改底部抽屉

风险与回退

  • 没有数据迁移,也没有后端协议变更。
  • 新增依赖:Geist / Geist Mono 字体(许可证位于 apps/web/public/licenses)和 @rc-component/motion。
  • 回退 PR 即可恢复原弹窗。
  • 未验证:Windows / Linux 原生窗口、真实读屏软件。
  • 原有问题:反馈托盘会遮住提交按钮,development 上相同,不属于本次范围,已另行跟踪。

Clone this wiki locally