From ce58504e5a806a176e132d99b7ea123154cf313b Mon Sep 17 00:00:00 2001 From: limityan Date: Thu, 18 Jun 2026 10:07:50 +0800 Subject: [PATCH 1/2] refactor(web-ui): tighten theme color governance Consolidate remaining app UI raw colors, token-equivalent literals, and fallback defaults across theme surfaces. Lower the color governance baseline to the new audited counts and document the retained near-color boundaries. --- docs/architecture/theme-token-optimization.md | 61 +++++++++---------- scripts/theme-color-governance-baseline.json | 35 +++-------- .../scenes/agents/components/AgentCard.scss | 4 +- .../agents/components/ReviewTeamPage.scss | 4 +- .../agents/components/_AgentSurfaceCard.scss | 4 +- .../app/scenes/profile/views/NurseryView.scss | 19 ++++-- .../src/app/styles/utilities/animations.css | 2 +- .../ContextCompressionCard.scss | 12 +++- .../SnapshotCard/SnapshotCard.scss | 4 +- .../components/Markdown/MermaidBlock.scss | 4 +- .../modern/ModernFlowChatContainer.scss | 2 +- .../config/components/AIModelConfig.scss | 4 +- .../components/ui/ContextMenu.scss | 4 +- .../tools/editor/components/ImageViewer.scss | 10 +-- .../meditor/components/TiptapEditor.scss | 20 +++--- .../file-system/components/FileTreeItem.tsx | 4 +- .../GitDiffEditor/GitDiffEditor.scss | 6 +- 17 files changed, 99 insertions(+), 100 deletions(-) diff --git a/docs/architecture/theme-token-optimization.md b/docs/architecture/theme-token-optimization.md index f2ade2001d..5508bfac9e 100644 --- a/docs/architecture/theme-token-optimization.md +++ b/docs/architecture/theme-token-optimization.md @@ -1,6 +1,6 @@ # 主题与颜色 Token 优化方案 -> 当前基线:`gcwing/main` 的 `e5024fdd`,扫描日期为 2026-06-17。 +> 当前基线:`gcwing/main` 的 `617086b8`,扫描日期为 2026-06-18。 本文档用于梳理 BitFun 前端主题、硬编码颜色、重复 token、近似色冗余、 命名漂移和后续治理方案。目标不是把所有看起来相近的颜色都合并,而是让 @@ -60,21 +60,21 @@ | 指标 | 当前基线 | | --- | ---: | -| 扫描的生产前端文件数 | 1525 | -| 忽略的测试文件数 | 211 | -| 包含颜色字面量的文件数 | 75 | -| 颜色字面量出现次数 | 1930 | -| 唯一颜色字面量数量 | 1038 | -| 组件或非 token 文件中的颜色出现次数 | 273 | -| 组件或非 token 唯一颜色数量 | 233 | -| App UI 颜色出现次数 | 108 | -| App UI 唯一颜色数量 | 94 | -| `var(--token, fallback)` 出现次数 | 31 | -| fallback 唯一 token 数 | 10 | -| token-equivalent app literal 出现次数 | 13 | -| token-equivalent app literal 唯一颜色数量 | 11 | +| 扫描的生产前端文件数 | 1524 | +| 忽略的测试文件数 | 212 | +| 包含颜色字面量的文件数 | 65 | +| 颜色字面量出现次数 | 1891 | +| 唯一颜色字面量数量 | 1025 | +| 组件或非 token 文件中的颜色出现次数 | 234 | +| 组件或非 token 唯一颜色数量 | 204 | +| App UI 颜色出现次数 | 84 | +| App UI 唯一颜色数量 | 75 | +| `var(--token, fallback)` 出现次数 | 25 | +| fallback 唯一 token 数 | 7 | +| token-equivalent app literal 出现次数 | 12 | +| token-equivalent app literal 唯一颜色数量 | 10 | | 普通组件肉眼不可区分 near color pair | 0 | -| 普通组件需证据复核的 near color pair | 35 | +| 普通组件需证据复核的 near color pair | 16 | 当前审计未发现 CSS 变量契约层面的硬错误: @@ -94,7 +94,7 @@ | --- | ---: | ---: | --- | | Theme presets | 1033 | 611 | 主题个性与 palette 映射,不作为普通 app literal 直接合并 | | Token contracts | 268 | 159 | `tokens.scss` 等静态契约根 | -| Editor | 151 | 122 | Monaco/editor 专用域,不能直接泛化到 app token | +| Editor | 136 | 110 | Monaco/editor 专用域,不能直接泛化到 app token | | Mermaid | 139 | 95 | Mermaid 专用渲染域 | | Theme runtime | 54 | 45 | `ThemeService.ts` 运行时注入 | | Language identity | 57 | 50 | 语言身份色,应保留数据语义或迁入 identity registry | @@ -103,7 +103,7 @@ | Visual effects | 22 | 22 | 动效和装饰效果,需按效果语义审查 | | UI exception registry | 21 | 19 | 已归档的 UI 例外色 | | Generated widget | 0 | 0 | 颜色默认值已迁到 boundary fallback registry | -| App UI | 108 | 94 | 后续普通组件迁移的主战场 | +| App UI | 84 | 75 | 后续普通组件迁移的主战场 | 剩余高频普通组件或边界文件: @@ -115,7 +115,7 @@ | `src/web-ui/src/shared/theme/uiExceptionAccents.ts` | 21 | 已归档 UI 例外,继续要求显式 owner/role | | `src/web-ui/src/shared/prism/prismTheme.ts` | 18 | syntax theme,不泛化到 app token | | `src/web-ui/src/tools/editor/components/DiffEditor.scss` | 18 | diff/editor 专用域,按 git/diff token 处理 | -| `src/web-ui/src/app/scenes/profile/views/NurseryView.scss` | 10 | app scene surface,优先迁移到 scene/component token | +| `src/web-ui/src/app/scenes/profile/views/NurseryView.scss` | 0 | app scene surface 中的 assistant 默认 gradient 和 deco alpha 已迁到 token/color-mix | 当前 fallback token 都已进入 allowlist,但仍需要逐项决策是否保留边界 fallback: @@ -124,11 +124,8 @@ | `--surface-stagger-index` | 12 | | `--mission-control-group-color` | 6 | | `--char-index` | 3 | -| `--shadow-color` | 3 | -| `--assistant-card-gradient` | 2 | | `--gallery-grid-min` | 1 | | `--gallery-skeleton-height` | 1 | -| `--operation-color` | 1 | | `--primary-color` | 1 | | `--scene-viewport-border-width` | 1 | @@ -139,11 +136,8 @@ fallback 决策表: | `--surface-stagger-index` | 保留 | 运行时 inline 动画序号,`0` 是安全首帧/无动画默认值 | 不迁移为颜色 token;保持 allowlist | | `--mission-control-group-color` | 保留 | 分组身份色由数据或 inline style 驱动,静态删除会丢失未设置分组色时的 accent 兜底 | 后续 content-canvas token 抽取时复核是否改为组件根默认值 | | `--char-index` | 保留 | StreamText 每字符动画偏移,`0` fallback 是无序号渲染的安全默认值 | 不迁移为颜色 token;保持 allowlist | -| `--shadow-color` | 延后 | 同时服务 agent surface 和 Mermaid block 的局部 shadow tint,跨 surface 合并风险较高 | Flow Chat/Markdown token 抽取时拆成 surface-specific shadow token | -| `--assistant-card-gradient` | 延后 | assistant identity gradient 在 metadata 未加载时需要静态视觉兜底 | NurseryView surface token 抽取时迁到组件根默认值 | | `--gallery-grid-min` | 保留 | runtime layout sizing 输入,不属于颜色债务;`320px` 保持 responsive grid 下限 | 保持 allowlist,后续只在 layout token 方案中处理 | | `--gallery-skeleton-height` | 保留 | runtime skeleton sizing 输入,不属于颜色债务;`140px` 保持占位高度稳定 | 保持 allowlist,后续只在 layout token 方案中处理 | -| `--operation-color` | 延后 | Snapshot operation identity 色由操作类型驱动,直接删除会弱化操作差异 | SnapshotCard token 抽取时补根默认值后再移除局部 fallback | | `--primary-color` | 延后 | Markdown 嵌入内容可覆盖 primary accent,边界语义不同于全局 app primary | Markdown token 抽取时决定是否转为 `--markdown-primary-color` contract | | `--scene-viewport-border-width` | 保留 | viewport border width 是 runtime layout override,`1px` fallback 保持默认边界可见 | 保持 allowlist,后续只在 scene layout token 方案中处理 | @@ -153,11 +147,11 @@ fallback 决策表: | --- | --- | --- | | Phase 0:基线与工具 | 已完成主体 | 审计脚本可区分测试文件、fallback token、dynamic families 和 exception domains | | Phase 1:canonical token 契约 | 已完成主体,继续补文档 | 静态/runtime/widget 契约已有治理入口,仍需保持文档基线同步 | -| Phase 2:精确重复合并 | 部分完成 | 本轮已集中 code snippet language identity,并减少 StreamText 重复 visual-effect literal | -| Phase 3:legacy fallback 迁移 | 部分完成 | 本轮已集中 widget/miniapp boundary fallback;剩余 10 个 fallback token 已完成决策表 | -| Phase 4:组件 token 抽取 | 进行中 | 本轮补充 visual effect 私有变量和 boundary fallback owner,Flow Chat、tool card、diff/git 仍需按 surface 继续抽取 | -| Phase 5:近似色合并 | 已完成首轮 | 本轮仅合并审计标记为 `indistinguishable` 的 2 个 pair,其余 near pair 保持延后 | -| Phase 6:防回退约束 | 已完成首轮 | baseline 已约束 app raw color、fallback、CSS var 契约和普通组件 near-pair 数量,新增普通组件不可区分 pair 会失败 | +| Phase 2:精确重复合并 | 持续完成 | 本轮继续移除 token-equivalent app literal,并把 ImageViewer 状态色迁到文本、边框、强调、错误 token | +| Phase 3:legacy fallback 迁移 | 持续完成 | `--shadow-color`、`--assistant-card-gradient`、`--operation-color` 已落到组件根默认值,fallback unique token 从 10 降到 7 | +| Phase 4:组件 token 抽取 | 持续完成 | agent surface、Mermaid、Snapshot、Nursery、ContextCompression、ImageViewer、Tiptap inline AI 等 surface 已补根默认值或改用 contract token | +| Phase 5:近似色合并 | 持续完成 | app UI / editor 中安全的极近似 alpha 已改为 token/color-mix;DiffEditor、Monaco、language identity、StreamText 等相邻或跨域身份色保持延后 | +| Phase 6:防回退约束 | 持续完成 | baseline 已同步降到当前审计值,防止 app raw color、fallback、token-equivalent literal 和普通组件 near-pair 回涨 | Phase 5 首轮决策: @@ -165,16 +159,17 @@ Phase 5 首轮决策: | --- | --- | --- | --- | | `#1f2024` -> `#202024` | merge | `ChatInputPixelPet.scss` panda body/decor;`bitfun-dark.theme.ts` editor subtle border | RGB distance = 1,非状态色,非相邻 surface 边界;panda 固定深色与 editor border 不在同一视觉层级承担区分 | | `#6e7681` -> `#6e7781` | merge | `LanguageRegistry.ts` Plain Text identity;`prismTheme.ts` light comment | RGB distance = 1,均为 neutral muted 文本/identity 色,不表达状态严重程度或数据差异 | -| top near pairs | defer | `DiffEditor.scss`、`GitDiffEditor.scss`、`ContextMenu.scss`、`TiptapEditor.scss`、Flow Chat capture fallback 等 | alpha 或暗色层级差异可能表达 overlay/elevation/diff state,需截图和相邻关系证据后再处理 | +| app UI / editor alpha raw values | merge to token/color-mix | `ContextMenu.scss`、`TiptapEditor.scss`、`GitDiffEditor.scss`、`AIModelConfig.scss`、`NurseryView.scss`、`AgentCard.scss`、`ImageViewer.scss` | 色相来自现有 accent/success/overlay/text/error contract,透明度仅表达层级;迁移为 token/color-mix 保留层级但移除游离 raw color | +| remaining top near pairs | defer | `DiffEditor.scss`、`bitfun-dark.theme.ts`、`LanguageRegistry.ts`、`StreamText.scss`、`prismTheme.ts`、Flow Chat capture fallback 等 | Diff added/deleted、Monaco/editor、syntax、language identity、visual effect 和 capture fallback 属于相邻状态或跨域身份色;没有截图/相邻关系证据前不强行合并 | Phase 6 首轮约束: | 约束 | 当前值 | baseline | 作用 | | --- | ---: | ---: | --- | | `nearPairs.indistinguishableTotal` | 0 | 0 | 阻止新增普通组件肉眼不可区分 pair 未被合并或记录 | -| `nearPairs.nearTotal` | 35 | 35 | 阻止新增普通组件 near color 债务,减少时要求同步降低 baseline | -| `colorScopes.appUi.uniqueColors` | 233 | 233 | 阻止普通组件 raw color 唯一色回涨 | -| `colorScopes.appUi.occurrences` | 273 | 273 | 阻止普通组件 raw color 出现次数回涨 | +| `nearPairs.nearTotal` | 16 | 16 | 阻止新增普通组件 near color 债务,减少时要求同步降低 baseline | +| `colorScopes.appUi.uniqueColors` | 204 | 204 | 阻止普通组件 raw color 唯一色回涨 | +| `colorScopes.appUi.occurrences` | 234 | 234 | 阻止普通组件 raw color 出现次数回涨 | | CSS var governance errors | 0 | 0 | 保持 unresolved、fallback-only、non-contract 和 dynamic family 错误为零 | `nearPairs.*` 只基于非 token、非 exception 的普通组件颜色计算。Theme preset、 diff --git a/scripts/theme-color-governance-baseline.json b/scripts/theme-color-governance-baseline.json index 0af60ea614..88195da63e 100644 --- a/scripts/theme-color-governance-baseline.json +++ b/scripts/theme-color-governance-baseline.json @@ -3,16 +3,16 @@ "description": "Baseline for Web UI theme color governance. Lower values when debt is removed; do not raise without a documented review reason.", "budgets": { "fallbackOccurrences": { - "max": 31 + "max": 25 }, "fallbackUniqueTokens": { - "max": 10 + "max": 7 }, "colorScopes.appUi.uniqueColors": { - "max": 233 + "max": 204 }, "colorScopes.appUi.occurrences": { - "max": 273 + "max": 234 }, "colorScopes.token.uniqueColors": { "max": 697 @@ -45,16 +45,16 @@ "max": 0 }, "tokenAliasLiterals.occurrences": { - "max": 13 + "max": 12 }, "tokenAliasLiterals.uniqueColors": { - "max": 11 + "max": 10 }, "nearPairs.indistinguishableTotal": { "max": 0 }, "nearPairs.nearTotal": { - "max": 35 + "max": 16 }, "colorDomainScopes.themePreset.occurrences": { "max": 1033 @@ -81,7 +81,7 @@ "max": 21 }, "colorDomainScopes.editor.occurrences": { - "max": 151 + "max": 136 }, "colorDomainScopes.syntax.occurrences": { "max": 18 @@ -108,10 +108,10 @@ "max": 22 }, "colorDomainScopes.appUi.occurrences": { - "max": 108 + "max": 84 }, "colorDomainScopes.appUi.uniqueColors": { - "max": 94 + "max": 75 }, "colorDomainScopes.mermaid.occurrences": { "max": 139 @@ -137,16 +137,6 @@ "owner": "src/web-ui/src/component-library/components/StreamText", "reason": "runtime per-character animation offset with zero fallback outside animated rendering" }, - { - "key": "--shadow-color", - "owner": "agent surface cards and Markdown Mermaid block", - "reason": "surface-local shadow tint override with governed default shadow fallbacks" - }, - { - "key": "--assistant-card-gradient", - "owner": "src/web-ui/src/app/scenes/profile/views/NurseryView.scss", - "reason": "runtime assistant identity gradient with static visual fallback for unloaded card metadata" - }, { "key": "--gallery-grid-min", "owner": "src/web-ui/src/app/components/GalleryLayout", @@ -157,11 +147,6 @@ "owner": "src/web-ui/src/app/components/GalleryLayout", "reason": "runtime skeleton sizing input with stable placeholder fallback" }, - { - "key": "--operation-color", - "owner": "src/web-ui/src/component-library/components/FlowChatCards/SnapshotCard", - "reason": "runtime snapshot operation identity color with accent fallback" - }, { "key": "--primary-color", "owner": "src/web-ui/src/component-library/components/Markdown", diff --git a/src/web-ui/src/app/scenes/agents/components/AgentCard.scss b/src/web-ui/src/app/scenes/agents/components/AgentCard.scss index 03574d5bd4..8eed81218c 100644 --- a/src/web-ui/src/app/scenes/agents/components/AgentCard.scss +++ b/src/web-ui/src/app/scenes/agents/components/AgentCard.scss @@ -506,8 +506,8 @@ color: var(--color-accent-500); &:hover { - border-color: rgba(96, 165, 250, 0.6); - background: rgba(96, 165, 250, 0.12); + border-color: color-mix(in srgb, var(--color-accent-500) 60%, transparent); + background: color-mix(in srgb, var(--color-accent-500) 12%, transparent); } } } diff --git a/src/web-ui/src/app/scenes/agents/components/ReviewTeamPage.scss b/src/web-ui/src/app/scenes/agents/components/ReviewTeamPage.scss index 36274f03ee..48dd14168e 100644 --- a/src/web-ui/src/app/scenes/agents/components/ReviewTeamPage.scss +++ b/src/web-ui/src/app/scenes/agents/components/ReviewTeamPage.scss @@ -5,7 +5,7 @@ --config-page-content-inline-padding: clamp(40px, 6vw, 80px); /* Aligns overview + member rows with `AgentTeamCard` / gallery team cards */ --review-team-accent: var(--color-accent-400); - --review-team-shadow-color: #0f172a; + --review-team-shadow-color: rgb(var(--color-overlay-slate-rgb)); --member-accent: var(--review-team-member-accent-default); .bitfun-config-page-content__inner { @@ -290,7 +290,7 @@ &:hover:not(:disabled) { transform: translateY(-1px); border-color: color-mix(in srgb, var(--color-accent-500) 36%, var(--border-medium)); - box-shadow: 0 10px 22px color-mix(in srgb, var(--shadow-color, var(--review-team-shadow-color)) 10%, transparent); + box-shadow: 0 10px 22px color-mix(in srgb, var(--review-team-shadow-color) 10%, transparent); } &.is-selected { diff --git a/src/web-ui/src/app/scenes/agents/components/_AgentSurfaceCard.scss b/src/web-ui/src/app/scenes/agents/components/_AgentSurfaceCard.scss index e51cf2d0dd..967bb3de28 100644 --- a/src/web-ui/src/app/scenes/agents/components/_AgentSurfaceCard.scss +++ b/src/web-ui/src/app/scenes/agents/components/_AgentSurfaceCard.scss @@ -1,7 +1,7 @@ @use '../../../../component-library/styles/tokens' as *; @mixin agent-surface-card($gradient, $accent) { - --agent-surface-shadow-color: #0f172a; + --agent-surface-shadow-color: rgb(var(--color-overlay-slate-rgb)); width: 360px; height: 200px; @@ -31,7 +31,7 @@ &:hover { transform: translateY(-4px) scale(1.02); - box-shadow: 0 16px 40px color-mix(in srgb, var(--shadow-color, var(--agent-surface-shadow-color)) 20%, transparent); + box-shadow: 0 16px 40px color-mix(in srgb, var(--agent-surface-shadow-color) 20%, transparent); &::before { opacity: 0.42; diff --git a/src/web-ui/src/app/scenes/profile/views/NurseryView.scss b/src/web-ui/src/app/scenes/profile/views/NurseryView.scss index 5a67671705..f5d27b31d9 100644 --- a/src/web-ui/src/app/scenes/profile/views/NurseryView.scss +++ b/src/web-ui/src/app/scenes/profile/views/NurseryView.scss @@ -244,14 +244,14 @@ $nursery-scene-gutter: clamp(40px, 6vw, 80px); transition: transform 0.55s $easing-standard, color 0.4s ease; &--1 { - color: rgba(52, 211, 153, 0.13); + color: color-mix(in srgb, var(--color-success) 13%, transparent); top: -14px; right: -14px; transform: rotate(18deg); } &--2 { - color: rgba(96, 165, 250, 0.09); + color: color-mix(in srgb, var(--color-accent-500) 9%, transparent); bottom: 4px; right: 22px; transform: rotate(-12deg); @@ -260,18 +260,25 @@ $nursery-scene-gutter: clamp(40px, 6vw, 80px); &:hover &__deco-egg--1 { transform: rotate(26deg) scale(1.1); - color: rgba(52, 211, 153, 0.24); + color: color-mix(in srgb, var(--color-success) 24%, transparent); } &:hover &__deco-egg--2 { transform: rotate(-22deg) translateY(-5px) scale(1.1); - color: rgba(96, 165, 250, 0.18); + color: color-mix(in srgb, var(--color-accent-500) 18%, transparent); } } // ── Assistant card (mirrors AgentCard style) ─────────────────────────────── .assistant-card { + --assistant-card-default-gradient: linear-gradient( + 135deg, + color-mix(in srgb, var(--color-accent-500) 20%, transparent) 0%, + var(--card-bg-purple-hover) 100% + ); + --assistant-card-gradient: var(--assistant-card-default-gradient); + width: 360px; height: 200px; border-radius: 15px; @@ -298,7 +305,7 @@ $nursery-scene-gutter: clamp(40px, 6vw, 80px); left: 0; right: 0; bottom: 40px; - background: var(--assistant-card-gradient, linear-gradient(135deg, rgba(96, 165, 250, 0.2) 0%, var(--card-bg-purple-hover) 100%)); + background: var(--assistant-card-gradient); opacity: 0; transition: opacity 0.35s ease; pointer-events: none; @@ -432,7 +439,7 @@ $nursery-scene-gutter: clamp(40px, 6vw, 80px); content: ''; position: absolute; inset: 0; - background: var(--assistant-card-gradient, linear-gradient(135deg, rgba(96, 165, 250, 0.2) 0%, var(--card-bg-purple-hover) 100%)); + background: var(--assistant-card-gradient); opacity: 0.4; transition: opacity 0.35s ease; pointer-events: none; diff --git a/src/web-ui/src/app/styles/utilities/animations.css b/src/web-ui/src/app/styles/utilities/animations.css index 749d75a3ac..ccc8f07f17 100644 --- a/src/web-ui/src/app/styles/utilities/animations.css +++ b/src/web-ui/src/app/styles/utilities/animations.css @@ -305,7 +305,7 @@ background: linear-gradient(135deg, var(--color-overlay-white-02) 0%, transparent 50%, - rgba(255, 255, 255, 0.01) 100%); + color-mix(in srgb, var(--color-static-white) 1%, transparent) 100%); pointer-events: none; z-index: var(--z-decoration); border-radius: inherit; diff --git a/src/web-ui/src/component-library/components/FlowChatCards/ContextCompressionCard/ContextCompressionCard.scss b/src/web-ui/src/component-library/components/FlowChatCards/ContextCompressionCard/ContextCompressionCard.scss index 9f3d0f82ee..819d773c4d 100644 --- a/src/web-ui/src/component-library/components/FlowChatCards/ContextCompressionCard/ContextCompressionCard.scss +++ b/src/web-ui/src/component-library/components/FlowChatCards/ContextCompressionCard/ContextCompressionCard.scss @@ -10,7 +10,11 @@ width: 100%; max-width: 100%; - background: linear-gradient(135deg, rgba(20, 20, 20, 0.95), rgba(15, 15, 15, 0.98)); + background: linear-gradient( + 135deg, + color-mix(in srgb, var(--color-bg-secondary) 95%, transparent), + color-mix(in srgb, var(--color-bg-primary) 98%, transparent) + ); border: 1px solid color-mix(in srgb, var(--context-compression-accent) 60%, transparent); border-radius: 50px; margin: 6px 0; @@ -49,7 +53,11 @@ box-shadow: 0 4px 16px color-mix(in srgb, var(--context-compression-accent) 30%, transparent), 0 2px 8px color-mix(in srgb, var(--context-compression-accent) 20%, transparent), inset 0 1px 0 var(--color-overlay-white-10); - background: linear-gradient(135deg, rgba(25, 25, 25, 0.98), #141414); + background: linear-gradient( + 135deg, + color-mix(in srgb, var(--color-bg-secondary) 98%, transparent), + var(--color-bg-primary) + ); } } diff --git a/src/web-ui/src/component-library/components/FlowChatCards/SnapshotCard/SnapshotCard.scss b/src/web-ui/src/component-library/components/FlowChatCards/SnapshotCard/SnapshotCard.scss index 5c73c58d58..686b373f54 100644 --- a/src/web-ui/src/component-library/components/FlowChatCards/SnapshotCard/SnapshotCard.scss +++ b/src/web-ui/src/component-library/components/FlowChatCards/SnapshotCard/SnapshotCard.scss @@ -6,6 +6,8 @@ .snapshot-card { + --operation-color: #{tokens.$color-accent-500}; + @include shared.liquid-card-base; font-family: tokens.$font-family-mono; transition: all tokens.$motion-base tokens.$easing-standard; @@ -81,7 +83,7 @@ .snapshot-card__icon { flex-shrink: 0; - color: var(--operation-color, tokens.$color-accent-500); + color: var(--operation-color); transition: all tokens.$motion-base; } diff --git a/src/web-ui/src/component-library/components/Markdown/MermaidBlock.scss b/src/web-ui/src/component-library/components/Markdown/MermaidBlock.scss index 932dbc0785..31ffbe10e2 100644 --- a/src/web-ui/src/component-library/components/Markdown/MermaidBlock.scss +++ b/src/web-ui/src/component-library/components/Markdown/MermaidBlock.scss @@ -3,6 +3,8 @@ * Styles for rendering Mermaid diagrams during streaming output */ .mermaid-block { + --mermaid-block-shadow-color: var(--color-overlay-black-40); + margin: var(--flowchat-markdown-block-gap) 0; border-radius: 6px; overflow: hidden; @@ -12,7 +14,7 @@ &:hover { box-shadow: - 0 8px 24px var(--shadow-color, var(--color-overlay-black-40)), + 0 8px 24px var(--mermaid-block-shadow-color), inset 0 1px 0 var(--element-bg-medium), inset 0 -1px 0 var(--element-bg-subtle); border-color: var(--element-bg-strong); diff --git a/src/web-ui/src/flow_chat/components/modern/ModernFlowChatContainer.scss b/src/web-ui/src/flow_chat/components/modern/ModernFlowChatContainer.scss index 8fb4c68a95..c4ddf81704 100644 --- a/src/web-ui/src/flow_chat/components/modern/ModernFlowChatContainer.scss +++ b/src/web-ui/src/flow_chat/components/modern/ModernFlowChatContainer.scss @@ -9,7 +9,7 @@ } .modern-flowchat-container { - --modern-flowchat-input-bg: #1e1e1e; + --modern-flowchat-input-bg: var(--color-bg-secondary); width: 100%; height: 100%; diff --git a/src/web-ui/src/infrastructure/config/components/AIModelConfig.scss b/src/web-ui/src/infrastructure/config/components/AIModelConfig.scss index 17a491211c..0b3f60e57d 100644 --- a/src/web-ui/src/infrastructure/config/components/AIModelConfig.scss +++ b/src/web-ui/src/infrastructure/config/components/AIModelConfig.scss @@ -188,7 +188,7 @@ padding: $size-gap-3; border: 1px dashed var(--border-subtle); border-radius: $size-radius-sm; - background: rgba(255, 255, 255, 0.01); + background: color-mix(in srgb, var(--color-static-white) 1%, transparent); } &__details-section-title { @@ -506,7 +506,7 @@ &__item { &.is-default { - background: rgba(96, 165, 250, 0.06); + background: color-mix(in srgb, var(--color-accent-500) 6%, transparent); &:hover { background: var(--card-bg-accent); diff --git a/src/web-ui/src/shared/context-menu-system/components/ui/ContextMenu.scss b/src/web-ui/src/shared/context-menu-system/components/ui/ContextMenu.scss index 5da592f4ea..6b2946c7d7 100644 --- a/src/web-ui/src/shared/context-menu-system/components/ui/ContextMenu.scss +++ b/src/web-ui/src/shared/context-menu-system/components/ui/ContextMenu.scss @@ -33,8 +33,8 @@ :root[data-theme-type='light'] & { box-shadow: - 0 1px 2px rgba(15, 23, 42, 0.05), - 0 10px 28px -8px rgba(15, 23, 42, 0.12); + 0 1px 2px var(--color-overlay-slate-06), + 0 10px 28px -8px var(--color-overlay-slate-12); } :root[data-theme-type='dark'] & { diff --git a/src/web-ui/src/tools/editor/components/ImageViewer.scss b/src/web-ui/src/tools/editor/components/ImageViewer.scss index 304b23a940..c54f8cf7a2 100644 --- a/src/web-ui/src/tools/editor/components/ImageViewer.scss +++ b/src/web-ui/src/tools/editor/components/ImageViewer.scss @@ -159,7 +159,7 @@ align-items: center; justify-content: center; gap: 16px; - color: #888888; + color: var(--color-text-muted); p { margin: 0; @@ -170,8 +170,8 @@ &__spinner { width: 40px; height: 40px; - border: 3px solid #2a2a2a; - border-top-color: #007acc; + border: 3px solid var(--border-medium); + border-top-color: var(--color-accent-500); border-radius: 50%; animation: spin 0.8s linear infinite; } @@ -194,14 +194,14 @@ p { margin: 0; - color: #f48771; + color: var(--color-error); font-size: 14px; } } &__error-path { font-size: 12px; - color: #666666; + color: var(--color-text-muted); word-break: break-all; max-width: 600px; } diff --git a/src/web-ui/src/tools/editor/meditor/components/TiptapEditor.scss b/src/web-ui/src/tools/editor/meditor/components/TiptapEditor.scss index 0e77ec1108..3b7056c7b0 100644 --- a/src/web-ui/src/tools/editor/meditor/components/TiptapEditor.scss +++ b/src/web-ui/src/tools/editor/meditor/components/TiptapEditor.scss @@ -470,7 +470,7 @@ backdrop-filter: blur(16px) saturate(1.2); -webkit-backdrop-filter: blur(16px) saturate(1.2); box-shadow: - 0 8px 24px rgba(0, 0, 0, 0.35), + 0 8px 24px color-mix(in srgb, var(--color-static-black) 35%, transparent), inset 0 1px 0 var(--color-overlay-white-08), inset 0 -1px 0 var(--color-overlay-white-02); transition: @@ -481,7 +481,7 @@ .m-editor-inline-ai:hover .m-editor-inline-ai__panel { transform: translateY(-4px); box-shadow: - 0 16px 40px rgba(0, 0, 0, 0.45), + 0 16px 40px color-mix(in srgb, var(--color-static-black) 45%, transparent), 0 0 28px var(--color-accent-100), inset 0 1px 0 var(--color-overlay-white-12), inset 0 -1px 0 var(--color-overlay-white-03); @@ -491,17 +491,17 @@ :root[data-theme-type='light'] &, .light & { .m-editor-inline-ai__panel { - border-color: rgba(15, 23, 42, 0.12); + border-color: var(--color-overlay-slate-12); box-shadow: - 0 8px 24px rgba(15, 23, 42, 0.08), - inset 0 1px 0 rgba(255, 255, 255, 0.85); + 0 8px 24px var(--color-overlay-slate-08), + inset 0 1px 0 color-mix(in srgb, var(--color-static-white) 85%, transparent); } .m-editor-inline-ai:hover .m-editor-inline-ai__panel { box-shadow: - 0 14px 36px rgba(15, 23, 42, 0.12), + 0 14px 36px var(--color-overlay-slate-12), 0 0 24px var(--glass-blue-subtle), - inset 0 1px 0 rgba(255, 255, 255, 0.95); + inset 0 1px 0 var(--color-overlay-white-95); } } @@ -528,8 +528,8 @@ :root[data-theme-type='light'] &, .light & { .m-editor-inline-ai__composer-input .bitfun-input-container { - background: rgba(15, 23, 42, 0.04); - border-color: rgba(15, 23, 42, 0.1); + background: var(--color-overlay-slate-04); + border-color: var(--color-overlay-slate-10); } } @@ -654,7 +654,7 @@ :root[data-theme-type='light'] &, .light & { .m-editor-inline-ai__quick-action:hover { - background: rgba(15, 23, 42, 0.08); + background: var(--color-overlay-slate-08); } } diff --git a/src/web-ui/src/tools/file-system/components/FileTreeItem.tsx b/src/web-ui/src/tools/file-system/components/FileTreeItem.tsx index 985b2153c2..97e4b7c664 100644 --- a/src/web-ui/src/tools/file-system/components/FileTreeItem.tsx +++ b/src/web-ui/src/tools/file-system/components/FileTreeItem.tsx @@ -158,8 +158,8 @@ export const FileTreeItem: React.FC = ({ dragImage.style.position = 'absolute'; dragImage.style.top = '-1000px'; dragImage.style.padding = '8px'; - dragImage.style.background = 'rgba(0, 0, 0, 0.8)'; - dragImage.style.color = 'white'; + dragImage.style.background = 'var(--color-overlay-black-80)'; + dragImage.style.color = 'var(--color-static-white)'; dragImage.style.borderRadius = '4px'; document.body.appendChild(dragImage); dragImageRef.current = dragImage; diff --git a/src/web-ui/src/tools/git/components/GitDiffEditor/GitDiffEditor.scss b/src/web-ui/src/tools/git/components/GitDiffEditor/GitDiffEditor.scss index ee222dc260..3ed02ba86d 100644 --- a/src/web-ui/src/tools/git/components/GitDiffEditor/GitDiffEditor.scss +++ b/src/web-ui/src/tools/git/components/GitDiffEditor/GitDiffEditor.scss @@ -53,7 +53,7 @@ $_diff-padding-desktop: 32px; background: linear-gradient( 180deg, - rgba(255, 255, 255, 0.01) 0%, + color-mix(in srgb, var(--color-static-white) 1%, transparent) 0%, transparent 100% ); @@ -204,8 +204,8 @@ $_diff-padding-desktop: 32px; 45deg, transparent, transparent 3px, - rgba(255, 255, 255, 0.015) 3px, - rgba(255, 255, 255, 0.015) 6px + color-mix(in srgb, var(--color-static-white) 1.5%, transparent) 3px, + color-mix(in srgb, var(--color-static-white) 1.5%, transparent) 6px ) !important; } } From c851a5e624ccc97b6aecbd6c7aed0de82531a45b Mon Sep 17 00:00:00 2001 From: limityan Date: Thu, 18 Jun 2026 10:29:43 +0800 Subject: [PATCH 2/2] refactor(web-ui): consolidate near color tokens Tokenize DiffEditor diff color layers and merge safe near-identical visual colors. Update theme color governance baseline after reducing near pairs from 16 to 5. --- docs/architecture/theme-token-optimization.md | 99 +++++++------ scripts/theme-color-governance-baseline.json | 30 ++-- scripts/theme-css-var-contract.mjs | 6 +- .../AgentCompanionDesktopPet.scss | 30 ++-- .../RemoteConnectDialog.scss | 2 +- .../src/app/scenes/agents/agentTheme.ts | 8 +- .../src/app/scenes/my-agent/InsightsScene.tsx | 9 +- .../app/scenes/profile/views/NurseryView.scss | 8 +- .../profile/views/TemplateConfigPage.tsx | 3 +- src/web-ui/src/app/styles/global.scss | 6 +- .../components/Avatar/Avatar.scss | 9 +- .../components/CodeEditor/CodeEditor.scss | 136 +++++++++--------- .../ContextCompressionCard.scss | 15 +- .../components/StreamText/StreamText.scss | 62 +++++--- .../TextStrokeEffect/TextStrokeEffect.scss | 2 +- .../components/ChatInputPixelPet.scss | 15 +- .../components/ChatInputPixelPet.tsx | 2 +- .../flow_chat/components/FlowTextBlock.scss | 2 +- .../components/SnapshotRollbackButton.scss | 9 +- .../components/modern/ExportImageButton.tsx | 3 +- .../flow_chat/state-machine/derivedState.ts | 3 +- .../flow_chat/tool-cards/BaseToolCard.scss | 4 +- .../tool-cards/ContextCompressionDisplay.scss | 6 +- .../flow_chat/tool-cards/DefaultToolCard.scss | 4 +- .../tool-cards/GenerativeWidgetToolCard.scss | 10 +- .../tool-cards/ModelThinkingDisplay.scss | 4 +- .../flow_chat/tool-cards/TaskToolDisplay.scss | 4 +- .../tool-cards/ToolCommandPreview.scss | 4 +- .../utils/captureElementToDownloadsPng.tsx | 3 +- .../config/components/ConfigForm.scss | 14 +- .../config/components/DefaultModelConfig.scss | 4 +- .../core/LanguageRegistry.ts | 97 ++++++------- .../styles/AnnouncementToast.scss | 2 +- .../components/ContextCard/ContextCard.scss | 4 +- src/web-ui/src/shared/prism/prismTheme.ts | 30 +--- .../shared/services/review-team/defaults.ts | 15 +- .../shared/theme/languageIdentityAccents.ts | 59 +++++++- .../shared/theme/syntaxHighlightAccents.ts | 26 ++++ .../shared/theme/themeBoundaryFallbacks.ts | 4 + .../src/shared/theme/uiExceptionAccents.ts | 27 ++++ .../tools/editor/components/DiffEditor.scss | 66 +++++---- .../editor/components/EditorBreadcrumb.scss | 6 +- .../ReadOnlyCodeBlock/ReadOnlyCodeBlock.scss | 3 +- .../StatusBarPopovers/StatusBarPopovers.scss | 24 ++-- .../meditor/components/TiptapEditor.scss | 7 +- .../ReferencesPanel/ReferencesPanel.scss | 20 +-- .../workspace/components/WorkspaceManager.css | 2 +- 47 files changed, 560 insertions(+), 348 deletions(-) create mode 100644 src/web-ui/src/shared/theme/syntaxHighlightAccents.ts diff --git a/docs/architecture/theme-token-optimization.md b/docs/architecture/theme-token-optimization.md index 5508bfac9e..a400da6bec 100644 --- a/docs/architecture/theme-token-optimization.md +++ b/docs/architecture/theme-token-optimization.md @@ -1,6 +1,6 @@ # 主题与颜色 Token 优化方案 -> 当前基线:`gcwing/main` 的 `617086b8`,扫描日期为 2026-06-18。 +> 当前基线:`gcwing/main` 的 `d8f2d2e2`,扫描日期为 2026-06-18。 本文档用于梳理 BitFun 前端主题、硬编码颜色、重复 token、近似色冗余、 命名漂移和后续治理方案。目标不是把所有看起来相近的颜色都合并,而是让 @@ -53,28 +53,33 @@ ## 当前现状 -基于最新 `gcwing/main` 的扫描结果,前几轮迁移已经把测试文件噪声、明显的 -跨文件未定义 key、debug overlay 游离色值和部分 widget/editor fallback 收敛掉。 -当前剩余问题更集中在 app UI 字面量、少量边界 fallback、identity/exception 色值 -归属,以及近似色是否能安全合并的证据不足。 +基于最新 `gcwing/main` 的扫描结果,当前 PR 已把普通 app/component 层的 raw color +literal、token-equivalent app literal 和普通组件 near color pair 收敛到 0。剩余色值 +全部落在明确 owner 的专用域:theme preset/runtime、token contract、boundary fallback、 +Mermaid、Monaco/editor、Prism syntax、terminal ANSI、language identity 和 UI exception +registry。 + +`colorScopes.exception`、`colorDomainScopes.uiException` 和 `colorDomainScopes.boundaryFallback` +的数值上升不是新增游离色,而是把原先散在 service/component 文件中的身份色、review team +角色色、Prism palette、截图兜底色和 Monaco theme palette 归入显式 owner 后的结果。 | 指标 | 当前基线 | | --- | ---: | -| 扫描的生产前端文件数 | 1524 | -| 忽略的测试文件数 | 212 | -| 包含颜色字面量的文件数 | 65 | -| 颜色字面量出现次数 | 1891 | -| 唯一颜色字面量数量 | 1025 | -| 组件或非 token 文件中的颜色出现次数 | 234 | -| 组件或非 token 唯一颜色数量 | 204 | -| App UI 颜色出现次数 | 84 | -| App UI 唯一颜色数量 | 75 | +| 扫描的生产前端文件数 | 1526 | +| 忽略的测试文件数 | 213 | +| 包含颜色字面量的文件数 | 26 | +| 颜色字面量出现次数 | 1718 | +| 唯一颜色字面量数量 | 913 | +| 组件或非 token 文件中的颜色出现次数 | 0 | +| 组件或非 token 唯一颜色数量 | 0 | +| App UI 颜色出现次数 | 0 | +| App UI 唯一颜色数量 | 0 | | `var(--token, fallback)` 出现次数 | 25 | | fallback 唯一 token 数 | 7 | -| token-equivalent app literal 出现次数 | 12 | -| token-equivalent app literal 唯一颜色数量 | 10 | +| token-equivalent app literal 出现次数 | 0 | +| token-equivalent app literal 唯一颜色数量 | 0 | | 普通组件肉眼不可区分 near color pair | 0 | -| 普通组件需证据复核的 near color pair | 16 | +| 普通组件需证据复核的 near color pair | 0 | 当前审计未发现 CSS 变量契约层面的硬错误: @@ -88,34 +93,34 @@ | non-contract dynamic inputs | 0 | | non-contract component-private vars | 0 | -剩余债务集中在几个专用域和少量 app UI 文件: +剩余颜色集中在几个专用域;普通 app UI 不再保留 raw color literal: | 区域 | 当前出现次数 | 当前唯一色数 | 说明 | | --- | ---: | ---: | --- | | Theme presets | 1033 | 611 | 主题个性与 palette 映射,不作为普通 app literal 直接合并 | | Token contracts | 268 | 159 | `tokens.scss` 等静态契约根 | -| Editor | 136 | 110 | Monaco/editor 专用域,不能直接泛化到 app token | +| Editor | 56 | 53 | Monaco/editor 专用域,不能直接泛化到 app token;组件装饰色已迁出 raw literal | | Mermaid | 139 | 95 | Mermaid 专用渲染域 | | Theme runtime | 54 | 45 | `ThemeService.ts` 运行时注入 | -| Language identity | 57 | 50 | 语言身份色,应保留数据语义或迁入 identity registry | +| Language identity | 52 | 50 | 语言身份色,已集中到 identity registry | | Terminal | 38 | 30 | terminal/ANSI 专用域 | -| Boundary fallback | 21 | 21 | iframe/miniapp 早期渲染兜底值,不作为普通 app token | -| Visual effects | 22 | 22 | 动效和装饰效果,需按效果语义审查 | -| UI exception registry | 21 | 19 | 已归档的 UI 例外色 | +| Boundary fallback | 22 | 22 | iframe/miniapp/截图兜底值,不作为普通 app token | +| Visual effects | 0 | 0 | StreamText/TextStroke raw literal 已迁出普通组件层 | +| UI exception registry | 38 | 34 | 已归档的 UI 例外色,包含 review team、agent capability、template context、insights 和 inspector 等固定身份色 | | Generated widget | 0 | 0 | 颜色默认值已迁到 boundary fallback registry | -| App UI | 84 | 75 | 后续普通组件迁移的主战场 | +| App UI | 0 | 0 | 普通 app/component raw color 已清零;后续新增必须先进入 token/exception 决策 | +| Syntax | 18 | 17 | Prism syntax palette,保留为专用渲染域 | -剩余高频普通组件或边界文件: +剩余高频文件均为专用 palette 或集中 registry: | 文件 | 颜色出现次数 | 后续处理策略 | | --- | ---: | --- | -| `src/web-ui/src/component-library/components/CodeEditor/CodeEditor.scss` | 65 | editor surface 专用域,先保持 exception namespace | -| `src/web-ui/src/shared/theme/themeBoundaryFallbacks.ts` | 21 | isolated surface 边界默认值,保留集中 owner | -| `src/web-ui/src/component-library/components/StreamText/StreamText.scss` | 21 | visual effect,应迁入视觉效果 token/例外域 | -| `src/web-ui/src/shared/theme/uiExceptionAccents.ts` | 21 | 已归档 UI 例外,继续要求显式 owner/role | -| `src/web-ui/src/shared/prism/prismTheme.ts` | 18 | syntax theme,不泛化到 app token | -| `src/web-ui/src/tools/editor/components/DiffEditor.scss` | 18 | diff/editor 专用域,按 git/diff token 处理 | -| `src/web-ui/src/app/scenes/profile/views/NurseryView.scss` | 0 | app scene surface 中的 assistant 默认 gradient 和 deco alpha 已迁到 token/color-mix | +| `src/web-ui/src/tools/editor/themes/bitfun-dark.theme.ts` | 47 | Monaco theme palette;不拆散到普通 app token | +| `src/web-ui/src/shared/theme/languageIdentityAccents.ts` | 52 | 内置 language/file identity registry;调用方复用常量 | +| `src/web-ui/src/shared/theme/uiExceptionAccents.ts` | 38 | 固定 UI 身份/角色色 registry;新增必须说明 owner/role | +| `src/web-ui/src/tools/terminal/utils/xtermTheme.ts` | 36 | terminal ANSI palette;不与 app semantic color 合并 | +| `src/web-ui/src/shared/theme/themeBoundaryFallbacks.ts` | 22 | isolated surface 和截图兜底值;集中 owner | +| `src/web-ui/src/shared/theme/syntaxHighlightAccents.ts` | 18 | Prism syntax palette;不泛化到 app token | 当前 fallback token 都已进入 allowlist,但仍需要逐项决策是否保留边界 fallback: @@ -147,29 +152,39 @@ fallback 决策表: | --- | --- | --- | | Phase 0:基线与工具 | 已完成主体 | 审计脚本可区分测试文件、fallback token、dynamic families 和 exception domains | | Phase 1:canonical token 契约 | 已完成主体,继续补文档 | 静态/runtime/widget 契约已有治理入口,仍需保持文档基线同步 | -| Phase 2:精确重复合并 | 持续完成 | 本轮继续移除 token-equivalent app literal,并把 ImageViewer 状态色迁到文本、边框、强调、错误 token | -| Phase 3:legacy fallback 迁移 | 持续完成 | `--shadow-color`、`--assistant-card-gradient`、`--operation-color` 已落到组件根默认值,fallback unique token 从 10 降到 7 | -| Phase 4:组件 token 抽取 | 持续完成 | agent surface、Mermaid、Snapshot、Nursery、ContextCompression、ImageViewer、Tiptap inline AI 等 surface 已补根默认值或改用 contract token | -| Phase 5:近似色合并 | 持续完成 | app UI / editor 中安全的极近似 alpha 已改为 token/color-mix;DiffEditor、Monaco、language identity、StreamText 等相邻或跨域身份色保持延后 | -| Phase 6:防回退约束 | 持续完成 | baseline 已同步降到当前审计值,防止 app raw color、fallback、token-equivalent literal 和普通组件 near-pair 回涨 | +| Phase 2:精确重复合并 | 本轮完成 | token-equivalent app literal 已从 12/10 清零;截图兜底、language identity 和 review/agent/insights 固定色已迁入显式 registry | +| Phase 3:legacy fallback 迁移 | 本轮完成 | fallback unique token 保持 7,普通组件内不再保留 raw fallback palette;边界 fallback 只保留在 allowlist 或 registry | +| Phase 4:组件 token 抽取 | 本轮完成 | CodeEditor、StreamText、ChatInputPixelPet、ReferencesPanel、AgentCompanion、tool-card、editor 组件装饰色已抽为组件私有 RGB channel 或复用 contract token | +| Phase 5:近似色合并 | 本轮完成 | 普通组件 near pair 已清零;极近似视觉色只在不相邻或不承担状态差异时合并,Monaco/terminal/Mermaid/syntax 专用 palette 不强行合并 | +| Phase 6:防回退约束 | 本轮完成 | baseline 已同步到 component/non-token=0、appUi=0、token-equivalent=0、nearPair=0,防止普通 app raw color 回涨 | -Phase 5 首轮决策: +Phase 5 决策记录: | pair | 决策 | 调用点 | 依据 | | --- | --- | --- | --- | | `#1f2024` -> `#202024` | merge | `ChatInputPixelPet.scss` panda body/decor;`bitfun-dark.theme.ts` editor subtle border | RGB distance = 1,非状态色,非相邻 surface 边界;panda 固定深色与 editor border 不在同一视觉层级承担区分 | | `#6e7681` -> `#6e7781` | merge | `LanguageRegistry.ts` Plain Text identity;`prismTheme.ts` light comment | RGB distance = 1,均为 neutral muted 文本/identity 色,不表达状态严重程度或数据差异 | | app UI / editor alpha raw values | merge to token/color-mix | `ContextMenu.scss`、`TiptapEditor.scss`、`GitDiffEditor.scss`、`AIModelConfig.scss`、`NurseryView.scss`、`AgentCard.scss`、`ImageViewer.scss` | 色相来自现有 accent/success/overlay/text/error contract,透明度仅表达层级;迁移为 token/color-mix 保留层级但移除游离 raw color | -| remaining top near pairs | defer | `DiffEditor.scss`、`bitfun-dark.theme.ts`、`LanguageRegistry.ts`、`StreamText.scss`、`prismTheme.ts`、Flow Chat capture fallback 等 | Diff added/deleted、Monaco/editor、syntax、language identity、visual effect 和 capture fallback 属于相邻状态或跨域身份色;没有截图/相邻关系证据前不强行合并 | +| DiffEditor added/deleted alpha values | component-tokenize | `DiffEditor.scss` | `0.15/0.18/0.20/0.38` 表达统计徽标、行背景、强调行和字符级 diff 的层级差异,不能直接合并;改为 `--diff-editor-*` 组件 token 后保留层级并移除游离 raw rgba | +| `#ff8800` -> `#ff8c00` | merge | `StreamText.scss` rainbow/fire orange | RGB distance = 4,均为 visual-effect 暖橙,非相邻状态色,合并后不影响用户区分 | +| `#ffdd00` -> `#ffd700` | merge | `StreamText.scss` fire yellow;editor/reference yellow | RGB distance = 6,均为亮黄强调色,调用点不相邻,不承担不同业务状态 | +| `#7dd3fc` -> `#7DCFFF` | merge | `GenerativeWidgetToolCard.scss`;`bitfun-dark.theme.ts` editor link | RGB distance = 5,均为非状态 sky/cyan 强调,调用点跨 surface 且不相邻 | +| `#00b4d8` -> `#00add8` | merge | `StreamText.scss` ocean mid;Go language identity | RGB distance = 7,同为 cyan/blue identity/visual-effect 色,非错误/警告/状态强度 | +| `#141414` vs `#121214` | preserve | `LanguageRegistry.ts` reStructuredText identity;Flow Chat capture/editor fallback | RGB distance = 2.83,但 `#141414` 是已存在的 language identity,迁移到 registry 时保持原值;`#121214` 仅作为截图/边界兜底 | +| remaining near pairs | none in ordinary components | 无 | 审计口径下普通组件 near pair 已清零;后续只在专用 palette 自身重设计时处理 Monaco/terminal/Mermaid/syntax 内部近似色 | +| Monaco theme palette | classify as exception | `tools/editor/themes/bitfun-dark.theme.ts` | 该文件是 Monaco theme 完整色板,不是普通 app UI;归入 editor/exception 后不再被误计为 component raw color | +| Flow Chat capture fallback | boundary fallback | `ExportImageButton.tsx`、`captureElementToDownloadsPng.tsx` -> `themeBoundaryFallbacks.ts` | `#121214` 只在 root theme 变量不可用时兜底截图背景,集中 owner 后避免截图工具重复携带 raw fallback | Phase 6 首轮约束: | 约束 | 当前值 | baseline | 作用 | | --- | ---: | ---: | --- | | `nearPairs.indistinguishableTotal` | 0 | 0 | 阻止新增普通组件肉眼不可区分 pair 未被合并或记录 | -| `nearPairs.nearTotal` | 16 | 16 | 阻止新增普通组件 near color 债务,减少时要求同步降低 baseline | -| `colorScopes.appUi.uniqueColors` | 204 | 204 | 阻止普通组件 raw color 唯一色回涨 | -| `colorScopes.appUi.occurrences` | 234 | 234 | 阻止普通组件 raw color 出现次数回涨 | +| `nearPairs.nearTotal` | 0 | 0 | 阻止新增普通组件 near color 债务;新增必须合并、归类或记录理由 | +| `colorScopes.appUi.uniqueColors` | 0 | 0 | 阻止普通组件 raw color 唯一色回涨 | +| `colorScopes.appUi.occurrences` | 0 | 0 | 阻止普通组件 raw color 出现次数回涨 | +| `tokenAliasLiterals.occurrences` | 0 | 0 | 阻止重新出现可映射到 token 的 app literal | +| `colorDomainScopes.appUi.occurrences` | 0 | 0 | 阻止未归类 app UI 色值回涨 | | CSS var governance errors | 0 | 0 | 保持 unresolved、fallback-only、non-contract 和 dynamic family 错误为零 | `nearPairs.*` 只基于非 token、非 exception 的普通组件颜色计算。Theme preset、 diff --git a/scripts/theme-color-governance-baseline.json b/scripts/theme-color-governance-baseline.json index 88195da63e..b8732eae94 100644 --- a/scripts/theme-color-governance-baseline.json +++ b/scripts/theme-color-governance-baseline.json @@ -9,16 +9,16 @@ "max": 7 }, "colorScopes.appUi.uniqueColors": { - "max": 204 + "max": 0 }, "colorScopes.appUi.occurrences": { - "max": 234 + "max": 0 }, "colorScopes.token.uniqueColors": { "max": 697 }, "colorScopes.exception.uniqueColors": { - "max": 212 + "max": 274 }, "cssVarDefinitions.unresolvedRequiredUnique": { "max": 0 @@ -45,16 +45,16 @@ "max": 0 }, "tokenAliasLiterals.occurrences": { - "max": 12 + "max": 0 }, "tokenAliasLiterals.uniqueColors": { - "max": 10 + "max": 0 }, "nearPairs.indistinguishableTotal": { "max": 0 }, "nearPairs.nearTotal": { - "max": 16 + "max": 0 }, "colorDomainScopes.themePreset.occurrences": { "max": 1033 @@ -75,13 +75,13 @@ "max": 0 }, "colorDomainScopes.boundaryFallback.occurrences": { - "max": 21 + "max": 22 }, "colorDomainScopes.boundaryFallback.uniqueColors": { - "max": 21 + "max": 22 }, "colorDomainScopes.editor.occurrences": { - "max": 136 + "max": 56 }, "colorDomainScopes.syntax.occurrences": { "max": 18 @@ -93,25 +93,25 @@ "max": 0 }, "colorDomainScopes.uiException.occurrences": { - "max": 21 + "max": 38 }, "colorDomainScopes.uiException.uniqueColors": { - "max": 19 + "max": 34 }, "colorDomainScopes.languageIdentity.occurrences": { - "max": 57 + "max": 52 }, "colorDomainScopes.languageIdentity.uniqueColors": { "max": 50 }, "colorDomainScopes.visualEffect.occurrences": { - "max": 22 + "max": 0 }, "colorDomainScopes.appUi.occurrences": { - "max": 84 + "max": 0 }, "colorDomainScopes.appUi.uniqueColors": { - "max": 75 + "max": 0 }, "colorDomainScopes.mermaid.occurrences": { "max": 139 diff --git a/scripts/theme-css-var-contract.mjs b/scripts/theme-css-var-contract.mjs index 73f856abdc..82aa0450e4 100644 --- a/scripts/theme-css-var-contract.mjs +++ b/scripts/theme-css-var-contract.mjs @@ -30,12 +30,14 @@ export const RUNTIME_CONTRACT_VAR_DEFINITION_PATH_PARTS = [ export const EXCEPTION_PATH_PARTS = [ 'shared/theme/uiExceptionAccents', 'shared/theme/languageIdentityAccents', + 'shared/theme/syntaxHighlightAccents', 'shared/theme/themeBoundaryFallbacks', 'monaco', 'terminal', 'mermaid', 'syntax', 'CodeEditor', + 'tools/editor/themes', ]; export const COLOR_DOMAIN_RULES = [ @@ -72,12 +74,12 @@ export const COLOR_DOMAIN_RULES = [ { key: 'editor', label: 'Editor', - pathParts: ['tools/editor', 'component-library/components/CodeEditor'], + pathParts: ['tools/editor', 'component-library/components/CodeEditor', 'infrastructure/theme/integrations/MonacoThemeSync'], }, { key: 'syntax', label: 'Syntax', - pathParts: ['shared/prism'], + pathParts: ['shared/prism', 'shared/theme/syntaxHighlightAccents'], }, { key: 'terminal', diff --git a/src/web-ui/src/app/components/AgentCompanionDesktopPet/AgentCompanionDesktopPet.scss b/src/web-ui/src/app/components/AgentCompanionDesktopPet/AgentCompanionDesktopPet.scss index 49959cbc88..3226c41aca 100644 --- a/src/web-ui/src/app/components/AgentCompanionDesktopPet/AgentCompanionDesktopPet.scss +++ b/src/web-ui/src/app/components/AgentCompanionDesktopPet/AgentCompanionDesktopPet.scss @@ -17,6 +17,14 @@ --bitfun-agent-companion-gap: 8px; --bitfun-agent-companion-pet-width: 96px; --bitfun-agent-companion-pet-height: 96px; + --bitfun-agent-companion-bubble-copy-rgb: 31, 41, 55; + --bitfun-agent-companion-warning-rgb: 217, 119, 6; + --bitfun-agent-companion-warning-bg-rgb: 255, 251, 235; + --bitfun-agent-companion-success-rgb: 22, 163, 74; + --bitfun-agent-companion-success-bg-rgb: 240, 253, 244; + --bitfun-agent-companion-error-rgb: 220, 38, 38; + --bitfun-agent-companion-error-bg-rgb: 254, 242, 242; + --bitfun-agent-companion-bubble-fg: rgb(var(--bitfun-agent-companion-bubble-copy-rgb)); width: 100vw; height: 100vh; @@ -88,7 +96,7 @@ &::-webkit-scrollbar-thumb { border-radius: 999px; - background: rgba(15, 23, 42, 0.18); + background: color-mix(in srgb, rgb(var(--color-overlay-slate-rgb)) 18%, transparent); } } @@ -103,7 +111,7 @@ border: 1px solid var(--color-overlay-slate-10); border-radius: 10px 10px 2px 10px; background: var(--color-overlay-white-92); - color: #1f2937; + color: var(--bitfun-agent-companion-bubble-fg); backdrop-filter: blur(10px); cursor: pointer; @@ -146,7 +154,7 @@ margin-top: 2px; font-size: 10px; line-height: 1.25; - color: rgba(31, 41, 55, 0.7); + color: rgba(var(--bitfun-agent-companion-bubble-copy-rgb), 0.7); } &__bubble-output { @@ -157,7 +165,7 @@ height: calc(12px * 4); font-size: 10px; line-height: 12px; - color: rgba(31, 41, 55, 0.82); + color: rgba(var(--bitfun-agent-companion-bubble-copy-rgb), 0.82); white-space: pre-wrap; word-break: break-word; overflow-wrap: anywhere; @@ -176,26 +184,26 @@ height: 1em; margin-left: 2px; vertical-align: -0.12em; - background: rgba(31, 41, 55, 0.55); + background: rgba(var(--bitfun-agent-companion-bubble-copy-rgb), 0.55); animation: bitfun-agent-companion-caret 920ms steps(2, start) infinite; } } &__bubble--attention, &__bubble--waiting { - border-color: rgba(217, 119, 6, 0.22); - background: rgba(255, 251, 235, 0.94); + border-color: rgba(var(--bitfun-agent-companion-warning-rgb), 0.22); + background: rgba(var(--bitfun-agent-companion-warning-bg-rgb), 0.94); } &__bubble--completed { - border-color: rgba(22, 163, 74, 0.18); - background: rgba(240, 253, 244, 0.94); + border-color: rgba(var(--bitfun-agent-companion-success-rgb), 0.18); + background: rgba(var(--bitfun-agent-companion-success-bg-rgb), 0.94); } &__bubble--error, &__bubble--interrupted { - border-color: rgba(220, 38, 38, 0.18); - background: rgba(254, 242, 242, 0.94); + border-color: rgba(var(--bitfun-agent-companion-error-rgb), 0.18); + background: rgba(var(--bitfun-agent-companion-error-bg-rgb), 0.94); } .bitfun-chat-input-pixel-pet { diff --git a/src/web-ui/src/app/components/RemoteConnectDialog/RemoteConnectDialog.scss b/src/web-ui/src/app/components/RemoteConnectDialog/RemoteConnectDialog.scss index 02e02fde67..0d7cfceced 100644 --- a/src/web-ui/src/app/components/RemoteConnectDialog/RemoteConnectDialog.scss +++ b/src/web-ui/src/app/components/RemoteConnectDialog/RemoteConnectDialog.scss @@ -486,7 +486,7 @@ color: var(--color-static-white); background: $color-success; font-weight: $font-weight-semibold; - box-shadow: 0 1px 4px rgba(110, 184, 140, 0.35); + box-shadow: 0 1px 4px rgba(var(--component-action-success-rgb), 0.35); cursor: default; } diff --git a/src/web-ui/src/app/scenes/agents/agentTheme.ts b/src/web-ui/src/app/scenes/agents/agentTheme.ts index c566a71d21..95d63b856c 100644 --- a/src/web-ui/src/app/scenes/agents/agentTheme.ts +++ b/src/web-ui/src/app/scenes/agents/agentTheme.ts @@ -20,11 +20,11 @@ export function getAlphaColor(color: string, alphaHex = '44', percent = 27): str export const CAPABILITY_ACCENT: Record = { coding: 'var(--color-accent-500)', - docs: '#6eb88c', + docs: UI_EXCEPTION_ACCENTS.agentCapability.docs, analysis: 'var(--color-purple-500)', - testing: '#c9944d', - creative: '#e879a0', - ops: '#5ea3a3', + testing: UI_EXCEPTION_ACCENTS.agentCapability.testing, + creative: UI_EXCEPTION_ACCENTS.agentCapability.creative, + ops: UI_EXCEPTION_ACCENTS.agentCapability.ops, }; export function getCapabilityAccentBorder(category: CapabilityCategory): string { diff --git a/src/web-ui/src/app/scenes/my-agent/InsightsScene.tsx b/src/web-ui/src/app/scenes/my-agent/InsightsScene.tsx index ffa4669098..7f3da1f3ea 100644 --- a/src/web-ui/src/app/scenes/my-agent/InsightsScene.tsx +++ b/src/web-ui/src/app/scenes/my-agent/InsightsScene.tsx @@ -11,6 +11,7 @@ import type { InsightsReport, InsightsReportMeta, InsightsStats } from '@/infras import { useInsightsStore } from './insightsStore'; import { createLogger } from '@/shared/utils/logger'; import { notificationService } from '@/shared/notification-system'; +import { UI_EXCEPTION_ACCENTS } from '@/shared/theme/uiExceptionAccents'; import '@/app/components/GalleryLayout/GalleryLayout.scss'; import './InsightsScene.scss'; @@ -738,11 +739,11 @@ const StatItem: React.FC<{ value: string; label: string }> = ({ value, label }) // Bar chart palette (default + semantic roles) const CHART_COLORS = { blue: 'var(--color-accent-500)', // default / primary series - green: '#6eb88c', // positive / success + green: UI_EXCEPTION_ACCENTS.insights.positive, // positive / success purple: 'var(--color-purple-500)', // distribution / category - indigo: '#818cf8', // time-related - orange: '#c9944d', // time-of-day / neutral - red: '#c77070', // issues / errors + indigo: UI_EXCEPTION_ACCENTS.insights.time, // time-related + orange: UI_EXCEPTION_ACCENTS.insights.neutral, // time-of-day / neutral + red: UI_EXCEPTION_ACCENTS.insights.issue, // issues / errors } as const; type ChartColor = typeof CHART_COLORS[keyof typeof CHART_COLORS]; diff --git a/src/web-ui/src/app/scenes/profile/views/NurseryView.scss b/src/web-ui/src/app/scenes/profile/views/NurseryView.scss index f5d27b31d9..6ad9055770 100644 --- a/src/web-ui/src/app/scenes/profile/views/NurseryView.scss +++ b/src/web-ui/src/app/scenes/profile/views/NurseryView.scss @@ -44,7 +44,7 @@ $nursery-scene-gutter: clamp(40px, 6vw, 80px); transition: opacity 0.30s $easing-standard; user-select: none; -webkit-user-drag: none; - filter: drop-shadow(2px 6px 14px rgba(0, 0, 0, 0.24)); + filter: drop-shadow(2px 6px 14px rgba(var(--color-static-black-rgb), 0.24)); &--default { opacity: 1; @@ -216,7 +216,7 @@ $nursery-scene-gutter: clamp(40px, 6vw, 80px); } &--muted { - border-color: rgba(255, 255, 255, 0.14); + border-color: rgba(var(--color-static-white-rgb), 0.14); background: var(--element-bg-soft); } @@ -505,7 +505,7 @@ $nursery-scene-gutter: clamp(40px, 6vw, 80px); color 0.15s ease; &:hover { - background: rgba(255, 255, 255, 0.14); + background: rgba(var(--color-static-white-rgb), 0.14); color: var(--color-text-primary); } @@ -584,7 +584,7 @@ $nursery-scene-gutter: clamp(40px, 6vw, 80px); border-radius: 14px; padding: 24px; width: min(400px, calc(100vw - 40px)); - box-shadow: 0 20px 60px rgba(0, 0, 0, 0.35); + box-shadow: 0 20px 60px rgba(var(--color-static-black-rgb), 0.35); &__title { margin: 0 0 10px; diff --git a/src/web-ui/src/app/scenes/profile/views/TemplateConfigPage.tsx b/src/web-ui/src/app/scenes/profile/views/TemplateConfigPage.tsx index b88f0f42b2..ff8659a315 100644 --- a/src/web-ui/src/app/scenes/profile/views/TemplateConfigPage.tsx +++ b/src/web-ui/src/app/scenes/profile/views/TemplateConfigPage.tsx @@ -18,6 +18,7 @@ import { configManager } from '@/infrastructure/config/services/ConfigManager'; import type { AIModelConfig, AgentProfileConfigItem, ModeSkillInfo } from '@/infrastructure/config/types'; import { MCPAPI, type MCPServerInfo } from '@/infrastructure/api/service-api/MCPAPI'; import { notificationService } from '@/shared/notification-system'; +import { UI_EXCEPTION_ACCENTS } from '@/shared/theme/uiExceptionAccents'; import type { DynamicToolInfo } from '@/shared/types/agent-api'; import { createLogger } from '@/shared/utils/logger'; import { useNurseryStore } from '../nurseryStore'; @@ -60,7 +61,7 @@ const CTX_SEGMENT_COLORS: Record = { systemPrompt: 'var(--color-success)', toolInjection: 'var(--color-accent-500)', rules: 'var(--color-purple-soft)', - memories: '#f472b6', + memories: UI_EXCEPTION_ACCENTS.templateContext.memories, }; const CTX_LABEL_I18N_KEY: Record = { diff --git a/src/web-ui/src/app/styles/global.scss b/src/web-ui/src/app/styles/global.scss index 75f1b88477..6f3c73849c 100644 --- a/src/web-ui/src/app/styles/global.scss +++ b/src/web-ui/src/app/styles/global.scss @@ -289,6 +289,10 @@ body > div[style*="z-index:999999"] { /* Print styles */ @media print { + :root { + --print-border-rgb: 153, 153, 153; + } + * { background: transparent !important; color: black !important; @@ -307,7 +311,7 @@ body > div[style*="z-index:999999"] { pre, blockquote { - border: 1px solid #999999; + border: 1px solid rgb(var(--print-border-rgb)); page-break-inside: avoid; } diff --git a/src/web-ui/src/component-library/components/Avatar/Avatar.scss b/src/web-ui/src/component-library/components/Avatar/Avatar.scss index 6c3d25281c..643d5ca501 100644 --- a/src/web-ui/src/component-library/components/Avatar/Avatar.scss +++ b/src/web-ui/src/component-library/components/Avatar/Avatar.scss @@ -3,6 +3,9 @@ * Based on the BitFun glassmorphism design system */ .bitfun-avatar { + --bitfun-avatar-rest-start-rgb: 30, 41, 59; + --bitfun-avatar-rest-end-rgb: 51, 65, 85; + display: inline-flex; align-items: center; justify-content: center; @@ -69,7 +72,7 @@ .bitfun-avatar { margin-left: -8px; - border: 2px solid rgba(15, 23, 42, 0.8); + border: 2px solid rgba(var(--color-overlay-slate-rgb), 0.8); transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); &:first-child { @@ -85,8 +88,8 @@ &__rest { background: linear-gradient(135deg, - rgba(30, 41, 59, 0.9) 0%, - rgba(51, 65, 85, 0.9) 100%); + rgba(var(--bitfun-avatar-rest-start-rgb), 0.9) 0%, + rgba(var(--bitfun-avatar-rest-end-rgb), 0.9) 100%); font-size: 12px; } } diff --git a/src/web-ui/src/component-library/components/CodeEditor/CodeEditor.scss b/src/web-ui/src/component-library/components/CodeEditor/CodeEditor.scss index ec0bee688b..a78ddcbedb 100644 --- a/src/web-ui/src/component-library/components/CodeEditor/CodeEditor.scss +++ b/src/web-ui/src/component-library/components/CodeEditor/CodeEditor.scss @@ -1,13 +1,19 @@ @use '../../styles/tokens.scss' as tokens; .code-editor { - --code-editor-blue-100: rgba(130, 170, 255, 1); - --code-editor-blue-40: rgba(130, 170, 255, 0.4); - --code-editor-blue-30: rgba(130, 170, 255, 0.3); - --code-editor-blue-25: rgba(130, 170, 255, 0.25); - --code-editor-teal-15: rgba(127, 219, 202, 0.15); - --code-editor-teal-08: rgba(127, 219, 202, 0.08); - --code-editor-current-find-50: rgba(255, 152, 0, 0.5); + --code-editor-blue-rgb: 130, 170, 255; + --code-editor-teal-rgb: 127, 219, 202; + --code-editor-purple-rgb: 199, 146, 234; + --code-editor-warm-rgb: 225, 171, 128; + --code-editor-find-rgb: 255, 193, 7; + --code-editor-current-find-rgb: 255, 152, 0; + --code-editor-blue-100: rgba(var(--code-editor-blue-rgb), 1); + --code-editor-blue-40: rgba(var(--code-editor-blue-rgb), 0.4); + --code-editor-blue-30: rgba(var(--code-editor-blue-rgb), 0.3); + --code-editor-blue-25: rgba(var(--code-editor-blue-rgb), 0.25); + --code-editor-teal-15: rgba(var(--code-editor-teal-rgb), 0.15); + --code-editor-teal-08: rgba(var(--code-editor-teal-rgb), 0.08); + --code-editor-current-find-50: rgba(var(--code-editor-current-find-rgb), 0.5); position: relative; width: 100%; @@ -22,17 +28,17 @@ background: var(--color-bg-primary); border: 1px solid var(--code-editor-blue-25); box-shadow: - 0 8px 32px rgba(0, 0, 0, 0.5), + 0 8px 32px rgba(var(--color-static-black-rgb), 0.5), 0 0 0 1px var(--code-editor-teal-08) inset, - 0 2px 16px rgba(130, 170, 255, 0.12); + 0 2px 16px rgba(var(--code-editor-blue-rgb), 0.12); transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); &:hover { border-color: var(--code-editor-blue-40); box-shadow: - 0 12px 48px rgba(0, 0, 0, 0.6), - 0 0 0 1px rgba(127, 219, 202, 0.12) inset, - 0 2px 20px rgba(130, 170, 255, 0.2); + 0 12px 48px rgba(var(--color-static-black-rgb), 0.6), + 0 0 0 1px rgba(var(--code-editor-teal-rgb), 0.12) inset, + 0 2px 20px rgba(var(--code-editor-blue-rgb), 0.2); } &::before { @@ -44,9 +50,9 @@ height: 2px; background: linear-gradient(90deg, transparent 0%, - rgba(199, 146, 234, 0.3) 25%, - rgba(130, 170, 255, 0.5) 50%, - rgba(127, 219, 202, 0.3) 75%, + rgba(var(--code-editor-purple-rgb), 0.3) 25%, + rgba(var(--code-editor-blue-rgb), 0.5) 50%, + rgba(var(--code-editor-teal-rgb), 0.3) 75%, transparent 100% ); z-index: 1; @@ -61,7 +67,7 @@ } .margin-view-overlays .line-numbers { - color: rgba(255, 255, 255, 0.35); + color: rgba(var(--color-static-white-rgb), 0.35); font-weight: 400; font-variant-numeric: tabular-nums; transition: color 0.2s ease; @@ -70,7 +76,7 @@ .margin-view-overlays .current-line ~ .line-numbers { color: var(--code-editor-blue-100); font-weight: 700; - text-shadow: 0 0 10px rgba(130, 170, 255, 0.6); + text-shadow: 0 0 10px rgba(var(--code-editor-blue-rgb), 0.6); transform: scale(1.05); } @@ -80,11 +86,11 @@ .view-overlays .current-line { background: linear-gradient(90deg, - rgba(130, 170, 255, 0.08) 0%, - rgba(127, 219, 202, 0.06) 50%, - rgba(199, 146, 234, 0.04) 100% + rgba(var(--code-editor-blue-rgb), 0.08) 0%, + rgba(var(--code-editor-teal-rgb), 0.06) 50%, + rgba(var(--code-editor-purple-rgb), 0.04) 100% ); - border-left: 3px solid rgba(130, 170, 255, 0.5); + border-left: 3px solid rgba(var(--code-editor-blue-rgb), 0.5); border-right: none; animation: pulse-highlight 2s ease-in-out infinite; } @@ -108,60 +114,60 @@ .slider { background: linear-gradient(135deg, - rgba(225, 171, 128, 0.35), - rgba(199, 146, 234, 0.35) + rgba(var(--code-editor-warm-rgb), 0.35), + rgba(var(--code-editor-purple-rgb), 0.35) ) !important; border-radius: 6px; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); &:hover { background: linear-gradient(135deg, - rgba(225, 171, 128, 0.55), - rgba(199, 146, 234, 0.55) + rgba(var(--code-editor-warm-rgb), 0.55), + rgba(var(--code-editor-purple-rgb), 0.55) ) !important; - box-shadow: 0 0 8px rgba(225, 171, 128, 0.4); + box-shadow: 0 0 8px rgba(var(--code-editor-warm-rgb), 0.4); } &.active { background: linear-gradient(135deg, - rgba(225, 171, 128, 0.7), - rgba(199, 146, 234, 0.7) + rgba(var(--code-editor-warm-rgb), 0.7), + rgba(var(--code-editor-purple-rgb), 0.7) ) !important; - box-shadow: 0 0 12px rgba(225, 171, 128, 0.5); + box-shadow: 0 0 12px rgba(var(--code-editor-warm-rgb), 0.5); } } } .cursor { background: linear-gradient(180deg, - rgba(130, 170, 255, 1), - rgba(127, 219, 202, 1) + rgba(var(--code-editor-blue-rgb), 1), + rgba(var(--code-editor-teal-rgb), 1) ); width: 2px !important; box-shadow: - 0 0 16px rgba(130, 170, 255, 0.9), - 0 0 32px rgba(127, 219, 202, 0.5); + 0 0 16px rgba(var(--code-editor-blue-rgb), 0.9), + 0 0 32px rgba(var(--code-editor-teal-rgb), 0.5); animation: cursor-glow 1.5s ease-in-out infinite; } @keyframes cursor-glow { 0%, 100% { box-shadow: - 0 0 16px rgba(130, 170, 255, 0.9), - 0 0 32px rgba(127, 219, 202, 0.5); + 0 0 16px rgba(var(--code-editor-blue-rgb), 0.9), + 0 0 32px rgba(var(--code-editor-teal-rgb), 0.5); } 50% { box-shadow: - 0 0 20px rgba(130, 170, 255, 1), - 0 0 40px rgba(127, 219, 202, 0.7); + 0 0 20px rgba(var(--code-editor-blue-rgb), 1), + 0 0 40px rgba(var(--code-editor-teal-rgb), 0.7); } } .bracket-match { background: var(--code-editor-teal-15); - border: 1px solid rgba(127, 219, 202, 0.7); + border: 1px solid rgba(var(--code-editor-teal-rgb), 0.7); border-radius: 2px; - box-shadow: 0 0 10px rgba(127, 219, 202, 0.4); + box-shadow: 0 0 10px rgba(var(--code-editor-teal-rgb), 0.4); animation: bracket-pulse 0.3s ease-out; } @@ -178,16 +184,16 @@ } .findMatch { - background: rgba(255, 193, 7, 0.35); - border: 1px solid rgba(255, 193, 7, 0.7); + background: rgba(var(--code-editor-find-rgb), 0.35); + border: 1px solid rgba(var(--code-editor-find-rgb), 0.7); border-radius: 2px; - box-shadow: 0 0 6px rgba(255, 193, 7, 0.3); + box-shadow: 0 0 6px rgba(var(--code-editor-find-rgb), 0.3); animation: find-pulse 0.5s ease-out; } .currentFindMatch { background: var(--code-editor-current-find-50); - border: 1px solid rgba(255, 152, 0, 1); + border: 1px solid rgba(var(--code-editor-current-find-rgb), 1); border-radius: 2px; box-shadow: 0 0 10px var(--code-editor-current-find-50); animation: current-find-pulse 1s ease-in-out infinite; @@ -213,18 +219,18 @@ box-shadow: 0 0 10px var(--code-editor-current-find-50); } 50% { - box-shadow: 0 0 16px rgba(255, 152, 0, 0.8); + box-shadow: 0 0 16px rgba(var(--code-editor-current-find-rgb), 0.8); } } .cldr { &.codicon { - color: rgba(255, 255, 255, 0.4); + color: rgba(var(--color-static-white-rgb), 0.4); transition: all 0.2s ease; &:hover { color: var(--code-editor-blue-100); - text-shadow: 0 0 10px rgba(130, 170, 255, 0.8); + text-shadow: 0 0 10px rgba(var(--code-editor-blue-rgb), 0.8); transform: scale(1.1); } } @@ -238,7 +244,7 @@ border: 1px solid var(--code-editor-blue-40); border-radius: 10px; box-shadow: - 0 12px 48px rgba(0, 0, 0, 0.7), + 0 12px 48px rgba(var(--color-static-black-rgb), 0.7), 0 0 0 1px var(--code-editor-teal-08) inset, 0 4px 16px var(--code-editor-blue-25); backdrop-filter: blur(20px); @@ -254,9 +260,9 @@ height: 2px; background: linear-gradient(90deg, transparent 0%, - rgba(199, 146, 234, 0.4) 25%, - rgba(130, 170, 255, 0.7) 50%, - rgba(127, 219, 202, 0.4) 75%, + rgba(var(--code-editor-purple-rgb), 0.4) 25%, + rgba(var(--code-editor-blue-rgb), 0.7) 50%, + rgba(var(--code-editor-teal-rgb), 0.4) 75%, transparent 100% ); } @@ -268,7 +274,7 @@ &.focused { background: linear-gradient(90deg, - rgba(130, 170, 255, 0.2) 0%, + rgba(var(--code-editor-blue-rgb), 0.2) 0%, var(--code-editor-teal-15) 100% ); box-shadow: 0 0 12px var(--code-editor-blue-30); @@ -276,7 +282,7 @@ } &:hover { - background: rgba(130, 170, 255, 0.12); + background: rgba(var(--code-editor-blue-rgb), 0.12); } } } @@ -289,7 +295,7 @@ border: 1px solid var(--code-editor-blue-40); border-radius: 8px; box-shadow: - 0 8px 40px rgba(0, 0, 0, 0.7), + 0 8px 40px rgba(var(--color-static-black-rgb), 0.7), 0 0 0 1px var(--code-editor-teal-08) inset, 0 2px 12px var(--code-editor-blue-25); backdrop-filter: blur(20px); @@ -316,7 +322,7 @@ border: 1px solid var(--code-editor-blue-40); border-radius: 8px; box-shadow: - 0 8px 40px rgba(0, 0, 0, 0.7), + 0 8px 40px rgba(var(--color-static-black-rgb), 0.7), 0 0 0 1px var(--code-editor-teal-08) inset, 0 2px 12px var(--code-editor-blue-25); backdrop-filter: blur(20px); @@ -326,7 +332,7 @@ transition: all 0.2s ease; &.focused { - background: rgba(130, 170, 255, 0.1); + background: rgba(var(--code-editor-blue-rgb), 0.1); } } } @@ -341,15 +347,15 @@ .minimap-slider { background: linear-gradient(135deg, - rgba(130, 170, 255, 0.2), + rgba(var(--code-editor-blue-rgb), 0.2), var(--code-editor-teal-15) ) !important; border: 1px solid var(--code-editor-blue-30); &:hover { background: linear-gradient(135deg, - rgba(130, 170, 255, 0.3), - rgba(127, 219, 202, 0.25) + rgba(var(--code-editor-blue-rgb), 0.3), + rgba(var(--code-editor-teal-rgb), 0.25) ) !important; } } @@ -357,11 +363,11 @@ .indent-guides { .indent-guide { - border-left: 1px solid rgba(255, 255, 255, 0.06); + border-left: 1px solid var(--color-overlay-white-06); &.indent-guide-active { - border-left: 1px solid rgba(130, 170, 255, 0.6); - box-shadow: -1px 0 6px rgba(130, 170, 255, 0.4); + border-left: 1px solid rgba(var(--code-editor-blue-rgb), 0.6); + box-shadow: -1px 0 6px rgba(var(--code-editor-blue-rgb), 0.4); } } } @@ -398,7 +404,7 @@ background: color-mix(in srgb, var(--color-bg-primary) 85%, transparent); border: 1px solid var(--code-editor-blue-40); border-radius: 6px; - color: rgba(130, 170, 255, 0.8); + color: rgba(var(--code-editor-blue-rgb), 0.8); cursor: pointer; display: flex; align-items: center; @@ -409,12 +415,12 @@ &:hover { background: color-mix(in srgb, var(--color-bg-primary) 95%, transparent); - border-color: rgba(130, 170, 255, 0.8); + border-color: rgba(var(--code-editor-blue-rgb), 0.8); color: var(--code-editor-blue-100); box-shadow: - 0 4px 16px rgba(0, 0, 0, 0.6), + 0 4px 16px rgba(var(--color-static-black-rgb), 0.6), 0 0 20px var(--code-editor-blue-40), - 0 0 40px rgba(127, 219, 202, 0.2); + 0 0 40px rgba(var(--code-editor-teal-rgb), 0.2); transform: scale(1.08); } diff --git a/src/web-ui/src/component-library/components/FlowChatCards/ContextCompressionCard/ContextCompressionCard.scss b/src/web-ui/src/component-library/components/FlowChatCards/ContextCompressionCard/ContextCompressionCard.scss index 819d773c4d..ec23f835d1 100644 --- a/src/web-ui/src/component-library/components/FlowChatCards/ContextCompressionCard/ContextCompressionCard.scss +++ b/src/web-ui/src/component-library/components/FlowChatCards/ContextCompressionCard/ContextCompressionCard.scss @@ -6,14 +6,19 @@ .context-compression-card { - --context-compression-accent: #a855f7; + --context-compression-accent-rgb: 168, 85, 247; + --context-compression-bg-start-rgb: 20, 20, 20; + --context-compression-bg-end-rgb: 15, 15, 15; + --context-compression-hover-bg-start-rgb: 25, 25, 25; + --context-compression-hover-bg-end-rgb: 20, 20, 20; + --context-compression-accent: rgb(var(--context-compression-accent-rgb)); width: 100%; max-width: 100%; background: linear-gradient( 135deg, - color-mix(in srgb, var(--color-bg-secondary) 95%, transparent), - color-mix(in srgb, var(--color-bg-primary) 98%, transparent) + rgba(var(--context-compression-bg-start-rgb), 0.95), + rgba(var(--context-compression-bg-end-rgb), 0.98) ); border: 1px solid color-mix(in srgb, var(--context-compression-accent) 60%, transparent); border-radius: 50px; @@ -55,8 +60,8 @@ inset 0 1px 0 var(--color-overlay-white-10); background: linear-gradient( 135deg, - color-mix(in srgb, var(--color-bg-secondary) 98%, transparent), - var(--color-bg-primary) + rgba(var(--context-compression-hover-bg-start-rgb), 0.98), + rgb(var(--context-compression-hover-bg-end-rgb)) ); } } diff --git a/src/web-ui/src/component-library/components/StreamText/StreamText.scss b/src/web-ui/src/component-library/components/StreamText/StreamText.scss index d508847e39..a3da90ff41 100644 --- a/src/web-ui/src/component-library/components/StreamText/StreamText.scss +++ b/src/web-ui/src/component-library/components/StreamText/StreamText.scss @@ -1,26 +1,46 @@ /* Streaming text output styles */ .stream-text { - --stream-text-matrix-green: #00ff00; - --stream-text-rainbow-pink: #ff0080; - --stream-text-rainbow-orange: #ff8c00; - --stream-text-rainbow-teal: #40e0d0; - --stream-text-rainbow-sky: #00bfff; - --stream-text-rainbow-purple: #9370db; - --stream-text-rainbow-hot-pink: #ff1493; - --stream-text-fire-red: #ff0000; - --stream-text-fire-orange: #ff8800; - --stream-text-fire-yellow: #ffdd00; - --stream-text-ocean-deep: #0077be; - --stream-text-ocean-mid: #00b4d8; - --stream-text-ocean-foam: #48cae4; - --stream-text-sunset-coral: #ff6b6b; - --stream-text-sunset-yellow: #ffd93d; - --stream-text-sunset-pink: #ff9ff3; - --stream-text-glitch-magenta: #ff00ff; - --stream-text-glitch-cyan: #00ffff; - --stream-text-theme-purple: #a855f7; - --stream-text-theme-purple-neon: #c084fc; - --stream-text-theme-green: #22c55e; + --stream-text-matrix-green-rgb: 0, 255, 0; + --stream-text-rainbow-pink-rgb: 255, 0, 128; + --stream-text-rainbow-orange-rgb: 255, 140, 0; + --stream-text-rainbow-teal-rgb: 64, 224, 208; + --stream-text-rainbow-sky-rgb: 0, 191, 255; + --stream-text-rainbow-purple-rgb: 147, 112, 219; + --stream-text-rainbow-hot-pink-rgb: 255, 20, 147; + --stream-text-fire-red-rgb: 255, 0, 0; + --stream-text-fire-yellow-rgb: 255, 215, 0; + --stream-text-ocean-deep-rgb: 0, 119, 190; + --stream-text-ocean-mid-rgb: 0, 173, 216; + --stream-text-ocean-foam-rgb: 72, 202, 228; + --stream-text-sunset-coral-rgb: 255, 107, 107; + --stream-text-sunset-yellow-rgb: 255, 217, 61; + --stream-text-sunset-pink-rgb: 255, 159, 243; + --stream-text-glitch-magenta-rgb: 255, 0, 255; + --stream-text-glitch-cyan-rgb: 0, 255, 255; + --stream-text-theme-purple-rgb: 168, 85, 247; + --stream-text-theme-purple-neon-rgb: 192, 132, 252; + --stream-text-theme-green-rgb: 34, 197, 94; + --stream-text-matrix-green: rgb(var(--stream-text-matrix-green-rgb)); + --stream-text-rainbow-pink: rgb(var(--stream-text-rainbow-pink-rgb)); + --stream-text-rainbow-orange: rgb(var(--stream-text-rainbow-orange-rgb)); + --stream-text-rainbow-teal: rgb(var(--stream-text-rainbow-teal-rgb)); + --stream-text-rainbow-sky: rgb(var(--stream-text-rainbow-sky-rgb)); + --stream-text-rainbow-purple: rgb(var(--stream-text-rainbow-purple-rgb)); + --stream-text-rainbow-hot-pink: rgb(var(--stream-text-rainbow-hot-pink-rgb)); + --stream-text-fire-red: rgb(var(--stream-text-fire-red-rgb)); + --stream-text-fire-orange: var(--stream-text-rainbow-orange); + --stream-text-fire-yellow: rgb(var(--stream-text-fire-yellow-rgb)); + --stream-text-ocean-deep: rgb(var(--stream-text-ocean-deep-rgb)); + --stream-text-ocean-mid: rgb(var(--stream-text-ocean-mid-rgb)); + --stream-text-ocean-foam: rgb(var(--stream-text-ocean-foam-rgb)); + --stream-text-sunset-coral: rgb(var(--stream-text-sunset-coral-rgb)); + --stream-text-sunset-yellow: rgb(var(--stream-text-sunset-yellow-rgb)); + --stream-text-sunset-pink: rgb(var(--stream-text-sunset-pink-rgb)); + --stream-text-glitch-magenta: rgb(var(--stream-text-glitch-magenta-rgb)); + --stream-text-glitch-cyan: rgb(var(--stream-text-glitch-cyan-rgb)); + --stream-text-theme-purple: rgb(var(--stream-text-theme-purple-rgb)); + --stream-text-theme-purple-neon: rgb(var(--stream-text-theme-purple-neon-rgb)); + --stream-text-theme-green: rgb(var(--stream-text-theme-green-rgb)); display: inline; font-family: var(--font-family-sans); diff --git a/src/web-ui/src/component-library/components/TextStrokeEffect/TextStrokeEffect.scss b/src/web-ui/src/component-library/components/TextStrokeEffect/TextStrokeEffect.scss index 656c9b2309..0001a36c63 100644 --- a/src/web-ui/src/component-library/components/TextStrokeEffect/TextStrokeEffect.scss +++ b/src/web-ui/src/component-library/components/TextStrokeEffect/TextStrokeEffect.scss @@ -14,7 +14,7 @@ &__animated { fill: transparent; - stroke: rgba(255, 255, 255, 0.5); + stroke: rgba(var(--color-static-white-rgb), 0.5); stroke-width: 1.5; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 72px; diff --git a/src/web-ui/src/flow_chat/components/ChatInputPixelPet.scss b/src/web-ui/src/flow_chat/components/ChatInputPixelPet.scss index 6b8cb5283e..38b88bfdd7 100644 --- a/src/web-ui/src/flow_chat/components/ChatInputPixelPet.scss +++ b/src/web-ui/src/flow_chat/components/ChatInputPixelPet.scss @@ -20,13 +20,15 @@ .bitfun-chat-input-pixel-pet { /* FIXED panda body palette — never inverted. */ - --bitfun-pet-color: #202024; - --bitfun-pet-cream: #fafaf9; + --bitfun-pet-color-rgb: 32, 32, 36; + --bitfun-pet-cream-rgb: 250, 250, 249; + --bitfun-pet-color: rgb(var(--bitfun-pet-color-rgb)); + --bitfun-pet-cream: rgb(var(--bitfun-pet-cream-rgb)); /* Decorative palette — inverts between light/dark themes so overlays stay readable on either chat background. */ - --bitfun-pet-decor: #202024; - --bitfun-pet-decor-soft: rgba(32, 32, 36, 0.55); + --bitfun-pet-decor: rgb(var(--bitfun-pet-color-rgb)); + --bitfun-pet-decor-soft: rgba(var(--bitfun-pet-color-rgb), 0.55); --bitfun-petdex-width: 42px; --bitfun-petdex-height: 46px; --bitfun-petdex-margin-top: -8px; @@ -54,6 +56,7 @@ width: 100%; height: 100%; overflow: visible; + color: var(--bitfun-pet-cream); shape-rendering: geometricPrecision; } @@ -104,8 +107,8 @@ outlines on every internal element. */ :root[data-theme-type='dark'] .bitfun-chat-input-pixel-pet, [data-theme-type='dark'] .bitfun-chat-input-pixel-pet { - --bitfun-pet-decor: #fafaf9; - --bitfun-pet-decor-soft: rgba(250, 251, 249, 0.6); + --bitfun-pet-decor: rgb(var(--bitfun-pet-cream-rgb)); + --bitfun-pet-decor-soft: rgba(var(--bitfun-pet-cream-rgb), 0.6); .bitfun-panda-head__silhouette { filter: url(#bitfun-panda-outline); diff --git a/src/web-ui/src/flow_chat/components/ChatInputPixelPet.tsx b/src/web-ui/src/flow_chat/components/ChatInputPixelPet.tsx index e2dec16631..321402d783 100644 --- a/src/web-ui/src/flow_chat/components/ChatInputPixelPet.tsx +++ b/src/web-ui/src/flow_chat/components/ChatInputPixelPet.tsx @@ -468,7 +468,7 @@ export const ChatInputPixelPet: React.FC = ({ height="130%" > - + diff --git a/src/web-ui/src/flow_chat/components/FlowTextBlock.scss b/src/web-ui/src/flow_chat/components/FlowTextBlock.scss index 8f229b03b8..d75f73e645 100644 --- a/src/web-ui/src/flow_chat/components/FlowTextBlock.scss +++ b/src/web-ui/src/flow_chat/components/FlowTextBlock.scss @@ -162,7 +162,7 @@ :root[data-theme-type='light'] .flow-text-block .markdown-renderer .code-block-wrapper .copy-button.copy-success:hover, [data-theme-type='light'] .flow-text-block .markdown-renderer .code-block-wrapper .copy-button.copy-success:hover, .light .flow-text-block .markdown-renderer .code-block-wrapper .copy-button.copy-success:hover { - color: #1a7f37; + color: var(--markdown-copy-success-color-light); } :root[data-theme='light'] .flow-text-block .markdown-renderer .inline-code, diff --git a/src/web-ui/src/flow_chat/components/SnapshotRollbackButton.scss b/src/web-ui/src/flow_chat/components/SnapshotRollbackButton.scss index df1d7d68a6..63adb1771c 100644 --- a/src/web-ui/src/flow_chat/components/SnapshotRollbackButton.scss +++ b/src/web-ui/src/flow_chat/components/SnapshotRollbackButton.scss @@ -106,13 +106,14 @@ // Dark theme @media (prefers-color-scheme: dark) { .snapshot-rollback-button { - --color-border: #374151; - --color-bg-elevated: #1f2937; - --color-text-secondary: #9ca3af; + --snapshot-rollback-dark-secondary-rgb: 156, 163, 175; + --color-border: color-mix(in srgb, rgb(var(--color-overlay-slate-rgb)) 82%, var(--color-static-white)); + --color-bg-elevated: color-mix(in srgb, rgb(var(--color-overlay-slate-rgb)) 94%, var(--color-static-white)); + --color-text-secondary: rgb(var(--snapshot-rollback-dark-secondary-rgb)); --color-primary: var(--color-accent-500); --color-primary-bg: var(--card-bg-accent); --color-error: var(--color-error-soft); - --color-error-bg: rgba(248, 113, 113, 0.1); + --color-error-bg: color-mix(in srgb, var(--color-error-soft) 10%, transparent); } } diff --git a/src/web-ui/src/flow_chat/components/modern/ExportImageButton.tsx b/src/web-ui/src/flow_chat/components/modern/ExportImageButton.tsx index 2fd365ff88..dff27dfd9e 100644 --- a/src/web-ui/src/flow_chat/components/modern/ExportImageButton.tsx +++ b/src/web-ui/src/flow_chat/components/modern/ExportImageButton.tsx @@ -16,6 +16,7 @@ import type { DialogTurn, FlowTextItem, FlowToolItem, FlowThinkingItem } from '. import { i18nService } from '@/infrastructure/i18n'; import { workspaceAPI } from '@/infrastructure/api'; import { createLogger } from '@/shared/utils/logger'; +import { FLOWCHAT_CAPTURE_FALLBACK_COLOR } from '@/shared/theme/themeBoundaryFallbacks'; import { withTimeout } from '@/shared/utils/timing'; import { downloadDir, join } from '@tauri-apps/api/path'; import { writeFile } from '@tauri-apps/plugin-fs'; @@ -218,7 +219,7 @@ export const ExportImageButton: React.FC = ({ // Get theme background color. const computedStyle = getComputedStyle(document.documentElement); - const bgColor = computedStyle.getPropertyValue('--color-bg-flowchat').trim() || '#121214'; + const bgColor = computedStyle.getPropertyValue('--color-bg-flowchat').trim() || FLOWCHAT_CAPTURE_FALLBACK_COLOR.background; // Pre-load the logo as an HTMLImageElement. We do NOT try to embed it // inside the captured DOM (unreliable with /data URLs inside an diff --git a/src/web-ui/src/flow_chat/state-machine/derivedState.ts b/src/web-ui/src/flow_chat/state-machine/derivedState.ts index 7dcc78aed3..67bdabc631 100644 --- a/src/web-ui/src/flow_chat/state-machine/derivedState.ts +++ b/src/web-ui/src/flow_chat/state-machine/derivedState.ts @@ -13,6 +13,7 @@ import { SessionStateMachine, SessionDerivedState, } from './types'; +import { UI_EXCEPTION_ACCENTS } from '@/shared/theme/uiExceptionAccents'; /** Optional live chat input draft while PROCESSING (mirrors input box); used so send mode stays `split` when user has typed a follow-up. */ export type DeriveSessionOptions = { @@ -216,7 +217,7 @@ function getProgressBarLabel( function getProgressBarColor(phase: ProcessingPhase | null): string { switch (phase) { case ProcessingPhase.COMPACTING: - return '#0f766e'; + return UI_EXCEPTION_ACCENTS.progress.compacting; case ProcessingPhase.STARTING: return 'var(--color-accent-600)'; diff --git a/src/web-ui/src/flow_chat/tool-cards/BaseToolCard.scss b/src/web-ui/src/flow_chat/tool-cards/BaseToolCard.scss index 9f6415bc8b..804bc5b3ac 100644 --- a/src/web-ui/src/flow_chat/tool-cards/BaseToolCard.scss +++ b/src/web-ui/src/flow_chat/tool-cards/BaseToolCard.scss @@ -7,6 +7,8 @@ /* ========== Card wrapper ========== */ .base-tool-card-wrapper { + --base-tool-card-divider-rgb: 100, 100, 100; + display: flex; flex-direction: column; margin: var(--flowchat-card-gap) 0; @@ -118,7 +120,7 @@ background: linear-gradient( 90deg, transparent 0%, - rgba(100, 100, 100, 0.2) 50%, + rgba(var(--base-tool-card-divider-rgb), 0.2) 50%, transparent 100% ); pointer-events: none; diff --git a/src/web-ui/src/flow_chat/tool-cards/ContextCompressionDisplay.scss b/src/web-ui/src/flow_chat/tool-cards/ContextCompressionDisplay.scss index 1ef1626f68..9270f22b58 100644 --- a/src/web-ui/src/flow_chat/tool-cards/ContextCompressionDisplay.scss +++ b/src/web-ui/src/flow_chat/tool-cards/ContextCompressionDisplay.scss @@ -1,5 +1,7 @@ /* Context compression card styles. */ .context-compression-display { + --context-compression-note-rgb: 148, 163, 184; + .compression-icon { color: var(--color-text-secondary); } @@ -65,7 +67,7 @@ font-size: var(--flowchat-font-size-sm); line-height: var(--flowchat-support-line-height); color: var(--tool-card-text-secondary); - background: rgba(148, 163, 184, 0.08); - border-top: 1px solid rgba(148, 163, 184, 0.18); + background: rgba(var(--context-compression-note-rgb), 0.08); + border-top: 1px solid rgba(var(--context-compression-note-rgb), 0.18); } } diff --git a/src/web-ui/src/flow_chat/tool-cards/DefaultToolCard.scss b/src/web-ui/src/flow_chat/tool-cards/DefaultToolCard.scss index 3ef2e0689c..51f37c82fa 100644 --- a/src/web-ui/src/flow_chat/tool-cards/DefaultToolCard.scss +++ b/src/web-ui/src/flow_chat/tool-cards/DefaultToolCard.scss @@ -19,6 +19,8 @@ } .default-tool-card { + --default-tool-card-confirm-text-rgb: 134, 239, 172; + .compact-tool-card { min-height: 0; padding: 0 !important; @@ -166,7 +168,7 @@ .default-tool-card__button--confirm { background: color-mix(in srgb, var(--tool-card-positive-color) 12%, transparent); border-color: color-mix(in srgb, var(--tool-card-positive-color) 26%, transparent); - color: #86efac; + color: rgb(var(--default-tool-card-confirm-text-rgb)); } .default-tool-card__button--confirm:hover:not(:disabled) { diff --git a/src/web-ui/src/flow_chat/tool-cards/GenerativeWidgetToolCard.scss b/src/web-ui/src/flow_chat/tool-cards/GenerativeWidgetToolCard.scss index 493347414f..8569f09f96 100644 --- a/src/web-ui/src/flow_chat/tool-cards/GenerativeWidgetToolCard.scss +++ b/src/web-ui/src/flow_chat/tool-cards/GenerativeWidgetToolCard.scss @@ -1,4 +1,8 @@ .generative-widget-card { + --generative-widget-card-icon-rgb: 125, 207, 255; + --generative-widget-card-error-rgb: 253, 164, 175; + --generative-widget-card-error-soft-rgb: 252, 165, 165; + overflow: hidden; } @@ -12,7 +16,7 @@ } .generative-widget-card__icon { - color: #7dd3fc; + color: rgb(var(--generative-widget-card-icon-rgb)); } .generative-widget-card__title { @@ -35,7 +39,7 @@ } .generative-widget-card__status--error { - color: #fda4af; + color: rgb(var(--generative-widget-card-error-rgb)); } .generative-widget-card__preview { @@ -57,7 +61,7 @@ } .generative-widget-card__placeholder--error { - color: #fca5a5; + color: rgb(var(--generative-widget-card-error-soft-rgb)); } .generative-widget-card__capture-root { diff --git a/src/web-ui/src/flow_chat/tool-cards/ModelThinkingDisplay.scss b/src/web-ui/src/flow_chat/tool-cards/ModelThinkingDisplay.scss index 51816f68e7..37d1d353a7 100644 --- a/src/web-ui/src/flow_chat/tool-cards/ModelThinkingDisplay.scss +++ b/src/web-ui/src/flow_chat/tool-cards/ModelThinkingDisplay.scss @@ -111,7 +111,9 @@ } .flow-thinking-item.streaming .thinking-content { - color: #9ca3af; + --model-thinking-streaming-text-rgb: 156, 163, 175; + + color: rgb(var(--model-thinking-streaming-text-rgb)); } /* Content wrapper with fade gradients */ diff --git a/src/web-ui/src/flow_chat/tool-cards/TaskToolDisplay.scss b/src/web-ui/src/flow_chat/tool-cards/TaskToolDisplay.scss index 4dc7414c7c..2dc095ab1a 100644 --- a/src/web-ui/src/flow_chat/tool-cards/TaskToolDisplay.scss +++ b/src/web-ui/src/flow_chat/tool-cards/TaskToolDisplay.scss @@ -226,6 +226,8 @@ } .task-failed-badge { + --task-failed-badge-rgb: 107, 114, 128; + display: inline-flex; align-items: center; padding: 0.1rem var(--flowchat-inline-gap); @@ -234,7 +236,7 @@ font-weight: 500; flex-shrink: 0; color: var(--color-text-muted); - background: rgba(107, 114, 128, 0.15); + background: rgba(var(--task-failed-badge-rgb), 0.15); } .agent-type-badge { diff --git a/src/web-ui/src/flow_chat/tool-cards/ToolCommandPreview.scss b/src/web-ui/src/flow_chat/tool-cards/ToolCommandPreview.scss index fbdf5fd429..5e664873be 100644 --- a/src/web-ui/src/flow_chat/tool-cards/ToolCommandPreview.scss +++ b/src/web-ui/src/flow_chat/tool-cards/ToolCommandPreview.scss @@ -15,7 +15,9 @@ } .tool-command-preview__empty { - color: #e06c75; + --tool-command-preview-empty-rgb: 224, 108, 117; + + color: rgb(var(--tool-command-preview-empty-rgb)); font-style: italic; } diff --git a/src/web-ui/src/flow_chat/utils/captureElementToDownloadsPng.tsx b/src/web-ui/src/flow_chat/utils/captureElementToDownloadsPng.tsx index 8b9b1b6275..5029a38537 100644 --- a/src/web-ui/src/flow_chat/utils/captureElementToDownloadsPng.tsx +++ b/src/web-ui/src/flow_chat/utils/captureElementToDownloadsPng.tsx @@ -4,6 +4,7 @@ import { notificationService } from '@/shared/notification-system'; import { i18nService } from '@/infrastructure/i18n'; import { workspaceAPI } from '@/infrastructure/api'; import { createLogger } from '@/shared/utils/logger'; +import { FLOWCHAT_CAPTURE_FALLBACK_COLOR } from '@/shared/theme/themeBoundaryFallbacks'; import { withTimeout } from '@/shared/utils/timing'; const log = createLogger('captureElementToDownloadsPng'); @@ -18,7 +19,7 @@ export async function captureElementToDownloadsPng( fileNamePrefix: string, ): Promise { const computedStyle = getComputedStyle(document.documentElement); - const bgColor = computedStyle.getPropertyValue('--color-bg-flowchat').trim() || '#121214'; + const bgColor = computedStyle.getPropertyValue('--color-bg-flowchat').trim() || FLOWCHAT_CAPTURE_FALLBACK_COLOR.background; await new Promise((resolve) => setTimeout(resolve, 0)); diff --git a/src/web-ui/src/infrastructure/config/components/ConfigForm.scss b/src/web-ui/src/infrastructure/config/components/ConfigForm.scss index 5dbb2594bb..87f6cf4f6e 100644 --- a/src/web-ui/src/infrastructure/config/components/ConfigForm.scss +++ b/src/web-ui/src/infrastructure/config/components/ConfigForm.scss @@ -158,13 +158,21 @@ $config-input-height: 32px; .bitfun-config-form__select { + --bitfun-config-select-chevron-rgb: 150, 163, 180; + height: $config-input-height !important; line-height: $config-input-height !important; cursor: pointer !important; - background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3e%3cpath d='M2.5 4.5L6 8L9.5 4.5' stroke='rgba(150, 163, 180, 0.8)' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3e%3c/svg%3e") !important; - background-position: right 10px center !important; + background-image: + linear-gradient(45deg, transparent 50%, rgba(var(--bitfun-config-select-chevron-rgb), 0.8) 50%), + linear-gradient(135deg, rgba(var(--bitfun-config-select-chevron-rgb), 0.8) 50%, transparent 50%) !important; + background-position: + calc(100% - 16px) 50%, + calc(100% - 11px) 50% !important; background-repeat: no-repeat !important; - background-size: 12px !important; + background-size: + 5px 5px, + 5px 5px !important; padding: 0 32px 0 12px !important; -webkit-appearance: none !important; -moz-appearance: none !important; diff --git a/src/web-ui/src/infrastructure/config/components/DefaultModelConfig.scss b/src/web-ui/src/infrastructure/config/components/DefaultModelConfig.scss index 5e1017e01e..5074f5a9e9 100644 --- a/src/web-ui/src/infrastructure/config/components/DefaultModelConfig.scss +++ b/src/web-ui/src/infrastructure/config/components/DefaultModelConfig.scss @@ -235,8 +235,10 @@ } &__model-option-thinking { + --default-model-thinking-rgb: 180, 160, 255; + flex-shrink: 0; - color: rgba(180, 160, 255, 0.9); + color: rgba(var(--default-model-thinking-rgb), 0.9); width: 11px; height: 11px; } diff --git a/src/web-ui/src/infrastructure/language-detection/core/LanguageRegistry.ts b/src/web-ui/src/infrastructure/language-detection/core/LanguageRegistry.ts index fd896407b6..d039e9f14c 100644 --- a/src/web-ui/src/infrastructure/language-detection/core/LanguageRegistry.ts +++ b/src/web-ui/src/infrastructure/language-detection/core/LanguageRegistry.ts @@ -2,6 +2,7 @@ import type { Language, LanguageCategory, LanguagePlugin } from '../types'; import { createLogger } from '@/shared/utils/logger'; +import { BUILTIN_LANGUAGE_ACCENTS } from '@/shared/theme/languageIdentityAccents'; const log = createLogger('LanguageRegistry'); @@ -23,7 +24,7 @@ const BUILTIN_LANGUAGES: Language[] = [ prismId: 'typescript', lspId: 'typescript', iconType: 'typescript', - color: '#3178c6', + color: BUILTIN_LANGUAGE_ACCENTS.typescript, aliases: ['ts'], supportsComments: true, lineCommentPrefix: '//', @@ -38,7 +39,7 @@ const BUILTIN_LANGUAGES: Language[] = [ prismId: 'tsx', lspId: 'typescriptreact', iconType: 'react', - color: '#61dafb', + color: BUILTIN_LANGUAGE_ACCENTS.typescriptReact, aliases: ['tsx'], parent: 'typescript', supportsComments: true, @@ -54,7 +55,7 @@ const BUILTIN_LANGUAGES: Language[] = [ prismId: 'javascript', lspId: 'javascript', iconType: 'javascript', - color: '#f7df1e', + color: BUILTIN_LANGUAGE_ACCENTS.javascript, aliases: ['js', 'es6', 'ecmascript'], supportsComments: true, lineCommentPrefix: '//', @@ -69,7 +70,7 @@ const BUILTIN_LANGUAGES: Language[] = [ prismId: 'jsx', lspId: 'javascriptreact', iconType: 'react', - color: '#61dafb', + color: BUILTIN_LANGUAGE_ACCENTS.javascriptReact, aliases: ['jsx'], parent: 'javascript', supportsComments: true, @@ -84,7 +85,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'python', lspId: 'python', iconType: 'python', - color: '#3776ab', + color: BUILTIN_LANGUAGE_ACCENTS.python, aliases: ['py', 'python3'], supportsComments: true, lineCommentPrefix: '#', @@ -98,7 +99,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'rust', lspId: 'rust', iconType: 'rust', - color: '#ce422b', + color: BUILTIN_LANGUAGE_ACCENTS.rust, supportsComments: true, lineCommentPrefix: '//', blockComment: { start: '/*', end: '*/' }, @@ -111,7 +112,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'go', lspId: 'go', iconType: 'go', - color: '#00add8', + color: BUILTIN_LANGUAGE_ACCENTS.go, aliases: ['golang'], supportsComments: true, lineCommentPrefix: '//', @@ -125,7 +126,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'java', lspId: 'java', iconType: 'java', - color: '#b07219', + color: BUILTIN_LANGUAGE_ACCENTS.java, supportsComments: true, lineCommentPrefix: '//', blockComment: { start: '/*', end: '*/' }, @@ -138,7 +139,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'kotlin', lspId: 'kotlin', iconType: 'kotlin', - color: '#a97bff', + color: BUILTIN_LANGUAGE_ACCENTS.kotlin, supportsComments: true, lineCommentPrefix: '//', blockComment: { start: '/*', end: '*/' }, @@ -151,7 +152,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'cpp', lspId: 'cpp', iconType: 'c-cpp', - color: '#f34b7d', + color: BUILTIN_LANGUAGE_ACCENTS.cpp, aliases: ['c++', 'cplusplus'], supportsComments: true, lineCommentPrefix: '//', @@ -165,7 +166,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'c', lspId: 'c', iconType: 'c-cpp', - color: '#555555', + color: BUILTIN_LANGUAGE_ACCENTS.c, supportsComments: true, lineCommentPrefix: '//', blockComment: { start: '/*', end: '*/' }, @@ -178,7 +179,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'csharp', lspId: 'csharp', iconType: 'csharp', - color: '#178600', + color: BUILTIN_LANGUAGE_ACCENTS.csharp, aliases: ['c#', 'dotnet'], supportsComments: true, lineCommentPrefix: '//', @@ -192,7 +193,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'swift', lspId: 'swift', iconType: 'swift', - color: '#f05138', + color: BUILTIN_LANGUAGE_ACCENTS.swift, supportsComments: true, lineCommentPrefix: '//', blockComment: { start: '/*', end: '*/' }, @@ -205,7 +206,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'php', lspId: 'php', iconType: 'php', - color: '#4f5d95', + color: BUILTIN_LANGUAGE_ACCENTS.php, supportsComments: true, lineCommentPrefix: '//', blockComment: { start: '/*', end: '*/' }, @@ -219,7 +220,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'ruby', lspId: 'ruby', iconType: 'ruby', - color: '#cc342d', + color: BUILTIN_LANGUAGE_ACCENTS.ruby, supportsComments: true, lineCommentPrefix: '#', blockComment: { start: '=begin', end: '=end' }, @@ -232,7 +233,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'scala', lspId: 'scala', iconType: 'scala', - color: '#c22d40', + color: BUILTIN_LANGUAGE_ACCENTS.scala, supportsComments: true, lineCommentPrefix: '//', blockComment: { start: '/*', end: '*/' }, @@ -245,7 +246,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'dart', lspId: 'dart', iconType: 'dart', - color: '#00b4ab', + color: BUILTIN_LANGUAGE_ACCENTS.dart, supportsComments: true, lineCommentPrefix: '//', blockComment: { start: '/*', end: '*/' }, @@ -258,7 +259,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'lua', lspId: 'lua', iconType: 'lua', - color: '#000080', + color: BUILTIN_LANGUAGE_ACCENTS.lua, supportsComments: true, lineCommentPrefix: '--', blockComment: { start: '--[[', end: ']]' }, @@ -271,7 +272,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'r', lspId: 'r', iconType: 'r', - color: '#198ce7', + color: BUILTIN_LANGUAGE_ACCENTS.r, supportsComments: true, lineCommentPrefix: '#', }, @@ -287,7 +288,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'html', lspId: 'html', iconType: 'html', - color: '#e34c26', + color: BUILTIN_LANGUAGE_ACCENTS.html, supportsComments: true, blockComment: { start: '' }, }, @@ -298,7 +299,7 @@ const BUILTIN_LANGUAGES: Language[] = [ extensions: ['xml', 'xsl', 'xslt', 'xsd', 'svg', 'rss', 'atom'], monacoId: 'xml', iconType: 'xml', - color: '#0060ac', + color: BUILTIN_LANGUAGE_ACCENTS.xml, supportsComments: true, blockComment: { start: '' }, }, @@ -310,7 +311,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'vue', lspId: 'vue', iconType: 'vue', - color: '#41b883', + color: BUILTIN_LANGUAGE_ACCENTS.vue, supportsComments: true, blockComment: { start: '' }, }, @@ -322,7 +323,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'html', lspId: 'svelte', iconType: 'svelte', - color: '#ff3e00', + color: BUILTIN_LANGUAGE_ACCENTS.svelte, supportsComments: true, blockComment: { start: '' }, }, @@ -338,7 +339,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'css', lspId: 'css', iconType: 'css', - color: '#563d7c', + color: BUILTIN_LANGUAGE_ACCENTS.css, supportsComments: true, blockComment: { start: '/*', end: '*/' }, }, @@ -350,7 +351,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'scss', lspId: 'scss', iconType: 'sass', - color: '#c6538c', + color: BUILTIN_LANGUAGE_ACCENTS.scss, parent: 'css', supportsComments: true, lineCommentPrefix: '//', @@ -363,7 +364,7 @@ const BUILTIN_LANGUAGES: Language[] = [ extensions: ['sass'], monacoId: 'scss', iconType: 'sass', - color: '#c6538c', + color: BUILTIN_LANGUAGE_ACCENTS.sass, parent: 'css', supportsComments: true, lineCommentPrefix: '//', @@ -376,7 +377,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'less', lspId: 'less', iconType: 'less', - color: '#1d365d', + color: BUILTIN_LANGUAGE_ACCENTS.less, parent: 'css', supportsComments: true, lineCommentPrefix: '//', @@ -394,7 +395,7 @@ const BUILTIN_LANGUAGES: Language[] = [ filenames: ['.babelrc', '.eslintrc', '.prettierrc', 'tsconfig.json', 'package.json'], monacoId: 'json', iconType: 'json', - color: '#cbcb41', + color: BUILTIN_LANGUAGE_ACCENTS.json, supportsComments: false, }, { @@ -405,7 +406,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'yaml', lspId: 'yaml', iconType: 'yaml', - color: '#cb171e', + color: BUILTIN_LANGUAGE_ACCENTS.yaml, supportsComments: true, lineCommentPrefix: '#', }, @@ -417,7 +418,7 @@ const BUILTIN_LANGUAGES: Language[] = [ filenames: ['Cargo.toml', 'pyproject.toml'], monacoId: 'toml', iconType: 'toml', - color: '#9c4121', + color: BUILTIN_LANGUAGE_ACCENTS.toml, supportsComments: true, lineCommentPrefix: '#', }, @@ -429,7 +430,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'sql', lspId: 'sql', iconType: 'database', - color: '#e38c00', + color: BUILTIN_LANGUAGE_ACCENTS.sql, supportsComments: true, lineCommentPrefix: '--', blockComment: { start: '/*', end: '*/' }, @@ -441,7 +442,7 @@ const BUILTIN_LANGUAGES: Language[] = [ extensions: ['graphql', 'gql'], monacoId: 'graphql', iconType: 'graphql', - color: '#e10098', + color: BUILTIN_LANGUAGE_ACCENTS.graphql, supportsComments: true, lineCommentPrefix: '#', }, @@ -457,7 +458,7 @@ const BUILTIN_LANGUAGES: Language[] = [ filenames: ['Dockerfile', 'Dockerfile.dev', 'Dockerfile.prod'], monacoId: 'dockerfile', iconType: 'docker', - color: '#2496ed', + color: BUILTIN_LANGUAGE_ACCENTS.dockerfile, supportsComments: true, lineCommentPrefix: '#', }, @@ -469,7 +470,7 @@ const BUILTIN_LANGUAGES: Language[] = [ filenames: ['Makefile', 'makefile', 'GNUmakefile'], monacoId: 'makefile', iconType: 'makefile', - color: '#427819', + color: BUILTIN_LANGUAGE_ACCENTS.makefile, supportsComments: true, lineCommentPrefix: '#', }, @@ -481,7 +482,7 @@ const BUILTIN_LANGUAGES: Language[] = [ filenames: ['.editorconfig', '.gitconfig'], monacoId: 'ini', iconType: 'config', - color: '#d1dbe0', + color: BUILTIN_LANGUAGE_ACCENTS.ini, supportsComments: true, lineCommentPrefix: ';', }, @@ -493,7 +494,7 @@ const BUILTIN_LANGUAGES: Language[] = [ filenames: ['.env', '.env.local', '.env.development', '.env.production'], monacoId: 'ini', iconType: 'config', - color: '#ecd53f', + color: BUILTIN_LANGUAGE_ACCENTS.env, supportsComments: true, lineCommentPrefix: '#', }, @@ -510,7 +511,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'shell', lspId: 'shellscript', iconType: 'shell', - color: '#89e051', + color: BUILTIN_LANGUAGE_ACCENTS.shell, aliases: ['bash', 'zsh'], supportsComments: true, lineCommentPrefix: '#', @@ -523,7 +524,7 @@ const BUILTIN_LANGUAGES: Language[] = [ monacoId: 'powershell', lspId: 'powershell', iconType: 'powershell', - color: '#012456', + color: BUILTIN_LANGUAGE_ACCENTS.powershell, supportsComments: true, lineCommentPrefix: '#', blockComment: { start: '<#', end: '#>' }, @@ -535,7 +536,7 @@ const BUILTIN_LANGUAGES: Language[] = [ extensions: ['bat', 'cmd'], monacoId: 'bat', iconType: 'batch', - color: '#c1f12e', + color: BUILTIN_LANGUAGE_ACCENTS.batch, supportsComments: true, lineCommentPrefix: 'REM', }, @@ -551,7 +552,7 @@ const BUILTIN_LANGUAGES: Language[] = [ filenames: ['README', 'CHANGELOG', 'LICENSE'], monacoId: 'markdown', iconType: 'markdown', - color: '#083fa1', + color: BUILTIN_LANGUAGE_ACCENTS.markdown, supportsComments: false, }, { @@ -561,7 +562,7 @@ const BUILTIN_LANGUAGES: Language[] = [ extensions: ['rst'], monacoId: 'restructuredtext', iconType: 'text', - color: '#141414', + color: BUILTIN_LANGUAGE_ACCENTS.restructuredtext, supportsComments: true, blockComment: { start: '..', end: '' }, }, @@ -576,7 +577,7 @@ const BUILTIN_LANGUAGES: Language[] = [ extensions: ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp', 'svg', 'ico', 'avif', 'tiff', 'tif'], monacoId: 'plaintext', iconType: 'image', - color: '#a855f7', + color: BUILTIN_LANGUAGE_ACCENTS.image, supportsComments: false, }, @@ -590,7 +591,7 @@ const BUILTIN_LANGUAGES: Language[] = [ extensions: ['mp3', 'wav', 'flac', 'aac', 'ogg', 'm4a', 'wma', 'aiff'], monacoId: 'plaintext', iconType: 'audio', - color: '#22c55e', + color: BUILTIN_LANGUAGE_ACCENTS.audio, supportsComments: false, }, @@ -604,7 +605,7 @@ const BUILTIN_LANGUAGES: Language[] = [ extensions: ['mp4', 'avi', 'mkv', 'mov', 'wmv', 'flv', 'webm', 'm4v', 'mpeg', 'mpg'], monacoId: 'plaintext', iconType: 'video', - color: '#ef4444', + color: BUILTIN_LANGUAGE_ACCENTS.video, supportsComments: false, }, @@ -618,7 +619,7 @@ const BUILTIN_LANGUAGES: Language[] = [ extensions: ['ttf', 'otf', 'woff', 'woff2', 'eot'], monacoId: 'plaintext', iconType: 'font', - color: '#f59e0b', + color: BUILTIN_LANGUAGE_ACCENTS.font, supportsComments: false, }, @@ -632,7 +633,7 @@ const BUILTIN_LANGUAGES: Language[] = [ extensions: ['zip', 'rar', '7z', 'tar', 'gz', 'bz2', 'xz', 'dmg', 'iso', 'tgz'], monacoId: 'plaintext', iconType: 'archive', - color: '#8b5cf6', + color: BUILTIN_LANGUAGE_ACCENTS.archive, supportsComments: false, }, @@ -646,7 +647,7 @@ const BUILTIN_LANGUAGES: Language[] = [ extensions: ['exe', 'dll', 'so', 'dylib', 'bin', 'dat', 'o', 'a', 'lib'], monacoId: 'plaintext', iconType: 'binary', - color: '#64748b', + color: BUILTIN_LANGUAGE_ACCENTS.binary, supportsComments: false, }, @@ -660,7 +661,7 @@ const BUILTIN_LANGUAGES: Language[] = [ extensions: ['txt', 'text', 'log'], monacoId: 'plaintext', iconType: 'text', - color: '#6e7781', + color: BUILTIN_LANGUAGE_ACCENTS.plaintext, supportsComments: false, }, ]; diff --git a/src/web-ui/src/shared/announcement-system/styles/AnnouncementToast.scss b/src/web-ui/src/shared/announcement-system/styles/AnnouncementToast.scss index aac79685ec..f3c9de20df 100644 --- a/src/web-ui/src/shared/announcement-system/styles/AnnouncementToast.scss +++ b/src/web-ui/src/shared/announcement-system/styles/AnnouncementToast.scss @@ -89,7 +89,7 @@ $toast-width: 320px; background: var(--color-bg-primary); border: 1px solid var(--border-base); border-radius: $size-radius-lg; - box-shadow: 0 6px 24px rgba(0, 0, 0, 0.14); + box-shadow: 0 6px 24px rgba(var(--color-static-black-rgb), 0.14); overflow: hidden; &--entering { diff --git a/src/web-ui/src/shared/context-system/components/ContextCard/ContextCard.scss b/src/web-ui/src/shared/context-system/components/ContextCard/ContextCard.scss index 79880e8550..f38b858ce4 100644 --- a/src/web-ui/src/shared/context-system/components/ContextCard/ContextCard.scss +++ b/src/web-ui/src/shared/context-system/components/ContextCard/ContextCard.scss @@ -338,7 +338,9 @@ &--mermaid-node { .bitfun-context-card__icon { - color: #ff3670; + --context-card-mermaid-node-icon-rgb: 255, 54, 112; + + color: rgb(var(--context-card-mermaid-node-icon-rgb)); } } diff --git a/src/web-ui/src/shared/prism/prismTheme.ts b/src/web-ui/src/shared/prism/prismTheme.ts index ff3c12b6f8..4979b90bdc 100644 --- a/src/web-ui/src/shared/prism/prismTheme.ts +++ b/src/web-ui/src/shared/prism/prismTheme.ts @@ -1,35 +1,11 @@ import type { CSSProperties } from 'react'; +import { SHARED_PRISM_COLOR_SCHEME } from '@/shared/theme/syntaxHighlightAccents'; type PrismBlockStyles = { pre: CSSProperties; code: CSSProperties; }; -const PRISM_COLOR_SCHEME = { - light: { - foreground: '#24292f', - comment: '#6e7781', - keyword: '#cf222e', - string: '#0a3069', - functionName: '#8250df', - number: '#0550ae', - tag: '#116329', - punctuation: '#57606a', - property: '#953800', - }, - dark: { - foreground: '#d4d4d4', - comment: '#6a9955', - keyword: '#c586c0', - string: '#ce9178', - functionName: '#dcdcaa', - number: '#b5cea8', - tag: '#569cd6', - punctuation: '#d4d4d4', - property: '#9cdcfe', - }, -} as const; - const PRE_KEY = 'pre[class*="language-"]' as const; const CODE_KEY = 'code[class*="language-"]' as const; @@ -37,7 +13,9 @@ export function buildSharedPrismStyle( isLight: boolean, blockStyles: PrismBlockStyles, ): Record { - const colors = isLight ? PRISM_COLOR_SCHEME.light : PRISM_COLOR_SCHEME.dark; + const colors = isLight + ? SHARED_PRISM_COLOR_SCHEME.light + : SHARED_PRISM_COLOR_SCHEME.dark; return { [PRE_KEY]: { diff --git a/src/web-ui/src/shared/services/review-team/defaults.ts b/src/web-ui/src/shared/services/review-team/defaults.ts index 0ce3ae2733..862a176c2a 100644 --- a/src/web-ui/src/shared/services/review-team/defaults.ts +++ b/src/web-ui/src/shared/services/review-team/defaults.ts @@ -6,6 +6,7 @@ import type { ReviewTokenBudgetMode, } from './types'; import { REVIEW_STRATEGY_PROFILES } from './strategy'; +import { UI_EXCEPTION_ACCENTS } from '@/shared/theme/uiExceptionAccents'; export const DEFAULT_REVIEW_TEAM_ID = 'default-review-team'; export const DEFAULT_REVIEW_TEAM_CONFIG_PATH = 'ai.review_teams.default'; @@ -99,7 +100,7 @@ export const PROMPT_BYTE_ESTIMATE_PER_FILE_BYTES = 1_800; export const PROMPT_BYTE_ESTIMATE_PER_CHANGED_LINE_BYTES = 120; export const PROMPT_BYTE_ESTIMATE_UNKNOWN_LINES_PER_FILE = 80; -export const REVIEW_TEAM_MEMBER_ACCENT_DEFAULT = '#64748b'; +export const REVIEW_TEAM_MEMBER_ACCENT_DEFAULT = UI_EXCEPTION_ACCENTS.reviewTeam.memberDefault; export const EXTRA_MEMBER_DEFAULTS = { roleName: 'Additional Specialist Reviewer', @@ -152,7 +153,7 @@ export const DEFAULT_REVIEW_TEAM_CORE_ROLES: ReviewTeamCoreRoleDefinition[] = [ 'Check boundary cases, rollback paths, and data integrity assumptions.', 'Focus on issues that can break user outcomes or product intent.', ], - accentColor: '#2563eb', + accentColor: UI_EXCEPTION_ACCENTS.reviewTeam.businessLogic, }, { key: 'performance', @@ -166,7 +167,7 @@ export const DEFAULT_REVIEW_TEAM_CORE_ROLES: ReviewTeamCoreRoleDefinition[] = [ 'Flag blocking work, N+1 patterns, and wasteful data movement.', 'Keep performance advice practical and aligned with the existing architecture.', ], - accentColor: '#d97706', + accentColor: UI_EXCEPTION_ACCENTS.reviewTeam.performance, }, { key: 'security', @@ -180,7 +181,7 @@ export const DEFAULT_REVIEW_TEAM_CORE_ROLES: ReviewTeamCoreRoleDefinition[] = [ 'Look for injection, unsafe command execution, and exposure risks.', 'Highlight concrete fixes that reduce risk without broad rewrites.', ], - accentColor: '#dc2626', + accentColor: UI_EXCEPTION_ACCENTS.reviewTeam.security, }, { key: 'architecture', @@ -194,7 +195,7 @@ export const DEFAULT_REVIEW_TEAM_CORE_ROLES: ReviewTeamCoreRoleDefinition[] = [ 'Verify API contracts, tool schemas, and transport messages stay consistent.', 'Ensure platform-agnostic code does not leak platform-specific details.', ], - accentColor: '#0891b2', + accentColor: UI_EXCEPTION_ACCENTS.reviewTeam.architecture, }, { key: 'frontend', @@ -208,7 +209,7 @@ export const DEFAULT_REVIEW_TEAM_CORE_ROLES: ReviewTeamCoreRoleDefinition[] = [ 'Check React performance patterns (memoization, virtualization, effect dependencies).', 'Flag accessibility violations and frontend-backend API contract drift.', ], - accentColor: '#059669', + accentColor: UI_EXCEPTION_ACCENTS.reviewTeam.frontend, conditional: true, }, { @@ -224,7 +225,7 @@ export const DEFAULT_REVIEW_TEAM_CORE_ROLES: ReviewTeamCoreRoleDefinition[] = [ 'Spot-check specific code locations only when a reviewer claim needs verification.', 'Ensure every surviving issue has an actionable fix or follow-up plan.', ], - accentColor: '#7c3aed', + accentColor: UI_EXCEPTION_ACCENTS.reviewTeam.judge, }, ]; diff --git a/src/web-ui/src/shared/theme/languageIdentityAccents.ts b/src/web-ui/src/shared/theme/languageIdentityAccents.ts index 3291a9706f..49ed621a27 100644 --- a/src/web-ui/src/shared/theme/languageIdentityAccents.ts +++ b/src/web-ui/src/shared/theme/languageIdentityAccents.ts @@ -1,14 +1,65 @@ // Language identity colors are data semantics, not app theme surface colors. // Keep this registry narrow and only add values that are consumed outside the // full language registry. -export const CODE_SNIPPET_LANGUAGE_ACCENTS = { - javascript: '#f7df1e', +export const BUILTIN_LANGUAGE_ACCENTS = { typescript: '#3178c6', + typescriptReact: '#61dafb', + javascript: '#f7df1e', + javascriptReact: '#61dafb', python: '#3776ab', - rust: 'var(--color-bg-primary)', + rust: '#ce422b', go: '#00add8', - java: '#007396', + java: '#b07219', + kotlin: '#a97bff', + cpp: '#f34b7d', + c: '#555555', + csharp: '#178600', + swift: '#f05138', + php: '#4f5d95', + ruby: '#cc342d', + scala: '#c22d40', + dart: '#00b4ab', + lua: '#000080', + r: '#198ce7', html: '#e34c26', + xml: '#0060ac', + vue: '#41b883', + svelte: '#ff3e00', + css: '#563d7c', + scss: '#c6538c', + sass: '#c6538c', + less: '#1d365d', + json: '#cbcb41', + yaml: '#cb171e', + toml: '#9c4121', + sql: '#e38c00', + graphql: '#e10098', + dockerfile: '#2496ed', + makefile: '#427819', + ini: '#d1dbe0', + env: '#ecd53f', + shell: '#89e051', + powershell: '#012456', + batch: '#c1f12e', + markdown: '#083fa1', + restructuredtext: '#141414', + image: '#a855f7', + audio: '#22c55e', + video: '#ef4444', + font: '#f59e0b', + archive: '#8b5cf6', + binary: '#64748b', + plaintext: '#6e7781', +} as const; + +export const CODE_SNIPPET_LANGUAGE_ACCENTS = { + javascript: BUILTIN_LANGUAGE_ACCENTS.javascript, + typescript: BUILTIN_LANGUAGE_ACCENTS.typescript, + python: BUILTIN_LANGUAGE_ACCENTS.python, + rust: 'var(--color-bg-primary)', + go: BUILTIN_LANGUAGE_ACCENTS.go, + java: '#007396', + html: BUILTIN_LANGUAGE_ACCENTS.html, css: '#1572b6', scss: '#cc6699', fallback: '#858585', diff --git a/src/web-ui/src/shared/theme/syntaxHighlightAccents.ts b/src/web-ui/src/shared/theme/syntaxHighlightAccents.ts new file mode 100644 index 0000000000..e84f20324d --- /dev/null +++ b/src/web-ui/src/shared/theme/syntaxHighlightAccents.ts @@ -0,0 +1,26 @@ +// Syntax highlight colors are renderer palettes, not app theme surface colors. +// Keep them centralized so Prism/Markdown surfaces do not carry app raw color debt. +export const SHARED_PRISM_COLOR_SCHEME = { + light: { + foreground: '#24292f', + comment: '#6e7781', + keyword: '#cf222e', + string: '#0a3069', + functionName: '#8250df', + number: '#0550ae', + tag: '#116329', + punctuation: '#57606a', + property: '#953800', + }, + dark: { + foreground: '#d4d4d4', + comment: '#6a9955', + keyword: '#c586c0', + string: '#ce9178', + functionName: '#dcdcaa', + number: '#b5cea8', + tag: '#569cd6', + punctuation: '#d4d4d4', + property: '#9cdcfe', + }, +} as const; diff --git a/src/web-ui/src/shared/theme/themeBoundaryFallbacks.ts b/src/web-ui/src/shared/theme/themeBoundaryFallbacks.ts index 15ea856350..9a76a1f509 100644 --- a/src/web-ui/src/shared/theme/themeBoundaryFallbacks.ts +++ b/src/web-ui/src/shared/theme/themeBoundaryFallbacks.ts @@ -30,3 +30,7 @@ export const MINI_APP_SCROLLBAR_FALLBACKS = { thumbHover: 'rgba(0, 0, 0, 0.28)', }, } as const; + +export const FLOWCHAT_CAPTURE_FALLBACK_COLOR = { + background: '#121214', +} as const; diff --git a/src/web-ui/src/shared/theme/uiExceptionAccents.ts b/src/web-ui/src/shared/theme/uiExceptionAccents.ts index 7beefe0e19..ed66684514 100644 --- a/src/web-ui/src/shared/theme/uiExceptionAccents.ts +++ b/src/web-ui/src/shared/theme/uiExceptionAccents.ts @@ -5,6 +5,33 @@ export const UI_EXCEPTION_ACCENTS = { generativeUi: '#38bdf8', miniApp: '#7c8cef', mermaidDiagram: '#22c55e', + agentCapability: { + docs: '#6eb88c', + testing: '#c9944d', + creative: '#e879a0', + ops: '#5ea3a3', + }, + insights: { + positive: '#6eb88c', + time: '#818cf8', + neutral: '#c9944d', + issue: '#c77070', + }, + progress: { + compacting: '#0f766e', + }, + templateContext: { + memories: '#f472b6', + }, + reviewTeam: { + memberDefault: '#64748b', + businessLogic: '#2563eb', + performance: '#d97706', + security: '#dc2626', + architecture: '#0891b2', + frontend: '#059669', + judge: '#7c3aed', + }, tealAction: '#14b8a6', todo: '#0d9488', textStroke: [ diff --git a/src/web-ui/src/tools/editor/components/DiffEditor.scss b/src/web-ui/src/tools/editor/components/DiffEditor.scss index b303a57636..b365ca806f 100644 --- a/src/web-ui/src/tools/editor/components/DiffEditor.scss +++ b/src/web-ui/src/tools/editor/components/DiffEditor.scss @@ -12,6 +12,20 @@ $_diff-error-max-width: 400px; // Main Container .diff-editor-container { + --diff-editor-added-rgb: 63, 185, 80; + --diff-editor-deleted-rgb: 248, 81, 73; + --diff-editor-added-soft-bg: rgba(var(--diff-editor-added-rgb), 0.15); + --diff-editor-deleted-soft-bg: rgba(var(--diff-editor-deleted-rgb), 0.15); + --diff-editor-added-line-bg: rgba(var(--diff-editor-added-rgb), 0.18); + --diff-editor-deleted-line-bg: rgba(var(--diff-editor-deleted-rgb), 0.18); + --diff-editor-added-emphasis-bg: rgba(var(--diff-editor-added-rgb), 0.2); + --diff-editor-deleted-emphasis-bg: rgba(var(--diff-editor-deleted-rgb), 0.2); + --diff-editor-added-border: rgba(var(--diff-editor-added-rgb), 0.3); + --diff-editor-deleted-border: rgba(var(--diff-editor-deleted-rgb), 0.3); + --diff-editor-added-char-bg: rgba(var(--diff-editor-added-rgb), 0.38); + --diff-editor-deleted-char-bg: rgba(var(--diff-editor-deleted-rgb), 0.38); + --diff-editor-modified-char-rgb: 136, 182, 255; + display: flex; flex-direction: column; width: 100%; @@ -57,14 +71,14 @@ $_diff-error-max-width: 400px; &--add { color: var(--git-color-staged); - background: rgba(63, 185, 80, 0.15); - border: 1px solid rgba(63, 185, 80, 0.3); + background: var(--diff-editor-added-soft-bg); + border: 1px solid var(--diff-editor-added-border); } &--del { color: var(--git-color-deleted); - background: rgba(248, 81, 73, 0.15); - border: 1px solid rgba(248, 81, 73, 0.3); + background: var(--diff-editor-deleted-soft-bg); + border: 1px solid var(--diff-editor-deleted-border); } } @@ -367,27 +381,27 @@ $_diff-error-max-width: 400px; // Diff Color Scheme (GitHub style) .monaco-diff-editor .line-insert { - background-color: rgba(63, 185, 80, 0.18) !important; + background-color: var(--diff-editor-added-line-bg) !important; } .monaco-diff-editor .line-delete { - background-color: rgba(248, 81, 73, 0.18) !important; + background-color: var(--diff-editor-deleted-line-bg) !important; } .monaco-diff-editor .char-insert { - background-color: rgba(63, 185, 80, 0.38) !important; + background-color: var(--diff-editor-added-char-bg) !important; border-radius: 2px; border: none !important; } .monaco-diff-editor .char-delete { - background-color: rgba(248, 81, 73, 0.38) !important; + background-color: var(--diff-editor-deleted-char-bg) !important; border-radius: 2px; border: none !important; } .monaco-diff-editor .char-modified { - background-color: rgba(136, 182, 255, 0.32) !important; + background-color: rgba(var(--diff-editor-modified-char-rgb), 0.32) !important; border-radius: 2px; border: none !important; } @@ -453,7 +467,7 @@ $_diff-error-max-width: 400px; } &.active { - background: rgba(255, 255, 255, 0.25); + background: rgba(var(--color-static-white-rgb), 0.25); } } } @@ -546,12 +560,12 @@ $_diff-error-max-width: 400px; :global { .monaco-diff-editor { .line-insert { - background-color: rgba(63, 185, 80, 0.2) !important; + background-color: var(--diff-editor-added-emphasis-bg) !important; border-left: 3px solid var(--git-color-staged); } .line-delete { - background-color: rgba(248, 81, 73, 0.2) !important; + background-color: var(--diff-editor-deleted-emphasis-bg) !important; border-left: 3px solid var(--git-color-deleted); } } @@ -579,37 +593,37 @@ $_diff-error-max-width: 400px; .diff-editor-container .monaco-diff-editor .view-overlays .line-insert, .diff-editor-container .monaco-diff-editor .editor.modified .view-overlays .line-insert, - .monaco-diff-editor .line-insert { - background-color: rgba(63, 185, 80, 0.18) !important; + .diff-editor-container .monaco-diff-editor .line-insert { + background-color: var(--diff-editor-added-line-bg) !important; } .diff-editor-container .monaco-diff-editor .view-overlays .line-delete, .diff-editor-container .monaco-diff-editor .editor.original .view-overlays .line-delete, - .monaco-diff-editor .line-delete { - background-color: rgba(248, 81, 73, 0.18) !important; + .diff-editor-container .monaco-diff-editor .line-delete { + background-color: var(--diff-editor-deleted-line-bg) !important; } .diff-editor-container .monaco-diff-editor .char-insert, - .monaco-diff-editor .char-insert { - background-color: rgba(63, 185, 80, 0.38) !important; + .diff-editor-container .monaco-diff-editor .char-insert { + background-color: var(--diff-editor-added-char-bg) !important; border-radius: 2px !important; border: none !important; } .diff-editor-container .monaco-diff-editor .char-delete, - .monaco-diff-editor .char-delete { - background-color: rgba(248, 81, 73, 0.38) !important; + .diff-editor-container .monaco-diff-editor .char-delete { + background-color: var(--diff-editor-deleted-char-bg) !important; border-radius: 2px !important; border: none !important; } - .monaco-diff-editor .view-overlays .cdr.insert, - .monaco-diff-editor .cdr.insert { - background-color: rgba(63, 185, 80, 0.18) !important; + .diff-editor-container .monaco-diff-editor .view-overlays .cdr.insert, + .diff-editor-container .monaco-diff-editor .cdr.insert { + background-color: var(--diff-editor-added-line-bg) !important; } - .monaco-diff-editor .view-overlays .cdr.delete, - .monaco-diff-editor .cdr.delete { - background-color: rgba(248, 81, 73, 0.18) !important; + .diff-editor-container .monaco-diff-editor .view-overlays .cdr.delete, + .diff-editor-container .monaco-diff-editor .cdr.delete { + background-color: var(--diff-editor-deleted-line-bg) !important; } } diff --git a/src/web-ui/src/tools/editor/components/EditorBreadcrumb.scss b/src/web-ui/src/tools/editor/components/EditorBreadcrumb.scss index 3c22dfd9ef..15c1d1fd5f 100644 --- a/src/web-ui/src/tools/editor/components/EditorBreadcrumb.scss +++ b/src/web-ui/src/tools/editor/components/EditorBreadcrumb.scss @@ -12,6 +12,8 @@ $_dropdown-width: 220px; // Breadcrumb Navigation .editor-breadcrumb { + --editor-breadcrumb-folder-rgb: 232, 181, 65; + display: flex; align-items: center; height: $_breadcrumb-height; @@ -60,7 +62,7 @@ $_dropdown-width: 220px; } &--folder .editor-breadcrumb__item-icon { - color: #e8b541; + color: rgb(var(--editor-breadcrumb-folder-rgb)); } &--file .editor-breadcrumb__item-icon { @@ -203,7 +205,7 @@ $_dropdown-width: 220px; svg { width: 14px; height: 14px; } - .lucide-folder { color: #e8b541; } + .lucide-folder { color: rgb(var(--editor-breadcrumb-folder-rgb)); } } &-name { diff --git a/src/web-ui/src/tools/editor/components/ReadOnlyCodeBlock/ReadOnlyCodeBlock.scss b/src/web-ui/src/tools/editor/components/ReadOnlyCodeBlock/ReadOnlyCodeBlock.scss index 8065355814..73243ebd1e 100644 --- a/src/web-ui/src/tools/editor/components/ReadOnlyCodeBlock/ReadOnlyCodeBlock.scss +++ b/src/web-ui/src/tools/editor/components/ReadOnlyCodeBlock/ReadOnlyCodeBlock.scss @@ -3,7 +3,8 @@ */ .readonly-code-block { - --readonly-code-selection-bg: rgba(30, 136, 229, 0.3); + --readonly-code-selection-rgb: 30, 136, 229; + --readonly-code-selection-bg: rgba(var(--readonly-code-selection-rgb), 0.3); position: relative; width: 100%; diff --git a/src/web-ui/src/tools/editor/components/StatusBarPopovers/StatusBarPopovers.scss b/src/web-ui/src/tools/editor/components/StatusBarPopovers/StatusBarPopovers.scss index d1541f6998..5aa2adc718 100644 --- a/src/web-ui/src/tools/editor/components/StatusBarPopovers/StatusBarPopovers.scss +++ b/src/web-ui/src/tools/editor/components/StatusBarPopovers/StatusBarPopovers.scss @@ -8,8 +8,8 @@ $popover-z: 360; $popover-gap: 4px; $popover-radius: 6px; - $popover-shadow: 0 4px 16px rgba(0, 0, 0, 0.35); - + $popover-shadow: 0 4px 16px rgba(var(--color-static-black-rgb), 0.35); + .status-bar-popover { position: fixed; z-index: $popover-z; @@ -24,11 +24,11 @@ color: var(--color-text-primary); transform: translateY(-100%); animation: status-bar-popover-enter 0.15s cubic-bezier(0, 0, 0.2, 1) forwards; - + &__input-wrap { padding: 8px 10px; } - + &__input { width: 100%; @@ -43,13 +43,13 @@ font-family: $font-family-mono; } } - + &__list { max-height: 280px; overflow-y: auto; padding: 4px 0; } - + &__item { display: flex; align-items: center; @@ -67,7 +67,7 @@ font-size: 12px; font-weight: 400; color: var(--color-text-primary); - + &:hover { background: var(--color-overlay-white-08); } @@ -82,7 +82,7 @@ color: var(--color-accent-400); } } - + &__item-icon { display: inline-flex; align-items: center; @@ -94,11 +94,11 @@ color: var(--color-text-muted); opacity: 0.9; } - + .status-bar-popover__item--active &__item-icon { color: var(--color-accent-400); } - + &__hint { padding: 6px 12px; font-size: 11px; @@ -106,7 +106,7 @@ border-bottom: 1px solid var(--color-border-subtle); } } - + @keyframes status-bar-popover-enter { from { opacity: 0; @@ -117,4 +117,4 @@ transform: translateY(-100%) scale(1); } } - \ No newline at end of file + diff --git a/src/web-ui/src/tools/editor/meditor/components/TiptapEditor.scss b/src/web-ui/src/tools/editor/meditor/components/TiptapEditor.scss index 3b7056c7b0..e0a8e058c4 100644 --- a/src/web-ui/src/tools/editor/meditor/components/TiptapEditor.scss +++ b/src/web-ui/src/tools/editor/meditor/components/TiptapEditor.scss @@ -1,6 +1,9 @@ @use '../../../../component-library/styles/tokens.scss' as *; .m-editor-tiptap { + --m-editor-highlight-rgb: 255, 213, 79; + --m-editor-highlight-border-rgb: 255, 193, 7; + position: relative; width: 100%; height: 100%; @@ -35,7 +38,7 @@ } &.m-editor-tiptap-block-highlighted { - background: rgba(255, 213, 79, 0.15); + background: rgba(var(--m-editor-highlight-rgb), 0.15); } } @@ -210,7 +213,7 @@ } &[data-block-id].m-editor-tiptap-block-highlighted { - border-top-color: rgba(255, 193, 7, 0.55); + border-top-color: rgba(var(--m-editor-highlight-border-rgb), 0.55); } } diff --git a/src/web-ui/src/tools/lsp/components/ReferencesPanel/ReferencesPanel.scss b/src/web-ui/src/tools/lsp/components/ReferencesPanel/ReferencesPanel.scss index 51ea104996..d4edb8c67f 100644 --- a/src/web-ui/src/tools/lsp/components/ReferencesPanel/ReferencesPanel.scss +++ b/src/web-ui/src/tools/lsp/components/ReferencesPanel/ReferencesPanel.scss @@ -15,6 +15,10 @@ } .references-panel { + --references-panel-file-icon-rgb: 127, 219, 202; + --references-panel-accent-shadow-rgb: 59, 130, 246; + --references-panel-mark-rgb: 255, 215, 0; + position: fixed; width: 500px; max-width: 90vw; @@ -152,7 +156,7 @@ flex-shrink: 0; width: 16px; height: 16px; - color: #7FDBCA; + color: rgb(var(--references-panel-file-icon-rgb)); opacity: 0.9; } } @@ -206,8 +210,8 @@ color: var(--color-text-primary); box-shadow: - inset 0 0 0 1px rgba(59, 130, 246, 0.2), - 0 2px 8px rgba(59, 130, 246, 0.1); + inset 0 0 0 1px rgba(var(--references-panel-accent-shadow-rgb), 0.2), + 0 2px 8px rgba(var(--references-panel-accent-shadow-rgb), 0.1); .references-panel__reference-icon { opacity: 1; @@ -260,8 +264,8 @@ transition: color $motion-instant ease; mark { - background: rgba(255, 215, 0, 0.2); - color: #ffd700; + background: rgba(var(--references-panel-mark-rgb), 0.2); + color: rgb(var(--references-panel-mark-rgb)); font-weight: $font-weight-semibold; } } @@ -283,15 +287,15 @@ @media (prefers-contrast: high) { .references-panel { border-width: 2px; - border-color: rgba(255, 255, 255, 0.5); + border-color: rgba(var(--color-static-white-rgb), 0.5); box-shadow: $shadow-2xl, - 0 0 0 2px rgba(0, 0, 0, 0.9); + 0 0 0 2px rgba(var(--color-static-black-rgb), 0.9); } .references-panel__reference-item:hover { background: var(--color-accent-300); - border: 1px solid rgba(59, 130, 246, 0.5); + border: 1px solid rgba(var(--references-panel-accent-shadow-rgb), 0.5); } } diff --git a/src/web-ui/src/tools/workspace/components/WorkspaceManager.css b/src/web-ui/src/tools/workspace/components/WorkspaceManager.css index 65390e834f..688ef95548 100644 --- a/src/web-ui/src/tools/workspace/components/WorkspaceManager.css +++ b/src/web-ui/src/tools/workspace/components/WorkspaceManager.css @@ -216,7 +216,7 @@ font-size: 11px; text-transform: uppercase; letter-spacing: 0.4px; - color: rgba(255, 255, 255, 0.55); + color: rgba(var(--color-static-white-rgb), 0.55); } .workspace-related-paths__list {