FN-7339: align Shadcn Ember colors with Ember

Align Shadcn Ember theme tokens with the Ember palette while preserving shadcn structure.

- Match Shadcn Ember accent text tokens to Ember values in dark and light modes.
- Strengthen regression coverage to compare every Ember-owned color token across both modes.
- Add a patch changeset for the published Fusion package.

Files changed:
 .changeset/fn-7339-shadcn-ember-colors.md          |  7 +++
 .../app/__tests__/shadcn-ember-theme.test.ts       | 69 +++++++++++++++-------
 packages/dashboard/app/public/theme-data.css       |  7 ++-
 3 files changed, 60 insertions(+), 23 deletions(-)

Fusion-Task-Id: FN-7339

Fusion-Task-Lineage: d0c2f0cf-938f-46a4-8da4-9acafc5cc4cf

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-06-30 22:30:09 -07:00
parent 5ff81cb460
commit ae1ca5cf16
3 changed files with 58 additions and 21 deletions

View File

@@ -0,0 +1,7 @@
---
"@runfusion/fusion": patch
---
summary: Make Shadcn Ember color tokens match Ember exactly.
category: fix
dev: Aligns Shadcn Ember inherited Ember-owned CSS tokens and adds regression coverage.

View File

@@ -7,47 +7,68 @@ import path from "path";
const themeDataPath = path.resolve(__dirname, "../public/theme-data.css");
const dashboardIndexPath = path.resolve(__dirname, "../index.html");
const desktopIndexPath = path.resolve(__dirname, "../../../desktop/src/renderer/index.html");
const EMBER_OWNED_COLOR_TOKENS = [
"--todo",
"--in-progress",
"--in-progress-rgb",
"--in-review",
"--triage",
"--done",
"--color-success",
"--color-error",
"--cta-bg",
"--cta-border",
"--cta-text",
"--cta-bg-hover",
"--cta-border-hover",
"--cta-glow",
"--logo-accent",
"--color-info",
"--accent",
"--accent-text",
];
/*
FNXC:DashboardTheming 2026-06-30-00:00:
Shadcn Ember is the default color-theme contract. Tests assert source-of-truth CSS and every bootstrap validator so unset/invalid installs converge on Shadcn Ember while explicit legacy ids remain valid.
FNXC:DashboardTheming 2026-06-30-21:41:
Symptom coverage compares Ember-owned token maps instead of selected literals because Shadcn Ember keeps shadcn structure while inheriting Ember's palette exactly in both modes.
*/
describe("Shadcn Ember color theme", () => {
const themeData = fs.readFileSync(themeDataPath, "utf-8");
const dashboardIndex = fs.readFileSync(dashboardIndexPath, "utf-8");
const desktopIndex = fs.readFileSync(desktopIndexPath, "utf-8");
it("defines dark and light shadcn structure with Ember color tokens", () => {
it("keeps dark and light shadcn structure while matching Ember-owned color tokens exactly", () => {
const darkEmberBlock = extractSelectorBlock(themeData, '[data-color-theme="ember"]');
const lightEmberBlock = extractSelectorBlock(themeData, '[data-color-theme="ember"][data-theme="light"]');
const darkBlock = extractSelectorBlock(themeData, '[data-color-theme="shadcn-ember"]');
const lightBlock = extractSelectorBlock(themeData, '[data-color-theme="shadcn-ember"][data-theme="light"]');
const darkEmberTokens = extractCustomProperties(darkEmberBlock);
const lightEmberTokens = extractCustomProperties(lightEmberBlock);
const darkShadcnEmberTokens = extractCustomProperties(darkBlock);
const lightShadcnEmberTokens = extractCustomProperties(lightBlock);
expect(darkBlock).toContain("--surface-hover:");
expect(lightBlock).toContain("--surface-hover:");
expect(darkBlock).toContain("--bg: #09090b;");
expect(darkBlock).toContain("--card: #18181b;");
expect(lightBlock).toContain("--bg: #ffffff;");
expect(lightBlock).toContain("--card-hover: #f4f4f5;");
expect(darkBlock).toContain("--btn-border-width: 1px;");
expect(darkBlock).toContain("--font-primary: \"Geist\",");
expect(darkShadcnEmberTokens["--color-warning"]).toBe("#f59e0b");
expect(lightShadcnEmberTokens["--color-muted"]).toBe("#71717a");
expect(darkBlock).toContain("--todo: #a0a0a0;");
expect(darkBlock).toContain("--in-progress: #b8b8b8;");
expect(darkBlock).toContain("--color-error: #ff6b6b;");
expect(darkBlock).toContain("--cta-bg: #d4622a;");
expect(darkBlock).toContain("--cta-border: #e8773a;");
expect(darkBlock).toContain("--color-info: #e8773a;");
expect(darkBlock).toContain("--accent: #e8773a;");
expect(Object.keys(darkEmberTokens)).toEqual(expect.arrayContaining(EMBER_OWNED_COLOR_TOKENS));
expect(Object.keys(lightEmberTokens)).toEqual(expect.arrayContaining(EMBER_OWNED_COLOR_TOKENS));
expect(lightBlock).toContain("--todo: #404040;");
expect(lightBlock).toContain("--in-progress: #606060;");
expect(lightBlock).toContain("--color-error: #dc2626;");
expect(lightBlock).toContain("--cta-bg: #c05820;");
expect(lightBlock).toContain("--cta-border: #d4622a;");
expect(lightBlock).toContain("--color-info: #c05820;");
expect(lightBlock).toContain("--accent: #d4622a;");
for (const token of Object.keys(darkEmberTokens)) {
expect(darkShadcnEmberTokens[token], `dark ${token}`).toBe(darkEmberTokens[token]);
}
expect(darkBlock).toContain("--color-warning: #f59e0b;");
expect(lightBlock).toContain("--color-muted: #71717a;");
for (const token of Object.keys(lightEmberTokens)) {
expect(lightShadcnEmberTokens[token], `light ${token}`).toBe(lightEmberTokens[token]);
}
});
it("registers the default theme in core, dashboard options, and bootstrap validators", () => {
@@ -85,6 +106,12 @@ function extractValidThemes(html: string): string[] {
return Array.from(match[1].matchAll(/["']([^"']+)["']/g), ([, theme]) => theme);
}
function extractCustomProperties(block: string): Record<string, string> {
return Object.fromEntries(
Array.from(block.matchAll(/(--[\w-]+)\s*:\s*([^;]+);/g), ([, token, value]) => [token, value.trim()]),
);
}
function extractSelectorBlock(css: string, selector: string): string {
const startIdx = css.indexOf(`${selector} {`);
if (startIdx === -1) {

View File

@@ -1431,6 +1431,9 @@ FN-6758 makes the default shadcn highlight/accent orange for focus rings, active
/*
FNXC:DashboardTheming 2026-06-30-00:00:
Shadcn Ember combines shadcn/ui zinc structure with Ember's warm orange/graphite CTA, status, accent, and info colors. It is the default for unset installs while explicit legacy theme ids stay valid.
FNXC:DashboardTheming 2026-06-30-21:41:
Shadcn Ember must keep shadcn structure but match every Ember-owned color token byte-for-byte against Ember in dark and light mode so the default theme cannot drift from Ember's palette.
*/
[data-color-theme="shadcn-ember"] {
--bg: #09090b;
@@ -1505,7 +1508,7 @@ Shadcn Ember combines shadcn/ui zinc structure with Ember's warm orange/graphite
--logo-accent: #e8773a;
--color-info: #e8773a;
--accent: #e8773a;
--accent-text: #ffffff;
--accent-text: #fff;
}
[data-color-theme="shadcn-ember"][data-theme="light"] {
@@ -1552,7 +1555,7 @@ Shadcn Ember combines shadcn/ui zinc structure with Ember's warm orange/graphite
--logo-accent: #d4622a;
--color-info: #c05820;
--accent: #d4622a;
--accent-text: #ffffff;
--accent-text: #fff;
}