feat(FN-4369): complete Step 2 — normalize badge dimensions

Fusion-Task-Id: FN-4369
Fusion-Task-Lineage: 3f08cecf-2e6c-41a6-804f-645c4b809e4a
This commit is contained in:
Fusion
2026-05-13 15:06:46 -07:00
committed by gsxdsm
parent c4e0e255eb
commit 187a02988d
3 changed files with 119 additions and 20 deletions

View File

@@ -0,0 +1,5 @@
---
"@runfusion/fusion": patch
---
Normalize task card badge heights so planning, merging, urgent, high, and low pills render at the same height.

View File

@@ -130,21 +130,28 @@
z-index: 1;
}
.card-status-badge {
.card-status-badge,
.card-priority-badge,
.card-size-badge {
display: inline-flex;
align-items: center;
font-size: 0.625rem;
font-weight: 600;
line-height: 1;
text-transform: uppercase;
letter-spacing: 0.5px;
padding: 2px 8px;
padding: calc(var(--space-xs) / 2) var(--space-sm);
border: var(--btn-border-width) solid transparent;
border-radius: var(--radius-pill);
}
.card-status-badge {
letter-spacing: 0.5px;
}
.card-status-badge.stalled-review {
background: color-mix(in srgb, var(--color-warning) 18%, transparent);
color: var(--color-warning);
border: var(--btn-border-width) solid color-mix(in srgb, var(--color-warning) 30%, transparent);
border-color: color-mix(in srgb, var(--color-warning) 30%, transparent);
}
.card-stalled-review-reason {
@@ -227,14 +234,7 @@
/* Size badge: positioned in card header, subtle color coding for effort estimation */
.card-size-badge {
display: inline-flex;
align-items: center;
font-size: 0.625rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
padding: 2px 8px;
border-radius: var(--radius-pill);
}
/* Size S: subtle green tint (low effort) */
@@ -256,14 +256,7 @@
}
.card-priority-badge {
display: inline-flex;
align-items: center;
font-size: 0.625rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.4px;
padding: 2px 8px;
border-radius: var(--radius-pill);
}
.card-priority-badge--low {
@@ -1215,9 +1208,11 @@
}
/* Card: smaller status badges for 280px width */
.card-status-badge {
.card-status-badge,
.card-priority-badge,
.card-size-badge {
font-size: 0.5625rem;
padding: 1px 6px;
padding: calc(var(--space-xs) / 4) calc((var(--space-xs) * 3) / 2);
}
.card-stalled-review-reason {

View File

@@ -0,0 +1,99 @@
import { describe, it, expect, vi } from "vitest";
import { render } from "@testing-library/react";
import { TaskCard } from "../TaskCard";
import type { Task } from "@fusion/core";
import { loadAllAppCss } from "../../test/cssFixture";
vi.mock("lucide-react", () => ({
Link: () => null,
GitBranch: () => null,
Clock: () => null,
Pencil: () => null,
Layers: () => null,
ChevronDown: () => null,
Folder: () => null,
GitPullRequest: () => null,
CircleDot: () => null,
Target: () => null,
Bot: () => null,
Trash2: () => null,
RotateCw: () => null,
Zap: () => null,
}));
vi.mock("../ProviderIcon", () => ({
ProviderIcon: () => null,
}));
vi.mock("../../hooks/useTaskDiffStats", () => ({
useTaskDiffStats: () => ({ stats: null, loading: false }),
}));
const noop = () => {};
function makeTask(overrides: Partial<Task> = {}): Task {
return {
id: "FN-001",
title: "Badge height",
column: "in-progress",
status: "planning" as Task["status"],
steps: [],
dependencies: [],
description: "",
...overrides,
} as Task;
}
function mountCss() {
const style = document.createElement("style");
style.textContent = loadAllAppCss();
document.head.appendChild(style);
return () => style.remove();
}
describe("TaskCard badge heights (FN-4369)", () => {
it("keeps planning, merging, and priority pills at identical dimensions", () => {
const cleanupCss = mountCss();
const planning = render(
<TaskCard task={makeTask({ id: "FN-100", column: "in-progress", status: "planning" as Task["status"] })} onOpenDetail={noop} addToast={noop} />,
).container.querySelector(".card-status-badge");
const merging = render(
<TaskCard task={makeTask({ id: "FN-101", column: "in-review", status: "merging" as Task["status"] })} onOpenDetail={noop} addToast={noop} />,
).container.querySelector(".card-status-badge");
const urgent = render(
<TaskCard task={makeTask({ id: "FN-102", priority: "urgent" as Task["priority"] })} onOpenDetail={noop} addToast={noop} />,
).container.querySelector(".card-priority-badge--urgent");
const high = render(
<TaskCard task={makeTask({ id: "FN-103", priority: "high" as Task["priority"] })} onOpenDetail={noop} addToast={noop} />,
).container.querySelector(".card-priority-badge--high");
const low = render(
<TaskCard task={makeTask({ id: "FN-104", priority: "low" as Task["priority"] })} onOpenDetail={noop} addToast={noop} />,
).container.querySelector(".card-priority-badge--low");
expect(planning).toBeTruthy();
expect(merging).toBeTruthy();
expect(urgent).toBeTruthy();
expect(high).toBeTruthy();
expect(low).toBeTruthy();
const baseline = getComputedStyle(planning!);
for (const badge of [merging!, urgent!, high!, low!]) {
const styles = getComputedStyle(badge);
expect(styles.height).toBe(baseline.height);
expect(styles.paddingTop).toBe(baseline.paddingTop);
expect(styles.paddingBottom).toBe(baseline.paddingBottom);
expect(styles.borderTopWidth).toBe(baseline.borderTopWidth);
expect(styles.borderBottomWidth).toBe(baseline.borderBottomWidth);
expect(styles.fontSize).toBe(baseline.fontSize);
expect(styles.lineHeight).toBe(baseline.lineHeight);
}
cleanupCss();
});
});