diff --git a/PROGRESS.md b/PROGRESS.md index 90752aa..f061375 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -2,7 +2,7 @@ > 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查 `git log` / `git diff` / `DESIGN §7.9`。 -最后更新:2026-05-21(system prompt 注入 task 预选 skill 提示) +最后更新:2026-05-21(dev.html CSS 精简 + 圆角降档 + modal 基类化) --- @@ -23,6 +23,7 @@ ### 2026-05-21 +- **dev.html CSS 精简 + 圆角降档 + modal 基类化(style 块 589 → 522 行,-11%)**:为了"没那么圆润"统一调整。引入 CSS tokens:① 语义色组 `--c-green/blue/purple/orange/red` + 同色 `-bg/-bd` 三件套,顶栏 5 个按钮 hover + dd-item + badge.completed + sp-copy/sp-move 全切到 token(同色 selector 合并:export ≈ sp-copy 蓝、abandon ≈ sp-move 橙,各省 1 条规则);② 圆角分档 `--r-sm/md/lg/xl` = 3/4/6/8px,主流 button/input/msg/menu 从 6px 降到 4px,modal card 从 8~12px 降到 6~8px,art-chip 999px 保留(胶囊语言);③ `--mono`/`--t`/`--shadow-card` 收敛重复 font-family/transition/box-shadow。④ 4 个 modal(`#admin-modal/#src-picker-modal/#new-task-modal/#file-preview-modal`)抽 `.modal` 基类(fixed/inset/bg/display/.show 五属性合并),id 选择器只留 z-index + 宽高差异;HTML 同步加 `class="modal"`(JS `classList.add("show")` 不动)。⑤ `.msg .body` 与 file-preview `.md-render` 合并 markdown 渲染规则(`.msg .body x, .md-render x { ... }`,从两套 17 条缩到一套 17 条多 selector)。⑥ `button:disabled` 全局兜底,删散落 2 处单独写;`#login input:focus` 与 `#admin-modal input:focus` 合并(规则一字不差)。`.dev-item.act-export/rename` 同色合并到一行。功能 0 改动,JS 完全不动;`.dd-item` 颜色微变(原 #2e7d32 → #27ae60 等,因为统一到 5 组色 token)是可接受的副作用。 - **工作目录回到原生 ``,首项 `(全部目录)`,onchange → `loadTaskList`;原 input 的 debounce listener 删,搜索 `filter-q` 的 debounce 保留独立写。③ `loadFolderSuggestions` 拉数据 + 新增 `populateFolderSelects` 灌两个 select(保留当前选中值);`enterApp` 启动时 fire-and-forget 预拉一次让左 pane 一打开就有选项。④ hint 在"输入新名恰好命中已有"时提示"将复用而非新建"。combobox 工厂 + .combo CSS + datalist 残留全删。 - **新建任务弹窗工作目录改 combobox + name 联动**:`web/static/dev.html` modal 里 `nt-wd-sel` 从 ``,删 `+ 新建目录…` sentinel + 二级 `nt-wd-new` 输入框;加 `wdManuallyEdited` flag —— name 输入时若 flag=false 自动同步到 wd(programmatic 改 value 不触发 wd input 事件不会假阳性),wd 非空输入置 flag=true 脱钩,wd 清空重置 flag=false 但保持空(避免 backspace 想换名字时被立刻填回打断);submit 保留 `working_dir || name` fallback 兜底空值。`loadFolderSuggestions` 不再渲染 select options,只灌共享 datalist + 缓存到 `state.folders` 供 hint 比对"命中已有/新建"。label 文案 `(可选,留空 → 用任务名...)` → `(默认跟随任务名;可输入新名或选已有目录复用)`,更直观。 - **system prompt 注入 task 预选 skill 提示**:`core/agent_builder.py::_build_system_prompt` 加 `task_skill` 参数,非空时在"工作目录与 task 上下文"段加一行 `- **task 预选 skill**: \`\` — 用户创建时声明的主 skill`;空字符串走老路径,prompt 字节级一致。LLM 拿到这条事实 + `general_v1.md:17-23` 已有的"对应 skill 领域先 load_skill" 规则自然组合 → 主动 load。否决"直接把完整 SKILL.md 预注入 prompt"方案 —— 那会把 `tasks.skill` 从 metadata 升格成 binding,需要同步改 DESIGN.md / 想清楚 PATCH 改 skill 的语义,投入产出比不划算;轻量提示保渐进披露三层架构不动。 diff --git a/web/static/dev.html b/web/static/dev.html index 94f6b79..03672ac 100644 --- a/web/static/dev.html +++ b/web/static/dev.html @@ -25,6 +25,21 @@ --code-bg: #f4f4f4; --user-bg: #eef4fb; --asst-bg: #ffffff; + /* 语义色组:done/export/clear/abandon/delete 按钮 + dd-item + badge 共用 */ + --c-green: #27ae60; --c-green-bg: #e9f7ef; --c-green-bd: #a9dfbf; + --c-blue: #2980b9; --c-blue-bg: #ebf5fb; --c-blue-bd: #aed6f1; + --c-purple: #8e44ad; --c-purple-bg: #f5eef8; --c-purple-bd: #d2b4de; + --c-orange: #e67e22; --c-orange-bg: #fef5e7; --c-orange-bd: #f5cba7; + --c-red: #c0392b; --c-red-bg: #fdedec; --c-red-bd: #f5b7b1; + /* 圆角:各档下调一档(没那么圆润) */ + --r-sm: 3px; /* code / 小标签 */ + --r-md: 4px; /* button / input / 消息气泡 / 卡片元素 */ + --r-lg: 6px; /* modal card / 中型容器 */ + --r-xl: 8px; /* 大 modal card(登录卡) */ + --shadow-card: 0 12px 32px rgba(0,0,0,.18); + --shadow-card-lg: 0 20px 60px rgba(0,0,0,.12), 0 2px 6px rgba(0,0,0,.04); + --mono: ui-monospace, "Cascadia Code", "SF Mono", Consolas, monospace; + --t: all .15s; } * { box-sizing: border-box; } html, body { height: 100%; margin: 0; } @@ -33,27 +48,36 @@ color: var(--text); background: var(--bg); overflow: hidden; /* 视窗锁死,所有滚动在 pane 内 */ } - button, input, textarea, select { - font: inherit; color: inherit; - } + button, input, textarea, select { font: inherit; color: inherit; } button { background: #fff; border: 1px solid var(--border); - padding: 4px 10px; border-radius: 6px; cursor: pointer; - transition: color .15s, border-color .15s, background .15s, box-shadow .15s; + padding: 4px 10px; border-radius: var(--r-md); cursor: pointer; + transition: var(--t); } - button:hover { background: var(--hover); } + button:hover:not(:disabled) { background: var(--hover); } + button:disabled { opacity: 0.4; cursor: not-allowed; } button.primary { background: var(--accent); color: #fff; border-color: var(--accent); } button.primary:hover { filter: brightness(1.08); } button.danger:hover { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); } input:not([type="checkbox"]):not([type="radio"]):not([type="file"]), textarea, select { background: #fff; border: 1px solid var(--border); - padding: 5px 8px; border-radius: 6px; width: 100%; + padding: 5px 8px; border-radius: var(--r-md); width: 100%; } input[type="checkbox"], input[type="radio"] { cursor: pointer; } textarea { resize: vertical; min-height: 60px; } a { color: var(--accent); text-decoration: none; } a:hover { text-decoration: underline; } + /* 4 个 modal 共用骨架(admin / src-picker / new-task / file-preview) */ + .modal { + position: fixed; inset: 0; background: rgba(0,0,0,0.4); + display: none; align-items: center; justify-content: center; + } + .modal.show { display: flex; } + .modal > .card { + background: var(--panel); border-radius: var(--r-lg); + box-shadow: var(--shadow-card); + } /* ───── login overlay ───── */ #login { @@ -67,9 +91,9 @@ #login .card { background: var(--panel); padding: 32px 36px 28px; - border-radius: 12px; + border-radius: var(--r-xl); width: 380px; - box-shadow: 0 20px 60px rgba(0,0,0,.12), 0 2px 6px rgba(0,0,0,.04); + box-shadow: var(--shadow-card-lg); border: 1px solid rgba(0,0,0,.04); animation: login-in .35s cubic-bezier(.2,.7,.2,1); } @@ -77,11 +101,9 @@ from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } - #login .brand { - display: flex; align-items: center; gap: 10px; margin-bottom: 4px; - } + #login .brand { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; } #login .brand .logo { - width: 32px; height: 32px; border-radius: 8px; + width: 32px; height: 32px; border-radius: var(--r-md); background: linear-gradient(135deg, var(--accent), #8e2a20); color: #fff; font-weight: 700; font-size: 16px; display: flex; align-items: center; justify-content: center; @@ -94,23 +116,20 @@ font-size: 12px; color: var(--muted); letter-spacing: .2px; } #login input { - padding: 9px 12px; border-radius: 6px; + padding: 9px 12px; border-radius: var(--r-md); border: 1px solid var(--border); background: #fafafa; - transition: border-color .15s, background .15s, box-shadow .15s; + transition: var(--t); } #login input:hover { background: #fff; } - #login input:focus { + #login input:focus, #admin-modal input:focus { outline: none; background: #fff; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(192,57,43,.12); } - #login .err { - color: var(--accent); font-size: 12px; margin-top: 12px; - min-height: 1em; transition: opacity .15s; - } + #login .err { color: var(--accent); font-size: 12px; margin-top: 12px; min-height: 1em; } #login .actions { margin-top: 18px; display: flex; gap: 8px; } #login .actions .primary { flex: 1; padding: 9px 14px; font-size: 14px; font-weight: 500; - border-radius: 6px; transition: filter .15s, transform .05s, box-shadow .15s; + border-radius: var(--r-md); transition: var(--t); box-shadow: 0 2px 6px rgba(192,57,43,.25); } #login .actions .primary:hover { box-shadow: 0 4px 12px rgba(192,57,43,.35); } @@ -122,8 +141,7 @@ #login .tabs button { background: none; border: none; border-bottom: 2px solid transparent; padding: 8px 4px; margin-right: 16px; font-size: 13px; - color: var(--muted); cursor: pointer; - transition: color .15s, border-color .15s; + color: var(--muted); cursor: pointer; transition: var(--t); } #login .tabs button:hover { color: var(--text); background: none; } #login .tabs button.active { color: var(--accent); border-bottom-color: var(--accent); } @@ -133,48 +151,28 @@ from { opacity: 0; transform: translateY(2px); } to { opacity: 1; transform: translateY(0); } } - #login code { - background: var(--code-bg); padding: 1px 5px; border-radius: 3px; - font-size: 11.5px; - } - #login .card-footer { - margin-top: 10px; display: flex; justify-content: flex-end; - } + #login code { background: var(--code-bg); padding: 1px 5px; border-radius: var(--r-sm); font-size: 11.5px; } + #login .card-footer { margin-top: 10px; display: flex; justify-content: flex-end; } #login .ghost-link { color: var(--muted); font-size: 12px; text-decoration: none; - padding: 2px 4px; border-radius: 4px; transition: color .15s, background .15s; + padding: 2px 4px; border-radius: var(--r-md); transition: var(--t); } #login .ghost-link:hover { color: var(--accent); background: var(--accent-soft); } /* ───── admin add-user modal ───── */ - #admin-modal { - position: fixed; inset: 0; background: rgba(0,0,0,0.4); - display: none; align-items: center; justify-content: center; z-index: 110; - } - #admin-modal.show { display: flex; } - #admin-modal .card { - background: var(--panel); padding: 20px 24px; border-radius: 10px; - width: 360px; box-shadow: 0 16px 40px rgba(0,0,0,.18); - } + #admin-modal { z-index: 110; } + #admin-modal .card { padding: 20px 24px; width: 360px; } #admin-modal h3 { margin: 0 0 12px; font-size: 15px; } #admin-modal label { display: block; margin-top: 10px; margin-bottom: 4px; font-size: 12px; color: var(--muted); } #admin-modal input { - width: 100%; padding: 8px 10px; border-radius: 6px; + width: 100%; padding: 8px 10px; border-radius: var(--r-md); border: 1px solid var(--border); background: #fafafa; } - #admin-modal input:focus { - outline: none; background: #fff; border-color: var(--accent); - box-shadow: 0 0 0 3px rgba(192,57,43,.12); - } - #admin-modal .err { - color: var(--accent); font-size: 12px; margin-top: 10px; min-height: 1em; - } - #admin-modal .actions { - margin-top: 14px; display: flex; gap: 8px; justify-content: flex-end; - } + #admin-modal .err { color: var(--accent); font-size: 12px; margin-top: 10px; min-height: 1em; } + #admin-modal .actions { margin-top: 14px; display: flex; gap: 8px; justify-content: flex-end; } /* ───── 3-pane layout ───── */ #app { display: none; height: 100vh; } @@ -197,14 +195,14 @@ } header .brand { display: flex; align-items: center; gap: 8px; } header .brand .logo { - width: 24px; height: 24px; border-radius: 6px; + width: 24px; height: 24px; border-radius: var(--r-md); background: linear-gradient(135deg, var(--accent), #8e2a20); color: #fff; font-weight: 700; font-size: 13px; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 6px rgba(192,57,43,.28); } header .title { font-weight: 600; font-size: 15px; letter-spacing: .2px; } - header .who { color: var(--muted); font-size: 12px; font-family: monospace; } + header .who { color: var(--muted); font-size: 12px; font-family: var(--mono); } header .spacer { flex: 1; } .pane { border-right: 1px solid var(--border); background: var(--panel); overflow: auto; min-height: 0; } @@ -225,26 +223,28 @@ background: #fff; border-bottom: 1px solid var(--border-soft); } - /* 对话顶栏按钮:常态中性 + hover 上语义色 — 完成 绿/导出 蓝/清空 紫/废弃 橙/删除 红 */ - #btn-done:hover:not(:disabled) { color: #27ae60; border-color: #a9dfbf; background: #e9f7ef; } - #btn-export:hover:not(:disabled) { color: #2980b9; border-color: #aed6f1; background: #ebf5fb; } - #btn-clear-msgs:hover:not(:disabled) { color: #8e44ad; border-color: #d2b4de; background: #f5eef8; } - #btn-abandon:hover:not(:disabled) { color: #e67e22; border-color: #f5cba7; background: #fef5e7; } - #btn-delete-task:hover:not(:disabled) { color: #c0392b; border-color: #f5b7b1; background: #fdedec; } - #pane-mid > .pane-head > button.small:disabled { opacity: 0.4; cursor: not-allowed; } + /* 对话顶栏按钮:常态中性 + hover 上语义色 — 完成 绿/导出 蓝/清空 紫/废弃 橙/删除 红 + 同色组合并 selector(export ≈ sp-copy 蓝, abandon ≈ sp-move 橙) */ + #btn-done:hover:not(:disabled) { color: var(--c-green); border-color: var(--c-green-bd); background: var(--c-green-bg); } + #btn-export:hover:not(:disabled), + #sp-copy:hover:not(:disabled) { color: var(--c-blue); border-color: var(--c-blue-bd); background: var(--c-blue-bg); } + #btn-clear-msgs:hover:not(:disabled) { color: var(--c-purple); border-color: var(--c-purple-bd); background: var(--c-purple-bg); } + #btn-abandon:hover:not(:disabled), + #sp-move:hover:not(:disabled) { color: var(--c-orange); border-color: var(--c-orange-bd); background: var(--c-orange-bg); } + #btn-delete-task:hover:not(:disabled) { color: var(--c-red); border-color: var(--c-red-bd); background: var(--c-red-bg); } /* ───── floating dropdown menu ───── */ /* 单例:position: fixed 逃出 pane overflow 裁剪;右上角触发,向下展开 */ .dd-toggle { padding: 2px 6px; font-size: 14px; line-height: 1; background: transparent; border: 1px solid transparent; - color: var(--muted); border-radius: 3px; cursor: pointer; + color: var(--muted); border-radius: var(--r-sm); cursor: pointer; } .dd-toggle:hover { background: var(--hover); color: var(--text); border-color: var(--border); } #floating-menu { display: none; position: fixed; min-width: 132px; background: #fff; - border: 1px solid var(--border); border-radius: 6px; + border: 1px solid var(--border); border-radius: var(--r-md); box-shadow: 0 4px 14px rgba(0,0,0,0.12); z-index: 60; padding: 4px 0; } @@ -258,12 +258,10 @@ .dd-item:hover { background: var(--hover); } .dd-item:disabled { color: var(--muted); cursor: not-allowed; opacity: 0.55; } .dd-item:disabled:hover { background: transparent; } - .dd-item.act-complete { color: #2e7d32; } - .dd-item.act-abandon { color: #c77800; } - .dd-item.act-export { color: #1565c0; } - .dd-item.act-rename { color: #1565c0; } - .dd-item.act-download { color: #2e7d32; } - .dd-item.act-delete { color: var(--accent); } + .dd-item.act-complete, .dd-item.act-download { color: var(--c-green); } + .dd-item.act-abandon { color: var(--c-orange); } + .dd-item.act-export, .dd-item.act-rename { color: var(--c-blue); } + .dd-item.act-delete { color: var(--accent); } /* ───── task list ───── */ .task-row { @@ -284,92 +282,82 @@ .task-row .meta .num.right-group { margin-left: auto; } /* 把数字+时间整组挤到右侧 */ .task-row .meta .time-ago { flex-shrink: 0; text-align: right; min-width: 64px; } .task-row .badge { - display: inline-block; padding: 0 6px; border-radius: 8px; font-size: 11px; + display: inline-block; padding: 0 6px; border-radius: var(--r-md); font-size: 11px; background: #eef; color: #336; } - .badge.completed { background: #e8f5e9; color: #2e7d32; } - .badge.abandoned { background: #fde9e7; color: var(--accent); } + .badge.completed { background: var(--c-green-bg); color: var(--c-green); } + .badge.abandoned { background: var(--accent-soft); color: var(--accent); } .badge.active { background: #eef; color: #336; } .empty { padding: 24px; color: var(--muted); text-align: center; font-size: 13px; } /* ───── chat ───── */ #chat-meta { padding: 8px 12px; border-bottom: 1px solid var(--border); background: #fafafa; font-size: 12px; color: var(--muted); display: flex; gap: 12px; align-items: center; flex-wrap: wrap; } - #chat-meta .tid { font-family: monospace; color: var(--text); } + #chat-meta .tid { font-family: var(--mono); color: var(--text); } #chat-meta .spacer { flex: 1; } /* 同 wd 并发软警告 banner — 非阻塞,只提示中间产物互覆风险 */ #wd-concurrent-warn { padding: 6px 12px; border-bottom: 1px solid #f0c36d; background: #fff8e1; color: #6a4500; font-size: 12px; } #wd-concurrent-warn .tname { font-weight: 600; } - #wd-concurrent-warn .rs { font-family: monospace; opacity: 0.7; } + #wd-concurrent-warn .rs { font-family: var(--mono); opacity: 0.7; } #chat-stream { flex: 1; overflow-y: auto; overflow-x: hidden; padding: 12px; display: flex; flex-direction: column; gap: 8px; - min-height: 0; /* 同上,允许在 flex 容器里收缩 + 触发自身滚动 */ - } - .msg { - border: 1px solid var(--border); border-radius: 6px; padding: 8px 12px; - max-width: 92%; + min-height: 0; /* 允许在 flex 容器里收缩 + 触发自身滚动 */ } + .msg { border: 1px solid var(--border); border-radius: var(--r-md); padding: 8px 12px; max-width: 92%; } .msg.user { background: var(--user-bg); align-self: flex-end; } .msg.assistant, .msg.system, .msg.tool, .msg.error { background: var(--asst-bg); align-self: flex-start; } .msg.error { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); } - .cancelled-badge { margin-top: 8px; padding: 4px 10px; font-size: 12px; color: var(--accent); background: var(--accent-soft); border: 1px dashed var(--accent); border-radius: 4px; display: inline-block; } - .msg .role { font-size: 11px; color: var(--muted); margin-bottom: 2px; font-family: monospace; } + .cancelled-badge { margin-top: 8px; padding: 4px 10px; font-size: 12px; color: var(--accent); background: var(--accent-soft); border: 1px dashed var(--accent); border-radius: var(--r-md); display: inline-block; } + .msg .role { font-size: 11px; color: var(--muted); margin-bottom: 2px; font-family: var(--mono); } .msg .body { word-wrap: break-word; font-size: 14px; line-height: 1.55; } .msg .body.streaming::after { content: "▌"; color: var(--accent); animation: blink 1s infinite; } @keyframes blink { 0%,49% { opacity: 1; } 50%,100% { opacity: 0; } } - /* markdown 输出元素紧凑化 */ - .msg .body > :first-child { margin-top: 0; } - .msg .body > :last-child { margin-bottom: 0; } - .msg .body p { margin: 0.4em 0; } - .msg .body h1, .msg .body h2, .msg .body h3, .msg .body h4 { + /* markdown 输出:.msg .body 与 file-preview .md-render 共用一组规则 */ + .msg .body > :first-child, .md-render > :first-child { margin-top: 0; } + .msg .body > :last-child, .md-render > :last-child { margin-bottom: 0; } + .msg .body p, .md-render p { margin: 0.4em 0; } + .msg .body h1, .msg .body h2, .msg .body h3, .msg .body h4, + .md-render h1, .md-render h2, .md-render h3, .md-render h4 { margin: 0.8em 0 0.3em; line-height: 1.3; } - .msg .body h1 { font-size: 1.4em; } - .msg .body h2 { font-size: 1.25em; } - .msg .body h3 { font-size: 1.1em; } - .msg .body h4 { font-size: 1em; font-weight: 600; } - .msg .body ul, .msg .body ol { margin: 0.4em 0; padding-left: 1.6em; } - .msg .body li { margin: 0.15em 0; } - .msg .body li > p { margin: 0.15em 0; } - .msg .body blockquote { + .msg .body h1, .md-render h1 { font-size: 1.4em; } + .msg .body h2, .md-render h2 { font-size: 1.25em; } + .msg .body h3, .md-render h3 { font-size: 1.1em; } + .msg .body h4, .md-render h4 { font-size: 1em; font-weight: 600; } + .msg .body ul, .msg .body ol, .md-render ul, .md-render ol { margin: 0.4em 0; padding-left: 1.6em; } + .msg .body li, .md-render li { margin: 0.15em 0; } + .msg .body li > p, .md-render li > p { margin: 0.15em 0; } + .msg .body blockquote, .md-render blockquote { margin: 0.4em 0; padding: 4px 12px; border-left: 3px solid var(--accent); background: var(--accent-soft); color: #555; } - .msg .body code:not(pre code) { - background: var(--code-bg); padding: 1px 5px; border-radius: 3px; - font-family: ui-monospace, "Cascadia Code", Consolas, monospace; - font-size: 0.92em; + .msg .body code:not(pre code), .md-render code:not(pre code) { + background: var(--code-bg); padding: 1px 5px; border-radius: var(--r-sm); + font-family: var(--mono); font-size: 0.92em; } - .msg .body pre { - margin: 0.5em 0; padding: 10px; background: #f6f8fa; border-radius: 4px; + .msg .body pre, .md-render pre { + margin: 0.5em 0; padding: 10px; background: #f6f8fa; border-radius: var(--r-md); overflow-x: auto; font-size: 12.5px; line-height: 1.4; } - .msg .body pre code { - font-family: ui-monospace, "Cascadia Code", Consolas, monospace; - background: transparent; padding: 0; - } - .msg .body table { - border-collapse: collapse; margin: 0.5em 0; font-size: 13px; - } - .msg .body th, .msg .body td { + .msg .body pre code, .md-render pre code { font-family: var(--mono); background: transparent; padding: 0; } + .msg .body table, .md-render table { border-collapse: collapse; margin: 0.5em 0; font-size: 13px; } + .msg .body th, .msg .body td, .md-render th, .md-render td { border: 1px solid var(--border); padding: 4px 8px; } - .msg .body th { background: #fafafa; font-weight: 600; } - .msg .body a { color: var(--accent); } - .msg .body img { max-width: 100%; } - .msg .body hr { border: none; border-top: 1px solid var(--border); margin: 0.8em 0; } - .tool-call { - margin-top: 6px; font-family: ui-monospace, Consolas, monospace; font-size: 12px; - } + .msg .body th, .md-render th { background: #fafafa; font-weight: 600; } + .msg .body a, .md-render a { color: var(--accent); } + .msg .body img, .md-render img { max-width: 100%; } + .msg .body hr, .md-render hr { border: none; border-top: 1px solid var(--border); margin: 0.8em 0; } + .tool-call { margin-top: 6px; font-family: var(--mono); font-size: 12px; } .tool-call summary { - cursor: pointer; padding: 4px 6px; background: var(--code-bg); border-radius: 3px; + cursor: pointer; padding: 4px 6px; background: var(--code-bg); border-radius: var(--r-sm); color: #555; } .tool-call summary:hover { background: #ebebeb; } .tool-call pre { - margin: 4px 0 0; padding: 8px; background: var(--code-bg); border-radius: 3px; + margin: 4px 0 0; padding: 8px; background: var(--code-bg); border-radius: var(--r-sm); overflow-x: auto; max-height: 300px; white-space: pre-wrap; } /* media tool 摘要 banner(model / size / cost / elapsed,折叠态也可见) */ @@ -378,36 +366,31 @@ margin-left: 8px; font-size: 11px; vertical-align: middle; } .tool-banner .kv { - padding: 1px 6px; border-radius: 3px; background: #fff; + padding: 1px 6px; border-radius: var(--r-sm); background: #fff; border: 1px solid var(--border); color: #555; } .tool-banner .kv.cost { color: #b34a4a; border-color: #e0c4c4; } .tool-banner .kv.model { color: var(--accent); border-color: #e0c4c4; } /* ───── artifact chips(对话内点产物预览/下载) ───── */ - .artifact-bar { - margin-top: 4px; display: flex; flex-wrap: wrap; gap: 4px; - font-family: ui-monospace, Consolas, monospace; - } + .artifact-bar { margin-top: 4px; display: flex; flex-wrap: wrap; gap: 4px; font-family: var(--mono); } .art-chip { font: inherit; font-size: 11px; line-height: 1.4; padding: 2px 8px 2px 6px; border: 1px solid var(--border); background: #fff; color: #555; border-radius: 999px; cursor: pointer; max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: inline-flex; align-items: center; gap: 4px; - transition: color .12s, border-color .12s, background .12s; + transition: var(--t); } .art-chip::before { content: "📄"; font-size: 11px; } - .art-chip:hover { - background: var(--accent-soft); border-color: var(--accent); color: var(--accent); - } + .art-chip:hover { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); } /* 内联图片/视频:产物 chip 替代,fetch 完直接展示 */ .art-media { - border: 1px solid var(--border); border-radius: 6px; overflow: hidden; + border: 1px solid var(--border); border-radius: var(--r-md); overflow: hidden; background: #fff; display: inline-block; line-height: 0; } .art-media .art-media-loading, .art-media .art-media-error { display: inline-block; padding: 6px 10px; font-size: 11px; - color: var(--muted); line-height: 1.4; font-family: ui-monospace, Consolas, monospace; + color: var(--muted); line-height: 1.4; font-family: var(--mono); } .art-media .art-media-error { color: #b34a4a; } .art-media img { @@ -437,7 +420,7 @@ } .file-row:hover { background: var(--hover); } .file-row .name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } - .file-row .size { font-size: 11px; color: var(--muted); font-family: monospace; } + .file-row .size { font-size: 11px; color: var(--muted); font-family: var(--mono); } .ico-dir::before { content: "▸ "; color: var(--accent); } .ico-file::before { content: "· "; color: var(--muted); } @@ -453,16 +436,10 @@ #file-droparea.show { display: flex; } /* ───── source picker modal(选入文件:勾源 + 复制/移动到主区当前目录) ───── */ - #src-picker-modal { - position: fixed; inset: 0; background: rgba(0,0,0,0.4); - display: none; align-items: center; justify-content: center; z-index: 95; - } - #src-picker-modal.show { display: flex; } + #src-picker-modal { z-index: 95; } #src-picker-modal .card { - background: var(--panel); border-radius: 8px; width: 560px; max-height: 82vh; display: flex; flex-direction: column; - box-shadow: 0 12px 32px rgba(0,0,0,.18); } #src-picker-modal h3 { margin: 0; padding: 14px 18px; font-size: 16px; @@ -477,19 +454,12 @@ padding: 8px 18px; font-size: 12px; color: var(--muted); border-bottom: 1px solid var(--border); } - #sp-crumbs { - padding: 8px 14px; border-bottom: 1px solid var(--border); - font-size: 12px; background: #fafafa; - } + #sp-crumbs { padding: 8px 14px; border-bottom: 1px solid var(--border); font-size: 12px; background: #fafafa; } #sp-crumbs a { margin-right: 4px; } - #sp-list { - flex: 1; overflow: auto; - min-height: 240px; max-height: 50vh; - } + #sp-list { flex: 1; overflow: auto; min-height: 240px; max-height: 50vh; } #sp-list .sp-row { padding: 6px 14px; border-bottom: 1px solid var(--border); - display: flex; align-items: center; gap: 8px; - font-size: 13px; + display: flex; align-items: center; gap: 8px; font-size: 13px; } #sp-list .sp-row:hover { background: var(--hover); } #sp-list .sp-row .sp-cb { flex-shrink: 0; margin: 0; } @@ -498,42 +468,24 @@ cursor: pointer; } #sp-list .sp-row.disabled .sp-name { color: var(--muted); cursor: not-allowed; } - #sp-list .sp-row .sp-size { font-size: 11px; color: var(--muted); font-family: monospace; } - #sp-list .empty { padding: 18px; color: var(--muted); text-align: center; font-size: 12px; } + #sp-list .sp-row .sp-size { font-size: 11px; color: var(--muted); font-family: var(--mono); } #src-picker-modal .actions { padding: 12px 18px; border-top: 1px solid var(--border); display: flex; gap: 8px; align-items: center; } - #src-picker-modal .actions .count { - flex: 1; font-size: 12px; color: var(--muted); - } - #sp-copy:hover:not(:disabled) { color: #1565c0; border-color: #aed6f1; background: #ebf5fb; } - #sp-move:hover:not(:disabled) { color: #c77800; border-color: #f5cba7; background: #fef5e7; } - #sp-copy:disabled, #sp-move:disabled { opacity: 0.4; cursor: not-allowed; } + #src-picker-modal .actions .count { flex: 1; font-size: 12px; color: var(--muted); } /* ───── new task modal ───── */ - #new-task-modal { - position: fixed; inset: 0; background: rgba(0,0,0,0.4); - display: none; align-items: center; justify-content: center; z-index: 80; - } - #new-task-modal.show { display: flex; } - #new-task-modal .card { - background: var(--panel); padding: 20px; border-radius: 8px; - width: 420px; box-shadow: 0 12px 32px rgba(0,0,0,.18); - } + #new-task-modal { z-index: 80; } + #new-task-modal .card { padding: 20px; width: 420px; } #new-task-modal h3 { margin: 0 0 12px; font-size: 16px; } #new-task-modal label { display: block; margin-top: 8px; font-size: 12px; color: var(--muted); } #new-task-modal .err { color: var(--accent); font-size: 12px; margin-top: 8px; min-height: 1em; } #new-task-modal .actions { margin-top: 14px; display: flex; gap: 8px; justify-content: flex-end; } - /* ───── file preview modal ───── */ - #file-preview-modal { - position: fixed; inset: 0; background: rgba(0,0,0,0.5); - display: none; align-items: center; justify-content: center; z-index: 90; - } - #file-preview-modal.show { display: flex; } + /* ───── file preview modal(略深的遮罩 0.5 + 更重阴影) ───── */ + #file-preview-modal { background: rgba(0,0,0,0.5); z-index: 90; } #file-preview-modal .card { - background: var(--panel); border-radius: 8px; width: 90vw; height: 90vh; max-width: 1200px; display: flex; flex-direction: column; box-shadow: 0 12px 32px rgba(0,0,0,.22); @@ -546,15 +498,9 @@ flex: 1; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } - #file-preview-modal .body { - flex: 1; overflow: auto; padding: 12px; position: relative; - } - #file-preview-modal .body.center { - display: flex; align-items: center; justify-content: center; - } - #file-preview-modal .body .ph { - color: var(--muted); font-size: 13px; text-align: center; - } + #file-preview-modal .body { flex: 1; overflow: auto; padding: 12px; position: relative; } + #file-preview-modal .body.center { display: flex; align-items: center; justify-content: center; } + #file-preview-modal .body .ph { color: var(--muted); font-size: 13px; text-align: center; } #file-preview-modal .body img.preview-img { max-width: 100%; max-height: 100%; object-fit: contain; display: block; margin: 0 auto; @@ -562,23 +508,14 @@ #file-preview-modal .body video.preview-video { max-width: 100%; max-height: 100%; display: block; margin: 0 auto; outline: none; } - #file-preview-modal .body iframe.preview-frame { - width: 100%; height: 100%; border: 0; - } + #file-preview-modal .body iframe.preview-frame { width: 100%; height: 100%; border: 0; } #file-preview-modal .body pre.preview-text { margin: 0; padding: 8px; background: var(--code-bg); - border-radius: 4px; white-space: pre-wrap; word-break: break-word; - font-family: ui-monospace, "SF Mono", Consolas, monospace; - font-size: 12px; line-height: 1.5; + border-radius: var(--r-md); white-space: pre-wrap; word-break: break-word; + font-family: var(--mono); font-size: 12px; line-height: 1.5; } - #file-preview-modal .body .md-render { - max-width: 860px; margin: 0 auto; line-height: 1.7; - } - #file-preview-modal .body .md-render pre { - background: var(--code-bg); padding: 10px; border-radius: 4px; overflow: auto; - } - #file-preview-modal .body .md-render code { background: var(--code-bg); padding: 1px 4px; border-radius: 3px; } - #file-preview-modal .body .md-render pre code { background: transparent; padding: 0; } + /* .md-render 通用样式已与 .msg .body 合并到上方 chat 段;这里只保留 file-preview 专属 */ + #file-preview-modal .body .md-render { max-width: 860px; margin: 0 auto; line-height: 1.7; } #file-preview-modal .body .docx-host { background: #fff; } #file-preview-modal .body .xlsx-tabs { display: flex; gap: 4px; flex-wrap: wrap; margin-bottom: 8px; @@ -587,12 +524,8 @@ #file-preview-modal .body .xlsx-tabs button.active { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); } - #file-preview-modal .body .xlsx-sheet { - overflow: auto; - } - #file-preview-modal .body .xlsx-sheet table { - border-collapse: collapse; font-size: 12px; - } + #file-preview-modal .body .xlsx-sheet { overflow: auto; } + #file-preview-modal .body .xlsx-sheet table { border-collapse: collapse; font-size: 12px; } #file-preview-modal .body .xlsx-sheet td, #file-preview-modal .body .xlsx-sheet th { border: 1px solid var(--border); padding: 4px 8px; white-space: nowrap; } @@ -649,7 +582,7 @@ -
+