refactor(frontend): 颜色 token 系统两层重构 + 三主题填色 + 去半透明

将前端配色从散落的硬编码/双命名体系(--claude-* / --theme-*)重构为
两层 token 结构(原始层 + 中性语义层),并按"经典抄 Claude、浅色抄
ChatGPT、深色自研"的定位完成三主题填色,同时建立 stylelint 防回退栏杆。
代码大量由 AI 生成的历史遗留配色问题(同语义多值、跨主题塌缩、强调色
撞文字色、fallback 第二真相源等)在此一并收口。

== 一、Token 结构重构(_tokens.scss)==
- 重写为两层:原始层 + 语义层;组件只引用中性语义名
  (--surface-* / --text-* / --border-* / --accent* / --state-* 等)。
- --claude-* / --theme-* 降级为兼容别名(41 个转发),迁移完成后删除。
- 三主题(classic / light / dark)+ 首屏回退(:root:not([data-theme]),
  与经典同值)全部补齐,结构对齐、不再缺项。

== 二、三主题填色 ==
- 经典 = Claude 官网亮色盘:暖奶油表面阶梯
  canvas #faf9f5 < soft #f5f0e8 < card #efe9de < cream-strong #e8e0d2
  < 纯白浮起;文字 #141413;hairline #e6dfd8;暖橙 primary #cc785c。
- 浅色 = ChatGPT 亮色盘:冷白 #ffffff / 侧栏 #f9f9f9 / 嵌套 #f3f3f3,
  中性灰文字,近黑 primary #181818。
- 深色 = 自研中性灰阶,本轮完全不动(原样保留)。
- 修复塌缩 bug:强调色在 light/dark 原被误填成灰(CTA 失去品牌色),
  现统一回品牌 primary;light 表面原全塌成 #ffffff(过于平面),
  现按灰阶拉开层次。
- 强调色克制(CTA-only voltage):primary 仅用于发送按钮/logo 等极少
  数处;hover / 选中 / 运行态一律走中性灰(运行态指示器从 amber 改灰)。
- 对话区背景从纯白改为暖奶油 canvas;个人空间下拉菜单、git 状态条、
  二级菜单等收口到统一语义色。

== 三、全面去半透明 ==
- 所有实体面板/二级菜单背景改为不透明(surface token 由半透明白改实色,
  --mobile-menu 三亮色主题改实色)。
- 移除已不透明面板上失效的 backdrop-filter 磨砂(移动端菜单、右键菜单、
  模型模式下拉等)。
- 遮罩 scrim(--overlay-scrim)与刻意玻璃质感装饰保留半透明。

== 四、块展开底色统一 ==
- 思考/工具块展开区底色统一为对话背景色:.collapsible-block 及其 header
  背景由 --surface-soft 改 transparent,与堆叠块(stacked-block)一致,
  消除"单块奶油底 vs 多块透明"的不一致。

== 五、布局修复 ==
- 工作区隐藏后残留空白:.workspace-panel--collapsed 补 flex-basis:0 +
  width/min-width:0,修正 flex-basis:auto 被子元素内容宽度撑开导致内联
  width:0 失效、collapsed 后仍占 ~300px 的问题。

== 六、防回退栏杆(新增)==
- 新增 .stylelintrc.cjs:三条规则拦截裸 hex / rgb()|hsl() 字面色 /
  var(--x, fallback) 兜底 / prefers-color-scheme;存量未清理文件用
  BASELINE_EXEMPT 临时豁免(现仅剩 5 个 admin 页面,本轮按用户要求不处理),
  清理一个移除一个、不再回退。
- package.json:build 脚本接入 stylelint(tsc → stylelint → vite),
  新增 lint:css 脚本及 stylelint/postcss-scss/postcss-html 依赖。
- 修复 25 处 \!important 笔误(zsh 历史扩展污染导致的无效 CSS)。

== 七、辅助脚本(新增 scripts/)==
- lint_check.py:Node 环境不可用时的 stylelint 替身(复刻三规则 + 括号
  校验,支持多行声明检测)。
- color_map.py:硬编码色 → token 反查,判定可映射/野色。
- strip_fallback.py:安全剥离已定义 token 的冗余 fallback。

== 八、文档 ==
- CLAUDE.md / AGENTS.md 前端设计规范更新:颜色规则扩写为三主题定位 +
  两层 token + 表面层次 + 强调色克制 + color-mix 派生 + stylelint 栏杆;
  新增"实体面板禁止半透明"规则;"禁止边缘光晕"补充"仅在用户明确允许
  或要求时才可使用"。

注:前端构建验证(npm run build / lint:css)由用户本机完成;AI 工具
上下文 Node v24 段错误无法运行 node/npm/vite/stylelint。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
JOJO 2026-06-06 16:20:58 +08:00
parent e34e2c965c
commit b4030c386e
42 changed files with 3245 additions and 1629 deletions

84
.stylelintrc.cjs Normal file
View File

@ -0,0 +1,84 @@
/**
* Stylelint 配置 颜色 Token 栏杆规范见 doc/frontend/color_token_spec.md
*
* 作用拦住三类"绕过设计 Token"的写法让规范从文字变成机制
* 规则1 color-no-hex 禁止裸十六进制色号 #da7756
* 规则2 declaration-property-value-... 禁止 rgb()/hsl() 字面色禁止 var(--x, #hex) 兜底
* 规则3 media-feature-name-disallowed-list 禁止组件内新增 prefers-color-scheme 主题分支
*
* 基线策略baseline
* - 颜色属性必须走 var(--token)
* - 下方 BASELINE_EXEMPT 列出的是"立规矩之前就存在违规"的存量文件暂时豁免
* - 新文件不在名单里 从第一行起就受三条规则约束
* - 每当治理清理掉一个存量文件就把它从 BASELINE_EXEMPT 删除它从此受约束不再回退
* - 设计上永久豁免_tokens.scssToken 定义源_virtual-monitor.scsscanvas 动画资产
*/
// 颜色相关属性:这些属性的值必须用 token不能写字面色
const COLOR_PROPS =
'/^(color|fill|stroke|background|background-color|border|border-color|border-top-color|border-right-color|border-bottom-color|border-left-color|box-shadow|outline|outline-color|text-decoration-color|caret-color|column-rule-color|stop-color)$/';
// 立规矩之前就存在硬编码颜色的存量文件baseline 豁免,治理后逐个移除)
const BASELINE_EXEMPT = [
'static/src/admin/AdminDashboardApp.vue',
'static/src/admin/ApiAdminApp.vue',
'static/src/admin/CustomToolsApp.vue',
'static/src/admin/CustomToolsGuideApp.vue',
'static/src/admin/PolicyApp.vue',
];
// 三条颜色规则(供默认与 override 复用)
const COLOR_RULES = {
// 规则1禁止裸 hex
'color-no-hex': [true, { message: '禁止裸 hex 色号,请使用设计 Tokenvar(--accent) 等(见 color_token_spec.md' }],
// 规则2禁止 rgb()/hsl() 字面色 + 禁止 var() 兜底色
'declaration-property-value-disallowed-list': [
{
[COLOR_PROPS]: ['/rgba?\\(/', '/hsla?\\(/', '/var\\(\\s*--[^,)]+,/'],
},
{
message:
'颜色属性禁止 rgb()/hsl() 字面色或 var(--x, #hex) 兜底,请直接用 var(--token)(见 color_token_spec.md',
},
],
// 规则3禁止组件内手写 prefers-color-scheme 主题分支(主题切换只在 _tokens.scss 的 [data-theme] 完成)
'media-feature-name-disallowed-list': [
['prefers-color-scheme'],
{ message: '禁止在组件内用 prefers-color-scheme 写主题分支,颜色随主题变化应通过 Token 自动完成' },
],
};
// 关闭三条规则(给存量豁免文件用)
const COLOR_RULES_OFF = {
'color-no-hex': null,
'declaration-property-value-disallowed-list': null,
'media-feature-name-disallowed-list': null,
};
module.exports = {
// 设计上永久豁免Token 定义源 + canvas 动画资产
ignoreFiles: [
'static/dist/**',
'static/src/styles/base/_tokens.scss',
'static/src/styles/components/chat/_virtual-monitor.scss',
],
// 顶层 rules 必填stylelint 16 要求)。具体规则按文件类型在 overrides 中施加。
rules: {},
overrides: [
{
files: ['static/src/**/*.scss'],
customSyntax: 'postcss-scss',
rules: COLOR_RULES,
},
{
files: ['static/src/**/*.vue'],
customSyntax: 'postcss-html',
rules: COLOR_RULES,
},
// baseline存量文件暂时关闭三条规则治理后从此数组移除该文件即可恢复约束
{
files: BASELINE_EXEMPT,
rules: COLOR_RULES_OFF,
},
],
};

View File

@ -141,16 +141,17 @@
> 适用范围:所有前端 UI`static/src` Web 为主;`cli/src` 在视觉可类比处同样适用;以及未来新增的任何界面)。
> 约束级别:写新 UI 或改动 UI 时**必须遵守**;遇到存量违规应在最小改动允许范围内顺手修正。
> 配色基础设施:三模式 CSS 变量定义在 `static/src/styles/base/_tokens.scss``:root[data-theme='classic'|'light'|'dark']`),切换逻辑见 `static/src/utils/theme.ts`
> 配色基础设施:两层 token原始层 + 语义层)定义在 `static/src/styles/base/_tokens.scss``:root[data-theme='classic'|'light'|'dark']` + 首屏回退 `:root:not([data-theme])`),切换逻辑见 `static/src/utils/theme.ts``.stylelintrc.cjs` 三条规则做防回退栏杆,`build` 含 `stylelint` 步骤
1. **禁止边缘光晕**:不使用任何 glow / 外发光 / 彩色光晕效果(大范围彩色 `box-shadow` 扩散、`filter: drop-shadow` 光圈、`::before/::after` 模糊光晕等)。已有的要移除。允许的只是中性、克制的投影——沿用 `--claude-shadow` / `--theme-shadow-*` 既有 token不自造发光阴影。
1. **禁止边缘光晕**:不使用任何 glow / 外发光 / 彩色光晕效果(大范围彩色 `box-shadow` 扩散、`filter: drop-shadow` 光圈、`::before/::after` 模糊光晕等)。已有的要移除。允许的只是中性、克制的投影——沿用 `--shadow-*` 既有 token不自造发光阴影。**仅在用户明确允许或要求时才可使用光晕效果。**
2. **禁止原生浏览器组件**:不直接使用浏览器默认外观的 `<select>`、`<input type=checkbox/radio/range/date/color>`、`alert/confirm/prompt`、原生右键菜单、原生 tooltip 等,一律换成与项目风格统一的自定义组件(下拉 / 开关 / 单选 / 滑块 / 模态 / Toast
3. **禁止圆角套娃**:不允许「圆角矩形套圆角矩形套圆角矩形」的多层嵌套卡片——典型垃圾审美,且极大占据有效显示面积。容器层级要扁平,优先用分隔线 / 留白 / 底色区分,不要多包一层带边框圆角的盒子。
4. **图标外框对齐**:同一组图标按钮的外框(点击热区 / 容器)必须统一对齐,不能一会居中、一会左对齐、一会右对齐;同组固定相同尺寸与对齐方式。
5. **图标视觉对齐而非理论对齐**:按图标视觉重心对齐而非几何边界盒;对重心偏移的图标(三角形 / 播放键 / 放大镜等)做微调,使其「看起来居中」。
6. **颜色遵循三模式切换**:所有颜色走原生三模式(经典 `classic` / 明亮 `light` / 夜间 `dark`),禁止写死颜色字面量,一律用 CSS 变量(`--claude-*` / `--theme-*`)。新增颜色必须在三套主题里都补齐。
6. **颜色遵循三模式切换 + 两层 Token**:所有颜色走原生三模式,禁止写死颜色字面量(裸 hex / `rgb()`/`hsl()` 字面色 / `var(--x, #hex)` 兜底),一律用**中性语义** CSS 变量(`--surface-*` / `--text-*` / `--border-*` / `--accent*` / `--state-*`)。三主题定位:**经典抄 Claude 亮色盘**(暖奶油 + 暖橙 primary `#cc785c`)、**浅色抄 ChatGPT 亮色盘**(冷白 + 灰 + 近黑 primary `#181818`)、**深色自研中性灰阶**。亮色表面靠灰阶拉层次(经典 `--surface-base #faf9f5` < `soft #f5f0e8` < `card #efe9de` < `muted #e8e0d2`不许全塌成白。primary 克制CTA-onlyhover/选中/运行态走中性灰。半透明 tint 用 `color-mix(in srgb, var(--token) N%, transparent)` 派生。`--claude-*`/`--theme-*` 是过时别名,新代码勿用。新增颜色必须三主题(含首屏回退)补齐。
7. **带文字容器固定高度**:所有含内部文字的选项 / 按钮 / 标签 / 容器固定高度,禁止因文字多少被撑大撑高;过长文字用省略号或内部滚动处理。
8. **窗口设最大尺寸 + 内部滚动**:所有弹窗 / 面板 / 列表设置 `max-height` / `max-width`,超出由内部容器滚动,不顶大整个窗口;滚动条要么隐藏,要么做样式适配,不暴露原生粗滚动条。
9. **实体面板禁止半透明**:实体 UI 容器(对话区 / 侧栏 / 下拉/二级菜单 / 抽屉 / 对话框本体 / 状态条 / tooltip / 输入栏)背景必须不透明,且不加 `backdrop-filter` 磨砂。唯一例外:遮罩层 scrim`--overlay-scrim``position:fixed;inset:0`)和刻意玻璃质感装饰保留半透明。
## 6) Git 工作流(开发 + Review

View File

@ -272,7 +272,7 @@ terminal.delete_conversation(conversation_id)
> 适用范围:所有前端 UI`static/src` Web 为主;`cli/src` 在视觉可类比处同样适用;以及未来新增的任何界面)。
> 约束级别:写新 UI 或改动 UI 时**必须遵守**;遇到存量违规应在最小改动允许范围内顺手修正。
1. **禁止边缘光晕**:不使用任何 glow / 外发光 / 彩色光晕效果(大范围彩色 `box-shadow` 扩散、用 `filter: drop-shadow` 做光圈、`::before/::after` 模糊光晕等)。已有的要移除。允许的只是中性、克制的投影——沿用 `--claude-shadow` / `--theme-shadow-*` 这类已有 token不要自造发光阴影。
1. **禁止边缘光晕**:不使用任何 glow / 外发光 / 彩色光晕效果(大范围彩色 `box-shadow` 扩散、用 `filter: drop-shadow` 做光圈、`::before/::after` 模糊光晕等)。已有的要移除。允许的只是中性、克制的投影——沿用 `--claude-shadow` / `--theme-shadow-*` 这类已有 token不要自造发光阴影。**仅在用户明确允许或要求时才可使用光晕效果。**
2. **禁止原生浏览器组件**:不直接使用浏览器默认外观的 `<select>`、`<input type=checkbox/radio/range/date/color>`、`alert/confirm/prompt`、原生右键菜单、原生 tooltip 等。一律替换为与项目风格统一的自定义组件下拉、开关、单选、滑块、模态、Toast 等)。
@ -282,12 +282,21 @@ terminal.delete_conversation(conversation_id)
5. **图标视觉对齐而非理论对齐**:按图标的视觉重心对齐,而不是几何边界盒。对视觉重心偏移的图标(三角形 / 播放键 / 放大镜等做微调micro-nudge让它「看起来居中」而非「数值上居中」。
6. **颜色遵循三模式切换**:所有颜色必须走原生三模式(经典 `classic` / 明亮 `light` / 夜间 `dark`)。禁止写死颜色字面量,一律使用 CSS 变量(`--claude-*` / `--theme-*`,定义在 `static/src/styles/base/_tokens.scss`,由 `:root[data-theme='classic'|'light'|'dark']` 提供;切换逻辑见 `static/src/utils/theme.ts`)。新增颜色必须在三套主题里都补齐。
6. **颜色遵循三模式切换 + 两层 Token**:所有颜色必须走原生三模式(经典 `classic` / 明亮 `light` / 夜间 `dark`),禁止写死颜色字面量(含裸 hex、`rgb()`/`hsl()` 字面色、`var(--x, #hex)` 兜底),一律使用语义 CSS 变量。
- **三主题定位**(填色基准):**经典 = 抄 Claude 官网亮色盘**(暖奶油色阶 + 暖橙 primary `#cc785c`**浅色 = 抄 ChatGPT 亮色盘**(冷白 + 中性灰 + 近黑 primary `#181818`**深色 = 自研中性灰阶**(浅灰/深灰/黑,不硬凑暖调)。
- **两层结构**token 定义在 `static/src/styles/base/_tokens.scss`,分原始层 + 语义层;组件只引用**中性语义名**`--surface-*` / `--text-*` / `--border-*` / `--accent*` / `--state-*` 等)。`--claude-*` / `--theme-*` 是**过时兼容别名**,迁移完成后会删,新代码不要用。
- **表面层次**(经典):画布 `--surface-base` `#faf9f5` < 侧栏 `--surface-soft` `#f5f0e8` < 卡片 `--surface-card` `#efe9de` < 嵌套 `--surface-muted` `#e8e0d2` < 纯白浮起 `--surface-raised`亮色主题不许把所有表面塌成同一个白必须靠暖/冷灰阶拉开层次
- **强调色克制**primary`--accent`)是 "CTA-only voltage",只点在主按钮/logo 等极少数处hover / 选中 / 运行态一律走中性灰(跟各自主题表面色),不抢镜。
- **派生色**:需要半透明 tint 时用 `color-mix(in srgb, var(--token) N%, transparent)` 从语义 token 派生,不写死 rgba。
- **新增颜色**必须在 classic / light / dark 三套主题(及首屏回退 `:root:not([data-theme])`,与经典同值)都补齐。
- **防回退栏杆**`.stylelintrc.cjs` 用 `color-no-hex` / `declaration-property-value-disallowed-list` / `media-feature-name-disallowed-list` 三条规则拦截违规,`build` 脚本含 `stylelint` 步骤会拦下裸色。存量未清理文件在 `BASELINE_EXEMPT` 临时豁免,清理一个移除一个,不再回退。切换逻辑见 `static/src/utils/theme.ts`
7. **带文字容器固定高度**:所有含内部文字的选项 / 按钮 / 标签 / 容器必须固定高度,禁止因文字多少被撑大撑高。文字过长用省略号或内部滚动处理,保持行高与块高稳定。
8. **窗口设最大尺寸 + 内部滚动**:所有弹窗 / 面板 / 列表必须设置 `max-height` / `max-width`,超出时由内部容器滚动,而不是把整个窗口顶大。滚动条要么隐藏,要么做样式适配(贴合整体设计,不暴露原生粗滚动条)。
9. **实体面板禁止半透明**:所有实体 UI 容器(对话区、侧栏、下拉/二级菜单、抽屉、对话框本体、状态条、tooltip 气泡、输入栏等)背景必须**不透明**,且不加 `backdrop-filter` 磨砂。背景一旦不透明,磨砂就失去意义,必须移除。**唯一例外**是遮罩层(弹窗背后压暗的 scrim`--overlay-scrim``position:fixed;inset:0`)和刻意的玻璃质感装饰,这类保留半透明。
## Security Considerations
- 所有用户操作在独立容器中执行,与宿主机隔离

2288
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -5,8 +5,9 @@
"type": "module",
"scripts": {
"dev": "vite build --watch",
"build": "tsc --noEmit && vite build",
"build": "tsc --noEmit && stylelint \"static/src/**/*.{scss,vue}\" && vite build",
"lint": "eslint \"static/src/**/*.{ts,tsx,js,vue}\" --max-warnings=0",
"lint:css": "stylelint \"static/src/**/*.{scss,vue}\"",
"format": "prettier --write \"static/src/**/*.{ts,tsx,js,vue,css}\"",
"preview": "vite preview",
"cli": "npm --prefix cli run dev",
@ -47,8 +48,11 @@
"@vue/eslint-config-typescript": "^12.0.0",
"eslint": "^8.56.0",
"eslint-plugin-vue": "^9.19.2",
"postcss-html": "^1.6.0",
"postcss-scss": "^4.0.9",
"prettier": "^3.1.1",
"sass": "^1.94.2",
"stylelint": "^16.10.0",
"typescript": "^5.3.3",
"vite": "^5.0.10",
"vue-tsc": "^1.8.22"

82
scripts/color_map.py Normal file
View File

@ -0,0 +1,82 @@
#!/usr/bin/env python3
"""
color_map.py 硬编码色值 token 反查
解析 _tokens.scss 各主题真实值对给定色值判定它等于哪个 tokenA类或无对应B类
用法:
python3 scripts/color_map.py <file> # 分析某文件里所有硬编码色的可映射性
"""
import sys, re, os
from collections import defaultdict
TOK = "static/src/styles/base/_tokens.scss"
def norm(v):
"""归一化色值:小写、去多余空格、#abc->#aabbcc、rgb 空格统一。"""
v = v.strip().lower()
v = re.sub(r'\s+', '', v)
m = re.fullmatch(r'#([0-9a-f])([0-9a-f])([0-9a-f])', v)
if m:
v = '#' + ''.join(c*2 for c in m.groups())
return v
def load_tokens():
txt = open(TOK, encoding='utf-8').read()
# semantic blocks only ([data-theme])
themes = {}
for m in re.finditer(r":root\[data-theme='([^']+)'\]\s*\{([^}]*)\}", txt):
name, body = m.group(1), m.group(2)
d = {}
for dm in re.finditer(r'(--[a-z0-9-]+)\s*:\s*([^;]+);', body):
d[norm(dm.group(2))] = dm.group(1)
themes[name] = d
return themes
def analyze(path, themes):
text = open(path, encoding='utf-8').read()
# only style content for vue
if path.endswith('.vue'):
style = '\n'.join(m.group(1) for m in re.finditer(r'<style[^>]*>(.*?)</style>', text, re.S|re.I))
else:
style = text
style = re.sub(r'/\*.*?\*/', '', style, flags=re.S)
style = re.sub(r'//[^\n]*', '', style)
vals = re.findall(r'#[0-9a-fA-F]{3,8}\b|rgba?\([0-9 ,.%/]+\)|hsla?\([0-9 ,.%/]+\)', style)
A = defaultdict(list) # value -> [(theme, token)]
B = defaultdict(int) # value -> count (no match)
counts = defaultdict(int)
for raw in vals:
n = norm(raw)
counts[raw] += 1
hits = []
for tname, d in themes.items():
if n in d:
hits.append((tname, d[n]))
if hits:
A[raw] = hits
else:
B[raw] += 1
return counts, A, B
def main():
themes = load_tokens()
path = sys.argv[1]
counts, A, B = analyze(path, themes)
print(f"=== {path} ===")
print(f"硬编码色值种类: {len(counts)}, 总出现: {sum(counts.values())}")
print(f"\n--- A类(有 token 对应, 可映射) ---")
for v in sorted(A, key=lambda x:-counts[x]):
# 取 classic 优先的 token 名
toks = {t:tok for t,tok in A[v]}
cls = toks.get('classic')
shown = cls or list(toks.values())[0]
themes_hit = ','.join(sorted(toks.keys()))
print(f" {counts[v]:3d}× {v:32s} -> {shown:28s} (命中主题: {themes_hit})")
print(f"\n--- B类(无 token 对应, 野色, 需决策) ---")
for v in sorted(B, key=lambda x:-B[x]):
print(f" {B[v]:3d}× {v}")
if not B:
print(" (无 — 此文件可全量安全迁移)")
if __name__ == '__main__':
main()

143
scripts/lint_check.py Normal file
View File

@ -0,0 +1,143 @@
#!/usr/bin/env python3
"""
lint_check.py Node 段错误环境下的 stylelint 替身验证器
复刻 .stylelintrc.cjs 的三条颜色规则 + 基础语法完整性用于在迁移每个文件后
确认它已彻底清理干净可安全从 BASELINE_EXEMPT 移除
用法:
python3 scripts/lint_check.py <file1> [file2] ...
python3 scripts/lint_check.py --all # 扫所有 .scss/.vue排除永久豁免
规则 stylelintrc 对齐:
R1 color-no-hex : 禁止裸 #hex
R2 literal-rgb-in-color : 颜色属性值禁止 rgb()/hsl() 字面色
R3 var-fallback-in-color : 颜色属性值禁止 var(--x, <fallback>)
R4 prefers-color-scheme : 禁止 @media prefers-color-scheme
注意: 只检查 <style> / scss 内容.vue 文件只扫 <style> 跳过 <template>/<script>
"""
import sys, re, os, glob
PERMANENT_IGNORE = {
'static/src/styles/base/_tokens.scss',
'static/src/styles/components/chat/_virtual-monitor.scss',
}
COLOR_PROP = re.compile(
r'^\s*(-?\w[\w-]*)?\s*('
r'color|fill|stroke|background|background-color|border|border-color|'
r'border-top-color|border-right-color|border-bottom-color|border-left-color|'
r'box-shadow|outline|outline-color|text-decoration-color|caret-color|'
r'column-rule-color|stop-color|text-shadow'
r')\s*:', re.I)
HEX = re.compile(r'#[0-9a-fA-F]{3,8}\b')
RGB = re.compile(r'\b(rgba?|hsla?)\s*\(')
VARFALLBACK = re.compile(r'var\(\s*--[^,()]+,')
def extract_style_blocks(text, is_vue):
"""返回 [(start_line, block_text)]。vue 只取 <style>scss 取全文。"""
if not is_vue:
return [(1, text)]
blocks = []
for m in re.finditer(r'<style[^>]*>(.*?)</style>', text, re.S | re.I):
start_line = text[:m.start(1)].count('\n') + 1
blocks.append((start_line, m.group(1)))
return blocks
def strip_comments(s):
s = re.sub(r'/\*.*?\*/', lambda m: '\n' * m.group(0).count('\n'), s, flags=re.S)
s = re.sub(r'//[^\n]*', '', s)
return s
def check_text(block_text, base_line):
errs = []
clean = strip_comments(block_text)
clean_lines = clean.splitlines()
# R1 hex / R4 prefers-color-scheme —— 行级
for i, line in enumerate(clean_lines):
ln = base_line + i
if 'prefers-color-scheme' in line:
errs.append((ln, 'R4 prefers-color-scheme', line.strip()))
if HEX.search(line):
errs.append((ln, 'R1 no-hex', line.strip()))
# R2/R3 —— 声明级(跨行)。按 ; { } 切成声明段,每段判断是否颜色属性,
# 段内若含 rgb/hsl 字面色或 var(--x, fallback),把违规行号定位到该 token
# 实际出现的那一行声明可能跨多行stylelint 报的是声明起始行;这里
# 我们用 token 出现行,足够定位)。
def line_of(char_idx):
return base_line + clean.count('\n', 0, char_idx)
pos = 0
for m in re.finditer(r'[;{}]', clean):
seg = clean[pos:m.start()]
seg_start = pos
pos = m.end()
if not COLOR_PROP.search(seg):
continue
for vm in VARFALLBACK.finditer(seg):
errs.append((line_of(seg_start + vm.start()), 'R3 var-fallback', seg.strip()[:80]))
for rm in RGB.finditer(seg):
errs.append((line_of(seg_start + rm.start()), 'R2 literal-rgb', seg.strip()[:80]))
# 处理最后一段(无尾分隔符的残留,通常为空)
seg = clean[pos:]
if COLOR_PROP.search(seg):
for vm in VARFALLBACK.finditer(seg):
errs.append((line_of(pos + vm.start()), 'R3 var-fallback', seg.strip()[:80]))
for rm in RGB.finditer(seg):
errs.append((line_of(pos + rm.start()), 'R2 literal-rgb', seg.strip()[:80]))
errs.sort(key=lambda e: e[0])
return errs
def syntax_check(text, is_vue):
"""大括号配对(针对 style 内容)。"""
blocks = extract_style_blocks(text, is_vue)
problems = []
for base, bt in blocks:
bt2 = strip_comments(bt)
if bt2.count('{') != bt2.count('}'):
problems.append(f" 大括号不配对 (block@L{base}): {{={bt2.count('{')} }}={bt2.count('}')}")
return problems
def lint_file(path):
text = open(path, encoding='utf-8').read()
is_vue = path.endswith('.vue')
all_errs = []
for base, bt in extract_style_blocks(text, is_vue):
all_errs.extend(check_text(bt, base))
syn = syntax_check(text, is_vue)
return all_errs, syn
def main():
args = sys.argv[1:]
if not args:
print("用法: python3 scripts/lint_check.py <file...> | --all")
sys.exit(2)
if args == ['--all']:
files = []
for pat in ('static/src/**/*.scss', 'static/src/**/*.vue'):
files += glob.glob(pat, recursive=True)
files = [f for f in files if f.replace('\\', '/') not in PERMANENT_IGNORE]
else:
files = args
total = 0
for f in sorted(files):
nf = f.replace('\\', '/')
if nf in PERMANENT_IGNORE:
print(f"SKIP (permanent ignore): {f}")
continue
errs, syn = lint_file(f)
if errs or syn:
print(f"\n{f}")
for ln, rule, txt in errs:
print(f" L{ln:<5} {rule:22} | {txt[:80]}")
for s in syn:
print(s)
total += len(errs) + len(syn)
else:
print(f"{f}")
print(f"\n总问题数: {total}")
sys.exit(1 if total else 0)
if __name__ == '__main__':
main()

120
scripts/strip_fallback.py Normal file
View File

@ -0,0 +1,120 @@
#!/usr/bin/env python3
"""
strip_fallback.py 安全剥离 var(--DEFINED_TOKEN, fallback) fallback
仅当 token _tokens.scss 中已定义时才剥离此时 fallback 永不生效剥离=零视觉变化
未定义 tokenfallback 是真实值一律跳过
--write 才落盘否则只 dry-run 报告
安全校验每个被改的位置改动后只是去掉了 ", fallback"token 名和其余内容不变
"""
import sys, re, glob, os
def load_defined():
txt = open('static/src/styles/base/_tokens.scss', encoding='utf-8').read()
return set(re.findall(r'(--[a-z0-9-]+)\s*:', txt))
def find_var_spans(s):
"""返回所有 var(...) 的 (start, end, inner) 支持嵌套end 是右括号下一位。"""
spans = []
i = 0
while True:
m = re.search(r'var\(', s[i:])
if not m:
break
start = i + m.start()
# 从 'var(' 的左括号开始做括号匹配
depth = 0
j = start + 3 # points at '('
assert s[j] == '('
k = j
while k < len(s):
if s[k] == '(':
depth += 1
elif s[k] == ')':
depth -= 1
if depth == 0:
break
k += 1
inner = s[j+1:k]
spans.append((start, k+1, inner))
i = k + 1
return spans
def strip_one(s, defined):
"""对字符串 s 处理最外层 var(),递归处理 inner。返回 (新串, 改动数)。"""
spans = find_var_spans(s)
if not spans:
return s, 0
out = []
last = 0
changes = 0
for start, end, inner in spans:
out.append(s[last:start])
# 先递归处理 inner处理嵌套 var
new_inner, c_inner = strip_one(inner, defined)
changes += c_inner
# 解析最外层 var(--tok, fallback?) —— 在顶层逗号处分割
mtok = re.match(r'\s*(--[a-z0-9-]+)\s*', new_inner)
if mtok:
tok = mtok.group(1)
rest = new_inner[mtok.end():]
if rest.startswith(','):
# 有 fallback。token 已定义 → 剥离
if tok in defined:
out.append(f'var({tok})')
changes += 1
else:
out.append(f'var({new_inner})')
else:
out.append(f'var({new_inner})')
else:
out.append(f'var({new_inner})')
last = end
out.append(s[last:])
return ''.join(out), changes
def process_file(path, defined, write):
src = open(path, encoding='utf-8').read()
new, ch = strip_one(src, defined)
if ch and write:
open(path, 'w', encoding='utf-8').write(new)
return ch, src, new
def verify(src, new):
"""校验去掉所有空白后new 必须是 src 删除若干 ', fallback' 的结果。
粗校验new 的非空白字符是 src 非空白字符的子序列且行数不变"""
if src.count('\n') != new.count('\n'):
return False, "行数变化"
# 每行new 行必须是 old 行的子序列(只删不增)
for o, n in zip(src.splitlines(), new.splitlines()):
oi = 0
for ch in n:
oi = o.find(ch, oi)
if oi == -1:
return False, f"非子序列: {o!r} -> {n!r}"
oi += 1
return True, "ok"
def main():
write = '--write' in sys.argv
args = [a for a in sys.argv[1:] if not a.startswith('--')]
defined = load_defined()
files = args or (glob.glob('static/src/**/*.scss', recursive=True) +
glob.glob('static/src/**/*.vue', recursive=True))
files = [f for f in files if '_tokens' not in f and '_virtual-monitor' not in f]
total = 0
for f in sorted(files):
ch, src, new = process_file(f, defined, write=False)
if not ch:
continue
ok, msg = verify(src, new)
flag = "OK" if ok else f"FAIL({msg})"
print(f"{ch:3d} strips [{flag}] {f}")
if ok and write:
open(f, 'w', encoding='utf-8').write(new)
total += ch
print(f"\n{'已写入' if write else 'DRY-RUN'} 总剥离: {total}")
if __name__ == '__main__':
main()

View File

@ -651,7 +651,7 @@ button {
border: none;
border-radius: 12px;
padding: 10px 14px;
background: var(--claude-highlight, #f3d2a8);
background: var(--claude-highlight);
color: #2a2013;
font-weight: 600;
cursor: pointer;

View File

@ -612,7 +612,7 @@ watch(secondaryVerified, async (val) => {
color: var(--muted);
}
.status.error {
color: #dc2626;
color: var(--state-danger);
}
.editor-only {
max-width: 1080px;
@ -708,7 +708,7 @@ watch(secondaryVerified, async (val) => {
color: var(--muted);
}
.error {
color: #dc2626;
color: var(--state-danger);
}
.empty {
color: var(--muted);
@ -729,8 +729,8 @@ watch(secondaryVerified, async (val) => {
.primary {
background: linear-gradient(
135deg,
var(--claude-accent, #da7756) 0%,
var(--claude-accent-strong, #bd5d3a) 100%
var(--claude-accent) 0%,
var(--claude-accent-strong) 100%
);
color: #fff;
border: none;

View File

@ -54,8 +54,8 @@ onMounted(() => {
--border: #e3d8c8;
--ink: #1a120b;
--muted: #6f635a;
--accent: var(--claude-accent, #da7756);
--accent-strong: var(--claude-accent-strong, #bd5d3a);
--accent: var(--claude-accent);
--accent-strong: var(--claude-accent-strong);
--shadow: 0 16px 40px rgba(47, 32, 21, 0.12);
max-width: 1080px;
@ -114,7 +114,7 @@ onMounted(() => {
color: var(--muted);
}
.status.error {
color: #d64545;
color: var(--state-danger);
}
.markdown :global(h1),
.markdown :global(h2),

View File

@ -1367,8 +1367,8 @@ button:disabled {
gap: 12px;
padding: 12px 14px;
border-radius: 14px;
border: 1px solid var(--theme-control-border, rgba(118, 103, 84, 0.25));
background: var(--theme-surface-muted, rgba(255, 255, 255, 0.85));
border: 1px solid var(--theme-control-border);
background: var(--theme-surface-muted);
cursor: pointer;
transition:
border-color 0.2s ease,
@ -1381,8 +1381,8 @@ button:disabled {
}
.toggle-row:hover {
border-color: var(--theme-control-border-strong, rgba(118, 103, 84, 0.35));
background: var(--theme-surface-soft, rgba(255, 255, 255, 0.92));
border-color: var(--theme-control-border-strong);
background: var(--theme-surface-soft);
}
.toggle-row input {
@ -1410,7 +1410,7 @@ button:disabled {
.fancy-path {
fill: none;
stroke: var(--claude-text-secondary, #7f7766);
stroke: var(--claude-text-secondary);
stroke-width: 5;
stroke-linecap: round;
stroke-linejoin: round;
@ -1423,13 +1423,13 @@ button:disabled {
}
.toggle-row input:checked + .fancy-check .fancy-path {
stroke: var(--claude-accent, #da7756);
stroke: var(--claude-accent);
stroke-dasharray: 70.5096664428711 9999999;
stroke-dashoffset: -262.2723388671875;
}
.toggle-row span {
color: var(--claude-text, #3d3929);
color: var(--claude-text);
font-weight: 600;
}

View File

@ -28,8 +28,8 @@ body {
padding: 30px;
border-radius: 18px;
background: var(--theme-surface-soft);
border: 1px solid var(--theme-control-border, var(--claude-border));
box-shadow: var(--theme-shadow-mid, var(--claude-shadow));
border: 1px solid var(--theme-control-border);
box-shadow: var(--theme-shadow-mid);
backdrop-filter: blur(8px);
}
@ -61,7 +61,7 @@ body {
min-height: 46px;
box-sizing: border-box;
border-radius: 12px;
border: 1px solid var(--theme-control-border, var(--claude-border));
border: 1px solid var(--theme-control-border);
background: var(--theme-surface-strong);
color: var(--claude-text);
padding: 11px 12px;
@ -86,7 +86,7 @@ body {
font-size: 0.95rem;
cursor: pointer;
background: linear-gradient(135deg, var(--claude-accent), var(--claude-accent-strong));
color: #fff;
color: var(--on-accent);
transition:
transform 0.15s ease,
filter 0.15s ease;
@ -117,7 +117,7 @@ body {
.auth-error {
min-height: 1.2em;
margin-top: 12px;
color: #e85b57;
color: var(--state-danger);
font-size: 0.86rem;
}

View File

@ -728,7 +728,7 @@ watch(
margin-top: calc((1em - 1.7em) / 2);
/* 滚动条样式(参考 git 状态侧边栏文件列表,滚动槽透明贴合灰色底色) */
scrollbar-width: thin; /* Firefox */
scrollbar-color: color-mix(in srgb, var(--claude-text-secondary, #6b7280) 55%, transparent)
scrollbar-color: color-mix(in srgb, var(--claude-text-secondary) 55%, transparent)
transparent;
}
@ -744,7 +744,7 @@ watch(
}
.thinking-content::-webkit-scrollbar-thumb {
background: color-mix(in srgb, var(--claude-text-secondary, #6b7280) 55%, transparent);
background: color-mix(in srgb, var(--claude-text-secondary) 55%, transparent);
border-radius: 999px;
border: 2px solid transparent;
background-clip: padding-box;

View File

@ -1089,7 +1089,7 @@ function renderEasterEgg(result: any, args: any): string {
.tool-result-meta {
margin-bottom: 12px;
padding: 8px 12px;
background: rgba(0, 0, 0, 0.02);
background: var(--hover-bg);
border-radius: 6px;
font-size: 13px;
line-height: 1.6;
@ -1106,10 +1106,10 @@ function renderEasterEgg(result: any, args: any): string {
.tool-result-content.scrollable {
max-height: 400px;
overflow-y: auto;
border: 1px solid rgba(0, 0, 0, 0.1);
border: 1px solid var(--border-default);
border-radius: 6px;
padding: 8px;
background: rgba(0, 0, 0, 0.01);
background: color-mix(in srgb, transparent 99%, var(--text-primary));
}
/* 结构化显示滚动条样式(参考 git 状态侧边栏文件列表,滚动槽透明贴合灰色底色) */
@ -1118,7 +1118,7 @@ function renderEasterEgg(result: any, args: any): string {
.code-block pre,
.output-block pre {
scrollbar-width: thin; /* Firefox */
scrollbar-color: color-mix(in srgb, var(--claude-text-secondary, #6b7280) 55%, transparent)
scrollbar-color: color-mix(in srgb, var(--claude-text-secondary) 55%, transparent)
transparent;
}
@ -1143,7 +1143,7 @@ function renderEasterEgg(result: any, args: any): string {
.tool-result-diff.scrollable::-webkit-scrollbar-thumb,
.code-block pre::-webkit-scrollbar-thumb,
.output-block pre::-webkit-scrollbar-thumb {
background: color-mix(in srgb, var(--claude-text-secondary, #6b7280) 55%, transparent);
background: color-mix(in srgb, var(--claude-text-secondary) 55%, transparent);
border-radius: 999px;
border: 2px solid transparent;
background-clip: padding-box;
@ -1165,7 +1165,7 @@ function renderEasterEgg(result: any, args: any): string {
}
.tool-result-empty {
color: rgba(0, 0, 0, 0.5);
color: var(--text-secondary);
font-style: italic;
padding: 8px;
}
@ -1178,15 +1178,15 @@ function renderEasterEgg(result: any, args: any): string {
.search-result-item {
padding: 10px;
margin-bottom: 8px;
border: 1px solid rgba(0, 0, 0, 0.1);
border: 1px solid var(--border-default);
border-radius: 6px;
background: rgba(0, 0, 0, 0.01);
background: color-mix(in srgb, transparent 99%, var(--text-primary));
}
/* 暗色模式下的搜索结果 */
:root[data-theme='dark'] .search-result-item {
background: #2a2a2a;
border: 1px solid rgba(255, 255, 255, 0.08);
background: var(--badge-bg);
border: 1px solid var(--border-default);
}
.search-result-title {
@ -1197,20 +1197,20 @@ function renderEasterEgg(result: any, args: any): string {
.search-result-url {
font-size: 12px;
color: rgba(0, 0, 0, 0.6);
color: var(--text-secondary);
}
:root[data-theme='dark'] .search-result-url {
color: rgba(255, 255, 255, 0.6);
color: var(--text-secondary);
}
.search-result-url a {
color: #0066cc;
color: var(--state-info);
text-decoration: none;
}
:root[data-theme='dark'] .search-result-url a {
color: #6b9fff;
color: var(--state-info);
}
.search-result-url a:hover {
@ -1228,10 +1228,10 @@ function renderEasterEgg(result: any, args: any): string {
.tool-result-diff.scrollable {
max-height: 400px;
overflow-y: auto;
border: 1px solid rgba(0, 0, 0, 0.1);
border: 1px solid var(--border-default);
border-radius: 6px;
padding: 8px;
background: rgba(0, 0, 0, 0.01);
background: color-mix(in srgb, transparent 99%, var(--text-primary));
}
.diff-line {
@ -1262,13 +1262,13 @@ function renderEasterEgg(result: any, args: any): string {
}
.diff-remove {
background: rgba(255, 0, 0, 0.1);
color: #c00;
background: var(--diff-del-bg);
color: var(--state-danger);
}
.diff-add {
background: rgba(0, 255, 0, 0.1);
color: #0a0;
background: var(--diff-add-bg);
color: var(--state-success);
}
.diff-separator {
@ -1286,7 +1286,7 @@ function renderEasterEgg(result: any, args: any): string {
.diff-operation {
font-weight: 600;
margin: 8px 0 4px;
color: rgba(0, 0, 0, 0.7);
color: var(--text-secondary);
}
/* 图片 */
@ -1299,7 +1299,7 @@ function renderEasterEgg(result: any, args: any): string {
max-width: 100%;
height: auto;
border-radius: 6px;
border: 1px solid rgba(0, 0, 0, 0.1);
border: 1px solid var(--border-default);
}
/* 代码块 */
@ -1318,8 +1318,8 @@ function renderEasterEgg(result: any, args: any): string {
.output-block pre {
margin: 0;
padding: 12px;
background: rgba(0, 0, 0, 0.03);
border: 1px solid rgba(0, 0, 0, 0.1);
background: var(--hover-bg);
border: 1px solid var(--border-default);
border-radius: 6px;
overflow-x: auto;
font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
@ -1332,17 +1332,17 @@ function renderEasterEgg(result: any, args: any): string {
/* 暗色模式run_python 代码/输出统一白字,去除任何描边/阴影观感 */
:root[data-theme='dark'] .code-block pre,
:root[data-theme='dark'] .output-block pre {
color: #ffffff !important;
background: rgba(255, 255, 255, 0.04);
border-color: rgba(255, 255, 255, 0.12);
color: var(--text-primary) !important;
background: var(--hover-bg);
border-color: var(--border-strong);
text-shadow: none !important;
}
:root[data-theme='dark'] .code-block pre code,
:root[data-theme='dark'] .output-block pre code {
color: #ffffff !important;
color: var(--text-primary) !important;
text-shadow: none !important;
-webkit-text-fill-color: #ffffff;
-webkit-text-fill-color: var(--text-primary);
}
.output-block {
@ -1363,18 +1363,18 @@ function renderEasterEgg(result: any, args: any): string {
}
.memory-add {
background: rgba(0, 255, 0, 0.1);
color: #0a0;
background: var(--diff-add-bg);
color: var(--state-success);
}
.memory-update {
background: rgba(255, 165, 0, 0.1);
color: #f90;
background: color-mix(in srgb, var(--state-warning) 10%, transparent);
color: var(--state-warning);
}
.memory-delete {
background: rgba(255, 0, 0, 0.1);
color: #c00;
background: var(--diff-del-bg);
color: var(--state-danger);
}
/* 待办事项 */
@ -1398,8 +1398,8 @@ function renderEasterEgg(result: any, args: any): string {
/* 彩蛋 */
.easter-egg-content {
padding: 12px;
background: linear-gradient(135deg, rgba(255, 215, 0, 0.1), rgba(255, 105, 180, 0.1));
border: 1px solid rgba(255, 215, 0, 0.3);
background: linear-gradient(135deg, color-mix(in srgb, var(--decorative-gold) 10%, transparent), color-mix(in srgb, var(--decorative-pink) 10%, transparent));
border: 1px solid color-mix(in srgb, var(--decorative-gold) 30%, transparent);
border-radius: 8px;
font-size: 14px;
line-height: 1.6;
@ -1408,7 +1408,7 @@ function renderEasterEgg(result: any, args: any): string {
/* 搜索匹配项 */
.search-match-separator {
text-align: center;
color: rgba(0, 0, 0, 0.3);
color: var(--text-tertiary);
margin: 12px 0;
font-size: 16px;
}
@ -1416,23 +1416,23 @@ function renderEasterEgg(result: any, args: any): string {
.search-match-item {
margin-bottom: 12px;
padding: 8px;
background: rgba(0, 0, 0, 0.02);
background: var(--hover-bg);
border-radius: 6px;
}
:root[data-theme='dark'] .search-match-item {
background: rgba(255, 255, 255, 0.05);
background: var(--hover-bg);
}
.search-match-line {
font-size: 11px;
color: rgba(0, 0, 0, 0.5);
color: var(--text-secondary);
margin-bottom: 4px;
font-weight: 600;
}
:root[data-theme='dark'] .search-match-line {
color: rgba(255, 255, 255, 0.5);
color: var(--text-secondary);
}
.search-match-item pre {
@ -1444,7 +1444,7 @@ function renderEasterEgg(result: any, args: any): string {
/* 提取片段 */
.segment-separator {
text-align: center;
color: rgba(0, 0, 0, 0.3);
color: var(--text-tertiary);
margin: 12px 0;
font-size: 16px;
}
@ -1452,23 +1452,23 @@ function renderEasterEgg(result: any, args: any): string {
.segment-item {
margin-bottom: 12px;
padding: 8px;
background: rgba(0, 0, 0, 0.02);
background: var(--hover-bg);
border-radius: 6px;
}
:root[data-theme='dark'] .segment-item {
background: rgba(255, 255, 255, 0.05);
background: var(--hover-bg);
}
.segment-range {
font-size: 11px;
color: rgba(0, 0, 0, 0.5);
color: var(--text-secondary);
margin-bottom: 4px;
font-weight: 600;
}
:root[data-theme='dark'] .segment-range {
color: rgba(255, 255, 255, 0.5);
color: var(--text-secondary);
}
.segment-item pre {
@ -1480,7 +1480,7 @@ function renderEasterEgg(result: any, args: any): string {
/* 个性化管理 */
.personalization-message {
padding: 12px;
background: rgba(0, 0, 0, 0.02);
background: var(--hover-bg);
border-radius: 6px;
font-size: 13px;
line-height: 1.6;
@ -1488,17 +1488,17 @@ function renderEasterEgg(result: any, args: any): string {
}
:root[data-theme='dark'] .personalization-message {
background: rgba(255, 255, 255, 0.05);
background: var(--hover-bg);
}
.personalization-config-title {
font-weight: 600;
margin-bottom: 8px;
color: rgba(0, 0, 0, 0.8);
color: var(--text-primary);
}
:root[data-theme='dark'] .personalization-config-title {
color: rgba(255, 255, 255, 0.9);
color: var(--text-primary);
}
.personalization-config-list {
@ -1511,30 +1511,30 @@ function renderEasterEgg(result: any, args: any): string {
justify-content: space-between;
align-items: center;
padding: 6px 10px;
background: rgba(0, 0, 0, 0.02);
background: var(--hover-bg);
border-radius: 4px;
font-size: 12px;
}
:root[data-theme='dark'] .config-item {
background: rgba(255, 255, 255, 0.05);
background: var(--hover-bg);
}
.config-label {
color: rgba(0, 0, 0, 0.6);
color: var(--text-secondary);
font-weight: 500;
}
:root[data-theme='dark'] .config-label {
color: rgba(255, 255, 255, 0.6);
color: var(--text-secondary);
}
.config-value {
color: rgba(0, 0, 0, 0.9);
color: var(--text-primary);
font-weight: 400;
}
:root[data-theme='dark'] .config-value {
color: rgba(255, 255, 255, 0.9);
color: var(--text-primary);
}
</style>

View File

@ -1689,9 +1689,9 @@ const contextUsagePercentLabel = computed(() => `${Math.round(contextUsagePercen
const contextUsageColor = computed(() => {
const percent = contextUsagePercent.value;
if (percent < 40) return '#16a34a';
if (percent <= 80) return '#f59e0b';
return '#ef4444';
if (percent < 40) return 'var(--state-success)';
if (percent <= 80) return 'var(--state-warning)';
return 'var(--state-danger)';
});
const formatCompactTokens = (value: number) => {
@ -1879,7 +1879,7 @@ onBeforeUnmount(() => {
padding: 4px 10px 4px 4px;
border: 1px solid var(--claude-border);
border-radius: 14px;
background: var(--theme-surface-muted);
background: var(--theme-surface-soft);
box-shadow: none;
pointer-events: auto;
}
@ -1935,8 +1935,8 @@ onBeforeUnmount(() => {
.floating-project-status__button--active,
.floating-project-status__notice--button:hover,
.floating-project-status__submenu button:hover {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
box-shadow: 0 1px 2px rgba(61, 57, 41, 0.08);
background: var(--theme-tab-active);
box-shadow: 0 1px 2px var(--shadow-color);
}
.floating-project-status__button--project {
@ -1976,8 +1976,8 @@ onBeforeUnmount(() => {
}
.floating-project-status__stats:hover {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
box-shadow: 0 1px 2px rgba(61, 57, 41, 0.08);
background: var(--theme-tab-active);
box-shadow: 0 1px 2px var(--shadow-color);
}
.floating-project-status__add {
@ -2006,7 +2006,7 @@ onBeforeUnmount(() => {
padding: 6px;
border: 1px solid var(--claude-border);
border-radius: 14px;
background: var(--theme-surface-muted);
background: var(--theme-surface-soft);
box-shadow: none;
overflow: hidden;
}
@ -2033,8 +2033,8 @@ onBeforeUnmount(() => {
:global(body[data-theme='dark'] .floating-project-status),
:global(html[data-theme='dark'] .floating-project-status__submenu),
:global(body[data-theme='dark'] .floating-project-status__submenu) {
background: #2a2a2a !important;
border-color: rgba(255, 255, 255, 0.1);
background: var(--badge-bg) !important;
border-color: var(--border-card-strong);
}
:global(html[data-theme='dark'] .floating-project-status__button:hover),
@ -2045,7 +2045,7 @@ onBeforeUnmount(() => {
:global(body[data-theme='dark'] .floating-project-status__stats:hover),
:global(html[data-theme='dark'] .floating-project-status__submenu button:hover),
:global(body[data-theme='dark'] .floating-project-status__submenu button:hover) {
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);
box-shadow: 0 1px 2px var(--shadow-color);
}
.floating-status-motion-enter-active,
@ -2082,9 +2082,9 @@ onBeforeUnmount(() => {
border-radius: 999px;
font-size: 12px;
line-height: 1.4;
color: var(--claude-text-secondary, #7f7766);
background: color-mix(in srgb, var(--theme-surface-soft, #fffaf0) 92%, var(--claude-text-tertiary, #a59a86) 8%);
border: 1px solid var(--theme-chip-border, rgba(118, 103, 84, 0.2));
color: var(--claude-text-secondary);
background: color-mix(in srgb, var(--theme-surface-soft) 92%, var(--claude-text-tertiary) 8%);
border: 1px solid var(--theme-chip-border);
user-select: none;
transition: gap 0.2s ease, padding 0.2s ease;
}
@ -2112,32 +2112,32 @@ onBeforeUnmount(() => {
opacity: 0;
}
.goal-mode-banner--running {
color: var(--claude-accent, #da7756);
border-color: var(--claude-accent, #da7756);
background: color-mix(in srgb, var(--theme-surface-soft, #fffaf0) 82%, var(--claude-accent, #da7756) 18%);
color: var(--claude-accent);
border-color: var(--claude-accent);
background: color-mix(in srgb, var(--theme-surface-soft) 82%, var(--claude-accent) 18%);
}
.goal-mode-banner--done {
color: var(--claude-success, #76b086);
border-color: var(--claude-success, #76b086);
background: color-mix(in srgb, var(--theme-surface-soft, #fffaf0) 82%, var(--claude-success, #76b086) 18%);
color: var(--claude-success);
border-color: var(--claude-success);
background: color-mix(in srgb, var(--theme-surface-soft) 82%, var(--claude-success) 18%);
}
:global(:root[data-theme='dark']) .goal-mode-banner,
:global(body[data-theme='dark']) .goal-mode-banner {
color: var(--claude-text-secondary, #a0a0a0);
background: color-mix(in srgb, var(--theme-surface-muted, #141414) 82%, var(--claude-text-tertiary, #707070) 18%);
border-color: var(--theme-control-border-strong, rgba(255, 255, 255, 0.12));
color: var(--claude-text-secondary);
background: color-mix(in srgb, var(--theme-surface-muted) 82%, var(--claude-text-tertiary) 18%);
border-color: var(--theme-control-border-strong);
}
:global(:root[data-theme='dark']) .goal-mode-banner--running,
:global(body[data-theme='dark']) .goal-mode-banner--running {
color: #e5e7eb;
background: color-mix(in srgb, var(--theme-surface-muted, #141414) 72%, var(--claude-accent, #606060) 28%);
border-color: color-mix(in srgb, var(--claude-accent, #606060) 70%, white 30%);
color: var(--text-primary);
background: color-mix(in srgb, var(--theme-surface-muted) 72%, var(--claude-accent) 28%);
border-color: color-mix(in srgb, var(--claude-accent) 70%, white 30%);
}
:global(:root[data-theme='dark']) .goal-mode-banner--done,
:global(body[data-theme='dark']) .goal-mode-banner--done {
color: #d1fae5;
background: color-mix(in srgb, var(--theme-surface-muted, #141414) 72%, var(--claude-success, #10b981) 28%);
border-color: color-mix(in srgb, var(--claude-success, #10b981) 70%, white 30%);
color: color-mix(in srgb, var(--state-success) 30%, white);
background: color-mix(in srgb, var(--theme-surface-muted) 72%, var(--claude-success) 28%);
border-color: color-mix(in srgb, var(--claude-success) 70%, white 30%);
}
.goal-mode-banner--clickable {
cursor: pointer;
@ -2146,14 +2146,14 @@ onBeforeUnmount(() => {
width: 7px;
height: 7px;
border-radius: 50%;
background: var(--claude-text-tertiary, #a59a86);
background: var(--claude-text-tertiary);
}
.goal-mode-banner--running .goal-mode-banner__dot {
background: var(--claude-accent, #da7756);
background: var(--claude-accent);
animation: goal-banner-pulse 1.4s ease-in-out infinite;
}
.goal-mode-banner--done .goal-mode-banner__dot {
background: var(--claude-success, #76b086);
background: var(--claude-success);
}
@keyframes goal-banner-pulse {
0%, 100% { opacity: 1; }
@ -2184,7 +2184,7 @@ onBeforeUnmount(() => {
border-radius: 6px;
overflow: hidden;
cursor: pointer;
border: 1px solid var(--border-color, #2a2f3a);
border: 1px solid var(--border-default);
}
.image-thumbnail {
@ -2199,7 +2199,7 @@ onBeforeUnmount(() => {
top: 0;
right: 0;
background: none;
color: #fff;
color: var(--on-accent);
border: none;
font-size: 20px;
font-weight: bold;
@ -2207,7 +2207,7 @@ onBeforeUnmount(() => {
cursor: pointer;
display: none;
padding: 2px 4px;
text-shadow: 0 0 3px rgba(0, 0, 0, 0.8);
text-shadow: 0 0 3px var(--text-shadow-legible);
transition: color 0.15s ease;
}
@ -2216,6 +2216,6 @@ onBeforeUnmount(() => {
}
.image-remove-btn-hover:hover {
color: #ef4444;
color: var(--state-danger);
}
</style>

View File

@ -240,14 +240,14 @@ const goalCompleted = computed(() => String(props.goalProgress?.status || '').to
.submenu-desc {
display: block;
font-size: 12px;
color: var(--text-secondary, #7f8792);
color: var(--text-secondary);
margin-top: 2px;
}
.menu-entry.goal-entry-active {
color: var(--claude-accent, #da7756);
color: var(--claude-accent);
}
.menu-entry.goal-entry-active .entry-arrow {
color: var(--claude-accent, #da7756);
color: var(--claude-accent);
font-size: 12px;
}
</style>

View File

@ -177,7 +177,7 @@ const formatUpdatedAt = (value: string | number) => {
.review-overlay {
position: fixed;
inset: 0;
background: var(--theme-overlay-scrim, rgba(18, 19, 22, 0.4));
background: var(--theme-overlay-scrim);
backdrop-filter: blur(8px);
display: flex;
align-items: center;
@ -248,7 +248,7 @@ const formatUpdatedAt = (value: string | number) => {
color: var(--claude-text-secondary);
padding: 0 10px;
border-radius: 8px;
background: var(--theme-tab-active, rgba(0, 0, 0, 0.05));
background: var(--theme-tab-active);
max-width: 280px;
white-space: nowrap;
text-overflow: ellipsis;
@ -273,7 +273,7 @@ const formatUpdatedAt = (value: string | number) => {
}
.icon-close-btn:hover:not(:disabled) {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.05));
background: var(--theme-tab-active);
color: var(--claude-text);
}
@ -371,7 +371,7 @@ const formatUpdatedAt = (value: string | number) => {
.conversation-item:hover:not(:disabled),
.conversation-item.active {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
background: var(--theme-tab-active);
}
/* 选中态:左侧强调条提示,不靠彩色光晕 */
@ -418,7 +418,7 @@ const formatUpdatedAt = (value: string | number) => {
border-radius: 999px;
font-size: 12px;
line-height: 1;
background: var(--theme-chip-bg, rgba(118, 103, 84, 0.12));
background: var(--theme-chip-bg);
color: var(--claude-text-secondary);
}
@ -463,7 +463,7 @@ const formatUpdatedAt = (value: string | number) => {
}
.load-more-btn:hover:not(:disabled) {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
background: var(--theme-tab-active);
color: var(--claude-text);
}
@ -496,7 +496,7 @@ const formatUpdatedAt = (value: string | number) => {
}
.preview-line:nth-child(odd) {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.04));
background: var(--theme-tab-active);
}
.placeholder {
@ -529,7 +529,7 @@ const formatUpdatedAt = (value: string | number) => {
}
.placeholder.error .text-main {
color: var(--claude-warning, #d99845);
color: var(--claude-warning);
}
/* ===== 底部操作栏 ===== */
@ -568,7 +568,7 @@ const formatUpdatedAt = (value: string | number) => {
width: 38px;
height: 22px;
border-radius: 999px;
background: var(--theme-switch-track, #d7d1c5);
background: var(--theme-switch-track);
position: relative;
transition: background 0.2s ease;
}
@ -579,7 +579,7 @@ const formatUpdatedAt = (value: string | number) => {
width: 18px;
height: 18px;
border-radius: 50%;
background: var(--theme-surface-strong, #ffffff);
background: var(--theme-surface-strong);
top: 2px;
left: 2px;
transition: transform 0.2s ease;
@ -608,7 +608,7 @@ const formatUpdatedAt = (value: string | number) => {
font-weight: 600;
cursor: pointer;
background: var(--claude-accent);
color: #fffaf0;
color: var(--on-accent);
transition:
background 140ms ease,
color 140ms ease;
@ -628,12 +628,6 @@ const formatUpdatedAt = (value: string | number) => {
cursor: default;
}
/* 暗色模式下主按钮文字保持白色accent 在暗色为灰,文字仍需高对比) */
:global(:root[data-theme='dark']) .primary-btn,
:global(body[data-theme='dark']) .primary-btn {
color: #ffffff;
}
/* ===== 窄屏:上下堆叠 ===== */
@media (max-width: 860px) {
.review-body {

View File

@ -167,52 +167,52 @@ const stoppedReasonLabel = computed(() => {
font-size: 12px;
padding: 2px 10px;
border-radius: 999px;
border: 1px solid var(--theme-chip-border, rgba(118, 103, 84, 0.2));
background: color-mix(in srgb, var(--theme-surface-soft, #fffaf0) 92%, var(--claude-text-tertiary, #a59a86) 8%);
color: var(--claude-text-secondary, #7f7766);
border: 1px solid var(--theme-chip-border);
background: color-mix(in srgb, var(--theme-surface-soft) 92%, var(--claude-text-tertiary) 8%);
color: var(--claude-text-secondary);
}
.goal-progress-status.is-running {
color: var(--claude-accent, #da7756);
border-color: var(--claude-accent, #da7756);
background: color-mix(in srgb, var(--theme-surface-soft, #fffaf0) 82%, var(--claude-accent, #da7756) 18%);
color: var(--claude-accent);
border-color: var(--claude-accent);
background: color-mix(in srgb, var(--theme-surface-soft) 82%, var(--claude-accent) 18%);
}
.goal-progress-status.is-done {
color: var(--claude-success, #76b086);
border-color: var(--claude-success, #76b086);
background: color-mix(in srgb, var(--theme-surface-soft, #fffaf0) 82%, var(--claude-success, #76b086) 18%);
color: var(--claude-success);
border-color: var(--claude-success);
background: color-mix(in srgb, var(--theme-surface-soft) 82%, var(--claude-success) 18%);
}
.goal-progress-status.is-stopped {
color: var(--claude-warning, #d99845);
border-color: var(--claude-warning, #d99845);
background: color-mix(in srgb, var(--theme-surface-soft, #fffaf0) 82%, var(--claude-warning, #d99845) 18%);
color: var(--claude-warning);
border-color: var(--claude-warning);
background: color-mix(in srgb, var(--theme-surface-soft) 82%, var(--claude-warning) 18%);
}
:global(:root[data-theme='dark']) .goal-progress-status,
:global(body[data-theme='dark']) .goal-progress-status {
color: var(--claude-text-secondary, #a0a0a0);
background: color-mix(in srgb, var(--theme-surface-muted, #141414) 82%, var(--claude-text-tertiary, #707070) 18%);
border-color: var(--theme-control-border-strong, rgba(255, 255, 255, 0.12));
color: var(--claude-text-secondary);
background: color-mix(in srgb, var(--theme-surface-muted) 82%, var(--claude-text-tertiary) 18%);
border-color: var(--theme-control-border-strong);
}
:global(:root[data-theme='dark']) .goal-progress-status.is-running,
:global(body[data-theme='dark']) .goal-progress-status.is-running {
color: #e5e7eb;
background: color-mix(in srgb, var(--theme-surface-muted, #141414) 72%, var(--claude-accent, #606060) 28%);
border-color: color-mix(in srgb, var(--claude-accent, #606060) 70%, white 30%);
color: var(--text-primary);
background: color-mix(in srgb, var(--theme-surface-muted) 72%, var(--claude-accent) 28%);
border-color: color-mix(in srgb, var(--claude-accent) 70%, white 30%);
}
:global(:root[data-theme='dark']) .goal-progress-status.is-done,
:global(body[data-theme='dark']) .goal-progress-status.is-done {
color: #d1fae5;
background: color-mix(in srgb, var(--theme-surface-muted, #141414) 72%, var(--claude-success, #10b981) 28%);
border-color: color-mix(in srgb, var(--claude-success, #10b981) 70%, white 30%);
color: color-mix(in srgb, var(--state-success) 30%, white);
background: color-mix(in srgb, var(--theme-surface-muted) 72%, var(--claude-success) 28%);
border-color: color-mix(in srgb, var(--claude-success) 70%, white 30%);
}
:global(:root[data-theme='dark']) .goal-progress-status.is-stopped,
:global(body[data-theme='dark']) .goal-progress-status.is-stopped {
color: #ffedd5;
background: color-mix(in srgb, var(--theme-surface-muted, #141414) 72%, var(--claude-warning, #f59e0b) 28%);
border-color: color-mix(in srgb, var(--claude-warning, #f59e0b) 70%, white 30%);
color: color-mix(in srgb, var(--state-warning) 30%, white);
background: color-mix(in srgb, var(--theme-surface-muted) 72%, var(--claude-warning) 28%);
border-color: color-mix(in srgb, var(--claude-warning) 70%, white 30%);
}
.goal-progress-goal {
font-size: 13px;
color: var(--claude-text-secondary, #7f7766);
color: var(--claude-text-secondary);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@ -228,37 +228,37 @@ const stoppedReasonLabel = computed(() => {
text-align: center;
padding: 10px 6px;
border-radius: 10px;
background: var(--theme-surface-muted, rgba(255, 255, 255, 0.85));
border: 1px solid var(--theme-control-border, rgba(118, 103, 84, 0.25));
background: var(--theme-surface-muted);
border: 1px solid var(--theme-control-border);
}
.goal-metric__value {
font-size: 18px;
font-weight: 600;
color: var(--claude-text, #3d3929);
color: var(--claude-text);
}
.goal-metric__label {
margin-top: 4px;
font-size: 11px;
color: var(--claude-text-tertiary, #a59a86);
color: var(--claude-text-tertiary);
}
.goal-progress-reason {
font-size: 13px;
color: var(--claude-warning, #d99845);
color: var(--claude-warning);
margin-bottom: 10px;
}
.goal-progress-summary {
border-top: 1px solid var(--theme-control-border, rgba(118, 103, 84, 0.25));
border-top: 1px solid var(--theme-control-border);
padding-top: 10px;
}
.goal-progress-summary__title {
font-size: 12px;
color: var(--claude-text-tertiary, #a59a86);
color: var(--claude-text-tertiary);
margin-bottom: 6px;
}
.goal-progress-summary__body {
font-size: 13px;
line-height: 1.6;
color: var(--claude-text, #3d3929);
color: var(--claude-text);
white-space: pre-wrap;
word-break: break-word;
max-height: 240px;

View File

@ -184,7 +184,7 @@ const handleOverlayClose = () => {
.host-workspace-dialog__error {
font-size: 13px;
color: #ef4444;
color: var(--state-danger);
}
.host-workspace-dialog__actions {
@ -210,7 +210,7 @@ const handleOverlayClose = () => {
.host-workspace-dialog__btn.primary {
background: var(--claude-accent);
border-color: var(--claude-accent-strong);
color: #fff;
color: var(--on-accent);
}
.host-workspace-dialog__btn:disabled {

View File

@ -300,12 +300,12 @@ const submitRename = (item: WorkspaceItem) => {
justify-self: flex-start;
background: var(--claude-accent);
border-color: var(--claude-accent-strong);
color: #fff;
color: var(--on-accent);
}
.host-workspace-dialog__btn.danger {
color: #ef4444;
border-color: color-mix(in srgb, #ef4444 45%, var(--theme-control-border-strong));
color: var(--state-danger);
border-color: color-mix(in srgb, var(--state-danger) 45%, var(--theme-control-border-strong));
}
.workspace-manage-list {
@ -375,7 +375,7 @@ const submitRename = (item: WorkspaceItem) => {
.host-workspace-dialog__error {
font-size: 13px;
color: #ef4444;
color: var(--state-danger);
}
@media (max-width: 640px) {

View File

@ -134,7 +134,7 @@ onMounted(() => {
.image-picker-backdrop {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.45);
background: var(--overlay-scrim);
display: flex;
align-items: center;
justify-content: center;
@ -143,20 +143,20 @@ onMounted(() => {
.image-picker-panel {
width: min(980px, 92vw);
max-height: 88vh;
background: #0f1116;
color: #e8ecf2;
border: 1px solid #2a2f3a;
background: var(--surface-panel);
color: var(--text-primary);
border: 1px solid var(--border-default);
border-radius: 12px;
display: flex;
flex-direction: column;
box-shadow: 0 16px 40px rgba(0, 0, 0, 0.4);
box-shadow: 0 16px 40px var(--shadow-color);
}
.header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px 16px;
border-bottom: 1px solid #1f2430;
border-bottom: 1px solid var(--border-default);
}
.header-left {
display: flex;
@ -167,11 +167,11 @@ onMounted(() => {
font-weight: 600;
}
.local-btn {
border: 1px solid #2f3645;
border: 1px solid var(--border-strong);
padding: 4px 10px;
border-radius: 8px;
background: #1b202c;
color: #c5ccda;
background: var(--surface-raised);
color: var(--text-secondary);
font-size: 12px;
cursor: pointer;
}
@ -181,7 +181,7 @@ onMounted(() => {
}
.close-btn {
background: transparent;
color: #9aa3b5;
color: var(--text-tertiary);
border: none;
font-size: 20px;
cursor: pointer;
@ -197,9 +197,9 @@ onMounted(() => {
gap: 12px;
}
.card {
border: 1px solid #1f2430;
border: 1px solid var(--border-default);
border-radius: 10px;
background: #151922;
background: var(--surface-card);
cursor: pointer;
overflow: hidden;
display: flex;
@ -209,49 +209,49 @@ onMounted(() => {
width: 100%;
height: 120px;
object-fit: cover;
background: #0c0f14;
background: var(--surface-base);
}
.card .name {
padding: 8px 10px;
font-size: 12px;
color: #c5ccda;
color: var(--text-secondary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.card.selected {
border-color: #4ca6ff;
box-shadow: 0 0 0 2px rgba(76, 166, 255, 0.2);
border-color: var(--state-info);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--state-info) 20%, transparent);
}
.loading,
.empty {
padding: 40px 0;
text-align: center;
color: #9aa3b5;
color: var(--text-tertiary);
}
.footer {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
border-top: 1px solid #1f2430;
border-top: 1px solid var(--border-default);
}
.actions {
display: flex;
gap: 10px;
}
.btn {
border: 1px solid #2f3645;
border: 1px solid var(--border-strong);
padding: 8px 14px;
border-radius: 8px;
background: #1b202c;
color: #e8ecf2;
background: var(--surface-raised);
color: var(--text-primary);
cursor: pointer;
}
.btn.primary {
background: #4ca6ff;
border-color: #4ca6ff;
color: #0d1117;
background: var(--state-info);
border-color: var(--state-info);
color: var(--text-primary);
}
.btn:disabled {
opacity: 0.5;
@ -259,7 +259,7 @@ onMounted(() => {
}
.count {
font-size: 13px;
color: #9aa3b5;
color: var(--text-tertiary);
}
@media (max-width: 640px) {
.grid {

View File

@ -47,23 +47,23 @@ const emitSkip = () => emit('skip');
display: grid;
place-items: center;
padding: 24px;
background: var(--theme-overlay-scrim, rgba(15, 23, 42, 0.45));
background: var(--theme-overlay-scrim);
backdrop-filter: blur(2px);
}
.new-user-tutorial-dialog {
width: min(520px, calc(100vw - 32px));
border-radius: 18px;
border: 1px solid var(--theme-control-border-strong, rgba(148, 163, 184, 0.35));
background: var(--theme-surface-card, #ffffff);
box-shadow: var(--theme-shadow-strong, 0 24px 64px rgba(15, 23, 42, 0.26));
border: 1px solid var(--theme-control-border-strong);
background: var(--theme-surface-card);
box-shadow: var(--theme-shadow-strong);
padding: 22px 22px 18px;
}
.eyebrow {
margin: 0;
font-size: 12px;
color: var(--theme-text-muted, #64748b);
color: var(--text-tertiary);
}
h3 {
@ -73,7 +73,7 @@ h3 {
.desc {
margin: 0;
color: var(--theme-text-muted, #64748b);
color: var(--text-tertiary);
line-height: 1.6;
}
@ -87,7 +87,7 @@ h3 {
button {
min-height: 38px;
border-radius: 999px;
border: 1px solid var(--theme-control-border, rgba(148, 163, 184, 0.3));
border: 1px solid var(--theme-control-border);
padding: 0 15px;
font-weight: 700;
font-size: 13px;
@ -101,12 +101,12 @@ button {
.primary {
border: none;
background: linear-gradient(135deg, var(--claude-accent), var(--claude-accent-strong));
color: #fff;
color: var(--on-accent);
}
.ghost {
background: var(--theme-surface-soft, rgba(248, 250, 252, 0.9));
color: var(--claude-text, inherit);
background: var(--theme-surface-soft);
color: var(--claude-text);
}
button:hover:not(:disabled) {

View File

@ -50,7 +50,7 @@ defineEmits<{
</script>
<style scoped>
.overlay-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,.35); display: flex; align-items: center; justify-content: center; z-index: 1000; }
.overlay-backdrop { position: fixed; inset: 0; background: var(--overlay-scrim); display: flex; align-items: center; justify-content: center; z-index: 1000; }
.overlay-card { width: min(680px, 92vw); background: var(--theme-surface-soft); border: 1px solid var(--theme-control-border); border-radius: 12px; padding: 12px; }
.overlay-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }
.overlay-header h3 { margin: 0; font-size: 16px; }

View File

@ -192,12 +192,12 @@ function submit() {
width: 12px;
height: 12px;
border-radius: 50%;
border: 1px solid rgba(0, 0, 0, 0.12);
border: 1px solid var(--border-strong);
padding: 0;
cursor: pointer;
}
.traffic-dot--close { background: #ff5f57; }
.traffic-dot--close { background: var(--mac-close); }
.user-question-window-title {
text-align: center;
@ -266,7 +266,7 @@ function submit() {
}
.user-question-nav button:hover:not(:disabled) {
background: var(--theme-hover-bg, rgba(0, 0, 0, 0.055));
background: var(--hover-bg);
color: var(--claude-text);
}
@ -318,7 +318,7 @@ function submit() {
}
.user-question-option:hover {
background: var(--theme-hover-bg, rgba(0, 0, 0, 0.055));
background: var(--hover-bg);
}
.user-question-option.active {
@ -408,18 +408,18 @@ function submit() {
}
.user-question-btn.ghost:hover {
background: var(--theme-hover-bg, rgba(0, 0, 0, 0.055));
background: var(--hover-bg);
color: var(--claude-text);
}
.user-question-btn.primary {
background: var(--claude-accent);
border-color: var(--claude-accent-strong);
color: #fffaf0;
color: var(--on-accent);
}
.user-question-btn.primary:hover:not(:disabled) {
background: var(--claude-button-hover, var(--claude-accent-strong));
background: var(--claude-button-hover);
}
.user-question-btn:disabled {

View File

@ -318,7 +318,7 @@ const formatTime = (value: string) => {
width: 38px;
height: 22px;
border-radius: 999px;
background: var(--theme-switch-track, #d7d1c5);
background: var(--theme-switch-track);
position: relative;
transition: background 0.2s ease;
}
@ -329,7 +329,7 @@ const formatTime = (value: string) => {
width: 18px;
height: 18px;
border-radius: 50%;
background: var(--theme-surface-strong, #ffffff);
background: var(--theme-surface-strong);
top: 2px;
left: 2px;
transition: transform 0.2s ease;
@ -386,7 +386,7 @@ const formatTime = (value: string) => {
}
.scope-select-button:hover:not(:disabled) {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.05));
background: var(--theme-tab-active);
}
.scope-select.disabled .scope-select-button,
@ -435,7 +435,7 @@ const formatTime = (value: string) => {
padding: 6px;
border: 1px solid var(--claude-border);
border-radius: 12px;
background: var(--theme-surface-strong, #fff);
background: var(--theme-surface-strong);
box-shadow: var(--theme-shadow-soft);
display: flex;
flex-direction: column;
@ -461,7 +461,7 @@ const formatTime = (value: string) => {
}
.scope-menu-option:hover:not(:disabled) {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.05));
background: var(--theme-tab-active);
}
.scope-menu-option.disabled,
@ -492,7 +492,7 @@ const formatTime = (value: string) => {
}
.refresh-btn:hover:not(:disabled) {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.05));
background: var(--theme-tab-active);
}
.refresh-btn:disabled {
@ -516,7 +516,7 @@ const formatTime = (value: string) => {
}
.icon-close-btn:hover {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.05));
background: var(--theme-tab-active);
color: var(--claude-text);
}
@ -572,7 +572,7 @@ const formatTime = (value: string) => {
.checkpoint-item:hover,
.checkpoint-item.active {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
background: var(--theme-tab-active);
}
.checkpoint-item.active {
@ -622,11 +622,11 @@ const formatTime = (value: string) => {
/* diff 红绿增删色:通用语义色,保留固定值,三模式下含义一致 */
.plus {
color: #16a34a;
color: var(--state-success);
}
.minus {
color: #dc2626;
color: var(--state-danger);
}
.files {
@ -671,11 +671,11 @@ const formatTime = (value: string) => {
}
.file-row:hover {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.04));
background: var(--theme-tab-active);
}
.file-row.expanded {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
background: var(--theme-tab-active);
}
.status {
@ -719,7 +719,7 @@ const formatTime = (value: string) => {
.workspace-mismatch-tip {
margin-right: auto;
color: var(--claude-warning, #d99845);
color: var(--claude-warning);
font-size: 13px;
font-weight: 600;
}
@ -732,7 +732,7 @@ const formatTime = (value: string) => {
font-size: 14px;
font-weight: 600;
background: var(--claude-accent);
color: #fffaf0;
color: var(--on-accent);
cursor: pointer;
transition: background 140ms ease;
}
@ -746,12 +746,6 @@ const formatTime = (value: string) => {
cursor: not-allowed;
}
/* 暗色下主按钮文字保持高对比 */
:global(:root[data-theme='dark']) .confirm-btn,
:global(body[data-theme='dark']) .confirm-btn {
color: #ffffff;
}
/* ===== diff 展示:与文件编辑差异保持一致 ===== */
.tool-result-diff {
margin-top: 10px;
@ -765,7 +759,7 @@ const formatTime = (value: string) => {
border: 1px solid var(--claude-border);
border-radius: 8px;
padding: 8px;
background: var(--theme-surface-soft, transparent);
background: var(--theme-surface-soft);
}
.diff-line {
@ -777,13 +771,13 @@ const formatTime = (value: string) => {
/* diff 增删色:通用语义色,保留固定值 */
.diff-remove {
background: rgba(220, 38, 38, 0.12);
color: #dc2626;
background: var(--diff-del-bg);
color: var(--state-danger);
}
.diff-add {
background: rgba(22, 163, 74, 0.12);
color: #16a34a;
background: var(--diff-add-bg);
color: var(--state-success);
}
.diff-context {

View File

@ -139,7 +139,7 @@ onMounted(() => {
.image-picker-backdrop {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.45);
background: var(--overlay-scrim);
display: flex;
align-items: center;
justify-content: center;
@ -148,20 +148,20 @@ onMounted(() => {
.image-picker-panel {
width: min(780px, 92vw);
max-height: 88vh;
background: #0f1116;
color: #e8ecf2;
border: 1px solid #2a2f3a;
background: var(--surface-panel);
color: var(--text-primary);
border: 1px solid var(--border-default);
border-radius: 12px;
display: flex;
flex-direction: column;
box-shadow: 0 16px 40px rgba(0, 0, 0, 0.4);
box-shadow: 0 16px 40px var(--shadow-color);
}
.header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px 16px;
border-bottom: 1px solid #1f2430;
border-bottom: 1px solid var(--border-default);
}
.header-left {
display: flex;
@ -172,11 +172,11 @@ onMounted(() => {
font-weight: 600;
}
.local-btn {
border: 1px solid #2f3645;
border: 1px solid var(--border-strong);
padding: 4px 10px;
border-radius: 8px;
background: #1b202c;
color: #c5ccda;
background: var(--surface-raised);
color: var(--text-secondary);
font-size: 12px;
cursor: pointer;
}
@ -186,7 +186,7 @@ onMounted(() => {
}
.close-btn {
background: transparent;
color: #9aa3b5;
color: var(--text-tertiary);
border: none;
font-size: 20px;
cursor: pointer;
@ -202,9 +202,9 @@ onMounted(() => {
gap: 12px;
}
.card {
border: 1px solid #1f2430;
border: 1px solid var(--border-default);
border-radius: 10px;
background: #151922;
background: var(--surface-card);
cursor: pointer;
overflow: hidden;
display: flex;
@ -214,61 +214,61 @@ onMounted(() => {
.video-thumb {
height: 110px;
border-radius: 8px;
background: linear-gradient(135deg, rgba(76, 166, 255, 0.12), rgba(76, 166, 255, 0.05));
border: 1px solid #243144;
background: linear-gradient(135deg, color-mix(in srgb, var(--state-info) 12%, transparent), color-mix(in srgb, var(--state-info) 5%, transparent));
border: 1px solid var(--border-strong);
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
color: #d9e6ff;
color: var(--text-primary);
gap: 6px;
font-size: 28px;
}
.video-thumb .ext {
font-size: 12px;
color: #9fb7d8;
color: var(--text-secondary);
}
.card .name {
padding: 8px 2px 0;
font-size: 12px;
color: #c5ccda;
color: var(--text-secondary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.card.selected {
border-color: #4ca6ff;
box-shadow: 0 0 0 2px rgba(76, 166, 255, 0.2);
border-color: var(--state-info);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--state-info) 20%, transparent);
}
.loading,
.empty {
padding: 40px 0;
text-align: center;
color: #9aa3b5;
color: var(--text-tertiary);
}
.footer {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
border-top: 1px solid #1f2430;
border-top: 1px solid var(--border-default);
}
.actions {
display: flex;
gap: 10px;
}
.btn {
border: 1px solid #2f3645;
border: 1px solid var(--border-strong);
padding: 8px 14px;
border-radius: 8px;
background: #1b202c;
color: #e8ecf2;
background: var(--surface-raised);
color: var(--text-primary);
cursor: pointer;
}
.btn.primary {
background: #4ca6ff;
border-color: #4ca6ff;
color: #0d1117;
background: var(--state-info);
border-color: var(--state-info);
color: var(--text-primary);
}
.btn:disabled {
opacity: 0.5;
@ -276,7 +276,7 @@ onMounted(() => {
}
.count {
font-size: 13px;
color: #9aa3b5;
color: var(--text-tertiary);
}
@media (max-width: 640px) {
.grid {

View File

@ -250,9 +250,9 @@ const parseFinalMessage = (text: string) => {
.auto-approval-block {
margin-top: 12px;
padding: 10px;
border: 1px solid var(--theme-control-border, var(--border-color, #2a2f3a));
border: 1px solid var(--theme-control-border);
border-radius: 8px;
background: var(--theme-surface-muted, var(--panel-bg, rgba(0, 0, 0, 0.12)));
background: var(--theme-surface-muted);
}
.auto-approval-block__title {
@ -281,11 +281,11 @@ const parseFinalMessage = (text: string) => {
}
.auto-approval-block__decision--approved {
color: #22c55e;
color: var(--state-success);
}
.auto-approval-block__decision--rejected {
color: #ef4444;
color: var(--state-danger);
}
.auto-approval-block__reason {
@ -294,8 +294,8 @@ const parseFinalMessage = (text: string) => {
}
.tool-approval-panel.is-goal-approval-mode .auto-approval-block {
background: var(--theme-surface-card, var(--theme-surface-soft));
border-color: var(--theme-control-border, var(--claude-border));
background: var(--theme-surface-card);
border-color: var(--theme-control-border);
color: var(--claude-text);
}
@ -310,12 +310,12 @@ const parseFinalMessage = (text: string) => {
:global(:root[data-theme='dark']) .auto-approval-block,
:global(body[data-theme='dark']) .auto-approval-block {
background: color-mix(in srgb, var(--theme-surface-muted, #141414) 86%, white 4%);
border-color: var(--theme-control-border-strong, rgba(255, 255, 255, 0.12));
color: var(--claude-text, #ffffff);
background: color-mix(in srgb, var(--theme-surface-muted) 86%, white 4%);
border-color: var(--theme-control-border-strong);
color: var(--claude-text);
}
:global(:root[data-theme='dark']) .auto-approval-block__content,
:global(body[data-theme='dark']) .auto-approval-block__content {
color: var(--claude-text-secondary, #a0a0a0);
color: var(--claude-text-secondary);
}
</style>

View File

@ -93,7 +93,7 @@ function confirmSelection() {
.exp-overlay {
position: fixed;
inset: 0;
background: rgba(33, 24, 14, 0.55);
background: var(--overlay-scrim);
display: flex;
align-items: center;
justify-content: center;
@ -102,11 +102,11 @@ function confirmSelection() {
}
.exp-card {
width: min(1100px, 96vw);
background: rgba(255, 255, 255, 0.96);
background: var(--surface-soft);
border-radius: 18px;
padding: 24px 28px;
box-shadow: none;
border: 1px solid rgba(118, 103, 84, 0.25);
border: 1px solid var(--border-default);
}
.exp-header {
display: flex;
@ -117,17 +117,17 @@ function confirmSelection() {
}
.title {
font-size: 22px;
color: #3d3929;
color: var(--text-primary);
font-weight: 700;
}
.subtitle {
font-size: 14px;
color: #7f7766;
color: var(--text-secondary);
}
.confirm-btn {
border: none;
background: #da7756;
color: #fff;
background: var(--accent);
color: var(--on-accent);
border-radius: 12px;
padding: 10px 18px;
font-weight: 600;
@ -139,20 +139,20 @@ function confirmSelection() {
gap: 16px;
}
.mode-card {
border: 1px solid rgba(118, 103, 84, 0.25);
border: 1px solid var(--border-default);
border-radius: 14px;
padding: 16px 14px;
cursor: pointer;
transition: 0.2s ease;
box-shadow: none;
background: #fff;
background: var(--surface-raised);
}
.mode-card:hover {
transform: translateY(-2px);
box-shadow: none;
}
.mode-card.active {
border-color: #da7756;
border-color: var(--accent);
box-shadow: none;
}
.badge {
@ -160,8 +160,8 @@ function confirmSelection() {
align-items: center;
gap: 6px;
font-size: 12px;
color: #bd5d3a;
background: rgba(218, 119, 86, 0.14);
color: var(--accent-strong);
background: var(--highlight);
padding: 4px 10px;
border-radius: 20px;
margin-bottom: 8px;
@ -170,12 +170,12 @@ function confirmSelection() {
width: 52px;
height: 52px;
border-radius: 14px;
background: rgba(218, 119, 86, 0.12);
background: var(--highlight);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 10px;
color: #bd5d3a;
color: var(--accent-strong);
}
.icon svg {
width: 30px;
@ -184,12 +184,12 @@ function confirmSelection() {
.mode-card h3 {
margin: 0 0 6px;
font-size: 17px;
color: #3d3929;
color: var(--text-primary);
}
.mode-card p {
margin: 0;
font-size: 13px;
line-height: 1.5;
color: #7f7766;
color: var(--text-secondary);
}
</style>

View File

@ -2353,29 +2353,29 @@ const applyDefaultHideWorkspaceOption = async (hidden: boolean) => {
<style scoped>
.settings-redesign-card {
--settings-floating-menu-bg: #ffffff;
--settings-floating-menu-hover: rgba(0, 0, 0, 0.055);
--settings-floating-menu-bg: color-mix(in srgb, var(--surface-soft) 90%, var(--surface-raised));
--settings-floating-menu-hover: var(--hover-bg);
--settings-floating-menu-shadow: none;
--settings-tab-hover-bg: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
--settings-tab-active-bg: var(--theme-tab-active, rgba(0, 0, 0, 0.078));
--settings-tab-hover-bg: var(--theme-tab-active);
--settings-tab-active-bg: var(--theme-tab-active);
position: relative;
width: min(70vw, calc(100vw - 24px));
height: min(80vh, calc(100vh - 24px));
padding: 30px 42px 24px;
border-radius: 32px;
overflow: visible;
background: var(--theme-surface-soft, var(--claude-panel));
border: 1px solid var(--theme-control-border, var(--claude-border));
background: var(--theme-surface-soft);
border: 1px solid var(--theme-control-border);
box-shadow: none;
}
:global(html[data-theme='dark']) .settings-redesign-card,
:global(body[data-theme='dark']) .settings-redesign-card {
--settings-floating-menu-bg: #1a1a1a;
--settings-floating-menu-hover: rgba(255, 255, 255, 0.08);
--settings-floating-menu-bg: var(--surface-panel);
--settings-floating-menu-hover: var(--hover-bg);
--settings-floating-menu-shadow: none;
--settings-tab-hover-bg: rgba(255, 255, 255, 0.078);
--settings-tab-active-bg: rgba(255, 255, 255, 0.078);
--settings-tab-hover-bg: var(--hover-bg);
--settings-tab-active-bg: var(--hover-bg);
}
.settings-close-button {
@ -2395,7 +2395,7 @@ const applyDefaultHideWorkspaceOption = async (hidden: boolean) => {
}
.settings-close-button:hover {
background: var(--theme-hover-bg, rgba(0, 0, 0, 0.06));
background: var(--hover-bg);
}
.settings-close-button svg {
@ -2422,7 +2422,7 @@ const applyDefaultHideWorkspaceOption = async (hidden: boolean) => {
margin-top: 68px;
height: calc(100% - 68px);
padding-right: 28px;
border-right: 1px solid var(--theme-control-border, var(--claude-border));
border-right: 1px solid var(--theme-control-border);
display: flex;
flex-direction: column;
gap: 3px;
@ -2509,7 +2509,7 @@ const applyDefaultHideWorkspaceOption = async (hidden: boolean) => {
.settings-redesign-title-line {
height: 1px;
background: var(--theme-control-border, var(--claude-border));
background: var(--theme-control-border);
margin: 22px 0 8px;
flex: 0 0 1px;
}
@ -2551,7 +2551,7 @@ const applyDefaultHideWorkspaceOption = async (hidden: boolean) => {
.settings-action-row,
.settings-toggle-row {
min-height: 64px;
border-bottom: 1px solid var(--theme-control-border, var(--claude-border));
border-bottom: 1px solid var(--theme-control-border);
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
align-items: center;
@ -2616,7 +2616,7 @@ const applyDefaultHideWorkspaceOption = async (hidden: boolean) => {
}
.settings-select-button:hover {
background: var(--theme-hover-bg, rgba(0, 0, 0, 0.055));
background: var(--hover-bg);
}
.settings-select-button .select-chevron {
@ -2651,7 +2651,7 @@ const applyDefaultHideWorkspaceOption = async (hidden: boolean) => {
padding: 6px;
border-radius: 20px;
background: var(--settings-floating-menu-bg);
border: 1px solid var(--theme-control-border, var(--claude-border));
border: 1px solid var(--theme-control-border);
box-shadow: var(--settings-floating-menu-shadow);
opacity: 1;
backdrop-filter: none;
@ -2664,23 +2664,23 @@ const applyDefaultHideWorkspaceOption = async (hidden: boolean) => {
}
.settings-floating-menu.dark {
background: #1a1a1a !important;
background: var(--surface-panel) !important;
box-shadow: none !important;
}
.settings-floating-menu.dark .settings-menu-option:hover {
background: rgba(255, 255, 255, 0.08) !important;
background: var(--hover-bg) !important;
}
:global(html[data-theme='dark']) :global(.settings-floating-menu),
:global(body[data-theme='dark']) :global(.settings-floating-menu) {
background: #1a1a1a !important;
background: var(--surface-panel) !important;
box-shadow: none !important;
}
:global(html[data-theme='dark']) :global(.settings-menu-option:hover),
:global(body[data-theme='dark']) :global(.settings-menu-option:hover) {
background: rgba(255, 255, 255, 0.08) !important;
background: var(--hover-bg) !important;
}
.settings-menu-option {
@ -2759,7 +2759,7 @@ const applyDefaultHideWorkspaceOption = async (hidden: boolean) => {
.settings-number-input,
.settings-compression-grid input {
height: 38px;
border: 1px solid var(--theme-control-border, var(--claude-border));
border: 1px solid var(--theme-control-border);
border-radius: 12px;
background: transparent;
color: var(--claude-text);
@ -2781,7 +2781,7 @@ const applyDefaultHideWorkspaceOption = async (hidden: boolean) => {
.settings-section-divider__label {
font-size: 12px;
font-weight: 600;
color: var(--claude-text-secondary, #7f7766);
color: var(--claude-text-secondary);
letter-spacing: 0.04em;
}
.settings-section-divider::after {
@ -2789,7 +2789,7 @@ const applyDefaultHideWorkspaceOption = async (hidden: boolean) => {
flex: 1;
height: 1px;
margin-left: 10px;
background: var(--theme-control-border, var(--claude-border));
background: var(--theme-control-border);
}
.settings-input-row > input {
@ -2836,7 +2836,7 @@ const applyDefaultHideWorkspaceOption = async (hidden: boolean) => {
.settings-add-row button,
.settings-secondary-button,
.settings-primary-button {
border: 1px solid var(--theme-control-border, var(--claude-border));
border: 1px solid var(--theme-control-border);
border-radius: 999px;
background: transparent;
color: var(--claude-text);
@ -2850,18 +2850,18 @@ const applyDefaultHideWorkspaceOption = async (hidden: boolean) => {
.settings-number-row button:hover,
.settings-add-row button:hover,
.settings-secondary-button:hover {
background: var(--theme-hover-bg, rgba(0, 0, 0, 0.055));
background: var(--hover-bg);
}
.settings-chip-row button.active,
.settings-primary-button {
border-color: var(--claude-accent);
background: var(--claude-accent);
color: #fff;
color: var(--on-accent);
}
.settings-secondary-button.danger {
color: var(--claude-warning, #c85f45);
color: var(--claude-warning);
}
.settings-inline-actions {
@ -2882,7 +2882,7 @@ const applyDefaultHideWorkspaceOption = async (hidden: boolean) => {
}
.settings-mini-status.warning {
color: var(--claude-warning, #c85f45);
color: var(--claude-warning);
}
.settings-add-row,
@ -2909,7 +2909,7 @@ const applyDefaultHideWorkspaceOption = async (hidden: boolean) => {
.settings-consideration-list li {
min-height: 34px;
border: 1px solid var(--theme-control-border, var(--claude-border));
border: 1px solid var(--theme-control-border);
border-radius: 12px;
padding: 0 8px;
display: grid;
@ -2982,7 +2982,7 @@ const applyDefaultHideWorkspaceOption = async (hidden: boolean) => {
}
.settings-group-block {
border-bottom: 1px solid var(--theme-control-border, var(--claude-border));
border-bottom: 1px solid var(--theme-control-border);
padding: 14px 0 16px;
}
@ -3101,7 +3101,7 @@ const applyDefaultHideWorkspaceOption = async (hidden: boolean) => {
.usage-summary-item {
padding: 12px 14px;
border-radius: 14px;
border: 1px solid var(--theme-control-border, var(--claude-border));
border: 1px solid var(--theme-control-border);
background: transparent;
}
@ -3134,7 +3134,7 @@ const applyDefaultHideWorkspaceOption = async (hidden: boolean) => {
}
.usage-summary-refresh {
border: 1px solid var(--theme-control-border, var(--claude-border));
border: 1px solid var(--theme-control-border);
border-radius: 999px;
padding: 7px 14px;
background: transparent;
@ -3172,7 +3172,7 @@ const applyDefaultHideWorkspaceOption = async (hidden: boolean) => {
padding-right: 0;
padding-bottom: 12px;
border-right: 0;
border-bottom: 1px solid var(--theme-control-border, var(--claude-border));
border-bottom: 1px solid var(--theme-control-border);
flex-direction: row;
overflow: auto;
scrollbar-width: none;

View File

@ -2,7 +2,7 @@
html,
body {
height: var(--app-viewport, 100vh);
height: var(--app-viewport);
}
body {

View File

@ -1,186 +1,318 @@
/* CSS variables + shared design tokens */
/* 设计 Token —— 两层结构:语义层(按主题取值)+ 兼容别名层 */
/* 规范见 doc/frontend/color_token_spec.md。本文件为结构重构产物值与重构前逐一致零视觉变化。 */
:root {
color-scheme: light;
/* 主题无关的布局变量 */
--app-viewport: 100vh;
--app-bottom-inset: env(safe-area-inset-bottom, 0px);
--claude-bg: #eeece2;
--claude-panel: rgba(255, 255, 255, 0.82);
--claude-left-rail: #f7f3ea;
--claude-sidebar: rgba(255, 255, 255, 0.68);
--claude-border: rgba(118, 103, 84, 0.25);
--claude-border-strong: rgba(118, 103, 84, 0.35);
--claude-text: #3d3929;
--claude-text-secondary: #7f7766;
--claude-text-tertiary: #a59a86;
--claude-muted: rgba(121, 109, 94, 0.4);
--claude-accent: #da7756;
--claude-accent-strong: #bd5d3a;
--claude-deep: #f2a93b;
--claude-deep-strong: #d07a14;
--claude-highlight: rgba(218, 119, 86, 0.14);
--claude-button-hover: #c76541;
--claude-button-active: #a95331;
--claude-shadow: 0 14px 36px rgba(61, 57, 41, 0.12);
--claude-success: #16a34a;
--claude-warning: #d99845;
--claude-danger: #dc2626;
--git-diff-add-text: #00e000;
--git-diff-del-text: #ff1a1a;
/* Theme-neutral surfaces */
--theme-surface-card: #fffaf4;
--theme-surface-strong: #ffffff;
--theme-surface-soft: rgba(255, 255, 255, 0.92);
--theme-surface-muted: rgba(255, 255, 255, 0.85);
--theme-overlay-scrim: rgba(33, 24, 14, 0.55);
--theme-shadow-strong: 0 28px 60px rgba(38, 28, 18, 0.25);
--theme-shadow-soft: 0 12px 24px rgba(38, 28, 18, 0.12);
--theme-shadow-mid: 0 20px 45px rgba(16, 24, 40, 0.08);
--theme-control-border: rgba(118, 103, 84, 0.25);
--theme-control-border-strong: rgba(118, 103, 84, 0.35);
--theme-switch-track: #d7d1c5;
--theme-chip-bg: rgba(118, 103, 84, 0.08);
--theme-chip-border: rgba(118, 103, 84, 0.2);
--theme-badge-bg: rgba(118, 103, 84, 0.12);
--theme-tab-active: rgba(189, 93, 58, 0.12);
--theme-mobile-menu: rgba(255, 255, 255, 0.35);
--theme-mobile-menu-shadow: 0 12px 30px rgba(38, 28, 18, 0.15);
--theme-card-border-strong: rgba(118, 103, 84, 0.25);
/* 装饰色主题无关固定品牌色macOS 风格窗口关闭红绿灯 */
--mac-close: #ff5f57;
--mac-close-hover: #ff3b30;
--mac-close-border: #e0443e;
/* 媒体上的文字可读性阴影(主题无关,需固定强暗影压住任意底图) */
--text-shadow-legible: rgba(0, 0, 0, 0.8);
/* 彩蛋装饰色主题无关固定festive色 */
--decorative-gold: #ffd700;
--decorative-pink: #ff69b4;
/* 玻璃质感/实验视觉装饰光斑(主题无关,固定品牌渐变色,刻意不随主题变) */
--glass-tint-blue: rgba(104, 147, 255, 0.2);
--glass-tint-blue-soft: rgba(128, 183, 255, 0.18);
--glass-tint-blue-mid: rgba(140, 180, 255, 0.35);
--glass-tint-amber: rgba(255, 200, 150, 0.22);
--glass-base-deep: rgba(28, 27, 41, 0.95);
--glass-shadow-deep: rgba(24, 20, 37, 0.45);
/* 进度环未完成轨道(主题无关,固定中性灰) */
--progress-track: rgba(127, 135, 146, 0.28);
/* 拖拽预览浮层投影(主题无关,固定黑投影) */
--drag-preview-shadow: rgba(0, 0, 0, 0.35);
/* === 兼容别名(旧 token 名 → 新语义 token迁移完成后删除 === */
--claude-bg: var(--surface-base);
--claude-panel: var(--surface-panel);
--claude-left-rail: var(--surface-rail);
--claude-sidebar: var(--surface-sidebar);
--theme-surface-card: var(--surface-card);
--theme-surface-strong: var(--surface-raised);
--theme-surface-soft: var(--surface-soft);
--theme-surface-muted: var(--surface-muted);
--claude-text: var(--text-primary);
--claude-text-secondary: var(--text-secondary);
--claude-text-tertiary: var(--text-tertiary);
--claude-muted: var(--text-muted);
--claude-border: var(--border-default);
--claude-border-strong: var(--border-strong);
--theme-card-border-strong: var(--border-card-strong);
--theme-chip-border: var(--chip-border);
--claude-accent: var(--accent);
--claude-accent-strong: var(--accent-strong);
--claude-button-hover: var(--accent-hover);
--claude-button-active: var(--accent-active);
--claude-deep: var(--accent-deep);
--claude-deep-strong: var(--accent-deep-strong);
--claude-success: var(--state-success);
--claude-warning: var(--state-warning);
--claude-danger: var(--state-danger);
--claude-highlight: var(--highlight);
--theme-tab-active: var(--tab-active);
--theme-chip-bg: var(--chip-bg);
--theme-badge-bg: var(--badge-bg);
--theme-switch-track: var(--switch-track);
--claude-shadow: var(--shadow-card);
--theme-shadow-soft: var(--shadow-soft);
--theme-shadow-mid: var(--shadow-mid);
--theme-shadow-strong: var(--shadow-strong);
--theme-overlay-scrim: var(--overlay-scrim);
--theme-mobile-menu: var(--mobile-menu);
--theme-mobile-menu-shadow: var(--mobile-menu-shadow);
--git-diff-add-text: var(--diff-add-text);
--git-diff-del-text: var(--diff-del-text);
/* 合并项:下列旧名与上面某新名同值,统一指向合并后的语义 token */
--theme-control-border: var(--border-default);
--theme-control-border-strong: var(--border-strong);
}
:root[data-theme='classic'] {
color-scheme: light;
--claude-bg: #eeece2;
--claude-panel: rgba(255, 255, 255, 0.82);
--claude-left-rail: #f7f3ea;
--claude-sidebar: rgba(255, 255, 255, 0.68);
--claude-border: rgba(118, 103, 84, 0.25);
--claude-border-strong: rgba(118, 103, 84, 0.35);
--claude-text: #3d3929;
--claude-text-secondary: #7f7766;
--claude-text-tertiary: #a59a86;
--claude-muted: rgba(121, 109, 94, 0.4);
--claude-accent: #da7756;
--claude-accent-strong: #bd5d3a;
--claude-deep: #f2a93b;
--claude-deep-strong: #d07a14;
--claude-highlight: rgba(218, 119, 86, 0.14);
--claude-button-hover: #c76541;
--claude-button-active: #a95331;
--claude-shadow: 0 14px 36px rgba(61, 57, 41, 0.12);
--claude-success: #16a34a;
--claude-warning: #d99845;
--claude-danger: #dc2626;
--git-diff-add-text: #00e000;
--git-diff-del-text: #ff1a1a;
--theme-surface-card: #fffaf4;
--theme-surface-strong: #ffffff;
--theme-surface-soft: rgba(255, 255, 255, 0.92);
--theme-surface-muted: rgba(255, 255, 255, 0.85);
--theme-overlay-scrim: rgba(33, 24, 14, 0.55);
--theme-shadow-strong: 0 28px 60px rgba(38, 28, 18, 0.25);
--theme-shadow-soft: 0 12px 24px rgba(38, 28, 18, 0.12);
--theme-shadow-mid: 0 20px 45px rgba(16, 24, 40, 0.08);
--theme-control-border: rgba(118, 103, 84, 0.25);
--theme-control-border-strong: rgba(118, 103, 84, 0.35);
--theme-switch-track: #d7d1c5;
--theme-chip-bg: rgba(118, 103, 84, 0.08);
--theme-chip-border: rgba(118, 103, 84, 0.2);
--theme-badge-bg: rgba(118, 103, 84, 0.12);
--theme-tab-active: rgba(189, 93, 58, 0.12);
--theme-mobile-menu: rgba(255, 255, 255, 0.35);
--theme-mobile-menu-shadow: 0 12px 30px rgba(38, 28, 18, 0.15);
--theme-card-border-strong: rgba(118, 103, 84, 0.25);
/* Surface 表面层级 —— Claude 亮色暖奶油盘canvas<soft<card<cream-strongraised纯白浮起 */
--surface-base: #faf9f5;
--surface-panel: #faf9f5;
--surface-rail: #f5f0e8;
--surface-sidebar: #f5f0e8;
--surface-card: #efe9de;
--surface-raised: #ffffff;
--surface-soft: #f5f0e8;
--surface-muted: #e8e0d2;
/* Text 文字 —— Claude */
--text-primary: #141413;
--text-secondary: #3d3d3a;
--text-tertiary: #6c6a64;
--text-muted: rgba(108, 106, 100, 0.55);
/* Border 边框 —— Claude hairline */
--border-default: #e6dfd8;
--border-strong: #d8cfc4;
--border-card-strong: #e6dfd8;
--chip-border: #ebe6df;
/* Accent 强调 —— Claude primary克制 CTA-only */
--accent: #cc785c;
--accent-strong: #a9583e;
--accent-hover: #bd6a4f;
--accent-active: #a9583e;
--accent-deep: #6c6a64;
--accent-deep-strong: #3d3d3a;
--on-accent: #ffffff;
/* State 状态 —— Claude semantic */
--state-success: #5db872;
--state-warning: #d4a017;
--state-danger: #c64545;
--state-danger-strong: #a83838;
--status-offline: #c64545;
--state-info: #5db8a6;
/* Highlight / 交互态 —— 中性暖灰(不带橙) */
--highlight: rgba(20, 20, 19, 0.05);
--tab-active: rgba(20, 20, 19, 0.07);
--chip-bg: #f5f0e8;
--badge-bg: #efe9de;
--switch-track: #d8cfc4;
--hover-bg: rgba(20, 20, 19, 0.05);
--pulse-ring: rgba(0, 0, 0, 0.1);
/* Shadow 阴影 */
--shadow-card: 0 14px 36px rgba(61, 57, 41, 0.12);
--shadow-soft: 0 12px 24px rgba(38, 28, 18, 0.12);
--shadow-mid: 0 20px 45px rgba(16, 24, 40, 0.08);
--shadow-strong: 0 28px 60px rgba(38, 28, 18, 0.25);
--shadow-color: rgba(0, 0, 0, 0.1);
/* Overlay / 移动端 */
--overlay-scrim: rgba(33, 24, 14, 0.55);
--mobile-menu: #f5f0e8;
--mobile-menu-shadow: 0 12px 30px rgba(38, 28, 18, 0.15);
/* 专用色 */
--diff-add-text: #00e000;
--diff-del-text: #ff1a1a;
--diff-add-bg: rgba(22, 163, 74, 0.12);
--diff-del-bg: rgba(220, 38, 38, 0.12);
}
:root[data-theme='light'] {
color-scheme: light;
/* 类似 ChatGPT 的明亮配色:白底黑字,优雅浅灰 */
--claude-bg: #ffffff;
--claude-panel: #ffffff;
--claude-left-rail: #f9f9f9;
--claude-sidebar: #ffffff;
--claude-border: rgba(0, 0, 0, 0.08);
--claude-border-strong: rgba(0, 0, 0, 0.12);
--claude-text: #0d0d0d;
--claude-text-secondary: #676767;
--claude-text-tertiary: #8e8e8e;
--claude-muted: rgba(0, 0, 0, 0.3);
--claude-accent: #acacac;
--claude-accent-strong: #8e8e8e;
--claude-deep: #c4c4c4;
--claude-deep-strong: #acacac;
--claude-highlight: rgba(0, 0, 0, 0.05);
--claude-button-hover: #d1d1d1;
--claude-button-active: #acacac;
--claude-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
--claude-success: #10b981;
--claude-warning: #f59e0b;
--claude-danger: #dc2626;
--git-diff-add-text: #00e000;
--git-diff-del-text: #ff1a1a;
--theme-surface-card: #ffffff;
--theme-surface-strong: #ffffff;
--theme-surface-soft: #ffffff;
--theme-surface-muted: #fafafa;
--theme-overlay-scrim: rgba(0, 0, 0, 0.5);
--theme-shadow-strong: 0 2px 4px rgba(0, 0, 0, 0.08);
--theme-shadow-soft: 0 1px 2px rgba(0, 0, 0, 0.05);
--theme-shadow-mid: 0 1px 3px rgba(0, 0, 0, 0.06);
--theme-control-border: rgba(0, 0, 0, 0.08);
--theme-control-border-strong: rgba(0, 0, 0, 0.12);
--theme-switch-track: #ececec;
--theme-chip-bg: #f5f5f5;
--theme-chip-border: rgba(0, 0, 0, 0.08);
--theme-badge-bg: #f5f5f5;
--theme-tab-active: rgba(0, 0, 0, 0.05);
--theme-mobile-menu: rgba(255, 255, 255, 0.95);
--theme-mobile-menu-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
--theme-card-border-strong: rgba(0, 0, 0, 0.1);
/* Surface 表面层级 —— ChatGPT 亮色冷白盘 */
--surface-base: #ffffff;
--surface-panel: #ffffff;
--surface-rail: #f9f9f9;
--surface-sidebar: #f9f9f9;
--surface-card: #ffffff;
--surface-raised: #ffffff;
--surface-soft: #f9f9f9;
--surface-muted: #f3f3f3;
/* Text 文字 —— ChatGPT */
--text-primary: #0d0d0d;
--text-secondary: #5d5d5d;
--text-tertiary: #8f8f8f;
--text-muted: rgba(13, 13, 13, 0.35);
/* Border 边框 —— ChatGPT hairline */
--border-default: rgba(13, 13, 13, 0.1);
--border-strong: rgba(13, 13, 13, 0.15);
--border-card-strong: rgba(13, 13, 13, 0.1);
--chip-border: rgba(13, 13, 13, 0.05);
/* Accent 强调 —— ChatGPT primary近黑克制 CTA-only */
--accent: #181818;
--accent-strong: #181818;
--accent-hover: #303030;
--accent-active: #414141;
--accent-deep: #5d5d5d;
--accent-deep-strong: #414141;
--on-accent: #ffffff;
/* State 状态 —— ChatGPT semantic */
--state-success: #00a240;
--state-warning: #e25507;
--state-danger: #e02e2a;
--state-danger-strong: #911e1b;
--status-offline: #e02e2a;
--state-info: #0285ff;
/* Highlight / 交互态 —— 中性冷灰 */
--highlight: rgba(13, 13, 13, 0.05);
--tab-active: rgba(13, 13, 13, 0.05);
--chip-bg: #f3f3f3;
--badge-bg: #f3f3f3;
--switch-track: #ececec;
--hover-bg: rgba(13, 13, 13, 0.05);
--pulse-ring: rgba(0, 0, 0, 0.1);
/* Shadow 阴影 */
--shadow-card: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-soft: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-mid: 0 1px 3px rgba(0, 0, 0, 0.06);
--shadow-strong: 0 2px 4px rgba(0, 0, 0, 0.08);
--shadow-color: rgba(0, 0, 0, 0.1);
/* Overlay / 移动端 */
--overlay-scrim: rgba(0, 0, 0, 0.5);
--mobile-menu: #ffffff;
--mobile-menu-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
/* 专用色 */
--diff-add-text: #00e000;
--diff-del-text: #ff1a1a;
--diff-add-bg: rgba(22, 163, 74, 0.12);
--diff-del-bg: rgba(220, 38, 38, 0.12);
}
:root[data-theme='dark'] {
color-scheme: dark;
/* 暗色主题:灰黑色底色,白色文字 */
--claude-bg: #1a1a1a;
--claude-panel: #1a1a1a;
--claude-left-rail: #181818;
--claude-sidebar: #181818;
--claude-border: rgba(255, 255, 255, 0.08);
--claude-border-strong: rgba(255, 255, 255, 0.12);
--claude-text: #ffffff;
--claude-text-secondary: #a0a0a0;
--claude-text-tertiary: #707070;
--claude-muted: rgba(255, 255, 255, 0.3);
--claude-accent: #606060;
--claude-accent-strong: #505050;
--claude-deep: #808080;
--claude-deep-strong: #606060;
--claude-highlight: rgba(255, 255, 255, 0.05);
--claude-button-hover: #707070;
--claude-button-active: #505050;
--claude-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
--claude-success: #10b981;
--claude-warning: #f59e0b;
--claude-danger: #dc2626;
--git-diff-add-text: #00e000;
--git-diff-del-text: #ff1a1a;
--theme-surface-card: #0a0a0a;
--theme-surface-strong: #1a1a1a;
--theme-surface-soft: #0f0f0f;
--theme-surface-muted: #141414;
--theme-overlay-scrim: rgba(0, 0, 0, 0.8);
--theme-shadow-strong: 0 4px 12px rgba(0, 0, 0, 0.6);
--theme-shadow-soft: 0 2px 6px rgba(0, 0, 0, 0.4);
--theme-shadow-mid: 0 3px 8px rgba(0, 0, 0, 0.5);
--theme-control-border: rgba(255, 255, 255, 0.08);
--theme-control-border-strong: rgba(255, 255, 255, 0.12);
--theme-switch-track: #2a2a2a;
--theme-chip-bg: #2a2a2a;
--theme-chip-border: rgba(255, 255, 255, 0.08);
--theme-badge-bg: #2a2a2a;
--theme-tab-active: rgba(255, 255, 255, 0.05);
--theme-mobile-menu: rgba(10, 10, 10, 0.95);
--theme-mobile-menu-shadow: 0 4px 12px rgba(0, 0, 0, 0.6);
--theme-card-border-strong: rgba(255, 255, 255, 0.1);
/* Surface 表面层级 */
--surface-base: #1a1a1a;
--surface-panel: #1a1a1a;
--surface-rail: #181818;
--surface-sidebar: #181818;
--surface-card: #0a0a0a;
--surface-raised: #1a1a1a;
--surface-soft: #0f0f0f;
--surface-muted: #141414;
/* Text 文字 */
--text-primary: #ffffff;
--text-secondary: #a0a0a0;
--text-tertiary: #707070;
--text-muted: rgba(255, 255, 255, 0.3);
/* Border 边框 */
--border-default: rgba(255, 255, 255, 0.08);
--border-strong: rgba(255, 255, 255, 0.12);
--border-card-strong: rgba(255, 255, 255, 0.1);
--chip-border: rgba(255, 255, 255, 0.08);
/* Accent 强调(含运行模式 deep */
--accent: #606060;
--accent-strong: #505050;
--accent-hover: #707070;
--accent-active: #505050;
--accent-deep: #808080;
--accent-deep-strong: #606060;
--on-accent: #ffffff;
/* State 状态 */
--state-success: #10b981;
--state-warning: #f59e0b;
--state-danger: #dc2626;
--state-danger-strong: #b91c1c;
--status-offline: #e34d4d;
--state-info: #60a5fa;
/* Highlight / 交互态 */
--highlight: rgba(255, 255, 255, 0.05);
--tab-active: rgba(255, 255, 255, 0.05);
--chip-bg: #2a2a2a;
--badge-bg: #2a2a2a;
--switch-track: #2a2a2a;
--hover-bg: rgba(255, 255, 255, 0.06);
--pulse-ring: rgba(255, 255, 255, 0.1);
/* Shadow 阴影 */
--shadow-card: 0 2px 8px rgba(0, 0, 0, 0.5);
--shadow-soft: 0 2px 6px rgba(0, 0, 0, 0.4);
--shadow-mid: 0 3px 8px rgba(0, 0, 0, 0.5);
--shadow-strong: 0 4px 12px rgba(0, 0, 0, 0.6);
--shadow-color: rgba(0, 0, 0, 0.4);
/* Overlay / 移动端 */
--overlay-scrim: rgba(0, 0, 0, 0.8);
--mobile-menu: rgba(10, 10, 10, 0.95);
--mobile-menu-shadow: 0 4px 12px rgba(0, 0, 0, 0.6);
/* 专用色 */
--diff-add-text: #00e000;
--diff-del-text: #ff1a1a;
--diff-add-bg: rgba(22, 163, 74, 0.12);
--diff-del-bg: rgba(220, 38, 38, 0.12);
}
/* 首屏JS 设置 data-theme 之前)回退到 classic 取值 */
:root:not([data-theme]) {
/* Surface 表面层级 —— 同 classicClaude 亮色暖奶油盘) */
--surface-base: #faf9f5;
--surface-panel: #faf9f5;
--surface-rail: #f5f0e8;
--surface-sidebar: #f5f0e8;
--surface-card: #efe9de;
--surface-raised: #ffffff;
--surface-soft: #f5f0e8;
--surface-muted: #e8e0d2;
/* Text 文字 */
--text-primary: #141413;
--text-secondary: #3d3d3a;
--text-tertiary: #6c6a64;
--text-muted: rgba(108, 106, 100, 0.55);
/* Border 边框 */
--border-default: #e6dfd8;
--border-strong: #d8cfc4;
--border-card-strong: #e6dfd8;
--chip-border: #ebe6df;
/* Accent 强调 */
--accent: #cc785c;
--accent-strong: #a9583e;
--accent-hover: #bd6a4f;
--accent-active: #a9583e;
--accent-deep: #6c6a64;
--accent-deep-strong: #3d3d3a;
--on-accent: #ffffff;
/* State 状态 */
--state-success: #5db872;
--state-warning: #d4a017;
--state-danger: #c64545;
--state-danger-strong: #a83838;
--status-offline: #c64545;
--state-info: #5db8a6;
/* Highlight / 交互态 —— 中性暖灰 */
--highlight: rgba(20, 20, 19, 0.05);
--tab-active: rgba(20, 20, 19, 0.07);
--chip-bg: #f5f0e8;
--badge-bg: #efe9de;
--switch-track: #d8cfc4;
--hover-bg: rgba(20, 20, 19, 0.05);
--pulse-ring: rgba(0, 0, 0, 0.1);
/* Shadow 阴影 */
--shadow-card: 0 14px 36px rgba(61, 57, 41, 0.12);
--shadow-soft: 0 12px 24px rgba(38, 28, 18, 0.12);
--shadow-mid: 0 20px 45px rgba(16, 24, 40, 0.08);
--shadow-strong: 0 28px 60px rgba(38, 28, 18, 0.25);
--shadow-color: rgba(0, 0, 0, 0.1);
/* Overlay / 移动端 */
--overlay-scrim: rgba(33, 24, 14, 0.55);
--mobile-menu: #f5f0e8;
--mobile-menu-shadow: 0 12px 30px rgba(38, 28, 18, 0.15);
/* 专用色 */
--diff-add-text: #00e000;
--diff-del-text: #ff1a1a;
--diff-add-bg: rgba(22, 163, 74, 0.12);
--diff-del-bg: rgba(220, 38, 38, 0.12);
}

View File

@ -1,7 +1,7 @@
/* 聊天容器整体布局,保证聊天区可见并支持上下滚动 */
.chat-container {
--chat-surface-color: var(--theme-surface-strong, #ffffff);
--composer-base-height: calc(80px + var(--app-bottom-inset, 0px));
--chat-surface-color: var(--surface-panel);
--composer-base-height: calc(80px + var(--app-bottom-inset));
--composer-reserved-height: var(--composer-base-height);
--composer-growth-height: 0px;
flex: 1;
@ -9,7 +9,7 @@
flex-direction: column;
background: var(--chat-surface-color);
min-width: 0;
height: var(--app-viewport, 100vh);
height: var(--app-viewport);
overflow: hidden;
position: relative;
backdrop-filter: blur(6px);
@ -23,7 +23,7 @@
display: flex;
align-items: center;
justify-content: space-between;
color: #0f172a;
color: var(--text-primary);
background: var(--chat-surface-color); /* 与对话区域保持一致且不透明 */
box-shadow: none;
pointer-events: auto;
@ -65,8 +65,8 @@
letter-spacing: 0.02em;
font-family: 'Iowan Old Style', ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif;
max-width: 60%;
color: #0f172a;
text-shadow: 0 1px 6px rgba(0, 0, 0, 0.12);
color: var(--text-primary);
text-shadow: 0 1px 6px var(--shadow-color);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@ -134,7 +134,7 @@
.messages-area::-webkit-scrollbar-thumb,
.sidebar::-webkit-scrollbar-thumb,
.conversation-list::-webkit-scrollbar-thumb {
background: rgba(121, 109, 94, 0.4);
background: var(--text-muted);
border-radius: 8px;
}
@ -175,7 +175,7 @@
@media (max-width: 768px) {
.chat-container {
--composer-base-height: calc(80px + var(--app-bottom-inset, 0px));
--composer-base-height: calc(80px + var(--app-bottom-inset));
--composer-reserved-height: var(--composer-base-height);
}
@ -220,7 +220,7 @@
border: none;
background: transparent;
box-shadow: none;
color: #0f172a;
color: var(--text-primary);
font-weight: 600;
font-size: 15px;
line-height: 1.35;
@ -230,7 +230,7 @@
}
.conversation-ribbon__selector:hover {
color: #111827;
color: var(--text-primary);
}
.conversation-ribbon__selector:disabled {
@ -239,7 +239,7 @@
}
.conversation-ribbon__selector.open {
color: #111827;
color: var(--text-primary);
}
.selector-label {
@ -258,7 +258,7 @@
.selector-mode {
font-weight: 500;
color: rgba(15, 23, 42, 0.8);
color: var(--text-secondary);
}
.selector-caret {
@ -276,9 +276,8 @@
gap: 12px;
padding: 12px;
border-radius: 14px;
background: rgba(255, 255, 255, 0.96);
background: var(--surface-soft);
box-shadow: none;
backdrop-filter: blur(8px);
pointer-events: auto;
width: min(640px, calc(100vw - 32px));
max-width: calc(100vw - 32px);
@ -339,7 +338,7 @@
font-weight: 700;
letter-spacing: 0.04em;
text-transform: uppercase;
color: rgba(15, 23, 42, 0.65);
color: var(--text-secondary);
padding: 2px 12px;
}
@ -354,11 +353,11 @@
gap: 6px;
cursor: pointer;
transition: all 0.18s ease;
color: #0f172a;
color: var(--text-primary);
}
.dropdown-item:hover:not(.disabled) {
background: #f6f7fb;
background: var(--hover-bg);
}
.dropdown-item.disabled {
@ -374,13 +373,13 @@
.item-desc {
grid-column: 1 / 2;
font-size: 12px;
color: rgba(15, 23, 42, 0.65);
color: var(--text-secondary);
}
.item-check {
align-self: center;
font-weight: 800;
color: #0f172a;
color: var(--text-primary);
}
.header-menu-enter-active,
@ -402,7 +401,7 @@
height: 36px;
border-radius: 50%;
border: 1px solid var(--claude-border);
background: rgba(255, 255, 255, 0.92);
background: var(--surface-soft);
display: flex;
align-items: center;
justify-content: center;
@ -499,7 +498,7 @@
}
.user-message .message-text {
background: #f5f5f5;
background: var(--chip-bg);
display: flex;
flex-direction: column;
gap: 10px;
@ -540,7 +539,7 @@
content: '';
flex: 1 1 auto;
height: 0;
border-top: 1px solid var(--theme-control-border, var(--claude-border));
border-top: 1px solid var(--theme-control-border);
}
.user-message.user-message--brief .compact-brief-text {
@ -552,17 +551,12 @@
}
.user-message .message-text .user-skill-link {
color: #2563eb;
color: var(--state-info);
font-weight: 600;
display: inline-block;
margin: 0 0.25em;
}
:root[data-theme='dark'] .user-message .message-text .user-skill-link,
body[data-theme='dark'] .user-message .message-text .user-skill-link {
color: #60a5fa;
}
.assistant-message .message-text {
background: var(--claude-highlight);
border-left: 4px solid var(--claude-accent);
@ -583,7 +577,7 @@ body[data-theme='dark'] .user-message .message-text .user-skill-link {
border-radius: 6px;
overflow: hidden;
cursor: pointer;
border: 1px solid var(--border-color, #2a2f3a);
border: 1px solid var(--border-default);
}
.user-message .message-text.user-bubble-text .image-thumbnail {
@ -651,7 +645,7 @@ body[data-theme='dark'] .user-message .message-text .user-skill-link {
}
.collapsible-block {
background: rgba(255, 255, 255, 0.78);
background: transparent;
border-radius: 12px;
margin-bottom: 12px;
overflow: hidden;
@ -667,7 +661,7 @@ body[data-theme='dark'] .user-message .message-text .user-skill-link {
align-items: center;
gap: 8px;
user-select: none;
background: rgba(255, 255, 255, 0.72);
background: transparent;
transition: background-color 0.2s ease;
position: relative;
min-height: 36px;
@ -1253,21 +1247,21 @@ show-html:not([data-rendered='1'])[ratio='3:4'] {
.text-output .text-content .md-table-scroll::-webkit-scrollbar-track,
.text-output .text-content [data-md-table-scroll='1']::-webkit-scrollbar-track {
background: color-mix(in srgb, var(--theme-surface-muted, #d1d5db) 70%, transparent);
background: color-mix(in srgb, var(--theme-surface-muted) 70%, transparent);
border-radius: 999px;
margin: 0 8px 6px;
}
.text-output .text-content .md-table-scroll::-webkit-scrollbar-thumb,
.text-output .text-content [data-md-table-scroll='1']::-webkit-scrollbar-thumb {
background: color-mix(in srgb, var(--claude-text-secondary, #6b7280) 55%, transparent);
background: color-mix(in srgb, var(--claude-text-secondary) 55%, transparent);
border-radius: 999px;
}
.text-output .text-content .md-table-scroll,
.text-output .text-content [data-md-table-scroll='1'] {
scrollbar-color: color-mix(in srgb, var(--claude-text-secondary, #6b7280) 55%, transparent)
color-mix(in srgb, var(--theme-surface-muted, #d1d5db) 70%, transparent);
scrollbar-color: color-mix(in srgb, var(--claude-text-secondary) 55%, transparent)
color-mix(in srgb, var(--theme-surface-muted) 70%, transparent);
scrollbar-width: thin;
}
@ -1299,8 +1293,8 @@ show-html:not([data-rendered='1'])[ratio='3:4'] {
margin: 12px 0;
padding: 10px 14px;
border-radius: 8px;
background: linear-gradient(135deg, rgba(99, 102, 241, 0.08), rgba(59, 130, 246, 0.08));
border-left: 4px solid rgba(79, 70, 229, 0.6);
background: linear-gradient(135deg, color-mix(in srgb, var(--state-info) 8%, transparent), color-mix(in srgb, var(--state-info) 8%, transparent));
border-left: 4px solid var(--state-info);
color: var(--claude-text);
font-size: 14px;
line-height: 1.5;
@ -1336,8 +1330,8 @@ show-html:not([data-rendered='1'])[ratio='3:4'] {
.append-block.append-error,
.append-placeholder.append-error {
background: rgba(255, 244, 242, 0.85);
border-left-color: rgba(216, 90, 66, 0.38);
background: color-mix(in srgb, var(--state-danger) 8%, var(--surface-soft));
border-left-color: color-mix(in srgb, var(--state-danger) 40%, transparent);
}
.append-header {
@ -1352,14 +1346,14 @@ show-html:not([data-rendered='1'])[ratio='3:4'] {
border-radius: 20px;
overflow: hidden;
margin: 16px 0;
background: var(--theme-surface-strong, #ffffff);
background: var(--theme-surface-strong);
min-height: 80px;
box-shadow: none;
}
.code-block-header {
min-height: 44px;
background: var(--theme-surface-strong, #ffffff);
background: var(--theme-surface-strong);
padding: 0 12px 0 18px;
display: flex;
justify-content: space-between;
@ -1404,7 +1398,7 @@ show-html:not([data-rendered='1'])[ratio='3:4'] {
}
.copy-code-btn:hover {
background-color: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
background-color: var(--theme-tab-active);
color: var(--claude-text);
}
@ -1414,7 +1408,7 @@ show-html:not([data-rendered='1'])[ratio='3:4'] {
}
.code-block-wrapper pre {
background: var(--theme-surface-strong, #ffffff) !important;
background: var(--theme-surface-strong) !important;
padding: 24px 28px 28px !important;
margin: 0 !important;
border-radius: 0 !important;

View File

@ -47,10 +47,10 @@
color: var(--claude-text-secondary);
}
// 动画 - 使用主题色的脉冲效果
// 动画 - 使用主题色的脉冲效果颜色走 --pulse-ring随主题自动适配
@keyframes drag-pulse {
0%, 100% {
box-shadow: 0 0 0 0 var(--claude-highlight);
box-shadow: 0 0 0 0 var(--pulse-ring);
}
50% {
box-shadow: 0 0 0 12px transparent;
@ -82,15 +82,6 @@
.drag-upload-hint {
color: var(--claude-text);
}
@keyframes drag-pulse {
0%, 100% {
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.1);
}
50% {
box-shadow: 0 0 0 12px transparent;
}
}
}
// 经典色主题(classic) - 提示文字改为黑色
@ -111,13 +102,4 @@
.drag-upload-icon {
color: var(--claude-text);
}
@keyframes drag-pulse {
0%, 100% {
box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.1);
}
50% {
box-shadow: 0 0 0 12px transparent;
}
}
}

View File

@ -113,8 +113,8 @@
}
.runtime-queue-item__action--danger:hover {
color: #b91c1c;
background: rgba(185, 28, 28, 0.12);
color: var(--state-danger-strong);
background: color-mix(in srgb, var(--state-danger) 12%, transparent);
}
.runtime-queue-item + .runtime-queue-item::before {
@ -153,7 +153,7 @@
border: 1px solid var(--claude-border);
border-top-left-radius: var(--skill-slash-radius);
border-top-right-radius: var(--skill-slash-radius);
background: rgba(255, 255, 255, 0.98);
background: var(--surface-soft);
box-shadow: none;
pointer-events: auto;
scrollbar-width: none;
@ -227,8 +227,8 @@
.skill-slash-item:hover,
.skill-slash-item--active {
background: rgba(118, 103, 84, 0.12);
box-shadow: 0 1px 2px rgba(61, 57, 41, 0.08);
background: var(--chip-bg);
box-shadow: 0 1px 2px var(--shadow-color);
}
.skill-slash-item--disabled,
@ -246,7 +246,7 @@
.skill-slash-item__name {
flex: 0 0 auto;
max-width: 210px;
color: #2563eb;
color: var(--state-info);
font-size: 13px;
font-weight: 600;
white-space: nowrap;
@ -277,7 +277,7 @@
body[data-theme='dark'] {
.runtime-queue-list {
--runtime-queue-bg: #2a2a2a;
--runtime-queue-bg: var(--badge-bg);
--runtime-queue-divider: rgba(255, 255, 255, 0.12);
--runtime-queue-border: rgba(255, 255, 255, 0.12);
background: transparent;
@ -294,23 +294,23 @@ body[data-theme='dark'] {
}
.skill-slash-menu {
background: #2a2a2a;
background: var(--badge-bg);
border-color: var(--claude-border);
}
.skill-slash-item__name {
color: #60a5fa;
color: var(--state-info);
}
.skill-slash-item:hover,
.skill-slash-item--active {
background: rgba(255, 255, 255, 0.078);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);
background: var(--hover-bg);
box-shadow: 0 1px 2px var(--shadow-color);
}
.stadium-input-editor .skill-md-link,
.stadium-input-highlight .skill-md-link {
color: #60a5fa;
color: var(--state-info);
}
}
@ -365,7 +365,7 @@ body[data-theme='dark'] {
height: 18px;
border-radius: 50%;
background:
conic-gradient(var(--context-ring-color) var(--context-progress), rgba(127, 135, 146, 0.28) 0);
conic-gradient(var(--context-ring-color) var(--context-progress), var(--progress-track) 0);
display: inline-flex;
align-items: center;
justify-content: center;
@ -511,7 +511,7 @@ body[data-theme='dark'] {
}
.permission-switcher__item-label--warn {
color: #d97706;
color: var(--state-warning);
}
@media (max-width: 768px) {
@ -547,8 +547,8 @@ body[data-theme='dark'] {
min-height: calc(var(--stadium-radius) * 2.1);
padding: 12px 18px;
border-radius: var(--stadium-radius);
border: 1px solid rgba(15, 23, 42, 0.12);
background: #ffffff;
border: 1px solid var(--border-default);
background: var(--surface-raised);
box-shadow: none;
display: flex;
gap: 12px;
@ -561,19 +561,19 @@ body[data-theme='dark'] {
padding-top: 16px;
padding-bottom: 16px;
min-height: calc(var(--stadium-radius) * 2.7);
border-color: rgba(15, 23, 42, 0.2);
border-color: var(--border-strong);
box-shadow: none;
}
.stadium-shell.is-focused,
.stadium-shell.has-text {
border-color: rgba(15, 23, 42, 0.12);
border-color: var(--border-default);
box-shadow: none;
}
.stadium-shell.is-multiline.is-focused,
.stadium-shell.is-multiline.has-text {
border-color: rgba(15, 23, 42, 0.2);
border-color: var(--border-strong);
box-shadow: none;
}
@ -603,7 +603,7 @@ body[data-theme='dark'] {
}
.stadium-input-editor .skill-md-link {
color: #2563eb;
color: var(--state-info);
font-weight: inherit;
border-radius: 4px;
padding: 0 1px;
@ -624,7 +624,7 @@ body[data-theme='dark'] {
gap: 6px;
padding: 0 4px 0;
font-size: 12px;
color: var(--text-secondary, #7f8792);
color: var(--text-secondary);
line-height: 1.4;
}
@ -638,7 +638,7 @@ body[data-theme='dark'] {
.image-remove-btn {
border: none;
background: transparent;
color: var(--text-secondary, #7f8792);
color: var(--text-secondary);
cursor: pointer;
padding: 0 4px;
font-size: 12px;
@ -646,7 +646,7 @@ body[data-theme='dark'] {
transition: color 0.15s ease, transform 0.15s ease;
}
.image-remove-btn:hover {
color: #d14b4b;
color: var(--state-danger);
transform: scale(1.05);
}
@ -734,7 +734,7 @@ body[data-theme='dark'] {
}
.stadium-btn:hover:not(:disabled) {
background: rgba(0, 0, 0, 0.05);
background: var(--hover-bg);
}
.add-btn {
@ -743,8 +743,8 @@ body[data-theme='dark'] {
.stadium-btn.send-btn {
background: var(--claude-accent);
color: #fffaf0;
box-shadow: 0 10px 20px rgba(189, 93, 58, 0.28);
color: var(--on-accent);
box-shadow: 0 10px 20px var(--shadow-color);
}
.stadium-btn.send-btn:hover:not(:disabled) {
@ -767,7 +767,7 @@ body[data-theme='dark'] {
height: 0;
border-top: 6px solid transparent;
border-bottom: 6px solid transparent;
border-left: 10px solid #fffaf0;
border-left: 10px solid var(--on-accent);
margin-left: 5px;
}
@ -775,16 +775,16 @@ body[data-theme='dark'] {
width: 12px;
height: 12px;
border-radius: 2px;
background-color: #fffaf0;
background-color: var(--on-accent);
display: block;
}
.stadium-btn.send-btn:disabled .send-icon {
border-left-color: rgba(255, 255, 255, 0.4);
border-left-color: color-mix(in srgb, var(--on-accent) 40%, transparent);
}
.stadium-btn.send-btn:disabled .stop-icon {
background-color: rgba(255, 255, 255, 0.4);
background-color: color-mix(in srgb, var(--on-accent) 40%, transparent);
}
.stadium-shell.is-multiline .stadium-btn {
@ -805,7 +805,7 @@ body[data-theme='dark'] {
gap: 6px;
width: 230px;
padding: 12px;
background: rgba(255, 255, 255, 0.98);
background: var(--surface-soft);
border: 1px solid var(--claude-border);
border-radius: 18px;
box-shadow: none;
@ -838,11 +838,11 @@ body[data-theme='dark'] {
}
.menu-entry:hover:not(:disabled) {
background: rgba(0, 0, 0, 0.05);
background: var(--hover-bg);
}
.menu-entry.active {
background: rgba(118, 103, 84, 0.12);
background: var(--chip-bg);
color: var(--claude-text);
font-weight: 600;
}
@ -866,7 +866,7 @@ body[data-theme='dark'] {
padding: 12px;
border-radius: 18px;
border: 1px solid var(--claude-border);
background: rgba(255, 255, 255, 0.98);
background: var(--surface-soft);
box-shadow: none;
z-index: 31;
}
@ -903,7 +903,7 @@ body[data-theme='dark'] {
.blank-hero-text {
font-size: 32px;
color: #2f3a4a;
color: var(--text-primary);
font-weight: 600;
margin: 0;
max-width: min(88vw, 680px);
@ -919,8 +919,8 @@ body[data-theme='dark'] {
.composer-container {
position: relative;
height: var(--composer-base-height, calc(80px + var(--app-bottom-inset, 0px)));
flex: 0 0 var(--composer-base-height, calc(80px + var(--app-bottom-inset, 0px)));
height: var(--composer-base-height, calc(80px + var(--app-bottom-inset)));
flex: 0 0 var(--composer-base-height, calc(80px + var(--app-bottom-inset)));
transition: transform 0.3s ease;
z-index: 2;
}
@ -1026,7 +1026,7 @@ body[data-theme='dark'] {
position: absolute;
right: 0;
bottom: calc(100% + 12px);
background: rgba(255, 255, 255, 0.96);
background: var(--surface-soft);
border: 1px solid var(--claude-border);
border-radius: 12px;
box-shadow: none;
@ -1045,7 +1045,7 @@ body[data-theme='dark'] {
right: 20px;
border-width: 10px 10px 0 10px;
border-style: solid;
border-color: rgba(255, 255, 255, 0.96) transparent transparent transparent;
border-color: var(--surface-soft) transparent transparent transparent;
filter: drop-shadow(0 3px 4px rgba(61, 57, 41, 0.12));
}
@ -1065,7 +1065,7 @@ body[data-theme='dark'] {
.tool-menu .tool-menu-status,
.tool-menu .tool-menu-empty {
font-size: 13px;
color: rgba(61, 57, 41, 0.78);
color: var(--text-secondary);
text-align: left;
}
@ -1081,9 +1081,9 @@ body[data-theme='dark'] {
align-items: center;
gap: 10px;
padding: 14px 10px;
border: 1px solid rgba(118, 103, 84, 0.14);
border: 1px solid var(--border-default);
border-radius: 10px;
background: rgba(255, 255, 255, 0.88);
background: var(--surface-soft);
font-size: 13px;
aspect-ratio: 1 / 1;
min-height: 0;
@ -1127,19 +1127,19 @@ body[data-theme='dark'] {
.menu-btn {
width: 100%;
padding: 8px 14px;
border: 1px solid rgba(118, 103, 84, 0.14);
border: 1px solid var(--border-default);
border-radius: 8px;
font-size: 13px;
font-weight: 500;
text-align: left;
background: rgba(255, 255, 255, 0.78);
background: var(--surface-soft);
color: var(--claude-text);
cursor: pointer;
transition: all 0.2s ease;
}
.menu-btn:not(:disabled):hover {
background: rgba(255, 255, 255, 0.95);
background: var(--surface-soft);
transform: translateY(-1px);
}
@ -1149,21 +1149,21 @@ body[data-theme='dark'] {
}
.menu-btn.compress-entry {
background: rgba(255, 255, 255, 0.78);
background: var(--surface-soft);
color: var(--claude-success);
}
.menu-btn.compress-entry:not(:disabled):hover {
background: rgba(255, 255, 255, 0.95);
background: var(--surface-soft);
}
.menu-btn.clear-entry {
background: rgba(255, 255, 255, 0.78);
color: #bf422b;
background: var(--surface-soft);
color: var(--state-danger);
}
.menu-btn.clear-entry:not(:disabled):hover {
background: rgba(255, 255, 255, 0.95);
background: var(--surface-soft);
}
.settings-menu-enter-active,
@ -1198,7 +1198,7 @@ body[data-theme='dark'] {
.mobile-panel-sheet--approval .approval-btn--approve {
background: var(--claude-accent);
color: #fff;
color: var(--on-accent);
border-color: var(--claude-accent);
}
@ -1253,10 +1253,10 @@ body[data-theme='dark'] {
min-width: 18px;
height: 18px;
padding: 0 5px;
border: 1.5px solid var(--theme-surface-strong, #fff);
border: 1.5px solid var(--theme-surface-strong);
border-radius: 999px;
background: #ff5f57;
color: #fff;
background: var(--mac-close);
color: var(--on-accent);
cursor: pointer;
font-size: 11px;
line-height: 15px;

File diff suppressed because it is too large Load Diff

View File

@ -56,6 +56,10 @@
.workspace-panel--collapsed {
pointer-events: none;
flex-basis: 0;
width: 0;
min-width: 0;
border: none;
}
.workspace-panel--collapsed > * {
@ -147,7 +151,7 @@
align-items: center;
justify-content: center;
background: linear-gradient(135deg, var(--mode-indicator-color-1), var(--mode-indicator-color-2));
color: #fffef8;
color: var(--on-accent);
box-shadow: 0 8px 20px var(--mode-indicator-shadow);
transition:
background 0.35s ease,
@ -161,14 +165,14 @@
.mode-indicator:focus-visible {
box-shadow:
0 0 0 2px rgba(255, 255, 255, 0.8),
0 0 0 2px color-mix(in srgb, var(--on-accent) 80%, transparent),
0 8px 20px var(--mode-indicator-shadow);
}
.mode-indicator.fast {
--mode-indicator-color-1: #ffe08c;
--mode-indicator-color-2: #f7b23c;
--mode-indicator-shadow: rgba(247, 178, 60, 0.35);
--mode-indicator-color-1: var(--accent-deep);
--mode-indicator-color-2: var(--accent-deep-strong);
--mode-indicator-shadow: color-mix(in srgb, var(--accent-deep) 35%, transparent);
}
.mode-indicator.thinking {
@ -192,7 +196,7 @@
width: 12px;
height: 12px;
border-radius: 6px;
background: #e34d4d;
background: var(--status-offline);
transition:
background 0.2s ease,
box-shadow 0.2s ease;
@ -205,7 +209,7 @@
position: absolute;
inset: 0;
border-radius: inherit;
background: #e34d4d;
background: var(--status-offline);
animation: statusPulse 2.4s ease-out infinite;
}
@ -266,8 +270,8 @@
}
.sidebar-manage-btn {
border: 1px solid rgba(118, 103, 84, 0.25);
background: rgba(255, 255, 255, 0.75);
border: 1px solid var(--border-default);
background: var(--surface-soft);
color: var(--claude-text);
padding: 4px 10px;
border-radius: 6px;
@ -279,16 +283,16 @@
}
.sidebar-manage-btn:hover {
background: rgba(255, 255, 255, 0.95);
border-color: rgba(118, 103, 84, 0.45);
background: var(--surface-soft);
border-color: var(--border-strong);
}
.sidebar-view-toggle {
width: 32px;
height: 32px;
border-radius: 8px;
border: 1px solid rgba(118, 103, 84, 0.3);
background: rgba(255, 255, 255, 0.85);
border: 1px solid var(--border-strong);
background: var(--surface-soft);
cursor: pointer;
display: flex;
align-items: center;
@ -299,7 +303,7 @@
}
.sidebar-view-toggle:hover {
background: rgba(255, 255, 255, 0.95);
background: var(--surface-soft);
}
.sidebar-panel-card-wrapper {
@ -349,8 +353,8 @@
top: 0;
display: flex;
gap: 6px;
background: rgba(255, 255, 255, 0.95);
border: 1px solid rgba(118, 103, 84, 0.2);
background: var(--surface-soft);
border: 1px solid var(--border-default);
border-radius: 8px;
padding: 6px 8px;
box-shadow: none;
@ -367,7 +371,7 @@
}
.panel-menu button.active {
background: rgba(108, 92, 231, 0.1);
background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.fade-enter-active,
@ -455,7 +459,7 @@
}
.sub-agent-card {
border: 1px solid rgba(118, 103, 84, 0.2);
border: 1px solid var(--border-default);
border-radius: 10px;
padding: 12px 14px;
background: color-mix(in srgb, var(--claude-left-rail) 88%, var(--theme-surface-strong) 12%);
@ -465,17 +469,17 @@
box-shadow 0.2s ease;
[data-theme='dark'] & {
background: rgba(30, 30, 30, 0.6);
border-color: rgba(255, 255, 255, 0.1);
background: color-mix(in srgb, var(--surface-base) 60%, transparent);
border-color: var(--border-card-strong);
}
}
.sub-agent-card:hover {
border-color: #6c5ce7;
border-color: var(--accent);
box-shadow: none;
[data-theme='dark'] & {
border-color: #8b7ce7;
border-color: var(--accent-hover);
box-shadow: none;
}
}
@ -494,18 +498,18 @@
}
.sub-agent-status.running {
color: #0984e3;
color: var(--state-info);
}
.sub-agent-status.completed {
color: #00b894;
color: var(--state-success);
}
.sub-agent-status.failed,
.sub-agent-status.timeout,
.sub-agent-status.terminated,
.sub-agent-status.cancelled {
color: #d63031;
color: var(--state-danger);
}
.sub-agent-summary {
@ -537,8 +541,8 @@
text-align: center;
[data-theme='dark'] & {
background: rgba(20, 20, 20, 0.9);
border-color: rgba(255, 255, 255, 0.12);
background: color-mix(in srgb, var(--surface-base) 90%, transparent);
border-color: var(--border-strong);
}
}
@ -674,14 +678,14 @@
&.default {
color: var(--claude-deep-strong);
border-color: rgba(208, 122, 20, 0.35);
background: rgba(242, 169, 59, 0.14);
border-color: color-mix(in srgb, var(--accent-deep-strong) 35%, transparent);
background: color-mix(in srgb, var(--accent-deep) 14%, transparent);
}
&.current {
color: #2f6f4e;
border-color: rgba(47, 111, 78, 0.35);
background: rgba(118, 176, 134, 0.18);
color: var(--state-success);
border-color: color-mix(in srgb, var(--state-success) 35%, transparent);
background: color-mix(in srgb, var(--state-success) 18%, transparent);
}
&.running {
@ -693,38 +697,38 @@
[data-theme='dark'] .host-workspace-header-box {
background: var(--claude-left-rail);
border-color: rgba(160, 160, 160, 0.45);
border-color: var(--border-strong);
}
[data-theme='dark'] .host-workspace-card {
background: color-mix(in srgb, var(--claude-left-rail) 88%, var(--theme-surface-strong) 12%);
&:hover:not(:disabled) {
background: #222222;
background: var(--badge-bg);
}
&.active {
background: #242424;
background: color-mix(in srgb, var(--badge-bg) 100%, white 4%);
}
}
[data-theme='dark'] .host-workspace-badge {
&.default {
color: #f7c56f;
border-color: rgba(247, 197, 111, 0.35);
background: rgba(247, 197, 111, 0.16);
color: var(--accent-deep);
border-color: color-mix(in srgb, var(--accent-deep) 35%, transparent);
background: color-mix(in srgb, var(--accent-deep) 16%, transparent);
}
&.current {
color: #8edbb4;
border-color: rgba(142, 219, 180, 0.34);
background: rgba(16, 185, 129, 0.2);
color: var(--state-success);
border-color: color-mix(in srgb, var(--state-success) 34%, transparent);
background: color-mix(in srgb, var(--state-success) 20%, transparent);
}
&.running {
color: #f7c56f;
border-color: rgba(247, 197, 111, 0.35);
background: rgba(247, 197, 111, 0.16);
color: var(--accent-deep);
border-color: color-mix(in srgb, var(--accent-deep) 35%, transparent);
background: color-mix(in srgb, var(--accent-deep) 16%, transparent);
}
}
@ -744,7 +748,7 @@
align-items: center;
justify-content: space-between;
padding: 10px 14px;
border: 1px solid rgba(118, 103, 84, 0.18);
border: 1px solid var(--border-default);
border-radius: 10px;
font-size: 13px;
color: var(--claude-text);
@ -752,8 +756,8 @@
}
.todo-task.done {
background: rgba(92, 190, 125, 0.08);
border-color: rgba(92, 190, 125, 0.3);
background: color-mix(in srgb, var(--state-success) 8%, transparent);
border-color: color-mix(in srgb, var(--state-success) 30%, transparent);
}
.todo-task-title {
@ -853,14 +857,13 @@
.context-menu {
position: fixed;
background: #ffffff;
border: 1px solid rgba(15, 23, 42, 0.08);
background: var(--surface-raised);
border: 1px solid var(--border-default);
border-radius: 8px;
box-shadow: none;
z-index: 3000;
min-width: 180px;
padding: 6px 0;
backdrop-filter: blur(8px);
}
.context-menu button {
@ -870,17 +873,17 @@
border: none;
text-align: left;
font-size: 13px;
color: #1f2933;
color: var(--text-primary);
cursor: pointer;
transition: background 0.15s ease;
}
.context-menu button:hover {
background: rgba(59, 130, 246, 0.12);
background: color-mix(in srgb, var(--state-info) 12%, transparent);
}
.context-menu button:disabled {
color: #9ca3af;
color: var(--text-tertiary);
cursor: not-allowed;
background: transparent;
}
@ -901,7 +904,7 @@
}
.sidebar-manage-btn:hover {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
background: var(--theme-tab-active);
border-color: transparent;
}
@ -922,7 +925,7 @@
}
.sidebar-view-toggle:hover {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
background: var(--theme-tab-active);
}
.panel-menu {
@ -957,5 +960,5 @@
.panel-menu button:hover,
.panel-menu button.active {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
background: var(--theme-tab-active);
}

View File

@ -21,7 +21,7 @@
background: var(--claude-panel);
border: 1px solid var(--claude-border);
border-radius: 26px;
box-shadow: 0 24px 42px rgba(61, 57, 41, 0.18);
box-shadow: 0 24px 42px var(--shadow-color);
transition: transform 0.35s ease, opacity 0.35s ease;
pointer-events: auto;
position: relative;
@ -170,18 +170,18 @@
left: 12px;
width: 14px;
height: 14px;
border: 1px solid #e0443e;
border: 1px solid var(--mac-close-border);
border-radius: 50%;
background: #ff5f56;
background: var(--mac-close);
display: block;
padding: 0;
cursor: pointer;
transition: background 0.2s ease, transform 0.2s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.16);
box-shadow: 0 2px 4px var(--shadow-color);
}
.token-close-btn:hover {
background: #ff3b30;
background: var(--mac-close-hover);
transform: translateY(-1px);
}
@ -328,7 +328,7 @@
border-radius: 999px;
font-size: 11px;
font-weight: 600;
background: rgba(125, 109, 94, 0.15);
background: var(--badge-bg);
color: var(--claude-text-secondary);
}
@ -340,7 +340,7 @@
border-radius: 12px;
background: var(--claude-bg);
border: 1px solid var(--claude-border-strong);
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.18);
box-shadow: 0 12px 30px var(--shadow-color);
z-index: 2000;
max-width: 320px;
color: var(--claude-text);
@ -388,8 +388,8 @@
padding: 12px 14px;
border-radius: 14px;
background: var(--claude-bg);
border: 1px solid var(--claude-border-strong, rgba(118,103,84,0.35));
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.18);
border: 1px solid var(--claude-border-strong);
box-shadow: 0 12px 30px var(--shadow-color);
color: var(--claude-text);
}
@ -410,7 +410,7 @@
}
.app-toast--error::before {
background: #d45f5f;
background: var(--state-danger);
}
.app-toast-body {
@ -444,17 +444,17 @@
.status-pill--running {
background: rgba(118, 176, 134, 0.18);
background: color-mix(in srgb, var(--state-success) 22%, transparent);
color: var(--claude-success);
}
.status-pill--stopped {
background: rgba(217, 152, 69, 0.2);
background: color-mix(in srgb, var(--state-warning) 22%, transparent);
color: var(--claude-warning);
}
.status-pill--host {
background: rgba(125, 109, 94, 0.12);
background: var(--badge-bg);
color: var(--claude-text-secondary);
}
@ -584,9 +584,9 @@
.search-result-item {
padding: 10px 12px;
border: 1px solid rgba(118, 103, 84, 0.16);
border: 1px solid var(--border-default);
border-radius: 8px;
background: rgba(255, 255, 255, 0.65);
background: var(--surface-soft);
word-break: break-word;
}

View File

@ -45,7 +45,7 @@
height: 32px;
border: none;
border-radius: 16px;
background: rgba(0, 0, 0, 0.08);
background: var(--hover-bg);
color: var(--claude-text);
font-size: 20px;
cursor: pointer;
@ -56,7 +56,7 @@
height: 32px;
border: none;
border-radius: 16px;
background: rgba(0, 0, 0, 0.08);
background: var(--hover-bg);
color: var(--claude-text);
font-size: 20px;
cursor: pointer;
@ -66,7 +66,7 @@
flex: 0 0 auto;
min-width: 340px;
max-width: min(600px, 52vw);
height: var(--app-viewport, 100vh);
height: var(--app-viewport);
display: flex;
flex-direction: column;
background: var(--claude-left-rail);
@ -139,9 +139,9 @@
}
.git-changes-panel__close:hover {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
background: var(--theme-tab-active);
color: var(--claude-text);
box-shadow: 0 1px 2px rgba(61, 57, 41, 0.08);
box-shadow: 0 1px 2px var(--shadow-color);
}
.git-changes-panel__body {
@ -149,14 +149,14 @@
min-height: 0;
overflow: auto;
padding: 12px;
scrollbar-color: color-mix(in srgb, var(--claude-text-secondary, #6b7280) 55%, transparent)
color-mix(in srgb, var(--theme-surface-muted, #d1d5db) 70%, transparent);
scrollbar-color: color-mix(in srgb, var(--claude-text-secondary) 55%, transparent)
color-mix(in srgb, var(--theme-surface-muted) 70%, transparent);
scrollbar-width: thin;
}
.git-changes-panel * {
scrollbar-color: color-mix(in srgb, var(--claude-text-secondary, #6b7280) 55%, transparent)
color-mix(in srgb, var(--theme-surface-muted, #d1d5db) 70%, transparent);
scrollbar-color: color-mix(in srgb, var(--claude-text-secondary) 55%, transparent)
color-mix(in srgb, var(--theme-surface-muted) 70%, transparent);
scrollbar-width: thin;
}
@ -168,14 +168,14 @@
.git-changes-panel::-webkit-scrollbar-track,
.git-changes-panel ::-webkit-scrollbar-track {
background: color-mix(in srgb, var(--theme-surface-muted, #d1d5db) 70%, transparent);
background: color-mix(in srgb, var(--theme-surface-muted) 70%, transparent);
border-radius: 999px;
margin: 8px;
}
.git-changes-panel::-webkit-scrollbar-thumb,
.git-changes-panel ::-webkit-scrollbar-thumb {
background: color-mix(in srgb, var(--claude-text-secondary, #6b7280) 55%, transparent);
background: color-mix(in srgb, var(--claude-text-secondary) 55%, transparent);
border-radius: 999px;
border: 2px solid transparent;
background-clip: padding-box;
@ -189,7 +189,7 @@
}
.git-changes-panel__empty--error {
color: var(--theme-danger, #c00);
color: var(--state-danger);
}
.git-change-file {
@ -238,9 +238,9 @@
.git-change-file__open-btn:hover,
.git-change-file__open-btn.open {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
background: var(--theme-tab-active);
color: var(--claude-text);
box-shadow: 0 1px 2px rgba(61, 57, 41, 0.08);
box-shadow: 0 1px 2px var(--shadow-color);
}
.git-change-file__open-btn:disabled {
@ -322,8 +322,8 @@ body[data-theme='dark'] .git-change-file__open-icon {
}
.git-change-file__open-option:hover {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
box-shadow: 0 1px 2px rgba(61, 57, 41, 0.08);
background: var(--theme-tab-active);
box-shadow: 0 1px 2px var(--shadow-color);
}
.git-change-file__open-empty {
@ -354,9 +354,9 @@ body[data-theme='dark'] .git-change-file__open-icon {
}
.git-change-file__reset:hover {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
background: var(--theme-tab-active);
color: var(--claude-text);
box-shadow: 0 1px 2px rgba(61, 57, 41, 0.08);
box-shadow: 0 1px 2px var(--shadow-color);
}
.git-change-file__diff {
@ -402,9 +402,9 @@ body[data-theme='dark'] .git-change-file__open-icon {
}
.git-change-file__fold:hover {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
background: var(--theme-tab-active);
color: var(--claude-text);
box-shadow: 0 1px 2px rgba(61, 57, 41, 0.08);
box-shadow: 0 1px 2px var(--shadow-color);
}
.git-change-file__fold-icon {
@ -471,13 +471,13 @@ body[data-theme='dark'] .git-change-file__open-icon {
}
.git-change-line--add {
background: rgba(0, 255, 0, 0.1);
color: #0a0;
background: var(--diff-add-bg);
color: var(--state-success);
}
.git-change-line--delete {
background: rgba(255, 0, 0, 0.1);
color: #c00;
background: var(--diff-del-bg);
color: var(--state-danger);
}
.git-changes-panel-slide-enter-active,
@ -514,8 +514,8 @@ body[data-theme='dark'] .git-change-file__open-icon {
border: 1px solid var(--claude-border);
border-radius: 12px;
overflow: hidden;
background: rgba(255, 255, 255, 0.75);
box-shadow: 0 12px 28px rgba(61, 57, 41, 0.08);
background: var(--surface-soft);
box-shadow: 0 12px 28px var(--shadow-color);
}
.tab-header {
@ -541,7 +541,7 @@ body[data-theme='dark'] .git-change-file__open-icon {
.file-content {
max-height: 320px;
overflow-y: auto;
background: #ffffff;
background: var(--surface-raised);
}
.file-content pre {
@ -553,7 +553,7 @@ body[data-theme='dark'] .git-change-file__open-icon {
font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
font-size: 13px;
line-height: 1.5;
color: #1f2227;
color: var(--text-primary);
}
.tool-approval-panel .approval-panel-body {
@ -621,10 +621,10 @@ body[data-theme='dark'] .git-change-file__open-icon {
line-height: 1.5;
max-height: 400px;
overflow-y: auto;
border: 1px solid rgba(0, 0, 0, 0.1);
border: 1px solid var(--border-default);
border-radius: 6px;
padding: 8px;
background: rgba(0, 0, 0, 0.01);
background: color-mix(in srgb, transparent 99%, var(--text-primary));
scrollbar-width: none;
-ms-overflow-style: none;
}
@ -685,13 +685,13 @@ body[data-theme='dark'] .git-change-file__open-icon {
}
.tool-approval-panel .diff-remove {
background: rgba(255, 0, 0, 0.1);
color: #c00;
background: var(--diff-del-bg);
color: var(--state-danger);
}
.tool-approval-panel .diff-add {
background: rgba(0, 255, 0, 0.1);
color: #0a0;
background: var(--diff-add-bg);
color: var(--state-success);
}
.approval-actions {
@ -719,8 +719,8 @@ body[data-theme='dark'] .git-change-file__open-icon {
}
.approval-btn--switch {
color: #fff;
background: #dc2626;
color: var(--on-accent);
background: var(--state-danger);
}
.approval-btn--reject {

View File

@ -9,8 +9,8 @@
top: 0;
z-index: 120;
width: var(--conversation-expanded-width);
height: var(--app-viewport, 100vh) !important;
min-height: var(--app-viewport, 100vh) !important;
height: var(--app-viewport) !important;
min-height: var(--app-viewport) !important;
overflow: hidden;
background: var(--claude-left-rail);
border-right: 0;
@ -97,13 +97,13 @@
.conversation-sidebar.collapsed .sidebar-nav-row:hover .sidebar-nav-icon,
.conversation-sidebar.collapsed .sidebar-nav-row:focus-visible .sidebar-nav-icon {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
background: var(--theme-tab-active);
}
.conversation-sidebar:not(.collapsed) .sidebar-nav-row:hover,
.conversation-sidebar:not(.collapsed) .sidebar-nav-row:focus-visible,
.conversation-sidebar:not(.collapsed) .sidebar-nav-row.active {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
background: var(--theme-tab-active);
outline: none;
}
@ -113,7 +113,7 @@
.conversation-sidebar:not(.collapsed) .workspace-control-btn.active:hover,
.conversation-sidebar:not(.collapsed) .workspace-control-btn.active:focus-visible {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
background: var(--theme-tab-active);
}
.sidebar-nav-label,
@ -178,7 +178,7 @@
.search-input-wrap:hover,
.search-input-wrap:focus-within {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
background: var(--theme-tab-active);
}
.search-inline-icon {
@ -257,7 +257,7 @@
.conversation-sidebar .running-task-item:hover,
.conversation-sidebar .running-task-item.active {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
background: var(--theme-tab-active);
}
.conversation-sidebar .running-task-workspace {
@ -294,7 +294,7 @@
[data-theme='dark'] .conversation-sidebar .running-task-item.active,
body[data-theme='dark'] .conversation-sidebar .running-task-item:hover,
body[data-theme='dark'] .conversation-sidebar .running-task-item.active {
background: #222222;
background: var(--hover-bg);
}
.conversation-sidebar .conversation-item {
@ -360,7 +360,7 @@ body[data-theme='dark'] .conversation-sidebar .running-task-item.active {
}
.conversation-sidebar .conversation-item.duplicate-source-mask:hover::after {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
background: var(--theme-tab-active);
}
:root[data-theme='dark']
@ -369,7 +369,7 @@ body[data-theme='dark'] .conversation-sidebar .running-task-item.active {
body[data-theme='dark']
.conversation-sidebar
.conversation-item.duplicate-source-mask:hover::after {
background: rgba(255, 255, 255, 0.078);
background: var(--hover-bg);
}
.conversation-sidebar .conversation-item.duplicate-source-mask > * {
@ -407,18 +407,18 @@ body[data-theme='dark']
.conversation-sidebar .conversation-item:focus-within,
.conversation-sidebar .conversation-item.active:hover,
.conversation-sidebar .conversation-item.active:focus-within {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055)) !important;
background: var(--theme-tab-active) !important;
box-shadow: none !important;
}
.conversation-sidebar .conversation-item.active {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055)) !important;
background: var(--theme-tab-active) !important;
box-shadow: none !important;
}
:root[data-theme='dark'] .conversation-sidebar .conversation-item.active,
body[data-theme='dark'] .conversation-sidebar .conversation-item.active {
background: rgba(255, 255, 255, 0.078) !important;
background: var(--hover-bg) !important;
box-shadow: none !important;
}
@ -430,7 +430,7 @@ body[data-theme='dark'] .conversation-sidebar .conversation-item:hover,
body[data-theme='dark'] .conversation-sidebar .conversation-item:focus-within,
body[data-theme='dark'] .conversation-sidebar .conversation-item.active:hover,
body[data-theme='dark'] .conversation-sidebar .conversation-item.active:focus-within {
background: rgba(255, 255, 255, 0.078) !important;
background: var(--hover-bg) !important;
box-shadow: none !important;
}
@ -543,7 +543,7 @@ body[data-theme='dark'] .conversation-sidebar .conversation-item.active:focus-wi
padding: 6px;
border: 1px solid var(--claude-border);
border-radius: 14px;
background: var(--theme-surface-strong, #fff);
background: var(--theme-surface-strong);
box-shadow: none;
opacity: 0;
transform: translateY(-4px) scale(0.98);
@ -579,11 +579,11 @@ body[data-theme='dark'] .conversation-sidebar .conversation-item.active:focus-wi
}
.conversation-sidebar .conversation-actions-menu button:hover {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
background: var(--theme-tab-active);
}
.conversation-sidebar .conversation-actions-menu button.danger {
color: #d6483b;
color: var(--state-danger);
}
.conversation-personal-entry {
@ -626,7 +626,7 @@ body[data-theme='dark'] .conversation-sidebar .conversation-item.active:focus-wi
}
.load-more-btn:hover:not(:disabled) {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055));
background: var(--theme-tab-active);
color: var(--claude-text);
}
@ -716,19 +716,19 @@ body[data-theme='dark'] .conversation-sidebar .conversation-item.active:focus-wi
.conversation-sidebar.collapsed .personal-page-btn:hover .sidebar-nav-icon,
.conversation-sidebar.collapsed .personal-page-btn:focus-visible .sidebar-nav-icon {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055)) !important;
background: var(--theme-tab-active) !important;
}
.conversation-sidebar:not(.collapsed) .personal-page-btn:hover,
.conversation-sidebar:not(.collapsed) .personal-page-btn:focus-visible {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055)) !important;
background: var(--theme-tab-active) !important;
}
:root[data-theme='dark'] .conversation-sidebar:not(.collapsed) .personal-page-btn:hover,
:root[data-theme='dark'] .conversation-sidebar:not(.collapsed) .personal-page-btn:focus-visible,
body[data-theme='dark'] .conversation-sidebar:not(.collapsed) .personal-page-btn:hover,
body[data-theme='dark'] .conversation-sidebar:not(.collapsed) .personal-page-btn:focus-visible {
background: rgba(255, 255, 255, 0.078) !important;
background: var(--hover-bg) !important;
}
.conversation-sidebar .load-more-btn {
@ -739,10 +739,10 @@ body[data-theme='dark'] .conversation-sidebar:not(.collapsed) .personal-page-btn
}
.conversation-sidebar .load-more-btn:hover:not(:disabled) {
background: var(--theme-tab-active, rgba(0, 0, 0, 0.055)) !important;
background: var(--theme-tab-active) !important;
}
:root[data-theme='dark'] .conversation-sidebar .load-more-btn:hover:not(:disabled),
body[data-theme='dark'] .conversation-sidebar .load-more-btn:hover:not(:disabled) {
background: rgba(255, 255, 255, 0.078) !important;
background: var(--hover-bg) !important;
}

View File

@ -3,13 +3,13 @@
position: relative;
display: flex;
flex-direction: row;
height: var(--app-viewport, 100vh);
height: var(--app-viewport);
align-items: stretch;
background: var(--claude-bg);
color: var(--claude-text);
}
#app {
min-height: var(--app-viewport, 100vh);
min-height: var(--app-viewport);
background: var(--claude-bg);
}

View File

@ -16,7 +16,7 @@
top: 0;
height: 100%;
z-index: 1000;
box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1);
box-shadow: 2px 0 10px var(--shadow-color);
transform: translateX(-100%);
}