- 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/ 目录。
17 KiB
17 KiB
前端美化与交互改造设计(2026-08-30)
背景与目标
当前前端(src/genesis/server/static/chat.html,单文件 1215 行内联 CSS+JS)沿用 Material/Google 风
(#1a73e8 蓝、Inter、胶囊按钮、扁平阴影),功能完整但视觉同质化严重,与"概要设计书自动生成
Agent"的项目定位缺少记忆点。
本次迭代在保持现有功能、API 协议、localStorage 键、所有 DOM id 完全不变的前提下,对整套前端 做视觉重塑 + 8 项交互改善,达成:
- 视觉差异化(深色指挥中心 + 文档工作台混合风格,单一青绿强调色)
- 体感现代化(拖拽、多行输入、消息气泡操作、骨架屏、空状态快捷指令)
- 架构可维护(chat.html 拆为 chat.html + chat.css + chat.js,chat_state.js / chat_ws.js 不动)
用户决策(brainstorming 已确认)
| # | 决策项 | 选定 |
|---|---|---|
| 1 | 视觉风格 | 深色指挥中心 + 文档工作台混合 |
| 2 | 强调色 | 青绿 #5EEAD4 |
| 3 | 字体策略 | 系统字体栈(不引入 Google Fonts / JetBrains Mono) |
| 4 | 抽屉遮罩 | backdrop-filter: blur(8px) |
| 5 | 文件拆分 | B2:chat.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)
: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)+ 名字 + chevron,hover 出现 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_collapsedgenesis_sessiongenesis_rag_enabledgenesis_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-activedrop:取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 时右上角浮出
⧉ 复制按钮
- 用户气泡: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>;用户/助手不同
- CSS:
- 复制:用
navigator.clipboard.writeText(text),无 HTTPS 时 fallbackdocument.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 shimmer1.4s 循环(亮色--bg-elevated与--bg-surface交替) - 逻辑:
loadSession()完成后skeleton.remove(),最多 5 秒超时兜底 - 超时处理:
setTimeout(5000)强制 remove 并显示错误提示
4.8 空状态快捷指令
- 位置:
renderEmptyOrWelcome()中,无sid且draftProject已选时 - 内容:欢迎气泡 + 3 个胶囊按钮:
- "上传要件定义"(点击触发
#file-inputclick) - "查看项目状态"(直接
send('现在什么状态?')) - "开始生成概要设计书"(
send('生成概要设计书'))
- "上传要件定义"(点击触发
- 样式:胶囊
--bg-elevated底 + 1px--border-subtle边, hover 出现--accent边 - 不显示:
draftProject为null时(保持现有欢迎语)
五、错误分级样式(4.10)
- 位置:扩展
addMsg(),新增可选level参数:'info' | 'warn' | 'error' - 样式:
info:--info1px 边 +rgba(96,165,250,.12)底warn:--warning1px 边 +rgba(251,191,36,.12)底error:--danger1px 边 +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 覆盖的逻辑,采用:
- 手动回归清单(见
docs/superpowers/specs/2026-08-30-frontend-beautify-checklist.md, 本 spec 不展开) - 截图对比(实施前用浏览器截 5 张关键页面对照,实施后比对)
- 关键流程脚本测试(用户手动跑通):
- 新建会话 → 选项目 → 上传要件 → 发送"生成概要设计书" → 收到下载链接
- 切换项目 → 不匹配徽章出现 → 点击"切到该项目" → 徽章消失
- 拖拽上传 xlsx → 自动选
requirements→ 上传成功 - 输入多行(Shift+Enter)→ 发送(Enter)→ 高度重置
- hover 助手气泡 → 复制 → 粘贴验证
- Esc 关闭抽屉;Cmd+K 打开/关闭项目切换器
- 启动恢复会话时显示骨架屏 → 加载完成消失
八、实施步骤(写作计划阶段会细化)
- 建文件骨架:chat.html 拆分为 chat.html + chat.css + chat.js,机械搬移不改样式
- 写 chat.css 令牌:
:root全部变量 - 重写 chat.css 样式:六大区域按 §二 改造
- chat.js 加 8 项交互:按 §四 / §五 顺序(不依赖外网)
- 本地手动回归:见 §七
- 同步 docs/design.md:新增"前端 UI 设计规范"一节
- 更新 _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)供未来复用