feat(web): 左栏筛选区可折叠(默认展开,偏好持久化)+ bump 0.12.3

- 搜索/状态/目录/排序四控件归到两行 .task-filter-row,标题行加「筛选 ▾」toggle
- 默认展开,折叠只藏 UI(已选条件仍生效),偏好存 localStorage(同 pane 折叠范式)
- 折叠后左栏顶部 4 行→2 行,任务列表可视区更高
- 状态下拉并入筛选区(flex),搜索框 flex:2 更宽;目录/排序合一行用 title 提示

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
caoqianming 2026-06-13 12:58:33 +08:00
parent ae9790601a
commit 18f702886f
5 changed files with 38 additions and 15 deletions

View File

@ -21,6 +21,12 @@
## 已完成关键能力
### 2026-06-13 / 左栏筛选区可折叠(默认展开)
- 左栏顶部原 4 行固定头把任务列表压矮。把搜索/状态/目录/排序四个筛选控件归到两行 `.task-filter-row`,标题行加「筛选 ▾」toggle:**默认展开**,点击折叠只藏 UI(已选条件仍生效),偏好存 `localStorage`(`zcbot.task-filters-collapsed`),与 pane 折叠同套范式。折叠后左栏顶部从 4 行降到 2 行(标题 + 新建),列表可视区更高。
- 顺手把状态下拉从标题行并入筛选区(原 `width:auto` → flex),搜索框给 `flex:2` 更宽;目录/排序合一行,去掉独立"排序"文字标签改 `title` 提示。
- 改动文件:`dev.html`(markup + CSS)、`chat.js`(toggle 接线 + 复用 LS 范式)、`state.js`(新增 LS key)。bump 0.12.2 → 0.12.3。
### 2026-06-13 / 前端 UI 优化:中栏操作收菜单 + 阅读限宽 + 色彩收敛
- **中栏顶栏 5 按钮 → 「完成」+「⋯」菜单**:原导出/清空/完成/废弃/删除 平铺,与任务行的 `⋯` 浮层菜单两套范式打架,且破坏性操作(废弃/删除)平铺易误点、移动端挤。改为只留高频「完成」+ 一个 `⋯`,菜单复用 `taskMenuItems`(过滤掉 complete);单一事实源,两处共用。顺带把「清空」在菜单里按 `run_status` 也禁用(taskMeta 带该字段,修了之前菜单清空运行中会 409-after-confirm 的小坑)。

View File

@ -1,3 +1,3 @@
# zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。
# 改版本只动这一行。
__version__ = "0.12.2"
__version__ = "0.12.3"

View File

@ -413,6 +413,10 @@
background: #fff;
border-bottom: 1px solid var(--border-soft);
}
/* 筛选区折叠(默认展开):body.task-filters-collapsed 时藏起搜索/状态/目录/排序两行 */
body.task-filters-collapsed .task-filter-row { display: none; }
#filter-toggle { white-space: nowrap; flex-shrink: 0; }
body.task-filters-collapsed #filter-toggle { color: var(--accent); border-color: var(--accent-soft); background: var(--accent-soft); }
/* 对话顶栏只剩「完成」(绿)+「⋯」菜单;其余操作收进浮层菜单按语义色(见 .dd-item.act-*)。
file-picker 的 sp-copy/sp-move 仍复用蓝/橙。 */
#btn-done:hover:not(:disabled) { color: var(--c-green); border-color: var(--c-green-bd); background: var(--c-green-bg); }
@ -1188,27 +1192,27 @@
<span class="label">任务</span>
<span class="small muted" id="task-count" style="font-size:11px;"></span>
<span class="spacer"></span>
<select id="filter-status" class="small" style="width: auto;">
<option value="">(全部)</option>
<option value="active">进行中</option>
<option value="completed">已完成</option>
<option value="abandoned">已废弃</option>
</select>
<button id="filter-toggle" class="small" title="展开/收起筛选">筛选 ▾</button>
<button id="btn-refresh-tasks" class="small" title="刷新"></button>
<button id="pane-toggle-left" class="small" title="折叠任务列表"></button>
</div>
<div class="pane-head">
<button id="hd-new" class="primary" style="flex:1;">+ 新建任务</button>
</div>
<div class="pane-head" style="gap: 6px;">
<input id="filter-q" class="small" placeholder="搜索名称/描述..." style="flex:1; padding: 3px 6px;" />
<select id="filter-wd" class="small" style="flex:1; padding: 3px 6px;">
<option value="">(全部目录)</option>
<div class="pane-head task-filter-row" style="gap: 6px;">
<input id="filter-q" class="small" placeholder="搜索名称/描述..." style="flex:2; padding: 3px 6px;" />
<select id="filter-status" class="small" style="flex:1; width:auto;" title="按状态筛选">
<option value="">(全部)</option>
<option value="active">进行中</option>
<option value="completed">已完成</option>
<option value="abandoned">已废弃</option>
</select>
</div>
<div class="pane-head" style="gap: 6px;">
<span class="small muted" style="white-space:nowrap;">排序</span>
<select id="filter-order" class="small" style="flex:1; width:auto;">
<div class="pane-head task-filter-row" style="gap: 6px;">
<select id="filter-wd" class="small" style="flex:1; padding: 3px 6px;" title="按工作目录筛选">
<option value="">(全部目录)</option>
</select>
<select id="filter-order" class="small" style="flex:1; width:auto;" title="排序方式">
<option value="-created_at">创建时间 ↓(新→旧)</option>
<option value="created_at">创建时间 ↑(旧→新)</option>
<option value="-updated_at">更新时间 ↓</option>

View File

@ -4,7 +4,7 @@
// 润色/粘贴文件、完成/废弃/删除/导出/清空。共享 state.liveRuns + chat-stream DOM。
// 各入口模块顶层自绑;对外导出 loadTaskList / loadModels / selectTask
// (供 main enterApp、embed、files、newtask)。
import { state } from "./state.js";
import { state, LS_TASK_FILTERS_COLLAPSED } from "./state.js";
import { $, showMenu } from "./dom.js";
import { api } from "./api.js";
import { escapeHtml, fmtTime, fmtTokens, fmtTimeAgo, taskUsageTooltip, formatTaskUsage, formatContextStats, formatUsageStats } from "./format.js";
@ -196,6 +196,18 @@ $("filter-order").onchange = () => loadTaskList();
$("filter-wd").onchange = () => loadTaskList(); // select 选完立即筛
$("btn-refresh-tasks").onclick = () => loadTaskList();
// 筛选区折叠(默认展开;偏好持久化)。折叠只藏 UI,已选中的筛选条件仍生效。
function applyTaskFiltersCollapsed(collapsed) {
document.body.classList.toggle("task-filters-collapsed", collapsed);
$("filter-toggle").textContent = collapsed ? "筛选 ▸" : "筛选 ▾";
}
$("filter-toggle").onclick = () => {
const next = !document.body.classList.contains("task-filters-collapsed");
localStorage.setItem(LS_TASK_FILTERS_COLLAPSED, next ? "1" : "");
applyTaskFiltersCollapsed(next);
};
applyTaskFiltersCollapsed(localStorage.getItem(LS_TASK_FILTERS_COLLAPSED) === "1");
// 搜索 q 是 text input → 300ms debounce 避免每字符打 API
let _filterDebounce = null;
$("filter-q").addEventListener("input", () => {

View File

@ -8,6 +8,7 @@ export const LS_LEFT_COLLAPSED = "zcbot.left-collapsed";
export const LS_RIGHT_COLLAPSED = "zcbot.right-collapsed";
export const LS_LEFT_WIDTH = "zcbot.left-width";
export const LS_RIGHT_WIDTH = "zcbot.right-width";
export const LS_TASK_FILTERS_COLLAPSED = "zcbot.task-filters-collapsed"; // 左栏筛选区折叠偏好(默认展开)
// ?embed=1&parent_origin=https://... → iframe 模式;父页面用 postMessage 推 token
// 可选 task_id=<uuid>:首次签发 token 后自动定位到该 task 并加载消息