Add context menus to task and file lists
This commit is contained in:
parent
bcdbdd4738
commit
61648f1114
|
|
@ -5,6 +5,10 @@
|
|||
> 所以不是每个版本号都有条目。条目格式 `## <版本> — <日期>`,新条目加在最上面。
|
||||
> 工程口径的完整记录见 `PROGRESS.md` / git log。
|
||||
|
||||
## 0.60.12 — 2026-07-29
|
||||
|
||||
- 任务列表以及文件、文件夹列表现在支持右键操作,可在鼠标位置直接打开与「⋯」按钮一致的菜单;菜单靠近屏幕边缘时会自动调整位置。
|
||||
|
||||
## 0.60.11 — 2026-07-29
|
||||
|
||||
- 网页工作台进一步回归清爽白色界面:助手回复改为开放式文档流,工具调用与结果合并成可展开的紧凑活动项;同时修复语音输入停止后按钮仍显示“停止”的问题。
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
> 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查 `git log` / `git diff` / `DESIGN §7.9`。
|
||||
|
||||
最后更新:2026-07-29(Web 对话流去卡片化,bump 0.60.11)
|
||||
最后更新:2026-07-29(任务与文件列表右键菜单,bump 0.60.12)
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
### 2026-07-29
|
||||
|
||||
- **07-29 / 0.60.12 / 任务与文件列表右键菜单**:任务行、文件行和目录行增加原生 `contextmenu` 入口,直接复用既有 `taskMenuItems` / `fileMenuItems`,因此与「⋯」按钮保持相同权限、状态禁用、确认弹框和后端调用;单例浮层菜单增加按鼠标坐标定位及视口双向钳制,右键任务不切换当前会话、右键文件不触发打开。纯前端加法,无 API、schema、migration 或依赖变化;3 个 JS 文件语法及 diff 格式检查通过,浏览器实例不可用故真实鼠标回放留页面复核。
|
||||
- **07-29 / 0.60.11 / Web 对话流去卡片化 + 工具活动合并 + 语音状态修复**:工作台背景统一以纯白为主,浅灰仅保留在 hover、代码块等局部状态;助手历史/实时回复移除重复角色标签、大卡片边框、左色条与运行态红框,改为左锚开放文档流。历史态按 `tool_call_id` 将 assistant 调用与 tool result 合并,实时态复用同一 details 原位更新结果,统一为默认折叠单行活动项(执行中/成功/失败状态明确),产物 chip、媒体 banner 与后台进程活化继续保留;顶部 task progress dock 的位置和逻辑未改。另修短按语音转连续录音时直接覆写按钮 `textContent`、销毁 SVG/label 导致停止后无法恢复“语音”的问题,收口为 class/label/ARIA 状态函数。相关 Python 24 项 + Node 5 项及 JS 语法、diff 格式检查通过;无 API、schema、migration 或依赖变化。
|
||||
- **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 或依赖变化。
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。
|
||||
# 改版本只动这一行。
|
||||
__version__ = "0.60.11"
|
||||
__version__ = "0.60.12"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
// 各入口模块顶层自绑;对外导出 loadTaskList / loadModels / selectTask
|
||||
// (供 main enterApp、embed、files、newtask)。
|
||||
import { state, LS_TASK_FILTERS_COLLAPSED } from "./state.js";
|
||||
import { $, showMenu } from "./dom.js";
|
||||
import { $, showMenu, showMenuAtPoint } from "./dom.js";
|
||||
import { api } from "./api.js";
|
||||
import { escapeHtml, fmtTime, fmtTokens, fmtTimeAgo, taskUsageTooltip, formatTaskUsage, formatContextStats, formatUsageStats, ctxRingHtml } from "./format.js";
|
||||
import { renderMd, highlightIn } from "./markdown.js";
|
||||
|
|
@ -238,6 +238,12 @@ function renderTaskList(tasks, append = false) {
|
|||
if (e.target.closest(".dd-toggle")) return; // 菜单按钮点击不触发选中
|
||||
selectTask(el.dataset.tid);
|
||||
};
|
||||
el.oncontextmenu = (e) => {
|
||||
e.preventDefault();
|
||||
const t = state.tasksById[el.dataset.tid];
|
||||
if (!t) return;
|
||||
showMenuAtPoint(e.clientX, e.clientY, taskMenuItems(t));
|
||||
};
|
||||
const btn = el.querySelector(".task-menu");
|
||||
if (btn) {
|
||||
btn.onclick = (e) => {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ export const $ = (id) => document.getElementById(id);
|
|||
// ───── floating dropdown menu (single instance) ─────
|
||||
// 用 position: fixed 单例避免被 pane overflow 裁剪;按位置算出右上角对齐
|
||||
let _menuItems = null;
|
||||
export function showMenu(triggerEl, items) {
|
||||
function renderMenu(items) {
|
||||
_menuItems = items;
|
||||
const menu = $("floating-menu");
|
||||
menu.innerHTML = items.map((it) => {
|
||||
|
|
@ -23,6 +23,20 @@ export function showMenu(triggerEl, items) {
|
|||
if (item && item.onclick) item.onclick();
|
||||
};
|
||||
});
|
||||
return menu;
|
||||
}
|
||||
|
||||
function clampMenuPosition(menu, left, top) {
|
||||
const mh = menu.offsetHeight || 120;
|
||||
const mw = menu.offsetWidth || 132;
|
||||
menu.style.left = Math.max(4, Math.min(left, window.innerWidth - mw - 4)) + "px";
|
||||
menu.style.right = "auto";
|
||||
menu.style.top = Math.max(4, Math.min(top, window.innerHeight - mh - 4)) + "px";
|
||||
menu.style.visibility = "";
|
||||
}
|
||||
|
||||
export function showMenu(triggerEl, items) {
|
||||
const menu = renderMenu(items);
|
||||
// 默认右下展开;若空间不足则改向上
|
||||
const rect = triggerEl.getBoundingClientRect();
|
||||
menu.style.visibility = "hidden";
|
||||
|
|
@ -45,6 +59,15 @@ export function showMenu(triggerEl, items) {
|
|||
}
|
||||
menu.style.visibility = "";
|
||||
}
|
||||
|
||||
// 右键菜单按指针位置展开;靠近视口边缘时向内收,避免操作项被裁掉。
|
||||
export function showMenuAtPoint(clientX, clientY, items) {
|
||||
const menu = renderMenu(items);
|
||||
menu.style.visibility = "hidden";
|
||||
menu.classList.add("show");
|
||||
clampMenuPosition(menu, clientX, clientY);
|
||||
}
|
||||
|
||||
export function hideMenu() {
|
||||
_menuItems = null;
|
||||
$("floating-menu").classList.remove("show");
|
||||
|
|
@ -54,6 +77,8 @@ document.addEventListener("click", (e) => {
|
|||
if (e.target.closest("#floating-menu")) return;
|
||||
hideMenu();
|
||||
}, true);
|
||||
// 在非自定义菜单区域右键时,先收掉可能残留的浮层;列表行的冒泡处理随后会重新打开。
|
||||
document.addEventListener("contextmenu", hideMenu, true);
|
||||
window.addEventListener("resize", hideMenu);
|
||||
// 滚动 pane 时菜单位置失效,直接关
|
||||
document.addEventListener("scroll", hideMenu, true);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
// 反向依赖:openFilePreview(preview)、logout(auth)、以及 main 的 glue
|
||||
// downloadFile / selectTask / loadTaskList / loadFolderSuggestions(后续随 media/tasks/newtask 模块化再迁)。
|
||||
import { state } from "./state.js";
|
||||
import { $, showMenu } from "./dom.js";
|
||||
import { $, showMenu, showMenuAtPoint } from "./dom.js";
|
||||
import { api } from "./api.js";
|
||||
import { escapeHtml, humanSize } from "./format.js";
|
||||
import { openFilePreview } from "./preview.js";
|
||||
|
|
@ -267,6 +267,14 @@ function renderFiles(data) {
|
|||
showMenu(btn, fileMenuItems(e));
|
||||
};
|
||||
});
|
||||
$("file-list").querySelectorAll(".file-row").forEach((row) => {
|
||||
row.oncontextmenu = (ev) => {
|
||||
ev.preventDefault();
|
||||
const e = state.entriesByRel[row.dataset.rel];
|
||||
if (!e) return;
|
||||
showMenuAtPoint(ev.clientX, ev.clientY, fileMenuItems(e));
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function fileMenuItems(e) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue