diff --git a/packages/dashboard/app/__tests__/space-token-defined.test.ts b/packages/dashboard/app/__tests__/space-token-defined.test.ts index ac3f63796d..470ad11715 100644 --- a/packages/dashboard/app/__tests__/space-token-defined.test.ts +++ b/packages/dashboard/app/__tests__/space-token-defined.test.ts @@ -7,24 +7,45 @@ const componentsDir = resolve(appDir, "components"); const stylesPath = resolve(appDir, "styles.css"); const themeDataPath = resolve(appDir, "public/theme-data.css"); +/* + * FNXC:DashboardTokens 2026-07-08-00:00: + * FN-7681 found --space-2xs references escaping this guard inside a + * subdirectory stylesheet (settings/sections/McpServersCard.css) because the + * original scan was non-recursive. Walk componentsDir recursively (bounded, + * no temp-root traversal) so every component CSS file is covered, while + * skipping __tests__ directories and non-.css files. + */ function listComponentCssFiles(): string[] { - return readdirSync(componentsDir) - .filter((name) => name.endsWith(".css")) - .sort(); + const results: string[] = []; + + function walk(dir: string): void { + for (const entry of readdirSync(dir, { withFileTypes: true })) { + if (entry.name === "__tests__") continue; + const entryPath = join(dir, entry.name); + if (entry.isDirectory()) { + walk(entryPath); + } else if (entry.isFile() && entry.name.endsWith(".css")) { + results.push(entryPath); + } + } + } + + walk(componentsDir); + return results.sort(); } describe("dashboard spacing token hygiene", () => { it("does not reference undefined --space-2xs in any component stylesheet", () => { const violations: string[] = []; - for (const fileName of listComponentCssFiles()) { - const filePath = join(componentsDir, fileName); + for (const filePath of listComponentCssFiles()) { + const relativePath = filePath.slice(componentsDir.length + 1); const source = readFileSync(filePath, "utf8"); const lines = source.split(/\r?\n/); for (let index = 0; index < lines.length; index += 1) { if (lines[index].includes("var(--space-2xs)")) { - violations.push(`${fileName}:${index + 1}:${lines[index].trim()}`); + violations.push(`${relativePath}:${index + 1}:${lines[index].trim()}`); } } } diff --git a/packages/dashboard/app/components/NewTaskModal.css b/packages/dashboard/app/components/NewTaskModal.css index 07ca5e2f03..1952f23037 100644 --- a/packages/dashboard/app/components/NewTaskModal.css +++ b/packages/dashboard/app/components/NewTaskModal.css @@ -492,7 +492,7 @@ The New Task create workflow selector is a real dropdown so workflow identity ic .task-workflow-option-copy { display: flex; flex-direction: column; - gap: var(--space-2xs); + gap: var(--space-xs); min-width: 0; flex: 1 1 auto; } diff --git a/packages/dashboard/app/components/QuickEntryBox.css b/packages/dashboard/app/components/QuickEntryBox.css index a8a8cb8dc9..f6617c23ff 100644 --- a/packages/dashboard/app/components/QuickEntryBox.css +++ b/packages/dashboard/app/components/QuickEntryBox.css @@ -12,9 +12,15 @@ border-color: var(--todo); } +/* +FNXC:DashboardTokens 2026-07-08-00:00: +--space-2xs is intentionally undefined (FN-5934 decision); the guard in +app/__tests__/space-token-defined.test.ts asserts it stays undefined. Use the +smallest defined token, --space-xs (4px), instead of reintroducing --space-2xs. +*/ .quick-entry-box--drag-over { border-color: var(--triage); - box-shadow: 0 0 0 var(--space-2xs) color-mix(in srgb, var(--triage) 35%, transparent); + box-shadow: 0 0 0 var(--space-xs) color-mix(in srgb, var(--triage) 35%, transparent); } .quick-entry-drop-target { @@ -26,7 +32,7 @@ justify-content: center; gap: var(--space-xs); padding: var(--space-sm); - border: var(--space-2xs) dashed var(--triage); + border: var(--space-xs) dashed var(--triage); border-radius: var(--radius-sm); background: color-mix(in srgb, var(--card) 86%, var(--triage)); color: var(--text); @@ -38,12 +44,12 @@ .quick-entry-attach-button { position: relative; min-width: calc(var(--space-xl) + var(--space-xs)); - gap: var(--space-2xs); + gap: var(--space-xs); } .quick-entry-attach-count { min-width: var(--space-md); - padding: 0 var(--space-2xs); + padding: 0 var(--space-xs); border-radius: calc(var(--radius) * 4); background: var(--triage); color: var(--provider-icon-contrast); @@ -54,7 +60,7 @@ @media (max-width: 768px) { .quick-entry-drop-target { - inset: var(--space-2xs); + inset: var(--space-xs); padding: var(--space-xs); text-align: center; } @@ -288,7 +294,7 @@ FN-7677 — the workflow trigger shares `.btn.btn-sm.dep-trigger` classes with o .quick-entry-workflow-option-copy { display: flex; flex-direction: column; - gap: var(--space-2xs); + gap: var(--space-xs); min-width: 0; } diff --git a/packages/dashboard/app/components/TaskReviewTab.css b/packages/dashboard/app/components/TaskReviewTab.css index 71ed0b4e24..d26e3831b5 100644 --- a/packages/dashboard/app/components/TaskReviewTab.css +++ b/packages/dashboard/app/components/TaskReviewTab.css @@ -248,7 +248,7 @@ The Review tab mirrors the Import-from-GitHub comment provenance model: avatar, .task-review-tab__comment-type-badge { display: inline-flex; align-items: center; - gap: var(--space-2xs); + gap: var(--space-xs); padding: 0 var(--space-xs); min-height: var(--space-lg); border-radius: var(--radius-pill); diff --git a/packages/dashboard/app/components/__tests__/QuickEntryBox.test.tsx b/packages/dashboard/app/components/__tests__/QuickEntryBox.test.tsx index d7f30b1f1a..69f47d30f8 100644 --- a/packages/dashboard/app/components/__tests__/QuickEntryBox.test.tsx +++ b/packages/dashboard/app/components/__tests__/QuickEntryBox.test.tsx @@ -1780,7 +1780,7 @@ describe("QuickEntryBox", () => { expect(menuRule).not.toContain("inset-inline-start: 0"); expect(menuRule).toContain("width: min(calc(var(--space-xl) * 16), calc(100vw - var(--space-lg)))"); expect(menuRule).toContain("min-width: min(calc(var(--space-xl) * 14), calc(100vw - var(--space-lg)))"); - expect(optionCopyRule).toContain("gap: var(--space-2xs)"); + expect(optionCopyRule).toContain("gap: var(--space-xs)"); expect(optionNameRule).toContain("overflow-wrap: anywhere"); expect(optionNameRule).toContain("white-space: normal"); expect(optionNameRule).not.toContain("text-overflow: ellipsis"); diff --git a/packages/dashboard/app/components/settings/sections/McpServersCard.css b/packages/dashboard/app/components/settings/sections/McpServersCard.css index 615b97064e..5ac84ed18d 100644 --- a/packages/dashboard/app/components/settings/sections/McpServersCard.css +++ b/packages/dashboard/app/components/settings/sections/McpServersCard.css @@ -86,7 +86,7 @@ display: inline-flex; align-items: center; border-radius: var(--radius-full); - padding: var(--space-2xs) var(--space-xs); + padding: var(--space-xs) var(--space-xs); font-size: var(--font-size-xs); line-height: var(--line-height-tight); border: var(--border-width) solid var(--border); @@ -128,7 +128,7 @@ display: inline-flex; align-items: center; border-radius: var(--radius-full); - padding: var(--space-2xs) var(--space-xs); + padding: var(--space-xs) var(--space-xs); border: var(--border-width) solid var(--border); color: inherit; }