Files
2026Technology-Competition/docs/superpowers/specs/2026-08-30-frontend-beautify-design.md
T
lhl b14c2213bc docs(superpowers): 补录前端美化与交互改造的设计规范与实施计划
- docs/superpowers/specs/2026-08-30-frontend-beautify-design.md
  前端美化与交互改造设计(深色指挥中心 + 文档工作台混合风格,
  单一青绿 #5EEAD4 强调色,chat.html 拆为 chat.html + chat.css + chat.js,
  8 项交互改善,用户决策 10 项)
- docs/superpowers/plans/2026-08-30-frontend-beautify.md
  前端美化与交互改造 Implementation Plan(三步走:机械拆分 → 视觉重塑 →
  交互改造,Task 独立 commit,浏览器手测验证)

按项目文档规则存入 docs/superpowers/ 目录。
2026-08-31 22:33:46 +08:00

368 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 前端美化与交互改造设计(2026-08-30)
## 背景与目标
当前前端(`src/genesis/server/static/chat.html`,单文件 1215 行内联 CSS+JS)沿用 Material/Google 风
`#1a73e8` 蓝、Inter、胶囊按钮、扁平阴影),功能完整但视觉同质化严重,与"概要设计书自动生成
Agent"的项目定位缺少记忆点。
本次迭代在**保持现有功能、API 协议、localStorage 键、所有 DOM id 完全不变**的前提下,对整套前端
做视觉重塑 + 8 项交互改善,达成:
1. 视觉差异化(深色指挥中心 + 文档工作台混合风格,单一青绿强调色)
2. 体感现代化(拖拽、多行输入、消息气泡操作、骨架屏、空状态快捷指令)
3. 架构可维护(chat.html 拆为 chat.html + chat.css + chat.jschat_state.js / chat_ws.js 不动)
## 用户决策(brainstorming 已确认)
| # | 决策项 | 选定 |
|---|---|---|
| 1 | 视觉风格 | 深色指挥中心 + 文档工作台混合 |
| 2 | 强调色 | 青绿 `#5EEAD4` |
| 3 | 字体策略 | 系统字体栈(不引入 Google Fonts / JetBrains Mono |
| 4 | 抽屉遮罩 | `backdrop-filter: blur(8px)` |
| 5 | 文件拆分 | B2chat.html 拆为 chat.html + chat.css + chat.js |
| 6 | 交互改造 | 本轮做 8 项(详见 §四) |
| 7 | 快捷键 | 只做 Esc + Cmd/Ctrl+K |
| 8 | 移动端改造 | **不做**(留到下个迭代) |
| 9 | 消息气泡"重新生成" | **不做**(避免触发后端协议变更) |
| 10 | 主题切换 | 单主题(无 dark/light 切换) |
## 范围
### 做
- 视觉重塑(六大区域,颜色 / 字体 / 间距 / 圆角 / 动效)
- chat.html 拆分为 chat.html + chat.css + chat.js
- 8 项交互改善(见 §四)
- 同步 `docs/design.md` 增加"前端 UI 设计规范"一节
- 追加 `_AI_USAGE_LOG.md` 三条记录(设计 / 实现 / 文档同步)
### 不做
- 移动端侧边栏抽屉化(断点 < 768px 的改造)
- 快捷键 `Cmd+Shift+O` / `Cmd+Shift+S`
- 消息气泡"重新生成"按钮
- 主题切换(dark/light
- 后端 API 协议变更
- localStorage / sessionStorage 键重命名
- DOM id 变更
## 架构
### 文件结构(B2 拆分后)
```
src/genesis/server/static/
├── chat.html # 仅 DOM 结构
├── chat.css # 新增:所有视觉样式
├── chat.js # 新增:原 chat.html 中 <script> 段(约 700 行)
├── chat_state.js # 不动
└── chat_ws.js # 不动
```
### chat.html 改动
- 头部:删除 `<link rel="preconnect">` 与 Google Fonts 的 `<link>`
- 头部:新增 `<link rel="stylesheet" href="/chat.css">`
- 头部末尾(`<body>` 之前):保持空白
- 主体:删除第 10-392 行 `<style>...</style>` 整段
- 主体:保留所有 DOM 节点 id(业务逻辑依赖)
- 末尾:删除第 509-1213 行 `<script>...</script>` 整段
- 末尾:新增 `<script src="/chat.js" defer></script>`
- 末尾:保留 `<script src="/chat_state.js">``<script src="/chat_ws.js">` 在 chat.js 之前
### chat.js 改造
- 整体结构保持不变(DOMContentLoaded 后绑定事件 + 启动恢复)
- 新增函数:`groupSessions``bindUploadDrag``attachBubbleOps``autoResizeTextarea`
`renderProjectMismatchBadge``renderSkeleton``renderEmptyQuickActions`
`addInfo``addWarn``bindKeyboardShortcuts`
- 保持函数签名与原内联版本一致(避免 chat_state.js 协议变化)
## 一、设计令牌(chat.css 顶部 `:root`
```css
:root {
/* === 颜色 === */
--bg-base: #0B0F17;
--bg-surface: #141A24;
--bg-elevated: #1B2330;
--bg-input: #0F141C;
--border-subtle: rgba(255, 255, 255, 0.08);
--border-strong: rgba(255, 255, 255, 0.14);
--text-primary: #E5EAF0;
--text-secondary: #8B95A7;
--text-muted: #5C6677;
--accent: #5EEAD4;
--accent-soft: rgba(94, 234, 212, 0.15);
--success: #34D399;
--warning: #FBBF24;
--danger: #F87171;
--info: #60A5FA;
/* === 字体 === */
--font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
"Microsoft YaHei", "Noto Sans CJK SC", system-ui, sans-serif;
--font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
"Liberation Mono", monospace;
/* === 间距 === */
--sp-1: 4px; --sp-2: 8px; --sp-3: 12px;
--sp-4: 16px; --sp-5: 20px; --sp-6: 24px;
/* === 圆角 === */
--r-sm: 6px; --r-md: 10px; --r-lg: 14px;
/* === 动效 === */
--ease: cubic-bezier(.2, 0, 0, 1);
--dur: .18s;
}
```
## 二、各区域视觉规约
### 2.1 侧边栏(`#sidebar`
- 底色 `--bg-surface`,右 1px `--border-subtle`
- 折叠按钮:从右外侧浮出的小竖条,hover 时变 `--accent`**不再旋转 180°**
改为左右 chevron`«` / `»`)切换
- 会话项 hover:背景 `--bg-elevated`,左侧 2px `--accent` 竖条
- 会话项 active:左侧 2px `--accent` 竖条 + 背景 `--bg-elevated`
- 折叠态:去掉头像逻辑,改成 4px 圆点(项目色 hash);折叠态下分组标题 `display:none`
### 2.2 顶栏(`header`
- 底色 `--bg-surface` + `backdrop-filter: blur(12px)` + 1px `--border-subtle` 底边
- 项目切换器:胶囊改为左 6px 圆点(项目色 hash+ 名字 + chevronhover 出现 1px `--accent`
- RAG 胶囊:去掉背景底色,改成 `🔘 0 片段` 风格的等宽小标签
- 已索引:实心圆点 + `--accent` 色 + 等宽数字
- 未索引:空心圆点 + `--text-muted`
- 会话徽标:窄屏下不再 `display:none`,限制 `max-width: 32%` + `text-overflow: ellipsis`
### 2.3 聊天区(`#chat`
- 主区底色 `--bg-base`,内边距 `var(--sp-6)`
- 气泡:去掉阴影,改用 1px 细边 + 内部留白
- **用户消息**`--bg-surface` + 左侧 2px `--accent` 竖条 + 字号 14,行高 1.65
- **助手消息**`--bg-surface` + 1px `--border-subtle` + 顶头 6px 圆点(`--accent` 静态)
- **进度消息**`--bg-input` + dashed 边 `--accent-soft`,等宽字体
- 思考中态:3 个等宽方块循环亮起(替代当前 `思考中…` 文案),用 `--accent`
- 消息出现动画:保留 `zoomIn`,幅度从 0.97 → 0.98
### 2.4 上传条(`#upload-bar`
- 底色 `--bg-surface`,与主区用 1px `--border-subtle` 分隔
- 升级为可拖入区域(详见 §四-2):dragover 时整条出现 dashed `--accent` 边 + `accent-soft` 底色
- select / button 深色样式:底色 `--bg-input`focus 时 `0 0 0 2px var(--accent-soft)`
- 项目提示(`#proj-hint`)改为左侧 4px 三角指示条 + inline note
### 2.5 输入区(`#composer`
- 底色 `--bg-surface`,顶 1px `--border-subtle`
- `<input id="input">` 升级为 `<textarea id="input" rows="1">`(详见 §四-4
- send 按钮:底色 `--accent`,文字 `--bg-base`hover 加 `accent-soft` 外发光
### 2.6 项目抽屉(`#proj-drawer`
- 整体 `--bg-surface`,背后遮罩 `rgba(11,15,23,.6)` + `backdrop-filter: blur(8px)`
- 左侧列表项:active 时左侧 2px `--accent` 竖条 + 背景 `--bg-elevated`
- 表单输入:深色底 `--bg-input`focus 时 `0 0 0 2px var(--accent-soft)`
- 「高级」details 改为纯线框展开,无背景填充
- 关闭按钮:hover 红色描边(保留现有语义)
## 三、关键不变量(兼容性保证)
### 3.1 必须保留的 DOM id(业务逻辑依赖)
```
sidebar, sidebar-toggle, brand-logo, brand-name, new-chat, session-list,
main, rag-bar, rag-enabled, rag-stats, impact-btn, sid-badge,
proj-switcher, ps-current, ps-name, ps-menu, chat, upload-bar, file-type,
file-input, upload-btn, upload-status, proj-hint, composer, input, send,
proj-drawer, drawer-list, drawer-form, drawer-close, pf-name, pf-display,
pf-template, pf-write, pf-rules, pf-code, pf-design, pf-save, pf-delete
```
### 3.2 必须保留的全局符号
- `window.GenesisState`(由 chat_state.js 提供,chat.js 通过回退默认值兜底)
- `window.GenesisWS`(由 chat_ws.js 提供,chat.js 通过 `connectProgressWs` / `applyProgressEvent` 消费)
### 3.3 必须保留的 localStorage / sessionStorage 键
- `genesis_sidebar_collapsed`
- `genesis_session`
- `genesis_rag_enabled`
- `genesis_skipped_project_hint`sessionStorage
新增键(无冲突):
- `genesis_session_group_collapsed`(分组折叠状态,本轮默认全展开,不实际写入)
### 3.4 必须保留的 API 端点
所有 `/api/...` 调用与请求体格式不变。
## 四、交互改造(8 项)
### 4.1 会话列表按时间分组
- **位置**`refreshSessions()` 内,对 `list.sort(...)` 之后插入分组
- **分组规则**:用 `updated_at` 字符串前缀(`YYYY-MM-DD`)与今天/昨天日期比较
- 今天 / 昨天 / 本周(7 天内)/ 本月 / 更早
- **DOM**:在 `.sess` 之间插入 `<div class="sess-group">今天</div>`,样式:
`font-family: var(--font-mono); font-size: 11px; letter-spacing: .1em; color: var(--text-muted)`
- **不影响**:折叠态下分组标题 `display:none`;分组内 `.sess` 仍可正常点击
- **行为**:分组标题不可点击,不参与折叠按钮 toggle
### 4.2 拖拽上传
- **位置**`#upload-bar` 监听 `dragenter / dragover / dragleave / drop`
- **行为**
- `dragover``upload-bar``.drag-active` 类(dashed `--accent` 边 + `accent-soft` 底色)
- `dragleave``upload-bar` 移除 `.drag-active`
- `drop`:取 `e.dataTransfer.files[0]`,写入 `#file-input.files`,并**按后缀自动选 `file-type`**
- `.xlsx``requirements`
- `.docx``template`(缺省兜底)
- `.zip``existing_system`
- **安全**:复用现有 `projectHasPrefixedType``UPLOAD_EXT_RULES` 校验
- **拖入整个文件夹**`webkitGetAsEntry` 拒绝并提示(仅取第一个文件)
### 4.3 消息气泡操作
- **触发**
- **用户气泡**:hover 时右上角浮出 `↺ 引用` 按钮(点击把消息文本填到 `#input` 并 focus
- **助手气泡**:hover 时右上角浮出 `⧉ 复制` 按钮
- **不实现**`↻ 重新生成` 按钮(见 §零-9 决策)
- **实现**
- CSS`.msg { position: relative; } .msg .ops { position: absolute; top: -10px; opacity: 0; ... }`
`:hover .ops { opacity: 1; }`
- JS:扩展 `addMsg()`,内部 appendChild `<div class="ops">...</div>`;用户/助手不同
- **复制**:用 `navigator.clipboard.writeText(text)`,无 HTTPS 时 fallback
`document.execCommand('copy')`(同步临时 textarea
- **不存储历史**:仅影响本次会话 UI
### 4.4 输入区多行 + 自动高度
- **位置**`<input id="input">` 改为 `<textarea id="input" rows="1">`
- **行为**
- `input` 事件:`element.style.height = 'auto'; element.style.height = Math.min(scrollHeight, 160) + 'px'`
- `keydown``Enter`(无 Shift 且无 IME 组合中)= 发送;`Shift+Enter` = 换行
- 发送后自动重置高度为 `auto`(下一帧设回 24px
- **保留**:现有 `maxlength=2000`
- **IME 兼容**keydown 中检查 `e.isComposing`(中文输入法组合中按 Enter 不应发送)
### 4.5 顶栏项目不匹配徽章化
- **位置**:在 `#rag-bar` 之前插入 `<span id="proj-mismatch-badge" hidden>`
- **行为**
- 替代现有 `renderProjectMismatchHint()` 的聊天区插入逻辑
- 徽章样式:黄色 1px 边 `--warning` + 圆角 `--r-md` + `⚠` 前缀 +
"项目: stock ≠ 草稿: foo" 文本
- 点击展开一个迷你 popover(不打开抽屉),提供"切到该项目"和"保留"两个按钮
- "保留"逻辑沿用现有 `sessionStorage` 标记(`genesis_skipped_project_hint`
- **不删除旧函数**:保留 `renderProjectMismatchHint` 但改为只调用新徽章渲染函数
### 4.6 快捷键(仅 2 个)
- **Esc**:已有,扩展为同时关闭项目切换器 + 抽屉 + 移动端侧边栏(本轮不做移动端,等价无变化)
- **Cmd/Ctrl + K**:切换 `#ps-menu`(与点击 `#ps-current` 行为一致),焦点在输入框时也能用
- **实现位置**`document.addEventListener('keydown', ...)`,沿用现有 Escape 监听并扩展
- **可视提示**:项目切换器 hover 时显示 `⌘K`CSS `::after`,仅 mac 显示,win/linux 省略)
### 4.7 骨架屏
- **位置**:启动时(`localStorage``genesis_session` 时)替换
`addMsg('assistant', '正在恢复上次会话…')`
- **样式**:3 条消息形状的占位(圆形 8px + 矩形条 `--bg-surface`),用
`linear-gradient``@keyframes shimmer` 1.4s 循环(亮色 `--bg-elevated`
`--bg-surface` 交替)
- **逻辑**`loadSession()` 完成后 `skeleton.remove()`,最多 5 秒超时兜底
- **超时处理**`setTimeout(5000)` 强制 remove 并显示错误提示
### 4.8 空状态快捷指令
- **位置**`renderEmptyOrWelcome()` 中,无 `sid``draftProject` 已选时
- **内容**:欢迎气泡 + 3 个胶囊按钮:
- "上传要件定义"(点击触发 `#file-input` click
- "查看项目状态"(直接 `send('现在什么状态?')`
- "开始生成概要设计书"(`send('生成概要设计书')`
- **样式**:胶囊 `--bg-elevated` 底 + 1px `--border-subtle` 边,
hover 出现 `--accent`
- **不显示**`draftProject``null` 时(保持现有欢迎语)
## 五、错误分级样式(4.10
- **位置**:扩展 `addMsg()`,新增可选 `level` 参数:`'info' | 'warn' | 'error'`
- **样式**
- `info``--info` 1px 边 + `rgba(96,165,250,.12)`
- `warn``--warning` 1px 边 + `rgba(251,191,36,.12)`
- `error``--danger` 1px 边 + `rgba(248,113,113,.12)`
- **兼容性**:现有所有 `addMsg('error', ...)` 调用不变(默认仍走 error 样式)
- **新增助手函数**`addInfo(text)` / `addWarn(text)`,内部调用 `addMsg('info' / 'warn', text)`
- **本轮替换点**(仅本轮改造涉及的错误,不全量替换):
- 上传类型不匹配 → `addWarn`(客户端校验,非后端失败)
- 项目名不能为空 → `addWarn`(客户端校验)
- 加载会话失败 → `addError`(现有)
- 网络/服务器错误 → `addError`(现有)
## 六、错误处理
| 场景 | 行为 |
|---|---|
| chat.css / chat.js 加载失败(404/网络) | 页面降级显示,肉眼可见(无样式白板)。可在 README 提示开发者 |
| Google Fonts 已无 link,不会再失败 | N/A |
| localStorage 不可用(隐私模式) | 沿用现有 try/catch,输出到 `console.warn` 而非 `addError` |
| 拖拽 API 不可用(旧浏览器) | `if (!('draggable' in document.createElement('div')) return;` 静默退出 |
| IME 中文输入中按 Enter | 走 `e.isComposing` 检查,**不发送**,保持原换行 |
| 快捷键冲突(浏览器原生 Cmd+K) | 始终 `e.preventDefault()`,已知会拦截 Firefox 切搜索栏 |
## 七、测试策略
由于本轮为**纯前端样式与交互改造**,且不新增可被 pytest 覆盖的逻辑,采用:
1. **手动回归清单**(见 `docs/superpowers/specs/2026-08-30-frontend-beautify-checklist.md`
本 spec 不展开)
2. **截图对比**(实施前用浏览器截 5 张关键页面对照,实施后比对)
3. **关键流程脚本测试**(用户手动跑通):
- 新建会话 → 选项目 → 上传要件 → 发送"生成概要设计书" → 收到下载链接
- 切换项目 → 不匹配徽章出现 → 点击"切到该项目" → 徽章消失
- 拖拽上传 xlsx → 自动选 `requirements` → 上传成功
- 输入多行(Shift+Enter)→ 发送(Enter)→ 高度重置
- hover 助手气泡 → 复制 → 粘贴验证
- Esc 关闭抽屉;Cmd+K 打开/关闭项目切换器
- 启动恢复会话时显示骨架屏 → 加载完成消失
## 八、实施步骤(写作计划阶段会细化)
1. **建文件骨架**chat.html 拆分为 chat.html + chat.css + chat.js,机械搬移不改样式
2. **写 chat.css 令牌**`:root` 全部变量
3. **重写 chat.css 样式**:六大区域按 §二 改造
4. **chat.js 加 8 项交互**:按 §四 / §五 顺序(不依赖外网)
5. **本地手动回归**:见 §七
6. **同步 docs/design.md**:新增"前端 UI 设计规范"一节
7. **更新 _AI_USAGE_LOG.md**:三条记录
## 九、风险与回滚
| 风险 | 缓解 |
|---|---|
| 内联 CSS/JS 拆分影响加载顺序 | `<link>``<head>``<script defer>``<body>` 末尾;chat_state.js / chat_ws.js 保持同步加载 |
| 改 class 破坏后端 | 后端不读 class;仅核对 id 列表(§三-1 |
| 系统字体在 win / linux 上回退差异 | 字体栈已含 PingFang / Microsoft YaHei / Noto Sans CJK 兜底 |
| backdrop-filter 性能 | 限定在抽屉遮罩 + 顶栏,不滥用 |
| localStorage 新增键冲突 | 全部以 `genesis_` 前缀 |
| 拖入文件夹行为 | 拒绝并 toast 提示"请拖入单个文件" |
**回滚**`git checkout` 上一版本,删除 `chat.css` / `chat.js` 即可。
## 十、里程碑外(后续)
- 移动端侧边栏抽屉化(< 768px 断点)
- 快捷键 `Cmd+Shift+O`(项目抽屉)/ `Cmd+Shift+S`(侧边栏折叠)
- 消息气泡"重新生成"按钮(需后端协议扩展)
- 深色 / 浅色主题切换
- 国际化(i18n)文案
- 设计系统独立文件(`static/design-tokens.css`)供未来复用