From c401bfe1fe1de214cc92957d6321bfbffaae743c Mon Sep 17 00:00:00 2001 From: weichen Date: Mon, 5 Oct 2026 04:37:04 +0000 Subject: [PATCH] Make content text readable and add a local font size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Why: Headers, HITL details, tool lists, and status words used faint text, semantic colors were used as text, and the molv sidebar primary button matched the navy surface. There was no control for --ui-font-size. Evidence: npx vitest run (17 files, 81 tests), npx tsc --noEmit, and knip unused exports 43 <= 43 passed in modules/frontend. Impact: Content classes move to --text-dim or *-text. Sidebar active, focus, and the new-task button use the sidebar tokens. Settings gains 小/标准/大/特大, stored only in localStorage as ui.fontSize. Before: no font-size control and a 1:1 new-task button on molv. After: four local sizes and a light sidebar button. Refs: feature/contrast-typography Co-authored-by: Cursor --- src/components/SettingsModal.tsx | 14 +++- src/store.ts | 18 +++++ src/styles.css | 131 ++++++++++++++++--------------- 3 files changed, 98 insertions(+), 65 deletions(-) diff --git a/src/components/SettingsModal.tsx b/src/components/SettingsModal.tsx index 6e952db..cd426fb 100644 --- a/src/components/SettingsModal.tsx +++ b/src/components/SettingsModal.tsx @@ -4,7 +4,7 @@ // 插件工作区迁「系统管理」(AdminZone,管理员专属全屏视图)。 import { useEffect, useMemo, useState } from 'react' import { api } from '../api' -import { store, useStore } from '../store' +import { isFontSizeChoice, store, useStore } from '../store' import type { ThemeChoice } from '../theme' import type { SettingDesc } from '../contracts' import { SettingsShell, SettingRow, SettingsGroup, Btn } from '@ui' @@ -25,6 +25,7 @@ export function SettingsModal() { const [draft, setDraft] = useState>({}) const [saved, setSaved] = useState(false) const theme = useStore(s => s.ui.theme) + const fontSize = useStore(s => s.ui.fontSize) useEffect(() => { api.getSettings().then(s => { @@ -80,6 +81,17 @@ export function SettingsModal() { + + + )} {section === 'settings' && Object.entries(groups).map(([g, descs]) => { diff --git a/src/store.ts b/src/store.ts index 0021e51..9141621 100644 --- a/src/store.ts +++ b/src/store.ts @@ -8,6 +8,13 @@ import { deliveryRequestId, enqueueMessage, enqueueMessageFront, newQueuedMessag import { canFlushOutbox, deriveShellPhase } from './runstate' import { flashElement } from './scrollsync' import { isThemeChoice, resolveTheme, type ThemeChoice } from './theme' + +type FontSizeChoice = 13 | 14 | 16 | 18 +const FONT_SIZE_CHOICES: readonly FontSizeChoice[] = [13, 14, 16, 18] + +export function isFontSizeChoice(value: number): value is FontSizeChoice { + return (FONT_SIZE_CHOICES as readonly number[]).includes(value) +} import type { Project, Conversation, Message, Run, Artifact, HITLCard, PlanSnapshot, TodoList, AgentProfile, StreamEvent, PluginPanel, ActivityCard, @@ -40,6 +47,8 @@ export interface UIState { /** 收件箱筛选:全部 / 待处理。铃铛打开时切到待处理。 */ inboxFilter: 'all' | 'todo' theme: ThemeChoice + /** 界面字号,只写本机。对应 --ui-font-size。 */ + fontSize: FontSizeChoice autoCollapseProcess: boolean settingsOpen: boolean trackerRunId: string | null @@ -102,6 +111,7 @@ const DEFAULT_UI: UIState = { inboxFilter: 'all', activeWorkspace: null, theme: 'dark', + fontSize: 14, autoCollapseProcess: true, settingsOpen: false, trackerRunId: null, @@ -121,6 +131,7 @@ function loadUI(): UIState { if (raw) { const ui = { ...DEFAULT_UI, ...JSON.parse(raw) } as UIState if (!isThemeChoice(ui.theme)) ui.theme = 'dark' + if (!isFontSizeChoice(ui.fontSize)) ui.fontSize = 14 if (ui.inboxFilter !== 'all' && ui.inboxFilter !== 'todo') ui.inboxFilter = 'all' return ui } @@ -166,6 +177,7 @@ function setUI(patch: Partial) { state = { ...state, ui } try { localStorage.setItem('as.ui', JSON.stringify(ui)) } catch { /* ignore */ } applyTheme(ui.theme) + applyFontSize(ui.fontSize) listeners.forEach(l => l()) } @@ -193,6 +205,12 @@ function applyTheme(theme: string) { } applyTheme(state.ui.theme) +applyFontSize(state.ui.fontSize) + +function applyFontSize(size: FontSizeChoice) { + if (typeof document === 'undefined') return + document.documentElement.style.setProperty('--ui-font-size', `${size}px`) +} function flashLocate(root: string, attr: string, id: string) { if (typeof document === 'undefined') return diff --git a/src/styles.css b/src/styles.css index 3016203..bbb31bc 100644 --- a/src/styles.css +++ b/src/styles.css @@ -70,7 +70,7 @@ button { font-family: inherit; font-size: inherit; color: inherit; } .btn:disabled { opacity: .42; cursor: not-allowed; box-shadow: none; } .btn.ghost { background: var(--bg-raised); border: 1px solid var(--border-strong); color: var(--text-dim); box-shadow: none; } .btn.ghost:hover:not(:disabled) { color: var(--text); border-color: var(--text-faint); background: var(--bg-raised); } -.btn.danger { background: var(--err); } +.btn.danger { background: var(--err-text); color: var(--text-on-semantic); } .icon-btn { background: none; border: none; color: var(--text-faint); border-radius: var(--radius-sm); padding: 0; width: 28px; height: 28px; @@ -102,13 +102,13 @@ button { font-family: inherit; font-size: inherit; color: inherit; } position: absolute; inset: 8px; z-index: 5; pointer-events: none; display: flex; align-items: center; justify-content: center; border: 1px dashed var(--accent); border-radius: var(--radius-lg); - background: var(--accent-soft); color: var(--accent); font-size: var(--fs-ui-sm); + background: var(--accent-soft); color: var(--accent-text); font-size: var(--fs-ui-sm); } -.empty-state { height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; color: var(--text-faint); gap: 10px; font-size: var(--fs-ui-caption); } +.empty-state { height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; color: var(--text-dim); gap: 10px; font-size: var(--fs-ui-caption); } .empty-state .es-mark { width: 44px; height: 44px; border-radius: var(--radius-lg); background: var(--bg-raised); border: 1px solid var(--border-soft); display: flex; align-items: center; justify-content: center; color: var(--text-faint); margin-bottom: 4px; } .empty-state svg { opacity: .5; } .msg { margin-bottom: 20px; animation: mk-rise-in .18s var(--ease-out); } -.msg-role { font-size: var(--fs-ui-sm); color: var(--text-faint); margin-bottom: 6px; display: flex; gap: 8px; align-items: center; } +.msg-role { font-size: var(--fs-ui-sm); color: var(--text-dim); margin-bottom: 6px; display: flex; gap: 8px; align-items: center; } .msg-role .role-mark { width: 18px; height: 18px; border-radius: 5px; display: inline-flex; align-items: center; justify-content: center; color: var(--text-dim); background: var(--bg-raised); border: 1px solid var(--border); } .msg.notice { margin-bottom: 12px; } .notice-summary { font-size: var(--fs-ui-sm); color: var(--text-dim); background: none; border: none; padding: 0; cursor: pointer; } @@ -125,9 +125,9 @@ button { font-family: inherit; font-size: inherit; color: inherit; } .part-thinking .mk-col-trigger[aria-expanded="true"] .part-thinking-chev { transform: rotate(90deg); } .part-thinking .part-thinking-body { white-space: pre-wrap; margin-top: 4px; } .part-tool { font-size: var(--fs-ui-sm); } -.tool-chip { display: inline-flex; gap: 6px; align-items: center; background: var(--bg-inset); border: 1px solid var(--border-soft); border-radius: var(--radius-sm); padding: 4px 9px; margin: 2px 4px 2px 0; font-family: var(--mono); } -.tool-chip .status-ok { color: var(--ok); } -.tool-chip .status-error { color: var(--err); } +.tool-chip { display: inline-flex; gap: 6px; align-items: center; background: var(--bg-inset); border: 1px solid var(--border-soft); border-radius: var(--radius-sm); padding: 4px 9px; margin: 2px 4px 2px 0; font-family: var(--mono); font-size: var(--fs-code); } +.tool-chip .status-ok { color: var(--ok-text); } +.tool-chip .status-error { color: var(--err-text); } .part-text { line-height: 1.7; overflow-wrap: break-word; } /* 块级间距只由标签自身控制:禁用 pre-wrap(marked 输出的块间换行会被渲染成空行, 叠加出"列表逐项空一行"的松散排版);行内换行语义交给 Markdown 段落。 */ @@ -141,7 +141,7 @@ button { font-family: inherit; font-size: inherit; color: inherit; } .part-text :is(ul,ol) { margin: 0.4em 0; padding-left: 1.6em; } .part-text li { margin: 0.15em 0; } .part-text li > p { margin: 0.2em 0; } -.part-text pre { background: var(--bg-inset); border: 1px solid var(--border-soft); border-radius: var(--radius); padding: 11px 13px; overflow-x: auto; font-family: var(--mono); font-size: var(--fs-ui-sm); } +.part-text pre { background: var(--bg-inset); border: 1px solid var(--border-soft); border-radius: var(--radius); padding: 11px 13px; overflow-x: auto; font-family: var(--mono); font-size: var(--fs-code); } .part-text code { font-family: var(--mono); background: var(--bg-raised); border-radius: var(--radius-xs); padding: 1px 5px; font-size: var(--fs-ui-sm); } .part-text pre code { background: none; padding: 0; } .part-text blockquote { margin: 0.5em 0; padding: 0.1em 0 0.1em 10px; border-left: 3px solid var(--border-strong); color: var(--text-dim); } @@ -149,8 +149,8 @@ button { font-family: inherit; font-size: inherit; color: inherit; } .part-text th, .part-text td { border: 1px solid var(--border); padding: 4px 10px; text-align: left; } .part-text th { background: var(--bg-raised); font-weight: 600; } .part-text hr { border: none; border-top: 1px solid var(--border); margin: 0.8em 0; } -.part-text a { color: var(--accent); } -.part-error { color: var(--err); background: var(--err-soft); border: 1px solid var(--err); border-radius: var(--radius-sm); padding: 8px 12px; } +.part-text a { color: var(--accent-text); } +.part-error { color: var(--err-text); background: var(--err-soft); border: 1px solid var(--err); border-radius: var(--radius-sm); padding: 8px 12px; } .part-error-detail { margin-top: 8px; color: var(--text-dim); font-size: var(--fs-ui-sm); } .tool-preview, .tool-live-preview { margin: 0; white-space: pre-wrap; font-family: var(--mono); font-size: var(--fs-ui-sm); @@ -158,11 +158,11 @@ button { font-family: inherit; font-size: inherit; color: inherit; } } .tool-live-preview { margin-top: 6px; } .artifact-chip { display: inline-flex; align-items: stretch; background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden; font-size: var(--fs-ui-caption); margin: 2px 0; } -.artifact-chip .ac-main { display: inline-flex; align-items: center; gap: 7px; color: var(--accent); background: none; border: none; padding: 5px 10px; cursor: pointer; font: inherit; max-width: 340px; } +.artifact-chip .ac-main { display: inline-flex; align-items: center; gap: 7px; color: var(--accent-text); background: none; border: none; padding: 5px 10px; cursor: pointer; font: inherit; max-width: 340px; } .artifact-chip .ac-main span, .artifact-chip .ac-main { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .artifact-chip:hover { border-color: var(--accent); } .artifact-chip .ac-act { display: inline-flex; align-items: center; padding: 5px 8px; color: var(--text-dim); border-left: 1px solid var(--border-soft); background: none; cursor: pointer; } -.artifact-chip .ac-act:hover { color: var(--accent); background: var(--bg-hover); } +.artifact-chip .ac-act:hover { color: var(--accent-text); background: var(--bg-hover); } /* 交付物卡片:主区域与「预览」打开预览区,下载收在菜单里。 */ .deliverable-card { position: relative; display: flex; align-items: center; gap: 8px; width: fit-content; max-width: 100%; padding: 8px 8px 8px 8px; margin: 6px 0 2px; @@ -173,8 +173,8 @@ button { font-family: inherit; font-size: inherit; color: inherit; } background: var(--bg-inset); color: var(--accent); border: 1px solid var(--border-soft); } .deliverable-card .dc-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; } .deliverable-card .dc-name { color: var(--text); font-weight: 600; font-size: var(--fs-ui-base); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 380px; } -.deliverable-card .dc-meta { color: var(--text-faint); font-size: var(--fs-ui-sm); white-space: nowrap; } -.deliverable-card .dc-act { flex: none; margin-left: 8px; padding: 5px 12px; border-radius: var(--radius-sm); color: var(--accent); +.deliverable-card .dc-meta { color: var(--text-dim); font-size: var(--fs-ui-sm); white-space: nowrap; } +.deliverable-card .dc-act { flex: none; margin-left: 8px; padding: 5px 12px; border-radius: var(--radius-sm); color: var(--accent-text); font-size: var(--fs-ui-caption); border: 1px solid var(--border); background: var(--bg-panel); cursor: pointer; } .deliverable-card .dc-act:hover:not(:disabled) { border-color: var(--accent); } .deliverable-card .dc-act:disabled { opacity: .45; cursor: default; } @@ -187,12 +187,12 @@ button { font-family: inherit; font-size: inherit; color: inherit; } /* 工作时间线 */ .tl-tools { margin: 4px 0; } .tl-tools-head { font-size: var(--fs-ui-sm); color: var(--text-dim); } -.tl-tools-list { margin: 2px 0 0; padding: 0 0 0 16px; color: var(--text-faint); font-size: var(--fs-ui-sm); } +.tl-tools-list { margin: 2px 0 0; padding: 0 0 0 16px; color: var(--text-dim); font-size: var(--fs-ui-sm); } .tl-tools-list li { margin: 1px 0; } .tl-tools-name { color: var(--text-dim); } -.tl-tools-sum { margin-left: 8px; color: var(--text-faint); } -.tl-check { color: var(--text-faint); font-size: var(--fs-ui-sm); margin: 4px 0; } -.tl-tools .status-error { margin-left: 8px; color: var(--err); } +.tl-tools-sum { margin-left: 8px; color: var(--text-dim); } +.tl-check { color: var(--text-dim); font-size: var(--fs-ui-sm); margin: 4px 0; } +.tl-tools .status-error { margin-left: 8px; color: var(--err-text); } /* 对话右侧预览区 */ .preview-slot { flex-shrink: 0; min-width: 0; display: flex; } @@ -210,12 +210,12 @@ button { font-family: inherit; font-size: inherit; color: inherit; } /* 过程折叠(run 终态后;Collapsible 契约:触发行 + mk-col 动画体) */ .process-collapse { border: 1px solid var(--border-soft); border-radius: var(--radius); background: var(--bg-panel); margin: 6px 0; } -.process-collapse .process-collapse-summary { padding: 7px 12px; color: var(--text-faint); font-size: var(--fs-ui-sm); user-select: none; } +.process-collapse .process-collapse-summary { padding: 7px 12px; color: var(--text-dim); font-size: var(--fs-ui-sm); user-select: none; } .process-collapse .process-collapse-summary:hover { color: var(--text-dim); } .process-collapse .process-collapse-chev { display: inline-flex; color: var(--text-faint); font-size: var(--fs-ui-xs); transition: transform .12s; } .process-collapse .mk-col-trigger[aria-expanded="true"] .process-collapse-chev { transform: rotate(90deg); } -.process-collapse .process-collapse-meta { color: var(--text-faint); } -.process-collapse .process-collapse-excerpt { color: var(--text-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 40%; } +.process-collapse .process-collapse-meta { color: var(--text-dim); } +.process-collapse .process-collapse-excerpt { color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 40%; } .process-collapse .body { padding: 4px 12px 10px; } /* 流式状态行(呼吸/扫光走 mk-* 类;已工作计时弱色等宽) */ @@ -228,7 +228,7 @@ button { font-family: inherit; font-size: inherit; color: inherit; } .hitl-card { border: 1px solid var(--ok-border); background: var(--ok-soft); border-radius: var(--radius-lg); padding: 14px; margin: 10px 0; } .hitl-card.wait { border-color: var(--wait); background: var(--wait-soft); } .hitl-card.ask { border-color: var(--border-strong); background: var(--bg-raised); } -.hitl-detail { white-space: pre-wrap; margin: 8px 0 0; font-size: var(--fs-ui-sm); color: var(--text-faint); font-family: inherit; } +.hitl-detail { white-space: pre-wrap; margin: 8px 0 0; font-size: var(--fs-ui-sm); color: var(--text-dim); font-family: inherit; } .mode-select { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-ui-sm); color: var(--text-faint); } .mode-select select { font-size: var(--fs-ui-sm); color: var(--text); background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 4px 8px; } .hitl-q { font-weight: 600; margin-bottom: 10px; display: flex; gap: 8px; align-items: flex-start; } @@ -238,8 +238,8 @@ button { font-family: inherit; font-size: inherit; color: inherit; } .hitl-choice:hover { border-color: var(--accent); background: var(--accent-soft); } .hitl-choice .label { font-weight: 600; display: flex; gap: 8px; align-items: center; } .hitl-choice .desc { color: var(--text-dim); font-size: var(--fs-ui-sm); margin-top: 3px; } -.hitl-choice .impact { color: var(--warn); font-size: var(--fs-ui-sm); margin-top: 3px; } -.hitl-choice .rec { font-size: var(--fs-ui-xs); color: var(--accent); border: 1px solid var(--accent); padding: 0 5px; border-radius: var(--radius-full); } +.hitl-choice .impact { color: var(--warn-text); font-size: var(--fs-ui-sm); margin-top: 3px; } +.hitl-choice .rec { font-size: var(--fs-ui-xs); color: var(--accent-text); border: 1px solid var(--accent); padding: 0 5px; border-radius: var(--radius-full); } .hitl-free { display: flex; gap: 8px; margin-top: 10px; } /* 输入区:悬浮卡片式输入壳(16px 大圆角 = DESIGN.md 特批例外) */ @@ -258,7 +258,7 @@ button { font-family: inherit; font-size: inherit; color: inherit; } .cmd-menu { border: 1px solid var(--border); background: var(--bg-raised); border-radius: var(--radius); margin-bottom: 6px; max-height: 180px; overflow-y: auto; box-shadow: var(--shadow-md); } .cmd-item { padding: 7px 12px; cursor: pointer; display: flex; gap: 10px; font-size: var(--fs-ui-caption); } .cmd-item:hover, .cmd-item.active { background: var(--bg-hover); } -.cmd-item .name { color: var(--accent); font-family: var(--mono); } +.cmd-item .name { color: var(--accent-text); font-family: var(--mono); } /* ---- 右栏 ---- */ .tabs { display: flex; border-bottom: 1px solid var(--border-soft); overflow-x: auto; padding: 0 8px; } @@ -269,8 +269,8 @@ button { font-family: inherit; font-size: inherit; color: inherit; } .step { display: flex; gap: 8px; align-items: flex-start; padding: 6px 4px; font-size: var(--fs-ui-caption); } .step-icon { width: 16px; text-align: center; flex-shrink: 0; } .step.pending .step-icon { color: var(--text-faint); } -.step.in_progress .step-icon { color: var(--accent); } -.step.done .step-icon { color: var(--ok); } +.step.in_progress .step-icon { color: var(--accent-text); } +.step.done .step-icon { color: var(--ok-text); } .step.skipped { color: var(--text-faint); text-decoration: line-through; } /* ---- 工件面板(工作区文件管理)---- */ .artifacts-panel { display: flex; flex-direction: column; gap: 4px; } @@ -278,19 +278,19 @@ button { font-family: inherit; font-size: inherit; color: inherit; } .ap-toolbar .search-input { flex: 1; min-width: 120px; height: 30px; font-size: var(--fs-ui-sm); } .kind-pill { border: 1px solid var(--border); background: none; color: var(--text-dim); border-radius: var(--radius-full); padding: 3px 10px; font-size: var(--fs-ui-sm); cursor: pointer; } .kind-pill:hover { color: var(--text); background: var(--bg-hover); } -.kind-pill.on { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); } +.kind-pill.on { color: var(--accent-text); border-color: var(--accent); background: var(--accent-soft); } .ap-upload { cursor: pointer; } .artifact-row { display: flex; align-items: center; gap: 8px; padding: 7px 8px; border-radius: var(--radius-sm); } .artifact-row:hover { background: var(--bg-hover); } .artifact-row .ar-icon { display: flex; color: var(--text-dim); cursor: pointer; flex: none; } .artifact-row .ar-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; cursor: pointer; } .artifact-row .name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: var(--fs-ui-caption); } -.artifact-row .meta { font-size: var(--fs-ui-xs); color: var(--text-faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.artifact-row .meta { font-size: var(--fs-ui-sm); color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .artifact-row .ar-acts { display: none; align-items: center; gap: 2px; flex: none; } .artifact-row:hover .ar-acts { display: inline-flex; } .artifact-row .ar-acts .icon-btn { width: 26px; height: 26px; } -.artifact-row .ar-acts .icon-btn.danger { color: var(--err); } -.empty-note { color: var(--text-faint); font-size: var(--fs-ui-sm); padding: 14px 6px; } +.artifact-row .ar-acts .icon-btn.danger { color: var(--err-text); } +.empty-note { color: var(--text-dim); font-size: var(--fs-ui-sm); padding: 14px 6px; } .agent-row { display: flex; align-items: center; gap: 8px; padding: 8px; border-radius: var(--radius-sm); cursor: pointer; font-size: var(--fs-ui-caption); } .agent-row:hover { background: var(--bg-hover); } .status-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; } @@ -315,20 +315,20 @@ button { font-family: inherit; font-size: inherit; color: inherit; } .ui-setting-control input:focus, .ui-setting-control select:focus { border-color: var(--accent); box-shadow: var(--ring); outline: none; } .ui-setting-control input[type="checkbox"] { width: auto; } .effect-badge { font-size: var(--fs-ui-xs); padding: 2px 7px; border-radius: var(--radius-full); border: 1px solid var(--border); color: var(--text-faint); white-space: nowrap; } -.effect-hot { color: var(--ok); border-color: var(--ok); } -.effect-new-run { color: var(--warn); border-color: var(--warn); } +.effect-hot { color: var(--ok-text); border-color: var(--ok); } +.effect-new-run { color: var(--warn-text); border-color: var(--warn); } /* ---- 文档查看器(单层 OverlayHost 内)---- */ .docv { display: flex; flex-direction: column; min-height: 0; } .docv-toolbar { display: flex; align-items: center; gap: 8px; padding: 0 0 10px; border-bottom: 1px solid var(--border-soft); margin-bottom: 10px; } .docv-toolbar .spacer { flex: 1; } .docv-meta { font-size: var(--fs-ui-xs); color: var(--text-faint); text-transform: capitalize; } -.docv-dirty { color: var(--warn); font-size: var(--fs-ui-sm); } +.docv-dirty { color: var(--warn-text); font-size: var(--fs-ui-sm); } .docv-dl { text-decoration: none; } .docv-body { flex: 1; min-height: 0; overflow: auto; } .docv-pdf { width: 100%; height: 100%; min-height: 60vh; border: 1px solid var(--border-soft); border-radius: var(--radius); background: var(--bg); } -.docv-editor { width: 100%; height: 56vh; font-family: var(--mono); font-size: var(--fs-ui-sm); resize: vertical; } -.docv-pre { font-family: var(--mono); font-size: var(--fs-ui-sm); white-space: pre-wrap; word-break: break-word; background: var(--bg-inset); border: 1px solid var(--border-soft); border-radius: var(--radius); padding: 12px 14px; } +.docv-editor { width: 100%; height: 56vh; font-family: var(--mono); font-size: var(--fs-code); resize: vertical; } +.docv-pre { font-family: var(--mono); font-size: var(--fs-code); white-space: pre-wrap; word-break: break-word; background: var(--bg-inset); border: 1px solid var(--border-soft); border-radius: var(--radius); padding: 12px 14px; } /* ---- 杂项 ---- */ .toast { position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%); background: var(--bg-raised); border: 1px solid var(--border); color: var(--text); padding: 9px 16px; border-radius: var(--radius-full); box-shadow: var(--shadow-lg); z-index: 90; font-size: var(--fs-ui-caption); } @@ -351,18 +351,18 @@ button { font-family: inherit; font-size: inherit; color: inherit; } .tsb-name { font-weight: 650; font-size: var(--fs-ui-caption); letter-spacing: -0.01em; } .tsb-iconbtn { width: 26px; height: 26px; border-radius: var(--radius-sm); background: none; border: none; color: var(--text-faint); cursor: pointer; font-size: var(--fs-ui-caption); display: inline-flex; align-items: center; justify-content: center; position: relative; } .tsb-iconbtn:hover { background: var(--bg-hover); color: var(--text); } -.tsb-iconbtn.active { color: var(--accent); background: var(--accent-soft); } +.tsb-iconbtn.active { color: var(--accent-sidebar); background: var(--accent-soft); } .tsb-actions { padding: 6px 12px 8px; display: flex; flex-direction: column; gap: 7px; } -.tsb-newtask { display: flex; height: 36px; border-radius: var(--radius); background: var(--primary); color: var(--primary-foreground); overflow: hidden; box-shadow: 0 1px 3px rgba(0, 0, 0, .3); transition: background .12s; } -.tsb-newtask:hover { background: color-mix(in srgb, var(--primary) 86%, var(--bg)); } +.tsb-newtask { display: flex; height: 36px; border-radius: var(--radius); background: var(--primary-sidebar); color: var(--primary-sidebar-foreground); overflow: hidden; box-shadow: 0 1px 3px rgba(0, 0, 0, .3); transition: background .12s; } +.tsb-newtask:hover { background: color-mix(in srgb, var(--primary-sidebar) 86%, var(--bg-sidebar)); } .tsb-newtask-main { flex: 1; display: flex; align-items: center; gap: 7px; padding: 0 11px; background: none; border: none; color: inherit; font-weight: 600; font-size: var(--fs-ui-caption); cursor: pointer; min-width: 0; } .tsb-newtask-main svg { flex: none; } .tsb-newtask-proj { font-weight: 450; font-size: var(--fs-ui-xs); opacity: .75; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } -.tsb-newtask-caret { width: 30px; border: none; border-left: 1px solid color-mix(in srgb, var(--primary-foreground) 18%, transparent); background: none; color: inherit; cursor: pointer; display: flex; align-items: center; justify-content: center; } -.tsb-newtask-caret:hover { background: color-mix(in srgb, var(--primary-foreground) 8%, transparent); } +.tsb-newtask-caret { width: 30px; border: none; border-left: 1px solid color-mix(in srgb, var(--primary-sidebar-foreground) 18%, transparent); background: none; color: inherit; cursor: pointer; display: flex; align-items: center; justify-content: center; } +.tsb-newtask-caret:hover { background: color-mix(in srgb, var(--primary-sidebar-foreground) 8%, transparent); } .tsb-search { display: flex; align-items: center; gap: 7px; height: 32px; border-radius: var(--radius); border: 1px solid var(--border); background: var(--bg-raised); color: var(--text-faint); padding: 0 10px; transition: border-color .12s, box-shadow .12s; } -.tsb-search:focus-within { border-color: var(--accent); box-shadow: var(--ring); } +.tsb-search:focus-within { border-color: var(--accent-sidebar); box-shadow: var(--ring); } .tsb-search svg { flex: none; } .tsb-search input { flex: 1; border: none; background: none; color: var(--text); font-size: var(--fs-ui-sm); outline: none; min-width: 0; } .tsb-search input::placeholder { color: var(--text-faint); } @@ -374,8 +374,8 @@ button { font-family: inherit; font-size: inherit; color: inherit; } .tsb-pill.on { background: var(--bg-raised); color: var(--text); font-weight: 550; box-shadow: 0 1px 2px rgba(0,0,0,.25); } .tsb-scroll { flex: 1; overflow-y: auto; padding: 0 10px 8px; min-height: 0; } -.tsb-seclabel { font-size: var(--fs-ui-xs); color: var(--text-faint); padding: 12px 8px 4px; letter-spacing: .05em; font-weight: 600; } -.tsb-empty { padding: 20px 14px; color: var(--text-faint); font-size: var(--fs-ui-sm); line-height: 1.9; text-align: center; } +.tsb-seclabel { font-size: var(--fs-ui-sm); color: var(--text-dim); padding: 12px 8px 4px; font-weight: 600; } +.tsb-empty { padding: 20px 14px; color: var(--text-dim); font-size: var(--fs-ui-sm); line-height: 1.9; text-align: center; } .tsb-newproject { padding: 0 2px 8px; } .tsb-group { margin-bottom: 2px; } @@ -392,11 +392,11 @@ button { font-family: inherit; font-size: inherit; color: inherit; } .tsb-task { display: flex; align-items: center; gap: 8px; height: 31px; padding: 0 8px; margin: 1px 0; border-radius: var(--radius-sm); color: var(--text-dim); cursor: pointer; position: relative; transition: background .1s, color .1s; } .tsb-task:hover { background: var(--bg-hover); color: var(--text); } .tsb-task.active { background: var(--bg-active); color: var(--text); } -.tsb-task.active::before { content: ''; position: absolute; left: -2px; top: 6px; bottom: 6px; width: 2.5px; border-radius: 2px; background: var(--accent); } +.tsb-task.active::before { content: ''; position: absolute; left: -2px; top: 6px; bottom: 6px; width: 2.5px; border-radius: 2px; background: var(--accent-sidebar); } .tsb-task.archived .tsb-task-t { text-decoration: line-through; opacity: .6; } .tsb-task-t { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: var(--fs-ui-caption); } .tsb-task-tm { font-size: var(--fs-ui-xs); color: var(--text-faint); font-variant-numeric: tabular-nums; } -.tsb-pbadge { font-size: var(--fs-ui-xs); color: var(--text-faint); border: 1px solid var(--border); border-radius: var(--radius-xs); padding: 0 5px; line-height: 1.5; white-space: nowrap; } +.tsb-pbadge { font-size: var(--fs-ui-xs); color: var(--text-dim); border: 1px solid var(--border); border-radius: var(--radius-xs); padding: 0 5px; line-height: 1.5; white-space: nowrap; } .tsb-row-acts { display: none; gap: 2px; } .tsb-task:hover .tsb-row-acts { display: inline-flex; } .tsb-task:hover .tsb-task-tm { display: none; } @@ -412,14 +412,17 @@ button { font-family: inherit; font-size: inherit; color: inherit; } .tsb-user-sub { font-size: var(--fs-ui-xs); color: var(--text-faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .tsb-user-chev { color: var(--text-faint); display: inline-flex; } -.tsb-menu { position: fixed; z-index: 300; min-width: 216px; background: var(--bg-raised); border: 1px solid var(--border-strong); border-radius: var(--radius); box-shadow: var(--shadow-lg); padding: 5px; display: flex; flex-direction: column; animation: mk-modal-in .12s var(--ease); } +.tsb-menu { position: fixed; z-index: 300; min-width: 216px; background: var(--bg-raised); border: 1px solid var(--border-strong); border-radius: var(--radius); box-shadow: var(--shadow-lg); padding: 5px; display: flex; flex-direction: column; animation: mk-modal-in .12s var(--ease); + /* 菜单挂在侧栏里,但纸面是主区底。侧栏对 --text* 的重映射不能漏进来。 */ + --text: var(--text-workspace); --text-dim: var(--text-workspace-dim); --text-faint: var(--text-workspace-faint); + color: var(--text-workspace); } .tsb-mi { display: flex; align-items: center; gap: 9px; min-height: 31px; padding: 4px 9px; border: none; border-radius: var(--radius-sm); background: none; color: var(--text-dim); font-size: var(--fs-ui-caption); cursor: pointer; text-align: left; } .tsb-mi svg { color: var(--text-faint); flex: none; } .tsb-mi:hover { background: var(--bg-hover); color: var(--text); } .tsb-mi:hover svg { color: var(--text-dim); } -.tsb-mi.danger { color: var(--err); } -.tsb-mi.danger:hover { background: var(--err); color: var(--text-on-accent); } -.tsb-mi.danger:hover svg { color: var(--text-on-accent); } +.tsb-mi.danger { color: var(--err-text); } +.tsb-mi.danger:hover { background: var(--err-text); color: var(--text-on-semantic); } +.tsb-mi.danger:hover svg { color: var(--text-on-semantic); } .tsb-mi kbd { margin-left: auto; font-size: var(--fs-ui-xs); font-family: var(--mono); color: var(--text-faint); } .tsb-menu-div { height: 1px; background: var(--border-soft); margin: 5px 4px; } .tsb-acc-head { display: flex; gap: 10px; align-items: center; padding: 8px 9px 6px; } @@ -451,7 +454,7 @@ button { font-family: inherit; font-size: inherit; color: inherit; } .lg-input { width: 100%; height: 38px; border-radius: var(--radius); border: 1px solid var(--border); background: var(--bg-raised); color: var(--text); padding: 0 12px; font-size: var(--fs-ui-caption); transition: border-color .12s, box-shadow .12s; } .lg-input:focus { border-color: var(--accent); box-shadow: var(--ring); outline: none; } .lg-mono { font-family: var(--mono); font-size: var(--fs-ui-sm); } -.lg-err { margin-top: 12px; font-size: var(--fs-ui-sm); color: var(--err); background: var(--err-soft); border: 1px solid color-mix(in srgb, var(--err) 35%, transparent); border-radius: var(--radius); padding: 8px 11px; display: flex; gap: 7px; align-items: flex-start; } +.lg-err { margin-top: 12px; font-size: var(--fs-ui-sm); color: var(--err-text); background: var(--err-soft); border: 1px solid color-mix(in srgb, var(--err) 35%, transparent); border-radius: var(--radius); padding: 8px 11px; display: flex; gap: 7px; align-items: flex-start; } .lg-err svg { flex: none; margin-top: 1px; } .lg-submit { width: 100%; height: 38px; margin-top: 16px; border: none; border-radius: var(--radius); @@ -478,7 +481,7 @@ button { font-family: inherit; font-size: inherit; color: inherit; } .az-nav-item { display: flex; align-items: center; gap: 9px; padding: 9px 11px; border: none; background: none; color: var(--text-dim); font-size: var(--fs-ui-caption); border-radius: var(--radius-sm); cursor: pointer; text-align: left; } .az-nav-item:hover { background: var(--bg-hover); color: var(--text); } .az-nav-item.on { background: var(--bg-active); color: var(--text); font-weight: 550; } -.az-nav-item.on svg { color: var(--accent); } +.az-nav-item.on svg { color: var(--accent-text); } .az-main { flex: 1; min-width: 0; overflow-y: auto; padding: 20px 24px; } .az-section-head { margin-bottom: 14px; } .az-section-head h3 { margin: 0 0 4px; font-size: var(--fs-ui-lg); font-weight: 600; letter-spacing: -0.01em; } @@ -493,18 +496,18 @@ button { font-family: inherit; font-size: inherit; color: inherit; } .ad-create-btn { width: auto; padding: 0 14px; margin-top: 0; height: 34px; flex: none; } .ad-mini { border: 1px solid var(--border); background: var(--bg-raised); color: var(--text-dim); border-radius: var(--radius-sm); padding: 4px 9px; font-size: var(--fs-ui-sm); cursor: pointer; white-space: nowrap; display: inline-flex; align-items: center; gap: 4px; } .ad-mini:hover { color: var(--text); border-color: var(--accent); } -.ad-hint { margin: 0; font-size: var(--fs-ui-xs); color: var(--text-faint); } -.ad-notice { font-size: var(--fs-ui-sm); color: var(--ok); background: var(--ok-soft); border: 1px solid var(--ok-border); border-radius: var(--radius); padding: 8px 11px; display: flex; gap: 7px; align-items: flex-start; } +.ad-hint { margin: 0; font-size: var(--fs-ui-sm); color: var(--text-dim); } +.ad-notice { font-size: var(--fs-ui-sm); color: var(--ok-text); background: var(--ok-soft); border: 1px solid var(--ok-border); border-radius: var(--radius); padding: 8px 11px; display: flex; gap: 7px; align-items: flex-start; } .ad-notice svg { flex: none; margin-top: 1px; } .ad-table { width: 100%; border-collapse: collapse; font-size: var(--fs-ui-sm); } -.ad-table th { text-align: left; font-weight: 600; color: var(--text-faint); font-size: var(--fs-ui-xs); text-transform: uppercase; letter-spacing: .06em; padding: 8px; border-bottom: 1px solid var(--border); } +.ad-table th { text-align: left; font-weight: 600; color: var(--text-dim); font-size: var(--fs-ui-sm); padding: 8px; border-bottom: 1px solid var(--border); } .ad-table td { padding: 9px 8px; border-bottom: 1px solid var(--border-soft); } .ad-table tr:last-child td { border-bottom: none; } .ad-mono { font-family: var(--mono); font-size: var(--fs-ui-sm); } -.ad-dim { color: var(--text-faint); } -.ad-chip { font-size: var(--fs-ui-xs); border-radius: var(--radius-xs); padding: 2px 7px; font-weight: 700; letter-spacing: .5px; background: var(--bg-hover); color: var(--text-faint); } -.ad-chip-admin { background: var(--accent-soft); color: var(--accent); } -.ad-chip-warn { background: var(--warn-soft); color: var(--warn); } +.ad-dim { color: var(--text-dim); } +.ad-chip { font-size: var(--fs-ui-xs); border-radius: var(--radius-xs); padding: 2px 7px; font-weight: 700; letter-spacing: .5px; background: var(--bg-hover); color: var(--text-dim); } +.ad-chip-admin { background: var(--accent-soft); color: var(--accent-text); } +.ad-chip-warn { background: var(--warn-soft); color: var(--warn-text); } .ad-reset { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; border: 1px solid color-mix(in srgb, var(--warn) 40%, transparent); background: var(--warn-soft); border-radius: var(--radius-lg); padding: 12px; font-size: var(--fs-ui-sm); } .ad-reset .lg-input { flex: 1; min-width: 160px; height: 32px; } .ad-changepw { display: flex; flex-direction: column; gap: 2px; max-width: 340px; } @@ -513,7 +516,7 @@ button { font-family: inherit; font-size: inherit; color: inherit; } .icon-only { display: flex; flex-direction: column; align-items: center; gap: 6px; padding-top: 12px; } .icon-only button { background: none; border: none; color: var(--text-faint); cursor: pointer; padding: 0; width: 34px; height: 34px; border-radius: var(--radius); display: inline-flex; align-items: center; justify-content: center; position: relative; } .icon-only button:hover { background: var(--bg-hover); color: var(--text); } -.rail-badge { position: absolute; top: 3px; right: 3px; min-width: 14px; height: 14px; border-radius: 7px; background: var(--warn); color: var(--text-on-accent); font-size: var(--fs-ui-xs); font-weight: 700; display: flex; align-items: center; justify-content: center; padding: 0 4px; } +.rail-badge { position: absolute; top: 3px; right: 3px; min-width: 14px; height: 14px; border-radius: 7px; background: var(--warn-text); color: var(--text-on-semantic); font-size: var(--fs-ui-xs); font-weight: 700; display: flex; align-items: center; justify-content: center; padding: 0 4px; } /* ---- UI 能力平台消费(消息头像列 / 设置外壳 / 管理弹层头像) ---- */ .role-mark { width: 20px; height: 20px; border-radius: 6px; display: inline-flex; align-items: center; justify-content: center; color: var(--text-dim); background: var(--bg-raised); border: 1px solid var(--border); } @@ -540,7 +543,7 @@ button { font-family: inherit; font-size: inherit; color: inherit; } .tsb-project:hover { background: var(--bg-hover); } .tsb-project.active { background: var(--bg-active); } .tsb-project-name { font-weight: 600; font-size: var(--fs-ui-sm); } -.tsb-project-meta { color: var(--text-faint); font-size: var(--fs-ui-xs); } +.tsb-project-meta { color: var(--text-dim); font-size: var(--fs-ui-xs); } .tsb-tool { display: flex; align-items: center; gap: 8px; width: 100%; background: none; border: none; cursor: pointer; color: inherit; @@ -548,10 +551,10 @@ button { font-family: inherit; font-size: inherit; color: inherit; } } .tsb-tool:hover { background: var(--bg-hover); } .tsb-tool kbd { margin-left: auto; font-family: var(--mono); font-size: var(--fs-ui-xs); color: var(--text-faint); } -.tsb-tool-note { color: var(--text-faint); font-size: var(--fs-ui-xs); padding: 2px 10px 8px; } +.tsb-tool-note { color: var(--text-dim); font-size: var(--fs-ui-xs); padding: 2px 10px 8px; } .tsb-tool-badge { margin-left: 6px; min-width: 16px; padding: 0 5px; border-radius: var(--radius-full); - background: var(--err); color: var(--text-on-accent); font-size: var(--fs-ui-xs); + background: var(--err-text); color: var(--text-on-semantic); font-size: var(--fs-ui-xs); } .rewind-row { margin-top: 8px; } .rewind-panel { @@ -564,4 +567,4 @@ button { font-family: inherit; font-size: inherit; color: inherit; } .msg-tools { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; margin-top: 4px; } .session-note { width: 12rem; } .rewind-actions { display: flex; gap: 8px; } -.rewind-error { color: var(--err); font-size: var(--fs-ui-sm); } +.rewind-error { color: var(--err-text); font-size: var(--fs-ui-sm); }