diff --git a/.changeset/fn-6686-command-center-css-token-fix.md b/.changeset/fn-6686-command-center-css-token-fix.md new file mode 100644 index 0000000000..cb8d17bade --- /dev/null +++ b/.changeset/fn-6686-command-center-css-token-fix.md @@ -0,0 +1,5 @@ +--- +"@runfusion/fusion": patch +--- + +Fix Command Center charts and shell styling to use the canonical `--accent` and `--text` dashboard tokens instead of undefined `--color-accent` and `--text-primary` aliases, so chart accents and primary text render with the intended colors. diff --git a/docs/dashboard-guide.md b/docs/dashboard-guide.md index a6293e2815..999f41ccdc 100644 --- a/docs/dashboard-guide.md +++ b/docs/dashboard-guide.md @@ -1255,7 +1255,7 @@ The `index.html` shell is templated server-side: the server injects a per-user ` **Always reference tokens. Never hardcode pixels, hex, or `rgba()` in component CSS** — global/theme token CSS is also covered by `global-theme-css-no-raw-rgba.test.ts`, so raw `rgba()` belongs only in explicit `var(--token, rgba(...))` fallbacks. For translucent backgrounds use `color-mix(in srgb, var(--color) X%, transparent)`, not `rgba()`. -Command Center chart surfaces are a stricter token-only zone: `CommandCenter.css`, `areas/areas.css`, and `charts/charts.css` should avoid raw color fallbacks and hardcoded dimensions in component rules, keep secondary copy on `--text-muted`, use `--duration-*` for animation durations, and encode mobile chart invariants with shared classes rather than one-off area styles. +Command Center chart surfaces are a stricter token-only zone: `CommandCenter.css`, `areas/areas.css`, and `charts/charts.css` should avoid raw color fallbacks and hardcoded dimensions in component rules, keep secondary copy on `--text-muted`, use canonical `--accent` / `--text` for generic accent and primary text styling, use `--duration-*` for animation durations, and encode mobile chart invariants with shared classes rather than one-off area styles. The undefined `--color-accent` / `--text-primary` aliases are forbidden under `components/command-center/**` and guarded by `command-center-css-token-canonicalization.test.ts`. ### Theme system diff --git a/packages/dashboard/app/components/command-center/CommandCenter.css b/packages/dashboard/app/components/command-center/CommandCenter.css index def55191ac..372d069cb4 100644 --- a/packages/dashboard/app/components/command-center/CommandCenter.css +++ b/packages/dashboard/app/components/command-center/CommandCenter.css @@ -59,12 +59,12 @@ The Command Center must remain scrollable on mobile inside the overflow-hidden . } .cc-tab:hover { - color: var(--text-primary); + color: var(--text); } .cc-tab.active { - color: var(--text-primary); - border-bottom-color: var(--color-accent); + color: var(--text); + border-bottom-color: var(--accent); } .cc-tabpanel { @@ -121,7 +121,7 @@ FN-6680 standardizes the Command Center card rhythm across overview, area, table .cc-stat-value { font-size: var(--font-size-xl); font-variant-numeric: tabular-nums; - color: var(--text-primary); + color: var(--text); } .cc-stat-card--gauge { @@ -182,9 +182,9 @@ FN-6680 keeps the FN-6664 live/chart shrink contract but replaces hardcoded trac border: var(--border-width) solid var(--border-subtle); border-radius: var(--radius-md); background: - linear-gradient(135deg, color-mix(in srgb, var(--color-accent) 14%, transparent), transparent), + linear-gradient(135deg, color-mix(in srgb, var(--accent) 14%, transparent), transparent), var(--surface-1); - box-shadow: 0 0 var(--space-4) color-mix(in srgb, var(--color-accent) 18%, transparent); + box-shadow: 0 0 var(--space-4) color-mix(in srgb, var(--accent) 18%, transparent); overflow: hidden; font-size: var(--font-size-sm); } @@ -193,7 +193,7 @@ FN-6680 keeps the FN-6664 live/chart shrink contract but replaces hardcoded trac content: ""; position: absolute; inset: 0; - background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--color-accent) 24%, transparent), transparent); + background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--accent) 24%, transparent), transparent); opacity: 0.45; transform: translateX(-100%); animation: cc-live-signal-sweep calc(var(--duration-slow) * 8) linear infinite; @@ -215,7 +215,7 @@ FN-6680 keeps the FN-6664 live/chart shrink contract but replaces hardcoded trac } .cc-live-strip-label { - color: var(--text-primary); + color: var(--text); font-weight: 600; } @@ -238,7 +238,7 @@ FN-6680 keeps the FN-6664 live/chart shrink contract but replaces hardcoded trac } .cc-live-metric-value { - color: var(--text-primary); + color: var(--text); font-size: var(--font-size-lg); font-weight: 700; font-variant-numeric: tabular-nums; @@ -283,7 +283,7 @@ Overview token totals now live-poll and should visibly count up on change in bot } .cc-live-trend .cc-sparkline-bar { - box-shadow: 0 0 var(--space-2) color-mix(in srgb, var(--color-accent) 28%, transparent); + box-shadow: 0 0 var(--space-2) color-mix(in srgb, var(--accent) 28%, transparent); animation: cc-live-signal-pulse calc(var(--duration-slow) * 5) ease-in-out infinite; } @@ -337,9 +337,9 @@ Overview charts must use dashboard tokens only and keep motion decorative; anima border: var(--border-width) solid var(--border-subtle); border-radius: var(--radius-md); background: - linear-gradient(145deg, color-mix(in srgb, var(--color-accent) 10%, transparent), transparent), + linear-gradient(145deg, color-mix(in srgb, var(--accent) 10%, transparent), transparent), var(--surface-1); - box-shadow: 0 0 var(--space-4) color-mix(in srgb, var(--color-accent) 12%, transparent); + box-shadow: 0 0 var(--space-4) color-mix(in srgb, var(--accent) 12%, transparent); overflow: hidden; animation: cc-overview-chart-rise var(--duration-normal) ease-out both; } @@ -352,7 +352,7 @@ Overview charts must use dashboard tokens only and keep motion decorative; anima content: ""; position: absolute; inset: 0; - background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--color-accent) 16%, transparent), transparent); + background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--accent) 16%, transparent), transparent); opacity: 0; pointer-events: none; animation: cc-overview-chart-sheen calc(var(--duration-slow) * 7) ease-in-out infinite; @@ -397,7 +397,7 @@ Overview recharts cards use token-derived height so ResponsiveContainer can rend .cc-overview-chart-card .cc-bar-fill, .cc-overview-chart-card .cc-sparkline-bar { - box-shadow: 0 0 var(--space-2) color-mix(in srgb, var(--color-accent) 30%, transparent); + box-shadow: 0 0 var(--space-2) color-mix(in srgb, var(--accent) 30%, transparent); } @keyframes cc-overview-chart-rise { diff --git a/packages/dashboard/app/components/command-center/DateRangePicker.css b/packages/dashboard/app/components/command-center/DateRangePicker.css index 37d6402a2f..52a1dd9fcc 100644 --- a/packages/dashboard/app/components/command-center/DateRangePicker.css +++ b/packages/dashboard/app/components/command-center/DateRangePicker.css @@ -57,6 +57,6 @@ Raw rgba fallbacks are replaced with byte-equivalent concrete-hex color-mix fall background: var(--surface-2, color-mix(in srgb, #7f7f7f 12%, transparent)); border: 1px solid var(--border-subtle, color-mix(in srgb, #7f7f7f 25%, transparent)); border-radius: var(--radius-sm, 4px); - color: var(--text-primary, #ddd); + color: var(--text); padding: var(--space-1, 0.25rem) var(--space-2, 0.5rem); } diff --git a/packages/dashboard/app/components/command-center/MissionControlPanel.css b/packages/dashboard/app/components/command-center/MissionControlPanel.css index 5bd94a32de..8e408737e1 100644 --- a/packages/dashboard/app/components/command-center/MissionControlPanel.css +++ b/packages/dashboard/app/components/command-center/MissionControlPanel.css @@ -85,7 +85,7 @@ Raw rgba fallbacks are replaced with byte-equivalent concrete-hex color-mix fall padding: 2px 6px; border-radius: var(--radius-sm, 6px); background: var(--surface-2, color-mix(in srgb, #3b82f6 15%, transparent)); - color: var(--text-primary, #ddd); + color: var(--text); } .cc-mc-badge.inactive { diff --git a/packages/dashboard/app/components/command-center/__tests__/command-center-css-token-canonicalization.test.ts b/packages/dashboard/app/components/command-center/__tests__/command-center-css-token-canonicalization.test.ts new file mode 100644 index 0000000000..13b0c720f5 --- /dev/null +++ b/packages/dashboard/app/components/command-center/__tests__/command-center-css-token-canonicalization.test.ts @@ -0,0 +1,40 @@ +import { readFileSync, readdirSync, statSync } from "node:fs"; +import path from "node:path"; +import { describe, expect, it } from "vitest"; + +const COMMAND_CENTER_ROOT = path.resolve(__dirname, ".."); + +function collectCssFiles(dir: string): string[] { + const out: string[] = []; + for (const entry of readdirSync(dir)) { + const fullPath = path.join(dir, entry); + const stats = statSync(fullPath); + if (stats.isDirectory()) { + out.push(...collectCssFiles(fullPath)); + continue; + } + if (entry.endsWith(".css")) { + out.push(path.relative(COMMAND_CENTER_ROOT, fullPath).split(path.sep).join("/")); + } + } + return out; +} + +describe("Command Center CSS token canonicalization", () => { + it("keeps undefined accent and primary text aliases out of Command Center CSS", () => { + const offenders: string[] = []; + for (const relPath of collectCssFiles(COMMAND_CENTER_ROOT)) { + const content = readFileSync(path.join(COMMAND_CENTER_ROOT, relPath), "utf8"); + if (/--(?:color-accent|text-primary)\b/.test(content)) offenders.push(relPath); + } + + expect(offenders, `Unexpected undefined Command Center token aliases in: ${offenders.join(", ")}`).toEqual([]); + }); + + it("keeps chart primitives wired to canonical accent and text tokens", () => { + const chartsCss = readFileSync(path.join(COMMAND_CENTER_ROOT, "charts/charts.css"), "utf8"); + + expect(chartsCss).toContain("var(--accent)"); + expect(chartsCss).toContain("var(--text)"); + }); +}); diff --git a/packages/dashboard/app/components/command-center/areas/SystemStatsArea.css b/packages/dashboard/app/components/command-center/areas/SystemStatsArea.css index 41cf734586..eb3ff44119 100644 --- a/packages/dashboard/app/components/command-center/areas/SystemStatsArea.css +++ b/packages/dashboard/app/components/command-center/areas/SystemStatsArea.css @@ -72,12 +72,12 @@ System control cards sit beside chart/stat cards, so FN-6680 gives them the same .cc-system-toggle-row, .cc-system-threshold-row { - color: var(--text-primary); + color: var(--text); font-size: var(--font-size-sm); } .cc-system-threshold-controls input[type="range"] { - accent-color: var(--color-accent); + accent-color: var(--accent); } .cc-system-threshold-controls .input { diff --git a/packages/dashboard/app/components/command-center/areas/areas.css b/packages/dashboard/app/components/command-center/areas/areas.css index 00d8049b49..a5d1227a89 100644 --- a/packages/dashboard/app/components/command-center/areas/areas.css +++ b/packages/dashboard/app/components/command-center/areas/areas.css @@ -76,9 +76,9 @@ The Tokens area needs a real hour/day/week control and live token-number motion. } .cc-token-granularity .btn.active { - border-color: var(--color-accent); - color: var(--text-primary); - background: color-mix(in srgb, var(--color-accent) 14%, var(--surface-1)); + border-color: var(--accent); + color: var(--text); + background: color-mix(in srgb, var(--accent) 14%, var(--surface-1)); } .cc-token-count-live { @@ -159,7 +159,7 @@ FN-6680 keeps table-heavy chart areas on the same --border-width/--border-subtle } .cc-table th.cc-sortable:hover { - color: var(--text-primary); + color: var(--text); } .cc-table tbody tr { @@ -171,13 +171,13 @@ FN-6680 keeps table-heavy chart areas on the same --border-width/--border-subtle } .cc-table tbody tr.cc-row-selected td { - color: var(--text-primary); + color: var(--text); } .cc-sort-caret { margin-inline-start: var(--space-1); font-size: 0.7em; - color: var(--color-accent); + color: var(--accent); } /* Unavailable sentinel ("—") with a help cursor for its tooltip. */ @@ -264,7 +264,7 @@ The Team view must use dashboard design tokens only, preserve .cc-tabpanel as th } .cc-team-agent-name { - color: var(--text-primary); + color: var(--text); font-weight: 600; } diff --git a/packages/dashboard/app/components/command-center/charts/charts.css b/packages/dashboard/app/components/command-center/charts/charts.css index 1448f3a108..900b630581 100644 --- a/packages/dashboard/app/components/command-center/charts/charts.css +++ b/packages/dashboard/app/components/command-center/charts/charts.css @@ -1,3 +1,8 @@ +/* +FNXC:CommandCenterStyling 2026-06-19-00:00: +FN-6686 requires Command Center CSS to use canonical --accent and --text tokens. Undefined legacy accent/text-primary aliases made chart primitives inherit fallback colors; the scoped token guard prevents reintroducing those aliases after the FN-6682 review finding. +*/ + /* FNXC:CommandCenterStyling 2026-06-17-18:46: Chart labels and legends must use --text-muted so command-center CSS stays aligned with the FN-4286 canonical text-token guard and avoids raw color fallbacks. @@ -65,7 +70,7 @@ FN-6680 re-checked FN-6664 in a real Blink layout engine because jsdom does not .cc-bar-fill { block-size: 100%; - background: var(--color-accent); + background: var(--accent); border-radius: var(--radius-sm); transition: width var(--transition-normal); } @@ -74,7 +79,7 @@ FN-6680 re-checked FN-6664 in a real Blink layout engine because jsdom does not min-inline-size: 0; font-size: var(--font-size-sm); font-variant-numeric: tabular-nums; - color: var(--text-primary); + color: var(--text); overflow-wrap: anywhere; text-align: end; } @@ -96,7 +101,7 @@ FN-6680 re-checked FN-6664 in a real Blink layout engine because jsdom does not .cc-stacked-segment { block-size: 100%; - background: var(--color-accent); + background: var(--accent); transition: width var(--transition-normal); } @@ -123,7 +128,7 @@ FN-6680 re-checked FN-6664 in a real Blink layout engine because jsdom does not inline-size: var(--space-2); block-size: var(--space-2); border-radius: var(--radius-sm); - background: var(--color-accent); + background: var(--accent); display: inline-block; } @@ -138,7 +143,7 @@ FN-6680 re-checked FN-6664 in a real Blink layout engine because jsdom does not .cc-sparkline-bar { flex: 1 1 0; min-inline-size: var(--border-width); - background: var(--color-accent); + background: var(--accent); border-radius: var(--border-width); transition: height var(--transition-normal); } @@ -163,7 +168,7 @@ The token-over-time chart is live-updated and animated, but the motion is decora padding: var(--space-3); border: var(--border-width) solid var(--border-subtle); border-radius: var(--radius-md); - background: linear-gradient(180deg, color-mix(in srgb, var(--color-accent) 10%, transparent), transparent), var(--surface-1); + background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 10%, transparent), transparent), var(--surface-1); overflow: hidden; } @@ -171,8 +176,8 @@ The token-over-time chart is live-updated and animated, but the motion is decora flex: 1 1 0; min-inline-size: var(--space-1); border-radius: var(--radius-sm) var(--radius-sm) 0 0; - background: linear-gradient(180deg, var(--color-accent), color-mix(in srgb, var(--color-accent) 45%, var(--surface-2))); - box-shadow: 0 0 var(--space-2) color-mix(in srgb, var(--color-accent) 24%, transparent); + background: linear-gradient(180deg, var(--accent), color-mix(in srgb, var(--accent) 45%, var(--surface-2))); + box-shadow: 0 0 var(--space-2) color-mix(in srgb, var(--accent) 24%, transparent); transition: height var(--transition-normal); animation: cc-token-series-rise var(--duration-normal) ease-out both; } @@ -240,12 +245,12 @@ Line-chart motion is decorative, token-timed, and disabled for reduced-motion us inline-size: 100%; block-size: clamp(var(--space-16), 22vw, calc(var(--space-20) * 2)); aspect-ratio: 5 / 2; - color: var(--color-accent); + color: var(--accent); overflow: hidden; } .cc-line-chart-series { - color: var(--color-accent); + color: var(--accent); } .cc-line-chart-series:nth-child(2n) { @@ -299,7 +304,7 @@ Line-chart motion is decorative, token-timed, and disabled for reduced-motion us display: grid; place-items: center; gap: var(--space-2); - color: var(--text-primary); + color: var(--text); } .cc-radial-gauge-ring { @@ -311,8 +316,8 @@ Line-chart motion is decorative, token-timed, and disabled for reduced-motion us border-radius: 50%; background: radial-gradient(circle at center, var(--surface-1) 0 54%, transparent 55%), - conic-gradient(var(--color-accent) var(--cc-radial-value), var(--surface-2) 0); - box-shadow: 0 0 var(--space-4) color-mix(in srgb, var(--color-accent) 35%, transparent); + conic-gradient(var(--accent) var(--cc-radial-value), var(--surface-2) 0); + box-shadow: 0 0 var(--space-4) color-mix(in srgb, var(--accent) 35%, transparent); isolation: isolate; animation: cc-radial-gauge-pulse calc(var(--duration-slow) * 6) ease-in-out infinite; } @@ -322,8 +327,8 @@ Line-chart motion is decorative, token-timed, and disabled for reduced-motion us position: absolute; inset: var(--space-2); border-radius: inherit; - border: var(--border-width) solid color-mix(in srgb, var(--color-accent) 45%, transparent); - box-shadow: inset 0 0 var(--space-3) color-mix(in srgb, var(--color-accent) 22%, transparent); + border: var(--border-width) solid color-mix(in srgb, var(--accent) 45%, transparent); + box-shadow: inset 0 0 var(--space-3) color-mix(in srgb, var(--accent) 22%, transparent); animation: cc-radial-gauge-sweep calc(var(--duration-slow) * 8) linear infinite; } @@ -429,7 +434,7 @@ Line-chart motion is decorative, token-timed, and disabled for reduced-motion us .cc-funnel-fill { block-size: 100%; - background: var(--color-accent); + background: var(--accent); border-radius: var(--radius-sm); transition: width var(--transition-normal); } @@ -437,7 +442,7 @@ Line-chart motion is decorative, token-timed, and disabled for reduced-motion us .cc-funnel-value { font-size: var(--font-size-sm); font-variant-numeric: tabular-nums; - color: var(--text-primary); + color: var(--text); } /* ---- Loading shimmer (used by chart skeletons) ---- */