feat(FN-4016): convert hardcoded rgba colors to CSS token variables across

Migrated dashboard component CSS from hardcoded `rgba()` values to design token variables across nine components including `CustomModelDropdown`, `CliBinaryPanel`, and `CliBinaryInstallBanner`, with test coverage added for the affected components.

Fusion-Task-Id: FN-4016
This commit is contained in:
Fusion
2026-05-11 10:49:33 -07:00
committed by gsxdsm
parent fc34907553
commit d6bea0d6e5
14 changed files with 160 additions and 95 deletions

View File

@@ -0,0 +1,39 @@
import { describe, expect, it } from "vitest";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
const root = resolve(__dirname, "../components");
const auditedCompliant = ["ChatView.css", "MobileNavBar.css", "ListView.css", "WorkflowResultsTab.css"];
const cleanedFiles = [
"ScriptsModal.css",
"InlineCreateCard.css",
"FileMentionPopup.css",
"BackgroundTasksIndicator.css",
"CliBinaryPanel.css",
"CliBinaryInstallBanner.css",
"GitHubImportModal.css",
"WorkspaceSelector.css",
"AgentReflectionsTab.css",
];
describe("dashboard component color tokenization", () => {
it("keeps audited compliant files free of raw rgba()", () => {
for (const file of auditedCompliant) {
const source = readFileSync(resolve(root, file), "utf8");
expect(source).not.toMatch(/rgba\(/);
}
});
it("keeps cleaned files free of raw rgba()", () => {
for (const file of cleanedFiles) {
const source = readFileSync(resolve(root, file), "utf8");
expect(source).not.toMatch(/rgba\(/);
}
});
it("keeps CustomModelDropdown free of raw rgba()", () => {
const source = readFileSync(resolve(root, "CustomModelDropdown.css"), "utf8");
expect(source).not.toMatch(/rgba\(/);
});
});

View File

@@ -348,7 +348,7 @@
gap: 8px; gap: 8px;
padding: 8px 12px; padding: 8px 12px;
border-radius: 6px; border-radius: 6px;
background: var(--state-error-bg, rgba(248,81,73,0.15)); background: var(--state-error-bg, color-mix(in srgb, var(--color-error) 15%, transparent));
color: var(--state-error-text, #f85149); color: var(--state-error-text, #f85149);
border: 1px solid var(--state-error-border, #f85149); border: 1px solid var(--state-error-border, #f85149);
font-size: 0.875rem; font-size: 0.875rem;

View File

@@ -43,7 +43,7 @@
background: var(--surface); background: var(--surface);
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: 8px; border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); box-shadow: var(--shadow-md);
z-index: 1000; z-index: 1000;
overflow: hidden; overflow: hidden;
} }

View File

@@ -6,10 +6,10 @@
padding: 12px 16px; padding: 12px 16px;
background: linear-gradient( background: linear-gradient(
90deg, 90deg,
rgba(59, 130, 246, 0.12), color-mix(in srgb, var(--todo) 12%, transparent),
rgba(59, 130, 246, 0.04) color-mix(in srgb, var(--todo) 4%, transparent)
); );
border: 1px solid rgba(59, 130, 246, 0.35); border: 1px solid color-mix(in srgb, var(--todo) 35%, transparent);
border-radius: 8px; border-radius: 8px;
} }
@@ -24,7 +24,7 @@
.cli-binary-banner__title { .cli-binary-banner__title {
font-weight: 600; font-weight: 600;
font-size: 14px; font-size: 14px;
color: var(--text-primary, #e6edf3); color: var(--text);
} }
.cli-binary-banner__text { .cli-binary-banner__text {
@@ -34,7 +34,7 @@
} }
.cli-binary-banner__text code { .cli-binary-banner__text code {
background: rgba(255, 255, 255, 0.06); background: color-mix(in srgb, var(--text) 6%, transparent);
padding: 1px 6px; padding: 1px 6px;
border-radius: 4px; border-radius: 4px;
font-size: 0.92em; font-size: 0.92em;
@@ -59,7 +59,7 @@
.cli-binary-banner__primary { .cli-binary-banner__primary {
background: var(--accent, #3b82f6); background: var(--accent, #3b82f6);
color: #fff; color: var(--accent-text);
} }
.cli-binary-banner__primary:hover:not(:disabled) { .cli-binary-banner__primary:hover:not(:disabled) {
@@ -72,22 +72,22 @@
} }
.cli-binary-banner__secondary { .cli-binary-banner__secondary {
background: rgba(255, 255, 255, 0.04); background: color-mix(in srgb, var(--text) 4%, transparent);
color: var(--text-primary, #e6edf3); color: var(--text);
border-color: rgba(255, 255, 255, 0.12); border-color: color-mix(in srgb, var(--text) 12%, transparent);
} }
.cli-binary-banner__secondary:hover { .cli-binary-banner__secondary:hover {
background: rgba(255, 255, 255, 0.08); background: color-mix(in srgb, var(--text) 8%, transparent);
} }
.cli-binary-banner__error { .cli-binary-banner__error {
margin-top: 4px; margin-top: 4px;
padding: 6px 10px; padding: 6px 10px;
background: rgba(218, 54, 51, 0.1); background: color-mix(in srgb, var(--color-error) 10%, transparent);
border-left: 3px solid rgba(218, 54, 51, 0.55); border-left: 3px solid color-mix(in srgb, var(--color-error) 55%, transparent);
border-radius: 0 4px 4px 0; border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
color: #f7c4c2; color: var(--color-error);
font-size: 12.5px; font-size: 12.5px;
line-height: 1.5; line-height: 1.5;
} }
@@ -108,6 +108,6 @@
} }
.cli-binary-banner__dismiss:hover { .cli-binary-banner__dismiss:hover {
background: rgba(255, 255, 255, 0.06); background: color-mix(in srgb, var(--text) 6%, transparent);
color: var(--text-primary, #e6edf3); color: var(--text);
} }

View File

@@ -34,21 +34,21 @@
} }
.cli-binary-pill--ok { .cli-binary-pill--ok {
background: rgba(46, 160, 67, 0.18); background: color-mix(in srgb, var(--color-success) 18%, transparent);
color: #57c97a; color: var(--color-success);
border: 1px solid rgba(46, 160, 67, 0.4); border: 1px solid color-mix(in srgb, var(--color-success) 40%, transparent);
} }
.cli-binary-pill--warn { .cli-binary-pill--warn {
background: rgba(210, 153, 34, 0.18); background: color-mix(in srgb, var(--color-warning) 18%, transparent);
color: #e3b341; color: var(--color-warning);
border: 1px solid rgba(210, 153, 34, 0.4); border: 1px solid color-mix(in srgb, var(--color-warning) 40%, transparent);
} }
.cli-binary-pill--err { .cli-binary-pill--err {
background: rgba(218, 54, 51, 0.18); background: color-mix(in srgb, var(--color-error) 18%, transparent);
color: #f48581; color: var(--color-error);
border: 1px solid rgba(218, 54, 51, 0.4); border: 1px solid color-mix(in srgb, var(--color-error) 40%, transparent);
} }
.cli-binary-help { .cli-binary-help {
@@ -57,7 +57,7 @@
} }
.cli-binary-help code { .cli-binary-help code {
background: rgba(255, 255, 255, 0.06); background: color-mix(in srgb, var(--text) 6%, transparent);
padding: 1px 6px; padding: 1px 6px;
border-radius: 4px; border-radius: 4px;
font-size: 0.92em; font-size: 0.92em;
@@ -69,7 +69,7 @@
} }
.cli-binary-status-line code { .cli-binary-status-line code {
background: rgba(255, 255, 255, 0.06); background: color-mix(in srgb, var(--text) 6%, transparent);
padding: 1px 6px; padding: 1px 6px;
border-radius: 4px; border-radius: 4px;
} }
@@ -103,7 +103,7 @@
} }
.cli-binary-info-list code { .cli-binary-info-list code {
background: rgba(255, 255, 255, 0.06); background: color-mix(in srgb, var(--text) 6%, transparent);
padding: 1px 6px; padding: 1px 6px;
border-radius: 4px; border-radius: 4px;
word-break: break-all; word-break: break-all;
@@ -133,7 +133,7 @@
.cli-binary-install-btn { .cli-binary-install-btn {
background: var(--accent, #3b82f6); background: var(--accent, #3b82f6);
color: #fff; color: var(--accent-text);
} }
.cli-binary-install-btn:hover:not(:disabled) { .cli-binary-install-btn:hover:not(:disabled) {
@@ -148,14 +148,14 @@
.cli-binary-refresh-btn, .cli-binary-refresh-btn,
.cli-binary-copy-btn { .cli-binary-copy-btn {
background: rgba(255, 255, 255, 0.04); background: color-mix(in srgb, var(--text) 4%, transparent);
color: var(--text-primary, #e6edf3); color: var(--text);
border-color: rgba(255, 255, 255, 0.12); border-color: color-mix(in srgb, var(--text) 12%, transparent);
} }
.cli-binary-refresh-btn:hover:not(:disabled), .cli-binary-refresh-btn:hover:not(:disabled),
.cli-binary-copy-btn:hover { .cli-binary-copy-btn:hover {
background: rgba(255, 255, 255, 0.08); background: color-mix(in srgb, var(--text) 8%, transparent);
} }
.cli-binary-commands { .cli-binary-commands {
@@ -175,8 +175,8 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
background: rgba(0, 0, 0, 0.25); background: color-mix(in srgb, var(--bg) 25%, transparent);
border: 1px solid rgba(255, 255, 255, 0.06); border: 1px solid color-mix(in srgb, var(--text) 6%, transparent);
border-radius: 6px; border-radius: 6px;
padding: 6px 8px 6px 12px; padding: 6px 8px 6px 12px;
} }
@@ -191,7 +191,7 @@
} }
.cli-binary-install-log { .cli-binary-install-log {
border-top: 1px solid rgba(255, 255, 255, 0.06); border-top: 1px solid color-mix(in srgb, var(--text) 6%, transparent);
padding-top: 10px; padding-top: 10px;
font-size: 12.5px; font-size: 12.5px;
} }
@@ -204,7 +204,7 @@
.cli-binary-install-output { .cli-binary-install-output {
margin: 6px 0 0; margin: 6px 0 0;
padding: 8px 10px; padding: 8px 10px;
background: rgba(0, 0, 0, 0.35); background: color-mix(in srgb, var(--bg) 35%, transparent);
border-radius: 4px; border-radius: 4px;
max-height: 220px; max-height: 220px;
overflow: auto; overflow: auto;
@@ -214,16 +214,16 @@
} }
.cli-binary-install-output--err { .cli-binary-install-output--err {
color: #f48581; color: var(--color-error);
} }
.cli-binary-permissions-hint { .cli-binary-permissions-hint {
margin: 6px 0; margin: 6px 0;
padding: 8px 10px; padding: 8px 10px;
background: rgba(218, 54, 51, 0.1); background: color-mix(in srgb, var(--color-error) 10%, transparent);
border-left: 3px solid rgba(218, 54, 51, 0.55); border-left: 3px solid color-mix(in srgb, var(--color-error) 55%, transparent);
border-radius: 0 4px 4px 0; border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
color: #f7c4c2; color: var(--color-error);
font-size: 12.5px; font-size: 12.5px;
line-height: 1.5; line-height: 1.5;
} }

View File

@@ -153,12 +153,12 @@
} }
.model-combobox-option--selected { .model-combobox-option--selected {
background: rgba(88, 166, 255, 0.15); background: color-mix(in srgb, var(--todo) 15%, transparent);
} }
.model-combobox-option--selected:hover, .model-combobox-option--selected:hover,
.model-combobox-option--selected.model-combobox-option--highlighted { .model-combobox-option--selected.model-combobox-option--highlighted {
background: rgba(88, 166, 255, 0.25); background: color-mix(in srgb, var(--todo) 25%, transparent);
} }
.model-combobox-option-main { .model-combobox-option-main {
@@ -380,22 +380,22 @@ html .column.drag-over * {
--status-color-unknown: #6e7781; --status-color-unknown: #6e7781;
/* Shadow for light mode */ /* Shadow for light mode */
--shadow-sm: 0 1px 2px rgba(31, 35, 40, 0.08); --shadow-sm: 0 1px 2px color-mix(in srgb, var(--text) 8%, transparent);
--shadow-md: 0 4px 6px rgba(31, 35, 40, 0.12); --shadow-md: 0 4px 6px color-mix(in srgb, var(--text) 12%, transparent);
--shadow-lg: 0 4px 24px rgba(31, 35, 40, 0.15); --shadow-lg: 0 4px 24px color-mix(in srgb, var(--text) 15%, transparent);
--shadow-glow: 0 0 8px rgba(9, 105, 218, 0.18); --shadow-glow: 0 0 8px color-mix(in srgb, var(--todo) 18%, transparent);
--glow-success: 0 0 8px rgba(26, 127, 55, 0.3); --glow-success: 0 0 8px color-mix(in srgb, var(--color-success) 30%, transparent);
--glow-warning: 0 0 8px rgba(154, 103, 0, 0.3); --glow-warning: 0 0 8px color-mix(in srgb, var(--color-warning) 30%, transparent);
--glow-danger: 0 0 8px rgba(207, 34, 46, 0.3); --glow-danger: 0 0 8px color-mix(in srgb, var(--color-error) 30%, transparent);
--focus-ring: 0 0 0 2px rgba(9, 105, 218, 0.12); --focus-ring: 0 0 0 2px color-mix(in srgb, var(--todo) 12%, transparent);
--focus-ring-strong: 0 0 0 2px rgba(9, 105, 218, 0.24); --focus-ring-strong: 0 0 0 2px color-mix(in srgb, var(--todo) 24%, transparent);
/* CTA tokens for light mode */ /* CTA tokens for light mode */
--cta-bg: #1a7f37; --cta-bg: #1a7f37;
--cta-border: #1f883d; --cta-border: #1f883d;
--cta-text: #fff; --cta-text: #fff;
--cta-bg-hover: #1f883d; --cta-bg-hover: #1f883d;
--cta-border-hover: #2ea043; --cta-border-hover: #2ea043;
--cta-glow: 0 0 8px rgba(26, 127, 55, 0.3); --cta-glow: 0 0 8px color-mix(in srgb, var(--color-success) 30%, transparent);
/* Info color for light mode */ /* Info color for light mode */
--color-info: #0969da; --color-info: #0969da;
@@ -435,7 +435,7 @@ html .column.drag-over * {
/* Mission autopilot — darker for light backgrounds */ /* Mission autopilot — darker for light backgrounds */
--autopilot-icon: #ca8a04; --autopilot-icon: #ca8a04;
--autopilot-shadow: rgba(34, 197, 94, 0.4); --autopilot-shadow: color-mix(in srgb, var(--color-success) 40%, transparent);
/* Terminal background */ /* Terminal background */
--terminal-bg: #f6f8fa; --terminal-bg: #f6f8fa;
@@ -443,8 +443,8 @@ html .column.drag-over * {
/* Card mission badge — darker purple for light bg */ /* Card mission badge — darker purple for light bg */
--badge-mission-text: #7c3aed; --badge-mission-text: #7c3aed;
--badge-mission-text-hover: #8b5cf6; --badge-mission-text-hover: #8b5cf6;
--badge-mission-bg: rgba(124, 58, 237, 0.12); --badge-mission-bg: color-mix(in srgb, var(--badge-mission-text) 12%, transparent);
--badge-mission-bg-hover: rgba(124, 58, 237, 0.22); --badge-mission-bg-hover: color-mix(in srgb, var(--badge-mission-text-hover) 22%, transparent);
/* Mission event type colors — darker/more saturated for light readability */ /* Mission event type colors — darker/more saturated for light readability */
--event-error-text: #dc2626; --event-error-text: #dc2626;
@@ -452,15 +452,15 @@ html .column.drag-over * {
--event-task-text: #059669; --event-task-text: #059669;
--event-slice-text: #d97706; --event-slice-text: #d97706;
--event-autopilot-text: #9333ea; --event-autopilot-text: #9333ea;
--event-error-bg: rgba(220, 38, 38, 0.12); --event-error-bg: color-mix(in srgb, var(--event-error-text) 12%, transparent);
--event-state-bg: rgba(37, 99, 235, 0.12); --event-state-bg: color-mix(in srgb, var(--event-state-text) 12%, transparent);
--event-task-bg: rgba(5, 150, 105, 0.12); --event-task-bg: color-mix(in srgb, var(--event-task-text) 12%, transparent);
--event-slice-bg: rgba(217, 119, 6, 0.12); --event-slice-bg: color-mix(in srgb, var(--event-slice-text) 12%, transparent);
--event-autopilot-bg: rgba(147, 51, 234, 0.12); --event-autopilot-bg: color-mix(in srgb, var(--event-autopilot-text) 12%, transparent);
/* Mission toggle & badge backgrounds */ /* Mission toggle & badge backgrounds */
--toggle-checked-bg: rgba(34, 197, 94, 0.15); --toggle-checked-bg: color-mix(in srgb, var(--color-success) 15%, transparent);
--meta-badge-bg: rgba(63, 185, 80, 0.08); --meta-badge-bg: color-mix(in srgb, var(--color-success) 8%, transparent);
/* Star favorites */ /* Star favorites */
--star-idle: #9ca3af; --star-idle: #9ca3af;
@@ -472,19 +472,19 @@ html .column.drag-over * {
[data-theme="light"] .agent-detail-overlay, [data-theme="light"] .agent-detail-overlay,
[data-theme="light"] .agent-dialog-overlay, [data-theme="light"] .agent-dialog-overlay,
[data-theme="light"] .chat-new-dialog-backdrop { [data-theme="light"] .chat-new-dialog-backdrop {
background: rgba(31, 35, 40, 0.5); background: color-mix(in srgb, var(--text) 50%, transparent);
} }
[data-theme="light"] .modal-header { [data-theme="light"] .modal-header {
background: rgba(246, 248, 250, 0.8); background: color-mix(in srgb, var(--surface) 80%, transparent);
} }
[data-theme="light"] .modal-actions { [data-theme="light"] .modal-actions {
background: rgba(246, 248, 250, 0.6); background: color-mix(in srgb, var(--surface) 60%, transparent);
} }
[data-theme="light"] .settings-sidebar { [data-theme="light"] .settings-sidebar {
background: rgba(246, 248, 250, 0.6); background: color-mix(in srgb, var(--surface) 60%, transparent);
} }
[data-theme="light"] .toast-success { [data-theme="light"] .toast-success {
@@ -1062,7 +1062,7 @@ html .column.drag-over * {
.theme-swatch-glass { .theme-swatch-glass {
--swatch-sample-1: #13111f; --swatch-sample-1: #13111f;
--swatch-sample-2: rgba(34, 27, 52, 0.78); --swatch-sample-2: color-mix(in srgb, #221b34 78%, transparent);
--swatch-sample-3: #c86bff; --swatch-sample-3: #c86bff;
--swatch-sample-4: #ff7aa8; --swatch-sample-4: #ff7aa8;
} }
@@ -1273,7 +1273,7 @@ html .column.drag-over * {
[data-theme="light"] .theme-swatch-glass { [data-theme="light"] .theme-swatch-glass {
--swatch-sample-1: #eceaf5; --swatch-sample-1: #eceaf5;
--swatch-sample-2: rgba(255, 255, 255, 0.75); --swatch-sample-2: color-mix(in srgb, #ffffff 75%, transparent);
--swatch-sample-3: #9d40cf; --swatch-sample-3: #9d40cf;
--swatch-sample-4: #c74b7a; --swatch-sample-4: #c74b7a;
} }

View File

@@ -144,7 +144,7 @@
.chat-new-dialog-backdrop { .chat-new-dialog-backdrop {
position: fixed; position: fixed;
inset: 0; inset: 0;
background: rgba(0, 0, 0, 0.6); background: color-mix(in srgb, var(--bg) 60%, transparent);
backdrop-filter: blur(4px); backdrop-filter: blur(4px);
display: flex; display: flex;
align-items: center; align-items: center;
@@ -281,8 +281,8 @@
} }
.chat-new-dialog-agent-item--selected { .chat-new-dialog-agent-item--selected {
background: var(--accent-color-light, rgba(59, 130, 246, 0.1)); background: color-mix(in srgb, var(--todo) 10%, transparent);
border: 1px solid var(--accent-color, rgba(59, 130, 246, 0.3)); border: 1px solid color-mix(in srgb, var(--todo) 30%, transparent);
} }
.chat-new-dialog-agent-name { .chat-new-dialog-agent-name {

View File

@@ -40,7 +40,7 @@
.github-import-toolbar__zone--filter input:focus { .github-import-toolbar__zone--filter input:focus {
border-color: var(--color-primary); border-color: var(--color-primary);
box-shadow: 0 0 0 2px rgba(var(--color-primary-rgb), 0.2); box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-primary) 20%, transparent);
outline: none; outline: none;
} }
@@ -106,7 +106,7 @@
.github-import-remote-select select:focus { .github-import-remote-select select:focus {
outline: none; outline: none;
border-color: var(--color-primary); border-color: var(--color-primary);
box-shadow: 0 0 0 2px rgba(var(--color-primary-rgb), 0.2); box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-primary) 20%, transparent);
} }
/* Load button */ /* Load button */
@@ -540,8 +540,8 @@
} }
.issue-item.selected { .issue-item.selected {
background: rgba(var(--in-progress-rgb), 0.12); background: color-mix(in srgb, var(--in-progress) 12%, transparent);
box-shadow: inset 0 0 0 1px rgba(var(--in-progress-rgb), 0.35); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--in-progress) 35%, transparent);
} }
.issue-item.imported { .issue-item.imported {
@@ -653,7 +653,7 @@
[data-theme="light"] .github-import-tab.active { [data-theme="light"] .github-import-tab.active {
background: var(--card); background: var(--card);
border-color: var(--border); border-color: var(--border);
box-shadow: 0 1px 3px rgba(31, 35, 40, 0.06); box-shadow: var(--shadow-sm);
} }
[data-theme="light"] .github-import-toolbar { [data-theme="light"] .github-import-toolbar {
@@ -668,7 +668,7 @@
[data-theme="light"] .github-import-toolbar__zone--filter input:focus { [data-theme="light"] .github-import-toolbar__zone--filter input:focus {
border-color: var(--color-primary, var(--todo)); border-color: var(--color-primary, var(--todo));
box-shadow: 0 0 0 2px rgba(var(--in-progress-rgb), 0.15); box-shadow: 0 0 0 2px color-mix(in srgb, var(--in-progress) 15%, transparent);
} }
[data-theme="light"] .issues-list { [data-theme="light"] .issues-list {
@@ -681,8 +681,8 @@
} }
[data-theme="light"] .issue-item.selected { [data-theme="light"] .issue-item.selected {
background: rgba(var(--in-progress-rgb), 0.08); background: color-mix(in srgb, var(--in-progress) 8%, transparent);
box-shadow: inset 0 0 0 1px rgba(var(--in-progress-rgb), 0.3); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--in-progress) 30%, transparent);
} }
[data-theme="light"] .issue-item.imported input[type="radio"] { [data-theme="light"] .issue-item.imported input[type="radio"] {

View File

@@ -189,8 +189,8 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background: rgba(0, 0, 0, 0.6); background: color-mix(in srgb, var(--bg) 60%, transparent);
color: #fff; color: var(--text);
border: none; border: none;
border-radius: 50%; border-radius: 50%;
width: 16px; width: 16px;
@@ -203,7 +203,7 @@
} }
.inline-create-preview-remove:hover { .inline-create-preview-remove:hover {
background: rgba(248, 81, 73, 0.9); background: color-mix(in srgb, var(--color-error) 90%, transparent);
} }
.inline-create-model-wrap { .inline-create-model-wrap {

View File

@@ -3940,16 +3940,16 @@
.changes-diff-patch .diff-add, .changes-diff-patch .diff-add,
.gm-diff-patch [data-prefix="+"], .gm-diff-patch [data-prefix="+"],
.changes-diff-patch [data-prefix="+"] { .changes-diff-patch [data-prefix="+"] {
color: #3fb950; color: var(--color-success);
background-color: rgba(63, 185, 80, 0.12); background-color: color-mix(in srgb, var(--color-success) 12%, transparent);
} }
.gm-diff-patch .diff-del, .gm-diff-patch .diff-del,
.changes-diff-patch .diff-del, .changes-diff-patch .diff-del,
.gm-diff-patch [data-prefix="-"], .gm-diff-patch [data-prefix="-"],
.changes-diff-patch [data-prefix="-"] { .changes-diff-patch [data-prefix="-"] {
color: #f85149; color: var(--color-error);
background-color: rgba(248, 81, 73, 0.12); background-color: color-mix(in srgb, var(--color-error) 12%, transparent);
} }
.gm-diff-patch .diff-hunk, .gm-diff-patch .diff-hunk,
@@ -3976,16 +3976,16 @@
[data-theme="light"] .changes-diff-patch .diff-add, [data-theme="light"] .changes-diff-patch .diff-add,
[data-theme="light"] .gm-diff-patch [data-prefix="+"], [data-theme="light"] .gm-diff-patch [data-prefix="+"],
[data-theme="light"] .changes-diff-patch [data-prefix="+"] { [data-theme="light"] .changes-diff-patch [data-prefix="+"] {
color: #1a7f37; color: var(--color-success);
background-color: rgba(26, 127, 55, 0.1); background-color: color-mix(in srgb, var(--color-success) 10%, transparent);
} }
[data-theme="light"] .gm-diff-patch .diff-del, [data-theme="light"] .gm-diff-patch .diff-del,
[data-theme="light"] .changes-diff-patch .diff-del, [data-theme="light"] .changes-diff-patch .diff-del,
[data-theme="light"] .gm-diff-patch [data-prefix="-"], [data-theme="light"] .gm-diff-patch [data-prefix="-"],
[data-theme="light"] .changes-diff-patch [data-prefix="-"] { [data-theme="light"] .changes-diff-patch [data-prefix="-"] {
color: #cf222e; color: var(--color-error);
background-color: rgba(207, 34, 46, 0.1); background-color: color-mix(in srgb, var(--color-error) 10%, transparent);
} }
[data-theme="light"] .gm-diff-patch .diff-hunk, [data-theme="light"] .gm-diff-patch .diff-hunk,

View File

@@ -89,7 +89,7 @@
} }
.workspace-selector-option.active { .workspace-selector-option.active {
background: rgba(88, 166, 255, 0.12); background: color-mix(in srgb, var(--todo) 12%, transparent);
} }
.workspace-selector-option-main { .workspace-selector-option-main {

View File

@@ -1,6 +1,8 @@
import { describe, it, expect, beforeEach, vi } from "vitest"; import { describe, it, expect, beforeEach, vi } from "vitest";
import { render, screen, fireEvent, waitFor } from "@testing-library/react"; import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import { AgentReflectionsTab } from "../AgentReflectionsTab"; import { AgentReflectionsTab } from "../AgentReflectionsTab";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { import {
addAgentRating, addAgentRating,
deleteAgentRating, deleteAgentRating,
@@ -281,4 +283,10 @@ describe("AgentReflectionsTab", () => {
expect(screen.queryByText("Insights")).not.toBeInTheDocument(); expect(screen.queryByText("Insights")).not.toBeInTheDocument();
}); });
}); });
it("keeps budget warning banner tokenized", () => {
const source = readFileSync(resolve(__dirname, "../AgentReflectionsTab.css"), "utf8");
expect(source).toMatch(/\.budget-warning-banner\s*\{[^}]*var\(--state-error-bg, color-mix\(in srgb, var\(--color-error\) 15%, transparent\)\)/);
expect(source).not.toMatch(/\.budget-warning-banner\s*\{[^}]*rgba\(/);
});
}); });

View File

@@ -10,6 +10,8 @@ import {
} from "../../api"; } from "../../api";
import type { Task } from "@fusion/core"; import type { Task } from "@fusion/core";
import type { GitRemote } from "../../api"; import type { GitRemote } from "../../api";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
// Mock the API module // Mock the API module
vi.mock("../../api", async (importOriginal) => { vi.mock("../../api", async (importOriginal) => {
@@ -68,6 +70,14 @@ describe("GitHubImportModal", () => {
const onClose = vi.fn(); const onClose = vi.fn();
const onImport = vi.fn(); const onImport = vi.fn();
it("uses color-mix tokens for focus and selection surfaces", () => {
const source = readFileSync(resolve(__dirname, "../GitHubImportModal.css"), "utf8");
expect(source).not.toContain("rgba(var(--color-primary-rgb)");
expect(source).not.toContain("rgba(var(--in-progress-rgb)");
expect(source).toContain("color-mix(in srgb, var(--in-progress) 12%, transparent)");
expect(source).toContain("Some hardcoded colors below");
});
beforeEach(() => { beforeEach(() => {
vi.clearAllMocks(); vi.clearAllMocks();
vi.mocked(fetchGitRemotes).mockReset(); vi.mocked(fetchGitRemotes).mockReset();

View File

@@ -4,6 +4,8 @@ import userEvent from "@testing-library/user-event";
import { WorkspaceSelector } from "../WorkspaceSelector"; import { WorkspaceSelector } from "../WorkspaceSelector";
import type { WorkspaceInfo } from "../../hooks/useWorkspaces"; import type { WorkspaceInfo } from "../../hooks/useWorkspaces";
import { loadAllAppCss } from "../../test/cssFixture"; import { loadAllAppCss } from "../../test/cssFixture";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
const workspaces: WorkspaceInfo[] = [ const workspaces: WorkspaceInfo[] = [
{ {
@@ -96,4 +98,10 @@ describe("WorkspaceSelector", () => {
expect(css).toMatch(/\.workspace-selector-menu\s*\{[^}]*left:\s*auto;[^}]*right:\s*0;/); expect(css).toMatch(/\.workspace-selector-menu\s*\{[^}]*left:\s*auto;[^}]*right:\s*0;/);
}); });
it("uses tokenized active-option background styling", () => {
const source = readFileSync(resolve(__dirname, "../WorkspaceSelector.css"), "utf8");
expect(source).toMatch(/\.workspace-selector-option\.active\s*\{[^}]*color-mix\(in srgb, var\(--todo\) 12%, transparent\)/);
expect(source).not.toMatch(/\.workspace-selector-option\.active\s*\{[^}]*rgba\(/);
});
}); });