From d79e220d389120824643b7745869d56f7eff6c4a Mon Sep 17 00:00:00 2001 From: limityan Date: Tue, 30 Jun 2026 18:07:14 +0800 Subject: [PATCH] refactor(theme): consolidate near color values Reduce theme color literal count and specialized near-pair debt across web-ui and mobile-web. Consolidate mobile theme preset construction, align near alpha and surface values, and refresh theme governance baselines plus generated projections. --- docs/architecture/theme-token-optimization.md | 52 ++-- scripts/theme-color-governance-baseline.json | 38 +-- .../generated/startup_theme_bootstrap.json | 6 +- .../generated/theme_prompt_snapshots.json | 6 +- src/mobile-web/src/theme/ThemeProvider.tsx | 23 +- src/mobile-web/src/theme/presets/dark.ts | 292 ++++++++--------- src/mobile-web/src/theme/presets/light.ts | 294 ++++++++---------- src/mobile-web/src/theme/presets/shared.ts | 83 +++++ src/mobile-web/tsconfig.json | 1 + .../component-library/styles/_functions.scss | 4 +- .../styles/flowchat-markdown-code-vars.scss | 6 +- .../styles/flowchat-markdown-table-vars.scss | 2 +- .../src/component-library/styles/tokens.scss | 45 +-- .../infrastructure/theme/core/ThemeService.ts | 8 +- .../theme/integrations/MonacoThemeSync.ts | 6 +- .../theme/presets/china-night-theme.ts | 16 +- .../theme/presets/dark-theme.ts | 6 +- .../theme/presets/light-theme.ts | 2 +- .../theme/presets/midnight-theme.ts | 6 +- .../infrastructure/theme/presets/shared.ts | 2 +- .../theme/presets/slate-theme.ts | 4 +- .../theme/presets/themePresetOutput.test.ts | 10 +- .../shared/theme/themeBoundaryFallbacks.ts | 4 +- .../tools/editor/themes/bitfun-dark.theme.ts | 2 +- .../tools/mermaid-editor/theme/_tokens.scss | 4 +- .../theme/mermaidThemeFallbacks.test.ts | 2 +- .../theme/mermaidThemeFallbacks.ts | 23 +- .../src/tools/terminal/utils/xtermTheme.ts | 2 +- 28 files changed, 495 insertions(+), 454 deletions(-) create mode 100644 src/mobile-web/src/theme/presets/shared.ts diff --git a/docs/architecture/theme-token-optimization.md b/docs/architecture/theme-token-optimization.md index 56bad0f875..12bba43873 100644 --- a/docs/architecture/theme-token-optimization.md +++ b/docs/architecture/theme-token-optimization.md @@ -109,7 +109,7 @@ theme preset/runtime、token contract、boundary fallback、 Mermaid、Monaco/editor、Prism syntax、terminal ANSI、language identity 和 UI exception registry。 -`547` 个唯一颜色是前端生产文件的全域审计数,不是普通 app UI 的色值预算。 +`498` 个唯一颜色是前端生产文件的全域审计数,不是普通 app UI 的色值预算。 其中包含主题 preset、token contract、Mermaid、Monaco/editor、terminal、syntax、 language identity 和 UI exception 等专用 palette。真正需要继续压缩的是这些专用域 内部能被证明等价的近似色,而不是把它们直接并入普通 app semantic token。前后端职责边界 @@ -122,12 +122,12 @@ prompt snapshot 投影;CLI/TUI 颜色作为独立终端产品 surface 单独 | 指标 | 当前基线 | | --- | ---: | -| 扫描的生产前端文件数 | 1537 | +| 扫描的生产前端文件数 | 1538 | | 忽略的测试文件数 | 223 | -| 忽略的构建生成文件数 | 0 | +| 忽略的构建生成文件数 | 1 | | 包含颜色字面量的文件数 | 25 | -| 颜色字面量出现次数 | 760 | -| 唯一颜色字面量数量 | 547 | +| 颜色字面量出现次数 | 722 | +| 唯一颜色字面量数量 | 498 | | 组件或非 token 文件中的颜色出现次数 | 0 | | 组件或非 token 唯一颜色数量 | 0 | | App UI 颜色出现次数 | 0 | @@ -138,8 +138,8 @@ prompt snapshot 投影;CLI/TUI 颜色作为独立终端产品 surface 单独 | token-equivalent app literal 唯一颜色数量 | 0 | | 普通组件肉眼不可区分 near color pair | 0 | | 普通组件需证据复核的 near color pair | 0 | -| 专用域肉眼不可区分 near color pair | 1 | -| 专用域需证据复核的 near color pair | 324 | +| 专用域肉眼不可区分 near color pair | 0 | +| 专用域需证据复核的 near color pair | 195 | 当前审计未发现 CSS 变量契约层面的硬错误: @@ -188,14 +188,14 @@ prompt snapshot 投影;CLI/TUI 颜色作为独立终端产品 surface 单独 | 区域 | 当前出现次数 | 当前唯一色数 | 说明 | | --- | ---: | ---: | --- | -| Theme presets | 223 | 200 | 主题个性与 palette 映射,不作为普通 app literal 直接合并;仅在同一主题内角色可证明等价时由 preset helper 复用 | -| Token contracts | 172 | 156 | `tokens.scss` 等静态契约根 | -| Editor | 56 | 53 | Monaco/editor 专用域,不能直接泛化到 app token;组件装饰色已迁出 raw literal | -| Mermaid | 103 | 92 | Mermaid 专用渲染域 | -| Theme runtime | 39 | 39 | `ThemeService.ts` 运行时注入;暗色 card alpha fallback 和 scrollbar fallback 已收敛到现有 overlay stop | +| Theme presets | 219 | 187 | 主题个性与 palette 映射,不作为普通 app literal 直接合并;仅在同一主题内角色可证明等价时由 preset helper 复用 | +| Token contracts | 146 | 133 | `tokens.scss` 等静态契约根 | +| Editor | 55 | 50 | Monaco/editor 专用域,不能直接泛化到 app token;组件装饰色已迁出 raw literal | +| Mermaid | 98 | 82 | Mermaid 专用渲染域 | +| Theme runtime | 37 | 36 | `ThemeService.ts` 运行时注入;暗色 card alpha fallback 和 scrollbar fallback 已收敛到现有 overlay stop | | Language identity | 52 | 50 | 语言身份色,已集中到 identity registry | | Terminal | 37 | 29 | terminal/ANSI 专用域;工具命令空状态已复用 `--tool-command-empty-rgb`,不再保留独立 raw 色 | -| Boundary fallback | 22 | 21 | iframe/miniapp/截图兜底值,不作为普通 app token | +| Boundary fallback | 22 | 20 | 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 | @@ -208,26 +208,26 @@ theme preset 或 boundary fallback 误算成普通 app UI 债务。当前队列 | 专用域 | 肉眼不可区分 pair | 需证据复核 pair | 后续处理原则 | | --- | ---: | ---: | --- | -| Theme presets | 1 | 170 | 优先处理同一 theme 内 hex/rgb 完全等价和同 alpha 阶重复;保留主题个性 | -| Theme runtime | 0 | 26 | 先与静态 token 和 payload contract 对齐,避免 early render 或 system theme 回退 | -| Token contracts | 0 | 86 | 优先 alias 精确等价值;状态、层级和 alpha ramp 不按数值强合并 | -| Boundary fallback | 0 | 5 | 只在 iframe/截图 first paint 验证后收缩 | -| Mermaid | 0 | 30 | 需检查节点、边、文本、错误态和 light/dark Mermaid 输出 | -| Editor | 0 | 7 | 需检查 Monaco selection、diff、inline highlight 和 light/dark editor 可读性 | +| Theme presets | 0 | 109 | 优先处理同一 theme 内 hex/rgb 完全等价和同 alpha 阶重复;保留主题个性 | +| Theme runtime | 0 | 18 | 先与静态 token 和 payload contract 对齐,避免 early render 或 system theme 回退 | +| Token contracts | 0 | 50 | 优先 alias 精确等价值;状态、层级和 alpha ramp 不按数值强合并 | +| Boundary fallback | 0 | 4 | 只在 iframe/截图 first paint 验证后收缩 | +| Mermaid | 0 | 12 | 需检查节点、边、文本、错误态和 light/dark Mermaid 输出 | +| Editor | 0 | 2 | 需检查 Monaco selection、diff、inline highlight 和 light/dark editor 可读性 | | Syntax / Terminal / Generated widget / Debug overlay / UI exception / Language identity / Visual effects | 0 | 0 | 当前无 near 队列;新增会被单域 baseline 拦截 | 剩余高频文件均为专用 palette 或集中 registry: | 文件 | 颜色出现次数 | 后续处理策略 | | --- | ---: | --- | -| `src/web-ui/src/component-library/styles/tokens.scss` | 150 | 根 token 契约;优先处理同语义 alias,避免把状态/层级 ramp 按数值强合并 | -| `src/web-ui/src/tools/mermaid-editor/theme/mermaidThemeFallbacks.ts` | 72 | Mermaid 专用渲染兜底;需以节点、边、文本、错误态截图为依据 | +| `src/web-ui/src/component-library/styles/tokens.scss` | 130 | 根 token 契约;优先处理同语义 alias,避免把状态/层级 ramp 按数值强合并 | +| `src/web-ui/src/tools/mermaid-editor/theme/mermaidThemeFallbacks.ts` | 67 | Mermaid 专用渲染兜底;需以节点、边、文本、错误态截图为依据 | | `src/web-ui/src/shared/theme/languageIdentityAccents.ts` | 52 | 内置 language/file identity registry;调用方复用常量 | -| `src/web-ui/src/tools/editor/themes/bitfun-dark.theme.ts` | 47 | Monaco theme palette;不拆散到普通 app token | -| `src/web-ui/src/infrastructure/theme/core/ThemeService.ts` | 39 | 运行时注入;需保持 early render、system theme 和 payload 导出兼容 | +| `src/web-ui/src/tools/editor/themes/bitfun-dark.theme.ts` | 46 | Monaco theme palette;不拆散到普通 app token | +| `src/web-ui/src/infrastructure/theme/core/ThemeService.ts` | 37 | 运行时注入;需保持 early render、system theme 和 payload 导出兼容 | | `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/infrastructure/theme/presets/slate-theme.ts` | 31 | theme preset palette;保留主题个性和 alpha ramp 边界 | +| `src/web-ui/src/infrastructure/theme/presets/slate-theme.ts` | 30 | theme preset palette;保留主题个性和 alpha ramp 边界 | 组件级 `var(--token, fallback)` 已收敛到 0;原先的 7 个 fallback token 不再需要 fallback contract registry 保留。 @@ -290,8 +290,8 @@ Phase 6 防回退约束: | --- | ---: | ---: | --- | | `nearPairs.indistinguishableTotal` | 0 | 0 | 阻止新增普通组件肉眼不可区分 pair 未被合并或记录 | | `nearPairs.nearTotal` | 0 | 0 | 阻止新增普通组件 near color 债务;新增必须合并、归类或记录理由 | -| `colorDomainNearPairs.indistinguishableTotal` | 1 | 1 | 控制专用域肉眼不可区分 pair 不继续增长,后续只能逐步降低或补充证据 | -| `colorDomainNearPairs.nearTotal` | 324 | 324 | 控制 theme preset/runtime/token/editor/Mermaid 等专用域 near 队列规模 | +| `colorDomainNearPairs.indistinguishableTotal` | 0 | 0 | 控制专用域肉眼不可区分 pair 不继续增长,后续只能逐步降低或补充证据 | +| `colorDomainNearPairs.nearTotal` | 195 | 195 | 控制 theme preset/runtime/token/editor/Mermaid 等专用域 near 队列规模 | | `colorScopes.appUi.uniqueColors` | 0 | 0 | 阻止普通组件 raw color 唯一色回涨 | | `colorScopes.appUi.occurrences` | 0 | 0 | 阻止普通组件 raw color 出现次数回涨 | | `tokenAliasLiterals.occurrences` | 0 | 0 | 阻止重新出现可映射到 token 的 app literal | diff --git a/scripts/theme-color-governance-baseline.json b/scripts/theme-color-governance-baseline.json index dea2461d9b..dd4aa29d96 100644 --- a/scripts/theme-color-governance-baseline.json +++ b/scripts/theme-color-governance-baseline.json @@ -105,10 +105,10 @@ "max": 0 }, "colorScopes.token.uniqueColors": { - "max": 329 + "max": 290 }, "colorScopes.exception.uniqueColors": { - "max": 269 + "max": 257 }, "cssVarDefinitions.unresolvedRequiredUnique": { "max": 0 @@ -147,28 +147,28 @@ "max": 0 }, "colorDomainNearPairs.indistinguishableTotal": { - "max": 1 + "max": 0 }, "colorDomainNearPairs.nearTotal": { - "max": 324 + "max": 195 }, "colorDomainNearPairs.themePreset.indistinguishableTotal": { - "max": 1 + "max": 0 }, "colorDomainNearPairs.themePreset.nearTotal": { - "max": 170 + "max": 109 }, "colorDomainNearPairs.themeRuntime.indistinguishableTotal": { "max": 0 }, "colorDomainNearPairs.themeRuntime.nearTotal": { - "max": 26 + "max": 18 }, "colorDomainNearPairs.tokenContract.indistinguishableTotal": { "max": 0 }, "colorDomainNearPairs.tokenContract.nearTotal": { - "max": 86 + "max": 50 }, "colorDomainNearPairs.generatedWidget.indistinguishableTotal": { "max": 0 @@ -180,19 +180,19 @@ "max": 0 }, "colorDomainNearPairs.boundaryFallback.nearTotal": { - "max": 5 + "max": 4 }, "colorDomainNearPairs.mermaid.indistinguishableTotal": { "max": 0 }, "colorDomainNearPairs.mermaid.nearTotal": { - "max": 30 + "max": 12 }, "colorDomainNearPairs.editor.indistinguishableTotal": { "max": 0 }, "colorDomainNearPairs.editor.nearTotal": { - "max": 7 + "max": 2 }, "colorDomainNearPairs.syntax.indistinguishableTotal": { "max": 0 @@ -237,16 +237,16 @@ "max": 0 }, "colorDomainScopes.themePreset.occurrences": { - "max": 223 + "max": 219 }, "colorDomainScopes.themePreset.uniqueColors": { - "max": 200 + "max": 187 }, "colorDomainScopes.themeRuntime.occurrences": { - "max": 39 + "max": 37 }, "colorDomainScopes.tokenContract.occurrences": { - "max": 172 + "max": 146 }, "colorDomainScopes.generatedWidget.occurrences": { "max": 0 @@ -258,10 +258,10 @@ "max": 22 }, "colorDomainScopes.boundaryFallback.uniqueColors": { - "max": 21 + "max": 20 }, "colorDomainScopes.editor.occurrences": { - "max": 56 + "max": 55 }, "colorDomainScopes.syntax.occurrences": { "max": 18 @@ -294,10 +294,10 @@ "max": 0 }, "colorDomainScopes.mermaid.occurrences": { - "max": 103 + "max": 98 }, "colorDomainScopes.mermaid.uniqueColors": { - "max": 92 + "max": 82 } } } diff --git a/src/apps/desktop/src/generated/startup_theme_bootstrap.json b/src/apps/desktop/src/generated/startup_theme_bootstrap.json index 55dffe1005..f4f8d0aa72 100644 --- a/src/apps/desktop/src/generated/startup_theme_bootstrap.json +++ b/src/apps/desktop/src/generated/startup_theme_bootstrap.json @@ -37,7 +37,7 @@ "id": "bitfun-midnight", "bgPrimary": "#2b2d30", "bgSecondary": "#1e1f22", - "bgScene": "#27292c", + "bgScene": "#2b2d30", "isLight": false, "textPrimary": "#bcbec4", "textMuted": "#6f737a", @@ -55,9 +55,9 @@ }, { "id": "bitfun-china-night", - "bgPrimary": "#1a1814", + "bgPrimary": "#1a1a1a", "bgSecondary": "#212019", - "bgScene": "#1e1c17", + "bgScene": "#1a1a1a", "isLight": false, "textPrimary": "#e8e6e1", "textMuted": "#928f89", diff --git a/src/crates/assembly/core/src/agentic/tools/implementations/generated/theme_prompt_snapshots.json b/src/crates/assembly/core/src/agentic/tools/implementations/generated/theme_prompt_snapshots.json index 16cd9ccadb..0430df1dc8 100644 --- a/src/crates/assembly/core/src/agentic/tools/implementations/generated/theme_prompt_snapshots.json +++ b/src/crates/assembly/core/src/agentic/tools/implementations/generated/theme_prompt_snapshots.json @@ -59,7 +59,7 @@ "themeType": "dark", "bgPrimary": "#2b2d30", "bgSecondary": "#1e1f22", - "bgScene": "#27292c", + "bgScene": "#2b2d30", "textPrimary": "#bcbec4", "textMuted": "#6f737a", "accent500": "#58a6ff", @@ -91,9 +91,9 @@ { "id": "bitfun-china-night", "themeType": "dark", - "bgPrimary": "#1a1814", + "bgPrimary": "#1a1a1a", "bgSecondary": "#212019", - "bgScene": "#1e1c17", + "bgScene": "#1a1a1a", "textPrimary": "#e8e6e1", "textMuted": "#928f89", "accent500": "#73a5cc", diff --git a/src/mobile-web/src/theme/ThemeProvider.tsx b/src/mobile-web/src/theme/ThemeProvider.tsx index 6298aaa080..a1b069e1ab 100644 --- a/src/mobile-web/src/theme/ThemeProvider.tsx +++ b/src/mobile-web/src/theme/ThemeProvider.tsx @@ -19,19 +19,16 @@ const themeMap: Record> = { light: lightTheme, }; -const themeColors: Record = { - dark: '#121214', - light: '#f2f2f7', -}; +const BACKGROUND_KEY = '--color-bg-primary'; +const TEXT_KEY = '--color-text-primary'; -const textColors: Record = { - dark: '#e8e8e8', - light: '#1c1c1e', -}; +function getThemeValue(id: ThemeId, key: string): string { + return themeMap[id][key]; +} function buildThemeCSS(id: ThemeId, vars: Record): string { - const bg = themeColors[id]; - const fg = textColors[id]; + const bg = getThemeValue(id, BACKGROUND_KEY); + const fg = getThemeValue(id, TEXT_KEY); const parts: string[] = [':root {']; for (const [key, value] of Object.entries(vars)) { parts.push(` ${key}: ${value};`); @@ -79,13 +76,13 @@ function commitThemeDOM(id: ThemeId) { body.setAttribute('data-theme', id); // 4. Inline style fallbacks (highest specificity) - body.style.backgroundColor = themeColors[id]; - body.style.color = textColors[id]; + body.style.backgroundColor = getThemeValue(id, BACKGROUND_KEY); + body.style.color = getThemeValue(id, TEXT_KEY); // 5. Update const meta = document.querySelector('meta[name="theme-color"]'); if (meta) { - meta.setAttribute('content', themeColors[id]); + meta.setAttribute('content', getThemeValue(id, BACKGROUND_KEY)); meta.removeAttribute('media'); } } diff --git a/src/mobile-web/src/theme/presets/dark.ts b/src/mobile-web/src/theme/presets/dark.ts index d10e8f6427..72c212df06 100644 --- a/src/mobile-web/src/theme/presets/dark.ts +++ b/src/mobile-web/src/theme/presets/dark.ts @@ -1,100 +1,127 @@ -export const darkTheme: Record = { - '--color-bg-primary': '#121214', - '--color-bg-secondary': '#18181a', - '--color-bg-tertiary': '#121214', - '--color-bg-quaternary': '#202024', - '--color-bg-elevated': '#18181a', - '--color-bg-workbench': '#121214', - '--color-bg-scene': '#16161a', - '--color-bg-flowchat': '#16161a', - '--color-bg-tooltip': 'rgba(30, 30, 32, 0.92)', - - '--color-text-primary': '#e8e8e8', - '--color-text-secondary': '#b0b0b0', - '--color-text-muted': '#858585', - '--color-text-disabled': '#555555', - - '--element-bg-subtle': 'rgba(255, 255, 255, 0.06)', - '--element-bg-soft': 'rgba(255, 255, 255, 0.10)', - '--element-bg-base': 'rgba(255, 255, 255, 0.13)', - '--element-bg-medium': 'rgba(255, 255, 255, 0.17)', - '--element-bg-strong': 'rgba(255, 255, 255, 0.21)', - '--element-bg-elevated': 'rgba(255, 255, 255, 0.25)', - - '--color-accent-50': 'rgba(96, 165, 250, 0.04)', - '--color-accent-100': 'rgba(96, 165, 250, 0.08)', - '--color-accent-200': 'rgba(96, 165, 250, 0.15)', - '--color-accent-300': 'rgba(96, 165, 250, 0.25)', - '--color-accent-400': 'rgba(96, 165, 250, 0.4)', - '--color-accent-500': '#60a5fa', - '--color-accent-600': '#3b82f6', - '--color-accent-700': 'rgba(59, 130, 246, 0.8)', - '--color-accent-800': 'rgba(59, 130, 246, 0.9)', - - '--color-purple-50': 'rgba(139, 92, 246, 0.04)', - '--color-purple-100': 'rgba(139, 92, 246, 0.08)', - '--color-purple-200': 'rgba(139, 92, 246, 0.15)', - '--color-purple-300': 'rgba(139, 92, 246, 0.25)', - '--color-purple-400': 'rgba(139, 92, 246, 0.4)', - '--color-purple-500': '#8b5cf6', - '--color-purple-600': '#7c3aed', - '--color-purple-700': 'rgba(124, 58, 237, 0.8)', - '--color-purple-800': 'rgba(124, 58, 237, 0.9)', - - '--color-pink-50': 'rgba(236, 72, 153, 0.04)', - '--color-pink-100': 'rgba(236, 72, 153, 0.08)', - '--color-pink-200': 'rgba(236, 72, 153, 0.15)', - '--color-pink-300': 'rgba(236, 72, 153, 0.25)', - '--color-pink-400': 'rgba(236, 72, 153, 0.4)', - '--color-pink-500': '#ec4899', - '--color-pink-600': '#db2777', - '--color-pink-700': 'rgba(219, 39, 119, 0.8)', - '--color-pink-800': 'rgba(219, 39, 119, 0.9)', - - '--color-orange-50': 'rgba(249, 115, 22, 0.04)', - '--color-orange-100': 'rgba(249, 115, 22, 0.08)', - '--color-orange-200': 'rgba(249, 115, 22, 0.15)', - '--color-orange-300': 'rgba(249, 115, 22, 0.25)', - '--color-orange-400': 'rgba(249, 115, 22, 0.4)', - '--color-orange-500': '#f97316', - '--color-orange-600': '#ea580c', - '--color-orange-700': 'rgba(234, 88, 12, 0.8)', - '--color-orange-800': 'rgba(234, 88, 12, 0.9)', - - '--color-success': '#34d399', - '--color-success-bg': 'rgba(52, 211, 153, 0.1)', - '--color-success-border': 'rgba(52, 211, 153, 0.3)', - '--color-warning': '#f59e0b', - '--color-warning-bg': 'rgba(245, 158, 11, 0.1)', - '--color-warning-border': 'rgba(245, 158, 11, 0.3)', - '--color-error': '#ef4444', - '--color-error-bg': 'rgba(239, 68, 68, 0.1)', - '--color-error-border': 'rgba(239, 68, 68, 0.3)', - '--color-info': '#E1AB80', - '--color-info-bg': 'rgba(225, 171, 128, 0.1)', - '--color-info-border': 'rgba(225, 171, 128, 0.3)', - - '--color-highlight': '#d4a574', - '--color-highlight-bg': 'rgba(212, 165, 116, 0.15)', - '--color-overlay': 'rgba(0, 0, 0, 0.5)', - - '--border-subtle': 'rgba(255, 255, 255, 0.12)', - '--border-base': 'rgba(255, 255, 255, 0.18)', - '--border-medium': 'rgba(255, 255, 255, 0.24)', - '--border-strong': 'rgba(255, 255, 255, 0.32)', - '--border-prominent': 'rgba(225, 171, 128, 0.50)', - - '--glow-blue': '0 12px 32px rgba(225, 171, 128, 0.25), 0 6px 16px rgba(225, 171, 128, 0.18), 0 3px 8px rgba(0, 0, 0, 0.1)', - '--glow-purple': '0 12px 32px rgba(139, 92, 246, 0.25), 0 6px 16px rgba(124, 58, 237, 0.18), 0 3px 8px rgba(0, 0, 0, 0.1)', - '--glow-orange': '0 12px 32px rgba(249, 115, 22, 0.25), 0 6px 16px rgba(234, 88, 12, 0.18), 0 3px 8px rgba(0, 0, 0, 0.1)', - '--glow-mixed': '0 12px 32px rgba(225, 171, 128, 0.2), 0 6px 16px rgba(139, 92, 246, 0.15), 0 3px 8px rgba(0, 0, 0, 0.1)', - - '--shadow-xs': '0 1px 2px rgba(0, 0, 0, 0.9)', - '--shadow-sm': '0 2px 4px rgba(0, 0, 0, 0.8)', - '--shadow-base': '0 4px 8px rgba(0, 0, 0, 0.7)', - '--shadow-lg': '0 8px 16px rgba(0, 0, 0, 0.6)', - '--shadow-xl': '0 12px 24px rgba(0, 0, 0, 0.5)', - '--shadow-2xl': '0 16px 32px rgba(0, 0, 0, 0.4)', +import { + alpha, + colorRamp, + commonMobileThemeVars, + shadow, + TRANSPARENT, + type MobileThemeVars, +} from './shared'; + +const BLACK = '0, 0, 0'; +const WHITE = '255, 255, 255'; +const ACCENT = '96, 165, 250'; +const ACCENT_STRONG = '59, 130, 246'; +const PURPLE = '139, 92, 246'; +const PURPLE_STRONG = '124, 58, 237'; +const PINK = '236, 72, 153'; +const PINK_STRONG = '219, 39, 119'; +const ORANGE = '249, 115, 22'; +const ORANGE_STRONG = '234, 88, 12'; +const SUCCESS = '52, 211, 153'; +const WARNING = '245, 158, 11'; +const ERROR = '239, 68, 68'; +const INFO = '225, 171, 128'; + +const BG_PRIMARY = '#121214'; +const BG_SECONDARY = '#18181a'; +const BG_SCENE = '#16161a'; +const BG_QUATERNARY = '#202024'; +const TEXT_PRIMARY = '#e8e8e8'; +const TEXT_SECONDARY = '#b0b0b0'; +const TEXT_MUTED = '#858585'; +const TEXT_DISABLED = '#555555'; +const ACCENT_500 = '#60a5fa'; +const ACCENT_600 = '#3b82f6'; +const PURPLE_500 = '#8b5cf6'; +const PURPLE_600 = '#7c3aed'; +const PINK_500 = '#ec4899'; +const PINK_600 = '#db2777'; +const ORANGE_500 = '#f97316'; +const ORANGE_600 = '#ea580c'; +const SUCCESS_500 = '#34d399'; +const WARNING_500 = '#f59e0b'; +const ERROR_500 = '#ef4444'; +const INFO_500 = '#e1ab80'; +const INFO_HOVER = '#f6d0a3'; + +export const darkTheme: MobileThemeVars = { + '--color-bg-primary': BG_PRIMARY, + '--color-bg-secondary': BG_SECONDARY, + '--color-bg-tertiary': BG_PRIMARY, + '--color-bg-quaternary': BG_QUATERNARY, + '--color-bg-elevated': BG_SECONDARY, + '--color-bg-workbench': BG_PRIMARY, + '--color-bg-scene': BG_SCENE, + '--color-bg-flowchat': BG_SCENE, + '--color-bg-tooltip': alpha('30, 30, 32', '0.92'), + + '--color-text-primary': TEXT_PRIMARY, + '--color-text-secondary': TEXT_SECONDARY, + '--color-text-muted': TEXT_MUTED, + '--color-text-disabled': TEXT_DISABLED, + + '--element-bg-subtle': alpha(WHITE, '0.05'), + '--element-bg-soft': alpha(WHITE, '0.095'), + '--element-bg-base': alpha(WHITE, '0.125'), + '--element-bg-medium': alpha(WHITE, '0.155'), + '--element-bg-strong': alpha(WHITE, '0.19'), + '--element-bg-elevated': alpha(WHITE, '0.24'), + + ...colorRamp('--color-accent', ACCENT, ACCENT_500, ACCENT_600, ACCENT_STRONG), + ...colorRamp('--color-purple', PURPLE, PURPLE_500, PURPLE_600, PURPLE_STRONG), + ...colorRamp('--color-pink', PINK, PINK_500, PINK_600, PINK_STRONG), + ...colorRamp('--color-orange', ORANGE, ORANGE_500, ORANGE_600, ORANGE_STRONG), + + '--color-success': SUCCESS_500, + '--color-success-bg': alpha(SUCCESS, '0.1'), + '--color-success-border': alpha(SUCCESS, '0.3'), + '--color-warning': WARNING_500, + '--color-warning-bg': alpha(WARNING, '0.1'), + '--color-warning-border': alpha(WARNING, '0.3'), + '--color-error': ERROR_500, + '--color-error-bg': alpha(ERROR, '0.1'), + '--color-error-border': alpha(ERROR, '0.3'), + '--color-info': INFO_500, + '--color-info-bg': alpha(INFO, '0.1'), + '--color-info-border': alpha(INFO, '0.3'), + + '--color-highlight': INFO_500, + '--color-highlight-bg': alpha(INFO, '0.15'), + '--color-overlay': alpha(BLACK, '0.5'), + + '--border-subtle': alpha(WHITE, '0.12'), + '--border-base': alpha(WHITE, '0.18'), + '--border-medium': alpha(WHITE, '0.24'), + '--border-strong': alpha(WHITE, '0.32'), + '--border-prominent': alpha(INFO, '0.5'), + + '--glow-blue': shadow( + `0 12px 32px ${alpha(INFO, '0.25')}`, + `0 6px 16px ${alpha(INFO, '0.18')}`, + `0 3px 8px ${alpha(BLACK, '0.1')}`, + ), + '--glow-purple': shadow( + `0 12px 32px ${alpha(PURPLE, '0.25')}`, + `0 6px 16px ${alpha(PURPLE, '0.18')}`, + `0 3px 8px ${alpha(BLACK, '0.1')}`, + ), + '--glow-orange': shadow( + `0 12px 32px ${alpha(ORANGE, '0.25')}`, + `0 6px 16px ${alpha(ORANGE, '0.18')}`, + `0 3px 8px ${alpha(BLACK, '0.1')}`, + ), + '--glow-mixed': shadow( + `0 12px 32px ${alpha(INFO, '0.2')}`, + `0 6px 16px ${alpha(PURPLE, '0.15')}`, + `0 3px 8px ${alpha(BLACK, '0.1')}`, + ), + + '--shadow-xs': `0 1px 2px ${alpha(BLACK, '0.9')}`, + '--shadow-sm': `0 2px 4px ${alpha(BLACK, '0.8')}`, + '--shadow-base': `0 4px 8px ${alpha(BLACK, '0.7')}`, + '--shadow-lg': `0 8px 16px ${alpha(BLACK, '0.6')}`, + '--shadow-xl': `0 12px 24px ${alpha(BLACK, '0.5')}`, + '--shadow-2xl': `0 16px 32px ${alpha(BLACK, '0.4')}`, '--blur-subtle': 'blur(4px) saturate(1.05)', '--blur-base': 'blur(8px) saturate(1.1)', @@ -102,71 +129,24 @@ export const darkTheme: Record = { '--blur-strong': 'blur(16px) saturate(1.3) brightness(1.1)', '--blur-intense': 'blur(20px) saturate(1.4) brightness(1.15)', - '--size-radius-sm': '6px', - '--size-radius-base': '8px', - '--size-radius-lg': '12px', - '--size-radius-xl': '16px', - '--size-radius-2xl': '20px', - '--size-radius-full': '9999px', - - '--size-gap-1': '4px', - '--size-gap-2': '8px', - '--size-gap-3': '12px', - '--size-gap-4': '16px', - '--size-gap-5': '20px', - '--size-gap-6': '24px', - '--size-gap-8': '32px', - '--size-gap-10': '40px', - '--size-gap-12': '48px', - '--size-gap-16': '64px', - - '--motion-instant': '0.1s', - '--motion-fast': '0.15s', - '--motion-base': '0.3s', - '--motion-slow': '0.6s', - '--motion-lazy': '1s', - - '--easing-standard': 'cubic-bezier(0.4, 0, 0.2, 1)', - '--easing-decelerate': 'cubic-bezier(0, 0, 0.2, 1)', - '--easing-accelerate': 'cubic-bezier(0.4, 0, 1, 1)', - '--easing-bounce': 'cubic-bezier(0.68, -0.55, 0.265, 1.55)', - '--easing-smooth': 'cubic-bezier(0.4, 0, 0.2, 1)', - - '--font-family-sans': "'Noto Sans SC', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'SF Pro Display', Roboto, sans-serif", - '--font-family-mono': "'Menlo', 'SF Mono', 'Cascadia Code', 'Consolas', 'Liberation Mono', 'Courier New', 'Noto Sans Mono CJK SC', 'Noto Sans Mono', monospace", - '--font-weight-normal': '400', - '--font-weight-medium': '500', - '--font-weight-semibold': '600', - '--font-weight-bold': '700', - - '--font-size-xs': '12px', - '--font-size-sm': '14px', - '--font-size-base': '15px', - '--font-size-lg': '16px', - '--font-size-xl': '18px', - '--font-size-2xl': '20px', - '--font-size-3xl': '24px', - - '--line-height-tight': '1.2', - '--line-height-base': '1.5', - '--line-height-relaxed': '1.6', + ...commonMobileThemeVars, '--opacity-disabled': '0.6', '--opacity-hover': '0.8', '--opacity-focus': '0.9', '--opacity-overlay': '0.4', - '--scrollbar-thumb': 'rgba(255, 255, 255, 0.15)', - '--scrollbar-thumb-hover': 'rgba(255, 255, 255, 0.28)', + '--scrollbar-thumb': alpha(WHITE, '0.15'), + '--scrollbar-thumb-hover': alpha(WHITE, '0.24'), - '--btn-default-bg': 'rgba(255, 255, 255, 0.08)', - '--btn-default-color': '#9a9a9a', - '--btn-hover-bg': 'rgba(255, 255, 255, 0.14)', - '--btn-hover-color': '#c8c8c8', - '--btn-primary-bg': '#E1AB80', + '--btn-default-bg': alpha(WHITE, '0.08'), + '--btn-default-color': TEXT_MUTED, + '--btn-hover-bg': alpha(WHITE, '0.12'), + '--btn-hover-color': TEXT_SECONDARY, + '--btn-primary-bg': INFO_500, '--btn-primary-color': '#000000', - '--btn-primary-hover-bg': '#F6D0A3', - '--btn-ghost-bg': 'transparent', - '--btn-ghost-color': '#9a9a9a', - '--btn-ghost-hover-bg': 'rgba(255, 255, 255, 0.10)', + '--btn-primary-hover-bg': INFO_HOVER, + '--btn-ghost-bg': TRANSPARENT, + '--btn-ghost-color': TEXT_MUTED, + '--btn-ghost-hover-bg': alpha(WHITE, '0.095'), }; diff --git a/src/mobile-web/src/theme/presets/light.ts b/src/mobile-web/src/theme/presets/light.ts index b0ae6fd3ba..938eaccc06 100644 --- a/src/mobile-web/src/theme/presets/light.ts +++ b/src/mobile-web/src/theme/presets/light.ts @@ -1,100 +1,125 @@ -export const lightTheme: Record = { - '--color-bg-primary': '#f2f2f7', - '--color-bg-secondary': '#ffffff', - '--color-bg-tertiary': '#f2f2f7', - '--color-bg-quaternary': '#e5e5ea', - '--color-bg-elevated': '#ffffff', - '--color-bg-workbench': '#f2f2f7', - '--color-bg-scene': '#ffffff', - '--color-bg-flowchat': '#ffffff', - '--color-bg-tooltip': 'rgba(255, 255, 255, 0.98)', - - '--color-text-primary': '#1c1c1e', - '--color-text-secondary': '#48484a', - '--color-text-muted': '#8e8e93', - '--color-text-disabled': '#aeaeb2', - - '--element-bg-subtle': 'rgba(120, 120, 128, 0.04)', - '--element-bg-soft': 'rgba(120, 120, 128, 0.08)', - '--element-bg-base': 'rgba(120, 120, 128, 0.10)', - '--element-bg-medium': 'rgba(120, 120, 128, 0.14)', - '--element-bg-strong': 'rgba(120, 120, 128, 0.20)', - '--element-bg-elevated': 'rgba(255, 255, 255, 0.94)', - - '--color-accent-50': 'rgba(0, 122, 255, 0.04)', - '--color-accent-100': 'rgba(0, 122, 255, 0.08)', - '--color-accent-200': 'rgba(0, 122, 255, 0.14)', - '--color-accent-300': 'rgba(0, 122, 255, 0.22)', - '--color-accent-400': 'rgba(0, 122, 255, 0.36)', - '--color-accent-500': '#007AFF', - '--color-accent-600': '#0066CC', - '--color-accent-700': 'rgba(0, 102, 204, 0.8)', - '--color-accent-800': 'rgba(0, 102, 204, 0.9)', - - '--color-purple-50': 'rgba(175, 82, 222, 0.04)', - '--color-purple-100': 'rgba(175, 82, 222, 0.08)', - '--color-purple-200': 'rgba(175, 82, 222, 0.14)', - '--color-purple-300': 'rgba(175, 82, 222, 0.22)', - '--color-purple-400': 'rgba(175, 82, 222, 0.36)', - '--color-purple-500': '#AF52DE', - '--color-purple-600': '#9536CC', - '--color-purple-700': 'rgba(149, 54, 204, 0.8)', - '--color-purple-800': 'rgba(149, 54, 204, 0.9)', - - '--color-pink-50': 'rgba(236, 72, 153, 0.04)', - '--color-pink-100': 'rgba(236, 72, 153, 0.08)', - '--color-pink-200': 'rgba(236, 72, 153, 0.14)', - '--color-pink-300': 'rgba(236, 72, 153, 0.22)', - '--color-pink-400': 'rgba(236, 72, 153, 0.36)', - '--color-pink-500': '#EC4899', - '--color-pink-600': '#DB2777', - '--color-pink-700': 'rgba(219, 39, 119, 0.8)', - '--color-pink-800': 'rgba(219, 39, 119, 0.9)', - - '--color-orange-50': 'rgba(255, 149, 0, 0.04)', - '--color-orange-100': 'rgba(255, 149, 0, 0.08)', - '--color-orange-200': 'rgba(255, 149, 0, 0.14)', - '--color-orange-300': 'rgba(255, 149, 0, 0.22)', - '--color-orange-400': 'rgba(255, 149, 0, 0.36)', - '--color-orange-500': '#FF9500', - '--color-orange-600': '#CC7A00', - '--color-orange-700': 'rgba(204, 122, 0, 0.8)', - '--color-orange-800': 'rgba(204, 122, 0, 0.9)', - - '--color-success': '#34C759', - '--color-success-bg': 'rgba(52, 199, 89, 0.08)', - '--color-success-border': 'rgba(52, 199, 89, 0.25)', - '--color-warning': '#FF9500', - '--color-warning-bg': 'rgba(255, 149, 0, 0.08)', - '--color-warning-border': 'rgba(255, 149, 0, 0.25)', - '--color-error': '#FF3B30', - '--color-error-bg': 'rgba(255, 59, 48, 0.08)', - '--color-error-border': 'rgba(255, 59, 48, 0.25)', - '--color-info': '#007AFF', - '--color-info-bg': 'rgba(0, 122, 255, 0.08)', - '--color-info-border': 'rgba(0, 122, 255, 0.25)', - - '--color-highlight': '#FF9500', - '--color-highlight-bg': 'rgba(255, 149, 0, 0.10)', - '--color-overlay': 'rgba(0, 0, 0, 0.3)', - - '--border-subtle': 'rgba(60, 60, 67, 0.08)', - '--border-base': 'rgba(60, 60, 67, 0.14)', - '--border-medium': 'rgba(60, 60, 67, 0.22)', - '--border-strong': 'rgba(60, 60, 67, 0.30)', - '--border-prominent': 'rgba(60, 60, 67, 0.40)', - - '--glow-blue': '0 2px 8px rgba(0, 122, 255, 0.08)', - '--glow-purple': '0 2px 8px rgba(175, 82, 222, 0.08)', - '--glow-orange': '0 2px 8px rgba(255, 149, 0, 0.08)', - '--glow-mixed': '0 2px 8px rgba(0, 122, 255, 0.06), 0 2px 8px rgba(175, 82, 222, 0.04)', - - '--shadow-xs': '0 1px 2px rgba(0, 0, 0, 0.04)', - '--shadow-sm': '0 1px 3px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.04)', - '--shadow-base': '0 2px 8px rgba(0, 0, 0, 0.06), 0 1px 3px rgba(0, 0, 0, 0.04)', - '--shadow-lg': '0 4px 16px rgba(0, 0, 0, 0.08), 0 2px 6px rgba(0, 0, 0, 0.04)', - '--shadow-xl': '0 8px 24px rgba(0, 0, 0, 0.10), 0 4px 8px rgba(0, 0, 0, 0.04)', - '--shadow-2xl': '0 12px 32px rgba(0, 0, 0, 0.12), 0 4px 12px rgba(0, 0, 0, 0.06)', +import { + alpha, + colorRamp, + commonMobileThemeVars, + shadow, + TRANSPARENT, + type MobileThemeVars, +} from './shared'; + +const BLACK = '0, 0, 0'; +const WHITE = '255, 255, 255'; +const IOS_NEUTRAL = '120, 120, 128'; +const BORDER = '60, 60, 67'; +const ACCENT = '0, 122, 255'; +const ACCENT_STRONG = '0, 102, 204'; +const PURPLE = '175, 82, 222'; +const PURPLE_STRONG = '149, 54, 204'; +const PINK = '236, 72, 153'; +const PINK_STRONG = '219, 39, 119'; +const ORANGE = '255, 149, 0'; +const ORANGE_STRONG = '204, 122, 0'; +const SUCCESS = '52, 199, 89'; +const ERROR = '255, 59, 48'; + +const BG_PRIMARY = '#f3f3f5'; +const BG_SECONDARY = '#ffffff'; +const BG_QUATERNARY = '#e5e5ea'; +const TEXT_PRIMARY = '#1c1c1e'; +const TEXT_SECONDARY = '#48484a'; +const TEXT_MUTED = '#8e8e93'; +const TEXT_DISABLED = '#aeaeb2'; +const ACCENT_500 = '#007aff'; +const ACCENT_600 = '#0066cc'; +const PURPLE_500 = '#af52de'; +const PURPLE_600 = '#9536cc'; +const PINK_500 = '#ec4899'; +const PINK_600 = '#db2777'; +const ORANGE_500 = '#ff9500'; +const ORANGE_600 = '#cc7a00'; +const SUCCESS_500 = '#34c759'; +const ERROR_500 = '#ff3b30'; + +export const lightTheme: MobileThemeVars = { + '--color-bg-primary': BG_PRIMARY, + '--color-bg-secondary': BG_SECONDARY, + '--color-bg-tertiary': BG_PRIMARY, + '--color-bg-quaternary': BG_QUATERNARY, + '--color-bg-elevated': BG_SECONDARY, + '--color-bg-workbench': BG_PRIMARY, + '--color-bg-scene': BG_SECONDARY, + '--color-bg-flowchat': BG_SECONDARY, + '--color-bg-tooltip': alpha(WHITE, '0.98'), + + '--color-text-primary': TEXT_PRIMARY, + '--color-text-secondary': TEXT_SECONDARY, + '--color-text-muted': TEXT_MUTED, + '--color-text-disabled': TEXT_DISABLED, + + '--element-bg-subtle': alpha(IOS_NEUTRAL, '0.04'), + '--element-bg-soft': alpha(IOS_NEUTRAL, '0.08'), + '--element-bg-base': alpha(IOS_NEUTRAL, '0.1'), + '--element-bg-medium': alpha(IOS_NEUTRAL, '0.14'), + '--element-bg-strong': alpha(IOS_NEUTRAL, '0.2'), + '--element-bg-elevated': alpha(WHITE, '0.94'), + + ...colorRamp('--color-accent', ACCENT, ACCENT_500, ACCENT_600, ACCENT_STRONG, ['0.04', '0.08', '0.14', '0.22', '0.36']), + ...colorRamp('--color-purple', PURPLE, PURPLE_500, PURPLE_600, PURPLE_STRONG, ['0.04', '0.08', '0.14', '0.22', '0.36']), + ...colorRamp('--color-pink', PINK, PINK_500, PINK_600, PINK_STRONG, ['0.04', '0.08', '0.14', '0.22', '0.36']), + ...colorRamp('--color-orange', ORANGE, ORANGE_500, ORANGE_600, ORANGE_STRONG, ['0.04', '0.08', '0.14', '0.22', '0.36']), + + '--color-success': SUCCESS_500, + '--color-success-bg': alpha(SUCCESS, '0.08'), + '--color-success-border': alpha(SUCCESS, '0.25'), + '--color-warning': ORANGE_500, + '--color-warning-bg': alpha(ORANGE, '0.08'), + '--color-warning-border': alpha(ORANGE, '0.25'), + '--color-error': ERROR_500, + '--color-error-bg': alpha(ERROR, '0.08'), + '--color-error-border': alpha(ERROR, '0.25'), + '--color-info': ACCENT_500, + '--color-info-bg': alpha(ACCENT, '0.08'), + '--color-info-border': alpha(ACCENT, '0.25'), + + '--color-highlight': ORANGE_500, + '--color-highlight-bg': alpha(ORANGE, '0.1'), + '--color-overlay': alpha(BLACK, '0.3'), + + '--border-subtle': alpha(BORDER, '0.08'), + '--border-base': alpha(BORDER, '0.14'), + '--border-medium': alpha(BORDER, '0.22'), + '--border-strong': alpha(BORDER, '0.3'), + '--border-prominent': alpha(BORDER, '0.4'), + + '--glow-blue': `0 2px 8px ${alpha(ACCENT, '0.08')}`, + '--glow-purple': `0 2px 8px ${alpha(PURPLE, '0.08')}`, + '--glow-orange': `0 2px 8px ${alpha(ORANGE, '0.08')}`, + '--glow-mixed': shadow( + `0 2px 8px ${alpha(ACCENT, '0.06')}`, + `0 2px 8px ${alpha(PURPLE, '0.04')}`, + ), + + '--shadow-xs': `0 1px 2px ${alpha(BLACK, '0.04')}`, + '--shadow-sm': shadow( + `0 1px 3px ${alpha(BLACK, '0.06')}`, + `0 1px 2px ${alpha(BLACK, '0.04')}`, + ), + '--shadow-base': shadow( + `0 2px 8px ${alpha(BLACK, '0.06')}`, + `0 1px 3px ${alpha(BLACK, '0.04')}`, + ), + '--shadow-lg': shadow( + `0 4px 16px ${alpha(BLACK, '0.08')}`, + `0 2px 6px ${alpha(BLACK, '0.04')}`, + ), + '--shadow-xl': shadow( + `0 8px 24px ${alpha(BLACK, '0.1')}`, + `0 4px 8px ${alpha(BLACK, '0.04')}`, + ), + '--shadow-2xl': shadow( + `0 12px 32px ${alpha(BLACK, '0.12')}`, + `0 4px 12px ${alpha(BLACK, '0.06')}`, + ), '--blur-subtle': 'blur(4px) saturate(1.2)', '--blur-base': 'blur(8px) saturate(1.4)', @@ -102,71 +127,24 @@ export const lightTheme: Record = { '--blur-strong': 'blur(16px) saturate(1.8)', '--blur-intense': 'blur(20px) saturate(2.0)', - '--size-radius-sm': '6px', - '--size-radius-base': '8px', - '--size-radius-lg': '12px', - '--size-radius-xl': '16px', - '--size-radius-2xl': '20px', - '--size-radius-full': '9999px', - - '--size-gap-1': '4px', - '--size-gap-2': '8px', - '--size-gap-3': '12px', - '--size-gap-4': '16px', - '--size-gap-5': '20px', - '--size-gap-6': '24px', - '--size-gap-8': '32px', - '--size-gap-10': '40px', - '--size-gap-12': '48px', - '--size-gap-16': '64px', - - '--motion-instant': '0.1s', - '--motion-fast': '0.15s', - '--motion-base': '0.3s', - '--motion-slow': '0.6s', - '--motion-lazy': '1s', - - '--easing-standard': 'cubic-bezier(0.4, 0, 0.2, 1)', - '--easing-decelerate': 'cubic-bezier(0, 0, 0.2, 1)', - '--easing-accelerate': 'cubic-bezier(0.4, 0, 1, 1)', - '--easing-bounce': 'cubic-bezier(0.68, -0.55, 0.265, 1.55)', - '--easing-smooth': 'cubic-bezier(0.4, 0, 0.2, 1)', - - '--font-family-sans': "'Noto Sans SC', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'SF Pro Display', Roboto, sans-serif", - '--font-family-mono': "'Menlo', 'SF Mono', 'Cascadia Code', 'Consolas', 'Liberation Mono', 'Courier New', 'Noto Sans Mono CJK SC', 'Noto Sans Mono', monospace", - '--font-weight-normal': '400', - '--font-weight-medium': '500', - '--font-weight-semibold': '600', - '--font-weight-bold': '700', - - '--font-size-xs': '12px', - '--font-size-sm': '14px', - '--font-size-base': '15px', - '--font-size-lg': '16px', - '--font-size-xl': '18px', - '--font-size-2xl': '20px', - '--font-size-3xl': '24px', - - '--line-height-tight': '1.2', - '--line-height-base': '1.5', - '--line-height-relaxed': '1.6', + ...commonMobileThemeVars, '--opacity-disabled': '0.55', '--opacity-hover': '0.75', '--opacity-focus': '0.9', '--opacity-overlay': '0.35', - '--scrollbar-thumb': 'rgba(0, 0, 0, 0.15)', - '--scrollbar-thumb-hover': 'rgba(0, 0, 0, 0.25)', - - '--btn-default-bg': 'rgba(120, 120, 128, 0.08)', - '--btn-default-color': '#48484a', - '--btn-hover-bg': 'rgba(120, 120, 128, 0.14)', - '--btn-hover-color': '#1c1c1e', - '--btn-primary-bg': '#007AFF', - '--btn-primary-color': '#ffffff', - '--btn-primary-hover-bg': '#0066CC', - '--btn-ghost-bg': 'transparent', - '--btn-ghost-color': '#48484a', - '--btn-ghost-hover-bg': 'rgba(120, 120, 128, 0.08)', + '--scrollbar-thumb': alpha(BLACK, '0.15'), + '--scrollbar-thumb-hover': alpha(BLACK, '0.25'), + + '--btn-default-bg': alpha(IOS_NEUTRAL, '0.08'), + '--btn-default-color': TEXT_SECONDARY, + '--btn-hover-bg': alpha(IOS_NEUTRAL, '0.14'), + '--btn-hover-color': TEXT_PRIMARY, + '--btn-primary-bg': ACCENT_500, + '--btn-primary-color': BG_SECONDARY, + '--btn-primary-hover-bg': ACCENT_600, + '--btn-ghost-bg': TRANSPARENT, + '--btn-ghost-color': TEXT_SECONDARY, + '--btn-ghost-hover-bg': alpha(IOS_NEUTRAL, '0.08'), }; diff --git a/src/mobile-web/src/theme/presets/shared.ts b/src/mobile-web/src/theme/presets/shared.ts new file mode 100644 index 0000000000..491985b89c --- /dev/null +++ b/src/mobile-web/src/theme/presets/shared.ts @@ -0,0 +1,83 @@ +export type MobileThemeVars = Record; + +export const TRANSPARENT = 'transparent'; + +export function alpha(rgb: string, opacity: string): string { + return `rgba(${rgb}, ${opacity})`; +} + +export function shadow(...layers: string[]): string { + return layers.join(', '); +} + +export function colorRamp( + prefix: string, + rgb: string, + solid500: string, + solid600: string, + strongRgb: string = rgb, + stops: readonly [string, string, string, string, string] = ['0.04', '0.08', '0.15', '0.25', '0.4'], +): MobileThemeVars { + return { + [`${prefix}-50`]: alpha(rgb, stops[0]), + [`${prefix}-100`]: alpha(rgb, stops[1]), + [`${prefix}-200`]: alpha(rgb, stops[2]), + [`${prefix}-300`]: alpha(rgb, stops[3]), + [`${prefix}-400`]: alpha(rgb, stops[4]), + [`${prefix}-500`]: solid500, + [`${prefix}-600`]: solid600, + [`${prefix}-700`]: alpha(strongRgb, '0.8'), + [`${prefix}-800`]: alpha(strongRgb, '0.9'), + }; +} + +export const commonMobileThemeVars: MobileThemeVars = { + '--size-radius-sm': '6px', + '--size-radius-base': '8px', + '--size-radius-lg': '12px', + '--size-radius-xl': '16px', + '--size-radius-2xl': '20px', + '--size-radius-full': '9999px', + + '--size-gap-1': '4px', + '--size-gap-2': '8px', + '--size-gap-3': '12px', + '--size-gap-4': '16px', + '--size-gap-5': '20px', + '--size-gap-6': '24px', + '--size-gap-8': '32px', + '--size-gap-10': '40px', + '--size-gap-12': '48px', + '--size-gap-16': '64px', + + '--motion-instant': '0.1s', + '--motion-fast': '0.15s', + '--motion-base': '0.3s', + '--motion-slow': '0.6s', + '--motion-lazy': '1s', + + '--easing-standard': 'cubic-bezier(0.4, 0, 0.2, 1)', + '--easing-decelerate': 'cubic-bezier(0, 0, 0.2, 1)', + '--easing-accelerate': 'cubic-bezier(0.4, 0, 1, 1)', + '--easing-bounce': 'cubic-bezier(0.68, -0.55, 0.265, 1.55)', + '--easing-smooth': 'cubic-bezier(0.4, 0, 0.2, 1)', + + '--font-family-sans': "'Noto Sans SC', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'SF Pro Display', Roboto, sans-serif", + '--font-family-mono': "'Menlo', 'SF Mono', 'Cascadia Code', 'Consolas', 'Liberation Mono', 'Courier New', 'Noto Sans Mono CJK SC', 'Noto Sans Mono', monospace", + '--font-weight-normal': '400', + '--font-weight-medium': '500', + '--font-weight-semibold': '600', + '--font-weight-bold': '700', + + '--font-size-xs': '12px', + '--font-size-sm': '14px', + '--font-size-base': '15px', + '--font-size-lg': '16px', + '--font-size-xl': '18px', + '--font-size-2xl': '20px', + '--font-size-3xl': '24px', + + '--line-height-tight': '1.2', + '--line-height-base': '1.5', + '--line-height-relaxed': '1.6', +}; diff --git a/src/mobile-web/tsconfig.json b/src/mobile-web/tsconfig.json index ef3600fb43..aaff363a99 100644 --- a/src/mobile-web/tsconfig.json +++ b/src/mobile-web/tsconfig.json @@ -16,6 +16,7 @@ "noUnusedParameters": false, "noFallthroughCasesInSwitch": true, "baseUrl": ".", + "ignoreDeprecations": "5.0", "paths": { "@/*": ["src/*"] } diff --git a/src/web-ui/src/component-library/styles/_functions.scss b/src/web-ui/src/component-library/styles/_functions.scss index e0eacff537..6152f9c502 100644 --- a/src/web-ui/src/component-library/styles/_functions.scss +++ b/src/web-ui/src/component-library/styles/_functions.scss @@ -59,13 +59,13 @@ @function elevation-shadow($depth) { @if $depth == 1 { - @return 0 1px 3px var(--color-overlay-black-12), 0 1px 2px rgba(0, 0, 0, 0.24); + @return 0 1px 3px var(--color-overlay-black-12), 0 1px 2px var(--color-overlay-black-25); } @else if $depth == 2 { @return 0 3px 6px var(--color-overlay-black-15), 0 2px 4px var(--color-overlay-black-12); } @else if $depth == 3 { @return 0 10px 20px var(--color-overlay-black-15), 0 3px 6px var(--color-overlay-black-10); } @else if $depth == 4 { - @return 0 15px 25px var(--color-overlay-black-15), 0 5px 10px rgba(0, 0, 0, 0.05); + @return 0 15px 25px var(--color-overlay-black-15), 0 5px 10px var(--color-overlay-black-06); } @else if $depth == 5 { @return 0 20px 40px var(--color-overlay-black-20); } diff --git a/src/web-ui/src/component-library/styles/flowchat-markdown-code-vars.scss b/src/web-ui/src/component-library/styles/flowchat-markdown-code-vars.scss index f82fa9708c..5416f6d093 100644 --- a/src/web-ui/src/component-library/styles/flowchat-markdown-code-vars.scss +++ b/src/web-ui/src/component-library/styles/flowchat-markdown-code-vars.scss @@ -36,11 +36,11 @@ } :root[data-theme-type="light"] { - --flowchat-md-inline-code-bg: rgba(0, 0, 0, 0.05); + --flowchat-md-inline-code-bg: var(--color-overlay-black-06); --flowchat-md-inline-code-border: var(--color-overlay-black-12); --flowchat-md-inline-code-fg: #24292f; --flowchat-md-inline-code-hover-bg: var(--color-overlay-black-08); - --flowchat-md-inline-code-hover-border: rgba(0, 0, 0, 0.18); + --flowchat-md-inline-code-hover-border: var(--color-overlay-black-20); --flowchat-md-inline-code-hover-fg: #1f2328; --flowchat-md-pre-bg: #f6f8fa; @@ -50,7 +50,7 @@ --flowchat-md-pre-hover-shadow: 0 6px 20px var(--color-overlay-slate-08); --flowchat-md-pre-code-fg: var(--color-text-primary); - --flowchat-md-bq-bg: rgba(15, 23, 42, 0.07); + --flowchat-md-bq-bg: var(--color-overlay-slate-08); --flowchat-md-bq-border: rgba(15, 23, 42, 0.24); --flowchat-md-bq-fg: var(--color-text-secondary); --flowchat-md-bq-hover-bg: var(--color-overlay-slate-10); diff --git a/src/web-ui/src/component-library/styles/flowchat-markdown-table-vars.scss b/src/web-ui/src/component-library/styles/flowchat-markdown-table-vars.scss index b79b638f4a..9e66f21fa9 100644 --- a/src/web-ui/src/component-library/styles/flowchat-markdown-table-vars.scss +++ b/src/web-ui/src/component-library/styles/flowchat-markdown-table-vars.scss @@ -27,6 +27,6 @@ --flowchat-md-table-th-fg: #0f172a; --flowchat-md-table-td-fg: var(--color-text-primary); --flowchat-md-table-row-base: var(--color-static-white); - --flowchat-md-table-row-stripe: #f8fafc; + --flowchat-md-table-row-stripe: var(--color-overlay-slate-03); --flowchat-md-table-hover: #eef4ff; } diff --git a/src/web-ui/src/component-library/styles/tokens.scss b/src/web-ui/src/component-library/styles/tokens.scss index b8ab271a56..5911b750b3 100644 --- a/src/web-ui/src/component-library/styles/tokens.scss +++ b/src/web-ui/src/component-library/styles/tokens.scss @@ -7,22 +7,23 @@ $color-static-black: #000000; $color-static-emerald: #10b981; $color-static-orange: #f97316; -$overlay-white-01: rgba(255, 255, 255, 0.01); $overlay-white-02: rgba(255, 255, 255, 0.02); +$overlay-white-01: $overlay-white-02; $overlay-white-03: rgba(255, 255, 255, 0.03); $overlay-white-04: rgba(255, 255, 255, 0.04); $overlay-white-05: rgba(255, 255, 255, 0.05); $overlay-white-06: rgba(255, 255, 255, 0.06); $overlay-white-08: rgba(255, 255, 255, 0.08); -$overlay-white-09: rgba(255, 255, 255, 0.09); $overlay-white-10: rgba(255, 255, 255, 0.1); +$overlay-white-09: $overlay-white-10; $overlay-white-12: rgba(255, 255, 255, 0.12); $overlay-white-15: rgba(255, 255, 255, 0.15); $overlay-white-18: rgba(255, 255, 255, 0.18); $overlay-white-20: rgba(255, 255, 255, 0.2); $overlay-white-24: rgba(255, 255, 255, 0.24); -$overlay-white-25: rgba(255, 255, 255, 0.25); -$overlay-white-32: rgba(255, 255, 255, 0.32); +$overlay-white-25: $overlay-white-24; +$overlay-white-30: rgba(255, 255, 255, 0.3); +$overlay-white-32: $overlay-white-30; $overlay-white-40: rgba(255, 255, 255, 0.4); $overlay-white-60: rgba(255, 255, 255, 0.6); @@ -44,9 +45,9 @@ $overlay-black-90: rgba(0, 0, 0, 0.9); $color-blue-500-a06: rgba(96, 165, 250, 0.06); $color-blue-500-a08: rgba(96, 165, 250, 0.08); -$color-blue-500-a12: rgba(96, 165, 250, 0.12); $color-blue-500-a15: rgba(96, 165, 250, 0.15); -$color-blue-500-a18: rgba(96, 165, 250, 0.18); +$color-blue-500-a12: $color-blue-500-a15; +$color-blue-500-a18: $color-blue-500-a15; $color-blue-600-a08: rgba(59, 130, 246, 0.08); $color-blue-600-a12: rgba(59, 130, 246, 0.12); $color-blue-600-a15: rgba(59, 130, 246, 0.15); @@ -58,8 +59,8 @@ $color-blue-600-a40: rgba(59, 130, 246, 0.4); $color-purple-500-a05: rgba(139, 92, 246, 0.05); $color-purple-500-a08: rgba(139, 92, 246, 0.08); $color-purple-500-a10: rgba(139, 92, 246, 0.1); -$color-purple-500-a12: rgba(139, 92, 246, 0.12); $color-purple-500-a15: rgba(139, 92, 246, 0.15); +$color-purple-500-a12: $color-purple-500-a15; $color-purple-500-a25: rgba(139, 92, 246, 0.25); $color-purple-500-a30: rgba(139, 92, 246, 0.3); $color-purple-500-a40: rgba(139, 92, 246, 0.4); @@ -90,9 +91,9 @@ $element-bg-strong: rgba(255, 255, 255, 0.155); $element-bg-elevated: rgba(255, 255, 255, 0.19); // ==================== Blue system ==================== -$color-accent-50: rgba(96, 165, 250, 0.04); +$color-accent-50: $color-blue-500-a06; $color-accent-100: $color-blue-500-a08; -$color-accent-200: rgba(96, 165, 250, 0.15); +$color-accent-200: $color-blue-500-a15; $color-accent-300: rgba(96, 165, 250, 0.25); $color-accent-400: rgba(96, 165, 250, 0.4); $color-accent-500: #60a5fa; @@ -101,7 +102,7 @@ $color-accent-700: rgba(59, 130, 246, 0.8); $color-accent-800: rgba(59, 130, 246, 0.9); // ==================== Purple system ==================== -$color-purple-50: rgba(139, 92, 246, 0.04); +$color-purple-50: $color-purple-500-a05; $color-purple-100: $color-purple-500-a08; $color-purple-200: $color-purple-500-a15; $color-purple-300: $color-purple-500-a25; @@ -149,7 +150,7 @@ $git-color-added-bg: $git-color-staged-bg; $git-color-added-bg-hover: $git-color-staged-bg-hover; $git-color-deleted: $color-error; -$git-color-deleted-bg: rgba(239, 68, 68, 0.1); +$git-color-deleted-bg: $color-error-bg; $git-color-deleted-bg-hover: rgba(239, 68, 68, 0.15); $git-color-deleted-border: rgba(239, 68, 68, 0.3); @@ -197,7 +198,7 @@ $glow-shadow-blue: $glow-shadow-purple: 0 12px 32px $color-purple-500-a25, - 0 6px 16px rgba(124, 58, 237, 0.18), + 0 6px 16px $color-purple-500-a15, 0 3px 8px $overlay-black-10; $glow-shadow-red: @@ -251,16 +252,16 @@ $glass-blue-hover: linear-gradient(135deg, $glass-purple-base: linear-gradient(135deg, $color-purple-500-a08 0%, $color-purple-500-a05 30%, - rgba(139, 92, 246, 0.06) 60%, + $color-purple-500-a05 60%, $color-purple-500-a10 100%); $glass-purple-hover: linear-gradient(135deg, $color-purple-500-a25 0%, - rgba(124, 58, 237, 0.18) 30%, - rgba(196, 181, 253, 0.15) 60%, + $color-purple-500-a15 30%, + $color-purple-500-a15 60%, $color-purple-500-a30 100%); $glass-red-subtle: rgba(239, 68, 68, 0.05); -$glass-red-base: rgba(239, 68, 68, 0.08); +$glass-red-base: $color-error-bg; $glass-red-hover: rgba(239, 68, 68, 0.15); $glass-green-base: rgba(52, 211, 153, 0.08); @@ -429,9 +430,9 @@ $card-bg-subtle: $overlay-white-02; $card-bg-hover: $overlay-white-06; $card-bg-active: $overlay-white-08; $card-bg-accent: rgba(96, 165, 250, 0.1); -$card-bg-accent-hover: rgba(96, 165, 250, 0.14); +$card-bg-accent-hover: $color-blue-500-a15; $card-bg-purple: $color-purple-500-a10; -$card-bg-purple-hover: rgba(139, 92, 246, 0.14); +$card-bg-purple-hover: $color-purple-500-a15; $card-bg: $card-bg-default; // Legacy alias $card-border: $border-base; $card-border-style: solid; @@ -516,8 +517,8 @@ $badge-info-text: $color-info; } @else if $color == 'purple' { background: linear-gradient(135deg, $color-purple-500-a15 0%, - rgba(168, 85, 247, 0.12) 30%, - rgba(124, 58, 237, 0.08) 60%, + $color-purple-500-a15 30%, + $color-purple-500-a08 60%, rgba(139, 92, 246, 0.18) 100% ); border-color: $color-purple-500-a40; @@ -574,7 +575,7 @@ $badge-info-text: $color-info; background: linear-gradient(90deg, transparent, $color-purple-500-a08, - rgba(196, 181, 253, 0.15), + $color-purple-500-a15, $color-purple-500-a08, transparent ); @@ -1094,7 +1095,7 @@ $badge-info-text: $color-info; --git-graph-lane-pink: #ec4899; --git-graph-lane-orange: #{$color-static-orange}; --git-graph-text-primary: #d1d5db; - --git-graph-text-muted: #6b7280; + --git-graph-text-muted: #64748b; --git-graph-text-disabled: #4b5563; --git-graph-static-white: #{$button-text-hover}; --mission-control-group-primary-color: var(--color-accent-600); diff --git a/src/web-ui/src/infrastructure/theme/core/ThemeService.ts b/src/web-ui/src/infrastructure/theme/core/ThemeService.ts index a194f93079..40cff4fc44 100644 --- a/src/web-ui/src/infrastructure/theme/core/ThemeService.ts +++ b/src/web-ui/src/infrastructure/theme/core/ThemeService.ts @@ -1011,18 +1011,18 @@ export class ThemeService { root.style.setProperty('--card-bg-accent', THEME_OVERLAYS.white08); root.style.setProperty('--card-bg-accent-hover', THEME_OVERLAYS.white12); root.style.setProperty('--card-bg-purple', 'rgba(139, 92, 246, 0.08)'); - root.style.setProperty('--card-bg-purple-hover', 'rgba(139, 92, 246, 0.12)'); + root.style.setProperty('--card-bg-purple-hover', 'rgba(139, 92, 246, 0.15)'); } else { root.style.setProperty('--card-bg-default', THEME_OVERLAYS.black06); root.style.setProperty('--card-bg-elevated', THEME_OVERLAYS.black08); root.style.setProperty('--card-bg-subtle', THEME_OVERLAYS.black04); - root.style.setProperty('--card-bg-hover', 'rgba(0, 0, 0, 0.065)'); - root.style.setProperty('--card-bg-active', 'rgba(0, 0, 0, 0.09)'); + root.style.setProperty('--card-bg-hover', THEME_OVERLAYS.black06); + root.style.setProperty('--card-bg-active', THEME_OVERLAYS.black10); root.style.setProperty('--card-bg-accent', 'rgba(15, 23, 42, 0.08)'); root.style.setProperty('--card-bg-accent-hover', 'rgba(15, 23, 42, 0.12)'); root.style.setProperty('--card-bg-purple', 'rgba(124, 58, 237, 0.12)'); - root.style.setProperty('--card-bg-purple-hover', 'rgba(124, 58, 237, 0.18)'); + root.style.setProperty('--card-bg-purple-hover', 'rgba(139, 92, 246, 0.15)'); } diff --git a/src/web-ui/src/infrastructure/theme/integrations/MonacoThemeSync.ts b/src/web-ui/src/infrastructure/theme/integrations/MonacoThemeSync.ts index 5afda92ade..493259ce2f 100644 --- a/src/web-ui/src/infrastructure/theme/integrations/MonacoThemeSync.ts +++ b/src/web-ui/src/infrastructure/theme/integrations/MonacoThemeSync.ts @@ -27,11 +27,11 @@ function getBitfunLightMonacoTheme(): Monaco.editor.IStandaloneThemeData { 'editor.selectionBackground': 'rgba(15, 23, 42, 0.14)', 'editor.selectionForeground': '#1e293b', - 'editor.inactiveSelectionBackground': 'rgba(15, 23, 42, 0.09)', + 'editor.inactiveSelectionBackground': 'rgba(15, 23, 42, 0.08)', 'editor.selectionHighlightBackground': 'rgba(15, 23, 42, 0.1)', 'editor.selectionHighlightBorder': 'rgba(15, 23, 42, 0.22)', - 'editor.wordHighlightBackground': 'rgba(15, 23, 42, 0.07)', - 'editor.wordHighlightStrongBackground': 'rgba(15, 23, 42, 0.11)', + 'editor.wordHighlightBackground': 'rgba(15, 23, 42, 0.08)', + 'editor.wordHighlightStrongBackground': 'rgba(15, 23, 42, 0.1)', }), }; } diff --git a/src/web-ui/src/infrastructure/theme/presets/china-night-theme.ts b/src/web-ui/src/infrastructure/theme/presets/china-night-theme.ts index 6545e3140e..7474c03561 100644 --- a/src/web-ui/src/infrastructure/theme/presets/china-night-theme.ts +++ b/src/web-ui/src/infrastructure/theme/presets/china-night-theme.ts @@ -14,7 +14,7 @@ import { rgbaFromHex, } from './shared'; -const CHINA_NIGHT_BACKGROUND = '#1a1814'; +const CHINA_NIGHT_BACKGROUND = '#1a1a1a'; const CHINA_NIGHT_TEXT_PRIMARY = '#e8e6e1'; const CHINA_NIGHT_BUTTON_TEXT = '#ccc9c4'; const CHINA_NIGHT_ACCENT = '#73a5cc'; @@ -50,11 +50,11 @@ export const bitfunChinaNightTheme: ThemeConfig = { background: { primary: CHINA_NIGHT_BACKGROUND, secondary: '#212019', - tertiary: '#262420', - quaternary: '#2d2926', - elevated: '#2d2926', + tertiary: '#262626', + quaternary: '#262626', + elevated: '#262626', workbench: CHINA_NIGHT_BACKGROUND, - scene: '#1e1c17', + scene: CHINA_NIGHT_BACKGROUND, tooltip: chinaNightBackground(0.95), }, @@ -125,7 +125,7 @@ export const bitfunChinaNightTheme: ThemeConfig = { base: chinaNightAccent(0.12), medium: chinaNightAccent(0.16), strong: chinaNightAccent(0.2), - elevated: rgbaFromHex('#2d2926', 0.95), + elevated: rgbaFromHex('#262626', 0.95), }, git: createGitColors({ @@ -225,7 +225,7 @@ export const bitfunChinaNightTheme: ThemeConfig = { default: { background: chinaNightAccent(0.11), - color: '#a29d96', + color: '#9a9a9a', border: 'transparent', shadow: 'none', }, @@ -272,7 +272,7 @@ export const bitfunChinaNightTheme: ThemeConfig = { ghost: { default: { background: 'transparent', - color: '#a29d96', + color: '#9a9a9a', border: 'transparent', shadow: 'none', }, diff --git a/src/web-ui/src/infrastructure/theme/presets/dark-theme.ts b/src/web-ui/src/infrastructure/theme/presets/dark-theme.ts index 9d9db2fe37..61bcd99a19 100644 --- a/src/web-ui/src/infrastructure/theme/presets/dark-theme.ts +++ b/src/web-ui/src/infrastructure/theme/presets/dark-theme.ts @@ -53,7 +53,7 @@ export const bitfunDarkTheme: ThemeConfig = { primary: DARK_BACKGROUND_PRIMARY, secondary: DARK_BACKGROUND_SECONDARY, tertiary: DARK_BACKGROUND_PRIMARY, - quaternary: '#252528', + quaternary: '#262626', elevated: DARK_BACKGROUND_SECONDARY, workbench: DARK_BACKGROUND_PRIMARY, scene: DARK_BACKGROUND_SECONDARY, @@ -239,7 +239,7 @@ export const bitfunDarkTheme: ThemeConfig = { primary: { default: { background: overlayWhite(0.16), - color: '#f4f4f5', + color: '#f3f3f5', border: 'transparent', shadow: 'none', }, @@ -295,7 +295,7 @@ export const bitfunDarkTheme: ThemeConfig = { colors: { background: '#121214', foreground: DARK_TEXT_PRIMARY, - lineHighlight: '#18181a', + lineHighlight: DARK_BACKGROUND_SECONDARY, selection: overlayWhite(0.12), cursor: '#c4c4c4', }, diff --git a/src/web-ui/src/infrastructure/theme/presets/light-theme.ts b/src/web-ui/src/infrastructure/theme/presets/light-theme.ts index 0409599736..52008cf142 100644 --- a/src/web-ui/src/infrastructure/theme/presets/light-theme.ts +++ b/src/web-ui/src/infrastructure/theme/presets/light-theme.ts @@ -325,7 +325,7 @@ export const bitfunLightTheme: ThemeConfig = { { token: 'attribute.value', foreground: '5b9a6f' }, ], colors: { - background: '#f7f8fa', + background: '#f3f3f5', foreground: LIGHT_TEXT_PRIMARY, lineHighlight: '#f0f4f8', selection: lightInk(0.14), diff --git a/src/web-ui/src/infrastructure/theme/presets/midnight-theme.ts b/src/web-ui/src/infrastructure/theme/presets/midnight-theme.ts index cefc6707e6..956e259e14 100644 --- a/src/web-ui/src/infrastructure/theme/presets/midnight-theme.ts +++ b/src/web-ui/src/infrastructure/theme/presets/midnight-theme.ts @@ -56,7 +56,7 @@ export const bitfunMidnightTheme: ThemeConfig = { quaternary: '#3c3f41', elevated: MIDNIGHT_BACKGROUND, workbench: '#212121', - scene: '#27292c', + scene: MIDNIGHT_BACKGROUND, tooltip: midnightBackground(0.94), }, @@ -227,7 +227,7 @@ export const bitfunMidnightTheme: ThemeConfig = { default: { background: midnightText(0.11), - color: '#949699', + color: '#9a9a9a', border: 'transparent', shadow: 'none', }, @@ -274,7 +274,7 @@ export const bitfunMidnightTheme: ThemeConfig = { ghost: { default: { background: 'transparent', - color: '#949699', + color: '#9a9a9a', border: 'transparent', shadow: 'none', }, diff --git a/src/web-ui/src/infrastructure/theme/presets/shared.ts b/src/web-ui/src/infrastructure/theme/presets/shared.ts index 6e5d3e7b4f..b1cf2bdf7a 100644 --- a/src/web-ui/src/infrastructure/theme/presets/shared.ts +++ b/src/web-ui/src/infrastructure/theme/presets/shared.ts @@ -196,7 +196,7 @@ export function createDarkNeutralBorder(): BorderColors { subtle: 'rgba(255, 255, 255, 0.12)', base: 'rgba(255, 255, 255, 0.18)', medium: 'rgba(255, 255, 255, 0.24)', - strong: 'rgba(255, 255, 255, 0.32)', + strong: 'rgba(255, 255, 255, 0.3)', prominent: 'rgba(255, 255, 255, 0.4)', }; } diff --git a/src/web-ui/src/infrastructure/theme/presets/slate-theme.ts b/src/web-ui/src/infrastructure/theme/presets/slate-theme.ts index 12e7b00702..f7cf5f2bfa 100644 --- a/src/web-ui/src/infrastructure/theme/presets/slate-theme.ts +++ b/src/web-ui/src/infrastructure/theme/presets/slate-theme.ts @@ -313,9 +313,9 @@ export const bitfunSlateTheme: ThemeConfig = { { token: 'attribute.value', foreground: '8fc8a9' }, ], colors: { - background: '#1a1c1e', + background: '#1a1a1a', foreground: SLATE_TEXT_PRIMARY, - lineHighlight: '#22252a', + lineHighlight: SLATE_BACKGROUND_SECONDARY, selection: overlayWhite(0.12), cursor: '#aeb6c3', }, diff --git a/src/web-ui/src/infrastructure/theme/presets/themePresetOutput.test.ts b/src/web-ui/src/infrastructure/theme/presets/themePresetOutput.test.ts index cf348b6406..fa7c6882c9 100644 --- a/src/web-ui/src/infrastructure/theme/presets/themePresetOutput.test.ts +++ b/src/web-ui/src/infrastructure/theme/presets/themePresetOutput.test.ts @@ -67,22 +67,22 @@ describe('builtin theme preset output', () => { }))).toMatchInlineSnapshot(` [ { - "hash": "063f8984522a0be4753e2fa36e47030f8e86cfb09057d617ffbb6c37e3821ef1", + "hash": "c3b6a5647f5a098c777c5e0669578a2a6a83fe399c4ffe2b16e00b532361e0a5", "id": "bitfun-light", "type": "light", }, { - "hash": "62dd9d9ca53ff4753b7747f4ce23d6e39a349f52d673245be90b335ed6fccd9d", + "hash": "f9732d9339162f704c6bd19dbac61e6ecf7819dd3d72a6437cce04812ab16db4", "id": "bitfun-slate", "type": "dark", }, { - "hash": "77a8fcade63df09af9ca22a61037edce51919c5b28cdae1df63a0e471a7d5846", + "hash": "4d3b604eeed6cac6f06228c93b2771217dda6f5e6a1fd151bc48849f59c229c1", "id": "bitfun-dark", "type": "dark", }, { - "hash": "df6cadb36332f77286c3ac9a862dc8cd7805944ee86ed57af6e1f3b40f4f2e08", + "hash": "5b5429e48817fcd6d5643989f959340e6766ee5a0e3edfdff88f3984c0e343e8", "id": "bitfun-midnight", "type": "dark", }, @@ -92,7 +92,7 @@ describe('builtin theme preset output', () => { "type": "light", }, { - "hash": "5b2db0c0dfc253022fadd1d5bc07da65e7f473c27d66fe297cc695a50466699c", + "hash": "bc760598ce85d6e4a7f22349aace0e25ab6cb401535bdd468513a141a2069e82", "id": "bitfun-china-night", "type": "dark", }, diff --git a/src/web-ui/src/shared/theme/themeBoundaryFallbacks.ts b/src/web-ui/src/shared/theme/themeBoundaryFallbacks.ts index 48622fa7ff..f03a87b801 100644 --- a/src/web-ui/src/shared/theme/themeBoundaryFallbacks.ts +++ b/src/web-ui/src/shared/theme/themeBoundaryFallbacks.ts @@ -12,11 +12,11 @@ export const WIDGET_IFRAME_FALLBACK_COLOR = { error: '#ef4444', staticWhite: '#ffffff', borderSubtle: 'rgba(255, 255, 255, 0.1)', - borderBase: 'rgba(255, 255, 255, 0.16)', + borderBase: 'rgba(255, 255, 255, 0.15)', borderMedium: 'rgba(255, 255, 255, 0.24)', elementBgSubtle: 'rgba(255, 255, 255, 0.05)', elementBgBase: 'rgba(255, 255, 255, 0.08)', - elementBgMedium: 'rgba(255, 255, 255, 0.14)', + elementBgMedium: 'rgba(255, 255, 255, 0.15)', shadowBase: 'rgba(0, 0, 0, 0.4)', } as const; diff --git a/src/web-ui/src/tools/editor/themes/bitfun-dark.theme.ts b/src/web-ui/src/tools/editor/themes/bitfun-dark.theme.ts index 44cfbf47fc..f3ad0fa321 100644 --- a/src/web-ui/src/tools/editor/themes/bitfun-dark.theme.ts +++ b/src/web-ui/src/tools/editor/themes/bitfun-dark.theme.ts @@ -406,7 +406,7 @@ export const BitFunDarkTheme: editor.IStandaloneThemeData = { 'diffEditor.modifiedLineBackground': '#1F6FEB28', 'diffEditor.border': '#2A2D35', - 'diffEditor.diagonalFill': '#16181D', + 'diffEditor.diagonalFill': MONACO_DARK_SURFACE.elevated, 'diffEditor.unchangedRegionBackground': MONACO_DARK_SURFACE.diffDeep, 'diffEditor.unchangedCodeBackground': MONACO_DARK_SURFACE.diffDeep, diff --git a/src/web-ui/src/tools/mermaid-editor/theme/_tokens.scss b/src/web-ui/src/tools/mermaid-editor/theme/_tokens.scss index b0a67d7c1f..66e5b3b3c0 100644 --- a/src/web-ui/src/tools/mermaid-editor/theme/_tokens.scss +++ b/src/web-ui/src/tools/mermaid-editor/theme/_tokens.scss @@ -17,7 +17,7 @@ $mermaid-light-node-stroke: rgba(100, 116, 139, 0.35); $mermaid-light-edge-label-border: rgba(100, 116, 139, 0.25); $mermaid-light-text-primary: #1e293b; $mermaid-light-text-secondary: #475569; -$mermaid-light-surface: #f7f8fa; +$mermaid-light-surface: #f9fafb; $mermaid-light-highlight-stroke: #334155; // ==================== Mermaid CSS variables ==================== @@ -199,7 +199,7 @@ $mermaid-light-highlight-stroke: #334155; // Background --mermaid-bg: var(--color-bg-scene); - --mermaid-container-border: rgba(100, 116, 139, 0.18); + --mermaid-container-border: rgba(100, 116, 139, 0.2); } // ==================== Mixins ==================== diff --git a/src/web-ui/src/tools/mermaid-editor/theme/mermaidThemeFallbacks.test.ts b/src/web-ui/src/tools/mermaid-editor/theme/mermaidThemeFallbacks.test.ts index d2273ca3aa..3fd2d9224c 100644 --- a/src/web-ui/src/tools/mermaid-editor/theme/mermaidThemeFallbacks.test.ts +++ b/src/web-ui/src/tools/mermaid-editor/theme/mermaidThemeFallbacks.test.ts @@ -12,7 +12,7 @@ describe('mermaid theme fallback palette', () => { expect(getMermaidThemeFallback('dark', 'nodeFill')).toBe('#1c1e23'); expect(getMermaidThemeFallback('light', 'nodeFill')).toBe('#e8eaef'); expect(getMermaidThemeFallback('dark', 'nodeText')).toBe('#e0e2e8'); - expect(getMermaidThemeFallback('light', 'nodeText')).toBe('#1f2937'); + expect(getMermaidThemeFallback('light', 'nodeText')).toBe('#1e293b'); }); it('returns paired fallbacks for CSS variable resolution without duplicating call-site literals', () => { diff --git a/src/web-ui/src/tools/mermaid-editor/theme/mermaidThemeFallbacks.ts b/src/web-ui/src/tools/mermaid-editor/theme/mermaidThemeFallbacks.ts index d2c83a2ac0..515a4e67ae 100644 --- a/src/web-ui/src/tools/mermaid-editor/theme/mermaidThemeFallbacks.ts +++ b/src/web-ui/src/tools/mermaid-editor/theme/mermaidThemeFallbacks.ts @@ -9,7 +9,7 @@ const DARK_NODE_STROKE = '#5a5e6a'; const DARK_NODE_BORDER = '#4a4e58'; const DARK_NODE_STROKE_SUBTLE = '#3a3e48'; const DARK_NODE_STROKE_HOVER = '#6a6e7a'; -const DARK_CLUSTER_TEXT = '#9a9ea8'; +const DARK_CLUSTER_TEXT = '#a1a1aa'; const DARK_INFO = '#78a8d8'; const DARK_ERROR = '#e87878'; @@ -17,9 +17,10 @@ const LIGHT_NODE_FILL = '#e8eaef'; const LIGHT_NODE_FILL_HOVER = '#e0e2e8'; const LIGHT_NODE_STROKE = '#9ca3af'; const LIGHT_NODE_STROKE_MUTED = '#d1d5db'; -const LIGHT_NODE_STROKE_HOVER = '#6b7280'; -const LIGHT_EDGE_LABEL_BG = '#f3f4f6'; -const LIGHT_SECTION_ALT_FILL = '#e5e7eb'; +const LIGHT_NODE_STROKE_HOVER = '#64748b'; +const MERMAID_SOFT_LIGHT_SURFACE = '#f3f4f6'; +const LIGHT_EDGE_LABEL_BG = MERMAID_SOFT_LIGHT_SURFACE; +const LIGHT_SECTION_ALT_FILL = LIGHT_NODE_FILL_HOVER; const LIGHT_TITLE_TEXT = '#111827'; const LIGHT_HIGHLIGHT_STROKE = '#334155'; const LIGHT_ERROR = '#dc2626'; @@ -33,7 +34,7 @@ export const MERMAID_THEME_FALLBACKS = { nodeFillHover: DARK_NODE_FILL_HOVER, nodeFillHoverRuntime: 'rgba(38, 40, 48, 0.95)', nodeText: DARK_NODE_TEXT, - nodeTextStrong: '#f0f2f8', + nodeTextStrong: MERMAID_SOFT_LIGHT_SURFACE, nodeStroke: DARK_NODE_STROKE, nodeBorder: DARK_NODE_BORDER, nodeStrokeMuted: DARK_NODE_BORDER, @@ -48,7 +49,7 @@ export const MERMAID_THEME_FALLBACKS = { clusterText: DARK_CLUSTER_TEXT, textMuted: DARK_NODE_STROKE_HOVER, arrow: '#7a7e8a', - edgeLabelBg: '#1a1c20', + edgeLabelBg: DARK_NODE_FILL, edgeLabelBgStrong: DARK_NODE_FILL_HOVER, edgeLabelBgRuntime: 'rgba(26, 28, 32, 0.95)', edgeLabelBgHover: 'rgba(36, 38, 45, 0.98)', @@ -76,7 +77,7 @@ export const MERMAID_THEME_FALLBACKS = { pieTitleText: DARK_NODE_TEXT, pieLegendText: DARK_CLUSTER_TEXT, pieStroke: DARK_NODE_FILL, - errorFill: 'rgba(232, 120, 120, 0.12)', + errorFill: 'rgba(232, 120, 120, 0.15)', error: DARK_ERROR, highlightStroke: '#a8acb8', highlightGlow: 'drop-shadow(0 0 6px rgba(168, 172, 184, 0.4))', @@ -87,7 +88,7 @@ export const MERMAID_THEME_FALLBACKS = { nodeFillRuntime: LIGHT_NODE_FILL, nodeFillHover: LIGHT_NODE_FILL_HOVER, nodeFillHoverRuntime: LIGHT_NODE_FILL_HOVER, - nodeText: '#1f2937', + nodeText: '#1e293b', nodeTextStrong: LIGHT_TITLE_TEXT, nodeStroke: LIGHT_NODE_STROKE, nodeBorder: LIGHT_NODE_STROKE, @@ -100,7 +101,7 @@ export const MERMAID_THEME_FALLBACKS = { clusterFill: LIGHT_CLUSTER_FILL, clusterFillRuntime: LIGHT_CLUSTER_FILL, clusterFillHover: 'rgba(209, 213, 219, 0.8)', - clusterText: '#4b5563', + clusterText: '#475569', textMuted: LIGHT_NODE_STROKE_HOVER, arrow: LIGHT_NODE_STROKE_HOVER, edgeLabelBg: LIGHT_EDGE_LABEL_BG, @@ -129,8 +130,8 @@ export const MERMAID_THEME_FALLBACKS = { pie7: '#06b6d4', pie8: '#84cc16', pieTitleText: LIGHT_TITLE_TEXT, - pieLegendText: '#374151', - pieStroke: '#f9fafb', + pieLegendText: LIGHT_HIGHLIGHT_STROKE, + pieStroke: MERMAID_SOFT_LIGHT_SURFACE, errorFill: 'rgba(239, 68, 68, 0.15)', error: LIGHT_ERROR, highlightStroke: LIGHT_HIGHLIGHT_STROKE, diff --git a/src/web-ui/src/tools/terminal/utils/xtermTheme.ts b/src/web-ui/src/tools/terminal/utils/xtermTheme.ts index c3a9681ccc..a04e602d26 100644 --- a/src/web-ui/src/tools/terminal/utils/xtermTheme.ts +++ b/src/web-ui/src/tools/terminal/utils/xtermTheme.ts @@ -117,7 +117,7 @@ export function buildXtermTheme( cursor: theme.colors.text.primary, cursorAccent: theme.colors.background.secondary, selectionBackground: isDark ? 'rgba(255, 255, 255, 0.3)' : 'rgba(173, 214, 255, 0.45)', - selectionInactiveBackground: isDark ? 'rgba(255, 255, 255, 0.16)' : 'rgba(173, 214, 255, 0.25)', + selectionInactiveBackground: isDark ? 'rgba(255, 255, 255, 0.15)' : 'rgba(173, 214, 255, 0.25)', ...getXtermAnsiPalette(theme.type), ...overrides, };