diff --git a/CHANGELOG.md b/CHANGELOG.md index 7497295..ae6fd4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ > 所以不是每个版本号都有条目。条目格式 `## <版本> — <日期>`,新条目加在最上面。 > 工程口径的完整记录见 `PROGRESS.md` / git log。 +## 0.60.10 — 2026-07-29 + +- 网页工作台恢复清爽的中性白色配色,助手回复回到左侧阅读轴;手机端进一步缩小顶部页签、操作按钮和输入区,并移除默认的文件保存位置提示,为对话正文留出更多空间。 + ## 0.60.9 — 2026-07-29 - 网页工作台改用更温和的暖白配色,任务与文件列表的分隔更加清楚;助手回复按完整轮次形成统一阅读块,手机端输入区也改为更紧凑的图标操作布局。 diff --git a/PROGRESS.md b/PROGRESS.md index c57047c..7ac37c8 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -2,7 +2,7 @@ > 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查 `git log` / `git diff` / `DESIGN §7.9`。 -最后更新:2026-07-29(Web 工作台视觉复核修正,bump 0.60.9) +最后更新:2026-07-29(Web 工作台移动端空间优化,bump 0.60.10) --- @@ -23,6 +23,7 @@ ### 2026-07-29 +- **07-29 / 0.60.10 / Web 工作台移动端空间优化**:根据第二轮手机实图反馈把暖白/浅米灰改回中性白色,桌面助手回答、工具卡与任务进度恢复左侧阅读轴;手机端压缩顶栏、Tab、任务操作区、模型区、消息间距和 composer,高频操作键由 44px 收至 40px、输入框最低高度由 64px 收至 52px,并隐藏空闲态“请选择文件保存位置/就绪”占位行,运行、上传与错误等有效状态提示继续按需显示。相关 Python 21 项 + Node 5 项及 JS 语法、diff 格式检查通过;无 API、schema、migration 或依赖变化。 - **07-29 / 0.60.9 / Web 工作台视觉复核修正(桌面 + 手机实图)**:据上线截图把冷蓝灰改为暖白/浅米灰;任务与文件行恢复明确分隔,助手消息收进居中 52rem 文档型回答块,工具与进度对齐同一阅读轨道;同时修掉 `task_progress`-only assistant 被过滤工具后仍留下空“助手”壳。手机端 composer 改为独立状态行 + 3 个 44px SVG 图标键 + 发送键,缩短 placeholder、加入安全区并压缩操作/模型区;录音与润色状态改只更新 label/ARIA,不再覆盖 SVG DOM。相关 Python 21 项 + Node 5 项及 JS 语法、HTML/SVG 结构、CSS 括号检查通过;无 API、schema、migration 或依赖变化。 - **07-29 / 0.60.8 / Web 工作台 Visual Polish v1**:新增零构建 `web/static/ui.css` 作为内部轻量视觉基础层,集中颜色、间距、圆角、阴影与 focus/disabled 等控件状态;收敛三栏层级、任务/资源导航、对话正文与工具过程块、输入区、文件栏、modal/toast 及 ≤640px 触控尺寸,不改 DOM 契约、API 或业务交互。新增 CSS 文件接入、MIME 与 `no-cache` 回归测试;相关 Python 20 项 + Node 5 项通过,浏览器连接不可用故截图级视觉验收留真实页面复核。 - **07-29 / 0.60.7 / 组合框内直接新建工作目录**:新对话目录 combobox 增加 allow-create 语义:输入时继续过滤已有目录,无完全同名项时在同一下拉内提供“创建工作目录「名称」”,明确选择后才进入新建状态,失焦搜索词不会误提交;删除外部新建按钮与二级输入框。纯前端改动,无 API、schema、migration 或目录绑定语义变化;全量 387 测试通过(17 项按环境跳过)。 diff --git a/core/__init__.py b/core/__init__.py index a63294f..14b105e 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -1,3 +1,3 @@ # zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。 # 改版本只动这一行。 -__version__ = "0.60.9" +__version__ = "0.60.10" diff --git a/tests/test_static_vendor.py b/tests/test_static_vendor.py index 506fc16..296c1ce 100644 --- a/tests/test_static_vendor.py +++ b/tests/test_static_vendor.py @@ -66,6 +66,8 @@ class StaticVendorTests(unittest.TestCase): self.assertIn('aria-label="润色提示词"', html) self.assertIn("hasVisibleAssistantContent", frontend) self.assertIn('input.placeholder = mqPhone.matches', frontend) + self.assertIn("#chat-hint:empty", css) + self.assertNotIn("请选择文件保存位置", frontend) def test_frontend_surfaces_context_and_cache_stats(self) -> None: src = _frontend_source() diff --git a/web/static/js/chat.js b/web/static/js/chat.js index ea2d9f2..b40eb58 100644 --- a/web/static/js/chat.js +++ b/web/static/js/chat.js @@ -403,7 +403,7 @@ let _draftFolderActiveIndex = -1; function syncDraftAction() { const ready = !!draftWorkingDir(); setActionMode(ready ? "idle" : "loading"); - $("chat-hint").textContent = ready ? "输入消息开始对话" : "请选择文件保存位置"; + $("chat-hint").textContent = ""; const note = $("new-chat-dir-note"); if (note) { note.textContent = ready @@ -685,6 +685,7 @@ export async function selectTask(tid) { renderMessages(state.loadedMessages); // 内部含 renderPersistedRunTerminal(须在 taskMeta 赋值后) renderChatMeta(); applyChannelComposerLock(meta); + $("chat-hint").textContent = ""; if (meta.run_status === "running" || meta.run_status === "cancelling") { ensureRunningTaskSubscribed(tid, `/v1/tasks/${tid}/events`, meta); } else { @@ -2457,7 +2458,7 @@ async function sendMessage(overrideText) { : e.message; appendErrorCard(msg); setActionMode("idle"); - $("chat-hint").textContent = "就绪"; + $("chat-hint").textContent = ""; } } @@ -2556,7 +2557,7 @@ async function fetchSse(url, run) { state.streaming = state.liveRuns.size > 0; syncTaskRowRunIndicator(ctx.taskId); // 先按本地态即时清标识,loadTaskList 随后带回服务端真相(如 error) if (state.taskId === ctx.taskId) { - hint.textContent = ctx.lastUsageHint || "就绪"; + hint.textContent = ctx.lastUsageHint || ""; setActionMode("idle"); } } diff --git a/web/static/ui.css b/web/static/ui.css index 0e67fa1..33cebd9 100644 --- a/web/static/ui.css +++ b/web/static/ui.css @@ -11,16 +11,16 @@ color-scheme: light; /* Neutral workspace palette */ - --bg: #f6f4f1; + --bg: #f7f7f7; --panel: #ffffff; - --panel-subtle: #fbfaf8; - --panel-muted: #f7f4f0; - --border: #e2ddd7; - --border-soft: #ede8e2; - --list-divider: #ddd7d0; - --text: #292623; - --text-strong: #1c1a18; - --muted: #756f69; + --panel-subtle: #fafafa; + --panel-muted: #f5f5f5; + --border: #e1e3e5; + --border-soft: #eceeef; + --list-divider: #d9dde0; + --text: #242424; + --text-strong: #171717; + --muted: #73777c; /* Institute red is deliberately reserved for primary emphasis. */ --accent: #b83a31; @@ -28,9 +28,9 @@ --accent-soft: #fbecea; --accent-ring: rgba(184, 58, 49, 0.16); - --hover: #f5f1ed; - --code-bg: #f6f3ef; - --user-bg: #f5f1eb; + --hover: #f2f3f4; + --code-bg: #f5f5f5; + --user-bg: #f2f6fa; --asst-bg: #ffffff; --c-green: #238653; @@ -98,7 +98,7 @@ button.small { } button:hover:not(:disabled) { - border-color: #cdc5bd; + border-color: #cbd1d6; } button.primary { @@ -137,7 +137,7 @@ select { input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):hover, textarea:hover, select:hover { - border-color: #c9c1b9; + border-color: #c7cdd2; } input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):focus, @@ -149,7 +149,7 @@ select:focus { } ::placeholder { - color: #9b958f; + color: #999fa5; } /* Application shell */ @@ -203,7 +203,7 @@ header .who { } .splitter::before { - background: #d9d3cc; + background: #d7dce0; } .pane-head { @@ -225,7 +225,7 @@ header .who { #task-scroll, #file-list { - scrollbar-color: #cec7bf transparent; + scrollbar-color: #cbd1d6 transparent; scrollbar-width: thin; } @@ -337,8 +337,8 @@ header .who { line-height: 1.7; } -/* Conversation: one centred reading rail, with each assistant turn grouped as - a document block rather than a floating chat label. */ +/* Conversation: one left-anchored reading rail, with each assistant turn grouped + as a document block rather than a floating chat label. */ #chat-meta { min-height: 40px; @@ -369,12 +369,12 @@ header .who { .msg.assistant { width: min(100%, 52rem); max-width: min(100%, 52rem); - align-self: center; + align-self: flex-start; padding: 16px 18px; border: 1px solid var(--border-soft); - border-left: 3px solid #cbc3bb; + border-left: 3px solid #cbd0d4; border-radius: var(--r-lg); - background: #fffdfa; + background: #ffffff; } .msg.assistant.live-run { @@ -401,7 +401,7 @@ header .who { display: flex; align-items: center; gap: 7px; - color: #6d665f; + color: #656b70; } .msg.assistant > .role::before { @@ -417,7 +417,7 @@ header .who { .msg.tool { width: min(100%, 52rem); max-width: min(100%, 52rem); - align-self: center; + align-self: flex-start; padding: 0 18px; border: 0; background: transparent; @@ -430,7 +430,7 @@ header .who { #task-progress-dock .task-progress { width: min(100%, 52rem); max-width: 52rem; - margin: 0 auto; + margin: 0; } .msg .body { @@ -456,7 +456,7 @@ header .who { .tool-call, .reasoning { - color: #5f5851; + color: #555b60; } .tool-call summary, @@ -490,13 +490,17 @@ header .who { padding: 10px 12px; line-height: 1.6; border-radius: var(--r-lg); - background: #fffdfa; + background: #ffffff; } #chat-form .row { align-items: center; } +#chat-hint:empty { + display: none; +} + .composer-spacer { flex: 1; } @@ -538,7 +542,7 @@ header .who { } .file-row .name { - color: #332f2b; + color: #303438; } .storage-foot { @@ -549,7 +553,7 @@ header .who { .storage-foot .bar { height: 5px; - background: #e8e3de; + background: #e5e8ea; } /* Dialogs and notifications */ @@ -612,37 +616,45 @@ header .who { @media (max-width: 640px) { header { - min-height: 46px; - padding: 7px 10px; + min-height: 42px; + padding: 5px 9px; } .pane-head { - min-height: 42px; + min-height: 36px; } .mobile-tabs { - gap: 6px; + gap: 5px; } .mobile-tabs button { - min-height: 38px; - padding: 6px 8px; + min-height: 34px; + padding: 4px 7px; + font-size: 11.5px; + } + + #hd-admin { + padding: 4px 8px; + font-size: 11px; } #pane-mid > .pane-head { - min-height: 38px; - padding: 5px 10px; + min-height: 34px; + padding: 4px 8px; } #pane-mid > .pane-head > button { - min-height: 30px; + min-height: 28px; + padding: 3px 8px; + font-size: 11.5px; } #chat-meta { min-height: auto; - padding: 7px 10px; - column-gap: 7px; - row-gap: 7px; + padding: 5px 8px; + column-gap: 5px; + row-gap: 5px; } #chat-meta > .spacer { @@ -658,15 +670,24 @@ header .who { #chat-meta select { width: 100% !important; max-width: none; + min-height: 30px; + padding: 2px 6px; + font-size: 12px; + } + + #chat-meta button { + min-height: 30px; + padding: 2px 7px; + font-size: 11.5px; } #task-progress-dock { - padding: 6px 10px; + padding: 5px 8px; } #chat-stream { - gap: 14px; - padding: 14px 12px 18px; + gap: 11px; + padding: 10px 10px 12px; } .msg { @@ -676,7 +697,7 @@ header .who { .msg.assistant { width: 100%; max-width: 100%; - padding: 13px 14px; + padding: 10px 12px; } .msg.tool { @@ -691,24 +712,23 @@ header .who { } #chat-form { - padding: 10px; - padding-bottom: calc(10px + env(safe-area-inset-bottom, 0px)); + padding: 8px 9px; + padding-bottom: calc(8px + env(safe-area-inset-bottom, 0px)); } #chat-input { - min-height: 64px; + min-height: 52px; } #chat-form .row { flex-wrap: wrap; justify-content: flex-end; - gap: 8px; + gap: 6px; } #chat-hint { order: -1; flex: 1 0 100%; - min-height: 18px; line-height: 18px; } @@ -717,16 +737,16 @@ header .who { } #chat-form .row .composer-tool { - width: 44px; - min-width: 44px; - height: 44px; - min-height: 44px; + width: 40px; + min-width: 40px; + height: 40px; + min-height: 40px; padding: 0; } .composer-tool svg { - width: 19px; - height: 19px; + width: 18px; + height: 18px; } .composer-tool .composer-label { @@ -742,10 +762,11 @@ header .who { } #chat-action { - width: 72px; - min-width: 72px; - height: 44px; - min-height: 44px; + width: 68px; + min-width: 68px; + height: 40px; + min-height: 40px; + padding: 5px 12px; } .modal {