fix(chat): UI 修复—抽屉+新建项目可见性/标题迁移/折叠按钮不遮挡logo
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
# 聊天前端 UI 修复计划(3 项)
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development or superpowers:executing-plans to implement task-by-task.
|
||||
|
||||
**Goal:** 修复 3 个 UI 问题:(1) 项目管理抽屉内的「+新建项目」入口不可见 → 强化可见性与渲染鲁棒性;(2) 顶栏标题文本迁移到侧边栏品牌名下方;(3) 折叠侧边栏后折叠按钮遮挡 logo。
|
||||
|
||||
**Architecture:** 纯前端改动,仅涉及 `src/genesis/server/static/chat.html`(HTML 结构 + 内嵌 CSS + 内嵌 JS)。无后端、无 schema、无新依赖。
|
||||
|
||||
**Tech Stack:** 原生 HTML/CSS/JS(内嵌于 chat.html,无构建步骤、无前端测试框架);校验用 `node --check` + 浏览器手动核对。
|
||||
|
||||
## 根因说明(问题 1)
|
||||
|
||||
代码层 `renderDrawerList()`(启动与 `openProjectDrawer → loadDrawerForm` 末尾均调用)确实会渲染「+新建项目」首项,且无 CSS 隐藏它、所有 `pf-*` 字段元素齐全。因此「看不到」是**可发现性问题**:该项与普通项目项外观几乎一致、位于左侧窄列易被忽略;同时若将来 `loadDrawerForm` 抛错会跳过 `renderDrawerList`,导致整列空白。
|
||||
|
||||
修复策略:**保留设计已有入口、不另增按钮**(遵循用户「不用再新增」的偏好),仅 (a) 给该项专属样式使其醒目,(b) 加固 `openProjectDrawer` 保证列表必现。
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
- Modify: `src/genesis/server/static/chat.html`
|
||||
- HTML:删除 header `<h1>`;侧边栏 `.brand-name` 增加副标题;抽屉「+新建项目」项加 `di-create` 类。
|
||||
- CSS:新增 `.brand-sub`、`.drawer-item.di-create` 及其 hover;折叠态 `#sidebar-toggle` / `#session-list` 规则。
|
||||
- JS:`renderDrawerList` 首项加 `di-create` 类;`openProjectDrawer` 加固。
|
||||
- Docs: 本计划文档。
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 让「+新建项目」可见且必现
|
||||
|
||||
**Files:** `src/genesis/server/static/chat.html`
|
||||
|
||||
**Interfaces:** Consumes `renderDrawerList`、`openProjectDrawer`、`loadDrawerForm`、`guardDrawerDirty`、`drawerSelected`。
|
||||
**Produces:** 抽屉左侧顶部始终显示一个虚线蓝底、加粗的「+ 新建项目」项;即使 `loadDrawerForm` 异常也不影响该列表渲染。
|
||||
|
||||
- [ ] **Step 1: 写失败验收(手动)**
|
||||
|
||||
浏览器打开(scripts/serve.py --fake)→ 顶栏项目下拉 → 点「+ 项目管理(打开抽屉)」→ 抽屉左侧列表**顶部**应有一个明显区别于项目项的「+ 新建项目」项,点击进入空白新建表单。
|
||||
|
||||
- [ ] **Step 2: 实现 — renderDrawerList 首项加 di-create 类**
|
||||
|
||||
替换(656-658):
|
||||
```javascript
|
||||
let html = '<div class="drawer-item' + (drawerSelected === null ? ' active' : '') + '" data-name="">'
|
||||
+ '<span class="di-new">+</span><span class="di-name">新建项目</span></div>';
|
||||
```
|
||||
为:
|
||||
```javascript
|
||||
let html = '<div class="drawer-item di-create' + (drawerSelected === null ? ' active' : '') + '" data-name="">'
|
||||
+ '<span class="di-new">+</span><span class="di-name">新建项目</span></div>';
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 实现 — openProjectDrawer 加固**
|
||||
|
||||
替换(589-593):
|
||||
```javascript
|
||||
function openProjectDrawer(projectName) {
|
||||
drawerOpen = true;
|
||||
toggleProjectSwitcher(false);
|
||||
drawer.classList.add('open');
|
||||
loadDrawerForm(projectName === undefined ? drawerSelected : projectName);
|
||||
}
|
||||
```
|
||||
为:
|
||||
```javascript
|
||||
function openProjectDrawer(projectName) {
|
||||
drawerOpen = true;
|
||||
toggleProjectSwitcher(false);
|
||||
drawer.classList.add('open');
|
||||
const sel = (projectName === undefined || projectName === null) ? drawerSelected : projectName;
|
||||
try { loadDrawerForm(sel); } catch (e) { console.error(e); }
|
||||
renderDrawerList(); // 始终渲染左侧列表(含 +新建项目)
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 实现 — CSS 强化 di-create**
|
||||
|
||||
在 `.drawer-item .di-new { color: var(--blue); }` 之后插入:
|
||||
```css
|
||||
.drawer-item.di-create {
|
||||
border: 1px dashed var(--blue-100); background: var(--blue-50);
|
||||
color: var(--blue-dark); font-weight: 700; justify-content: center; gap: 4px;
|
||||
}
|
||||
.drawer-item.di-create:hover { background: var(--blue-100); border-color: var(--blue); }
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 校验**
|
||||
|
||||
Run: `node --check`(抽取 <script> 校验语法)
|
||||
浏览器核对 Step 1 验收点。
|
||||
|
||||
- [ ] **Step 6: 提交**
|
||||
|
||||
```bash
|
||||
git add src/genesis/server/static/chat.html
|
||||
git commit -m 'fix(chat): 抽屉 +新建项目 入口强化可见性并加固渲染'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: 标题文本迁移
|
||||
|
||||
**Files:** `src/genesis/server/static/chat.html`
|
||||
|
||||
**Interfaces:** 纯展示层。
|
||||
**Produces:** header 不再显示「Genesis 概要设计书 Agent」;侧边栏 logo 右侧「Genesis」下方显示「概要设计书做成Agent」。
|
||||
|
||||
- [ ] **Step 1: 写失败验收(手动)**
|
||||
|
||||
顶栏左侧不再出现旧标题;侧边栏顶部 logo 下方出现两行文字「Genesis」与「概要设计书做成Agent」。
|
||||
|
||||
- [ ] **Step 2: 实现 — 删除 header h1**
|
||||
|
||||
删除(362):
|
||||
```html
|
||||
<h1>Genesis 概要设计书 Agent</h1>
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 实现 — 品牌名副标题**
|
||||
|
||||
替换(353):
|
||||
```html
|
||||
<div class="brand-name">Genesis</div>
|
||||
```
|
||||
为:
|
||||
```html
|
||||
<div class="brand-name">Genesis<span class="brand-sub">概要设计书做成Agent</span></div>
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 实现 — CSS .brand-sub**
|
||||
|
||||
在 `#sidebar.collapsed .brand-name { display: none; }` 之后插入:
|
||||
```css
|
||||
.brand-sub { display: block; font-size: 11px; font-weight: 600; color: var(--gray-500); margin-top: 2px; letter-spacing: 0; }
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 校验**
|
||||
|
||||
`node --check` + 浏览器核对 Step 1。
|
||||
|
||||
- [ ] **Step 6: 提交**
|
||||
|
||||
```bash
|
||||
git add src/genesis/server/static/chat.html
|
||||
git commit -m 'fix(chat): 标题文本从顶栏迁移至侧边栏品牌名下方'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: 折叠按钮不再遮挡 logo
|
||||
|
||||
**Files:** `src/genesis/server/static/chat.html`
|
||||
|
||||
**Interfaces:** 纯 CSS。
|
||||
**Produces:** 侧边栏折叠态下,折叠按钮移至左下角,与顶部居中的 logo 分离;会话列表底部留白避免压住末项。
|
||||
|
||||
- [ ] **Step 1: 写失败验收(手动)**
|
||||
|
||||
折叠侧边栏:顶部 logo 完整可见,不被折叠按钮遮挡;展开态外观不变。
|
||||
|
||||
- [ ] **Step 2: 实现 — 折叠态定位**
|
||||
|
||||
在 `#sidebar.collapsed { width: 56px; }` 之后插入:
|
||||
```css
|
||||
#sidebar.collapsed #sidebar-toggle { top: auto; bottom: 14px; right: auto; left: 14px; }
|
||||
#sidebar.collapsed #session-list { padding-bottom: 52px; }
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 校验**
|
||||
|
||||
`node --check` + 浏览器核对 Step 1。
|
||||
|
||||
- [ ] **Step 4: 提交**
|
||||
|
||||
```bash
|
||||
git add src/genesis/server/static/chat.html
|
||||
git commit -m 'fix(chat): 折叠态将切换按钮移至左下角避免遮挡 logo'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Self-Review
|
||||
|
||||
- 问题 1 保留设计已有「+新建项目」入口(不新增按钮),仅做可见性强化 + 渲染加固,符合用户偏好。
|
||||
- 问题 2 删除 header h1 并在侧边栏品牌名加副标题;折叠态 `.brand-name{display:none}` 已自动隐藏副标题。
|
||||
- 问题 3 仅改折叠态 CSS,展开态 `right:-14px; top:18px` 不变,logo 在左、按钮在右本不重叠。
|
||||
- 三项均为展示层改动,不影响后端与既有交互逻辑;`node --check` 通过即语法安全。
|
||||
@@ -55,6 +55,8 @@
|
||||
position: relative;
|
||||
}
|
||||
#sidebar.collapsed { width: 56px; }
|
||||
#sidebar.collapsed #sidebar-toggle { top: auto; bottom: 14px; right: auto; left: 14px; }
|
||||
#sidebar.collapsed #session-list { padding-bottom: 52px; }
|
||||
.brand {
|
||||
display: flex; align-items: center; gap: 12px;
|
||||
padding: 16px 12px 12px 16px; margin: 0 8px 8px;
|
||||
@@ -73,6 +75,7 @@
|
||||
.brand:hover .brand-logo { transform: scale(1.1); }
|
||||
.brand-name { font-size: 17px; font-weight: 900; letter-spacing: -.02em; line-height: 1.1; }
|
||||
#sidebar.collapsed .brand-name { display: none; }
|
||||
.brand-sub { display: block; font-size: 11px; font-weight: 600; color: var(--gray-500); margin-top: 2px; letter-spacing: 0; }
|
||||
|
||||
/* 折叠按钮 */
|
||||
#sidebar-toggle {
|
||||
@@ -312,6 +315,11 @@
|
||||
.drawer-item.active { background: #fff; border-color: var(--blue-100); color: var(--blue-dark); font-weight: 700; box-shadow: var(--shadow-1); }
|
||||
.drawer-item .di-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.drawer-item .di-new { color: var(--blue); }
|
||||
.drawer-item.di-create {
|
||||
border: 1px dashed var(--blue-100); background: var(--blue-50);
|
||||
color: var(--blue-dark); font-weight: 700; justify-content: center; gap: 4px;
|
||||
}
|
||||
.drawer-item.di-create:hover { background: var(--blue-100); border-color: var(--blue); }
|
||||
.drawer-form { flex: 1; overflow-y: auto; padding: 16px 20px; display: flex; flex-direction: column; gap: 10px; }
|
||||
.drawer-form label { font-size: 11px; font-weight: 700; color: var(--gray-500); text-transform: uppercase; letter-spacing: .1em; margin-bottom: 2px; display: block; }
|
||||
.drawer-form input {
|
||||
@@ -350,7 +358,7 @@
|
||||
<button id="sidebar-toggle" title="折叠/展开侧边栏">«</button>
|
||||
<div class="brand">
|
||||
<div class="brand-logo">G</div>
|
||||
<div class="brand-name">Genesis</div>
|
||||
<div class="brand-name">Genesis<span class="brand-sub">概要设计书做成Agent</span></div>
|
||||
</div>
|
||||
<button id="new-chat" title="新建会话"><span class="ic-plus">+</span><span class="nc-text">新会话</span></button>
|
||||
<h2>会话历史</h2>
|
||||
@@ -359,7 +367,7 @@
|
||||
|
||||
<div id="main">
|
||||
<header>
|
||||
<h1>Genesis 概要设计书 Agent</h1>
|
||||
|
||||
<div class="proj-switcher" id="proj-switcher">
|
||||
<button class="ps-current" id="ps-current" type="button" title="切换项目">
|
||||
<span class="ps-label">项目</span>
|
||||
@@ -590,7 +598,9 @@ function openProjectDrawer(projectName) {
|
||||
drawerOpen = true;
|
||||
toggleProjectSwitcher(false);
|
||||
drawer.classList.add('open');
|
||||
loadDrawerForm(projectName === undefined ? drawerSelected : projectName);
|
||||
const sel = (projectName === undefined || projectName === null) ? drawerSelected : projectName;
|
||||
try { loadDrawerForm(sel); } catch (e) { console.error(e); }
|
||||
renderDrawerList(); // 始终渲染左侧列表(含 +新建项目)
|
||||
}
|
||||
|
||||
function closeProjectDrawer() {
|
||||
@@ -654,8 +664,8 @@ function guardDrawerDirty() {
|
||||
}
|
||||
|
||||
function renderDrawerList() {
|
||||
let html = '<div class="drawer-item' + (drawerSelected === null ? ' active' : '') + '" data-name="">'
|
||||
+ '<span class="di-new">+</span><span class="di-name">新建项目</span></div>';
|
||||
let html = '<div class="drawer-item di-create' + (drawerSelected === null ? ' active' : '') + '" data-name="">'
|
||||
+ '<span class="di-new">+</span><span class="di-name">新建项目</span></div>';
|
||||
for (const p of projects) {
|
||||
html += '<div class="drawer-item' + (p.name === drawerSelected ? ' active' : '') + '" data-name="' + esc(p.name) + '">'
|
||||
+ '<span class="di-name">' + esc(p.display_name || p.name) + '</span></div>';
|
||||
|
||||
Reference in New Issue
Block a user