FN-8665: align task-card size badge heights

Align size badges with the shared task-card badge geometry across responsive layouts.

- Remove fixed size-chip heights so shared badge styling determines dimensions.
- Cover desktop and wrapped badge geometry for S, M, and L task sizes.
- Add a patch changeset for the visual consistency fix.

Files changed:
 .changeset/fn-8665-size-badge-height.md            |  7 +++++
 packages/dashboard/app/components/TaskCard.css     | 14 +++------
 .../__tests__/TaskCard.badge-height.test.tsx       | 33 ++++++++++++++++++++--
 .../__tests__/TaskCard.badge-wrap.test.tsx         | 18 ++++++------
 4 files changed, 50 insertions(+), 22 deletions(-)

Fusion-Task-Id: FN-8665
Fusion-Task-Lineage: e54e76d5-ba33-49d5-ac05-25c0cc4183db
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-07-31 22:03:15 -07:00
parent 182e3fdbe8
commit 031d0f3e0b
4 changed files with 50 additions and 22 deletions

View File

@@ -0,0 +1,7 @@
---
"@runfusion/fusion": patch
---
summary: Align task-card size badges with adjacent status badge heights.
category: fix
dev: Size chips now share the task-card header badge geometry at desktop and mobile breakpoints.

View File

@@ -547,16 +547,13 @@ FN-6774 removes the saturated stuck-task edge stripe from board cards. Keep the
}
/*
FNXC:TaskCardLayout 2026-07-26-08:29 (FN-8599):
As a direct header child after .card-id, the size chip must stay in the first chip-height row. Whole-header centering misaligned it when the middle badge group wrapped, so lock its tokenized height and anchor it at the header start while the shared badge rule centers its text.
FNXC:TaskCardLayout 2026-08-01-04:48 (FN-8665):
The size chip must derive its box from the shared header-chip padding, line-height, and border so it renders at the same height as status and metadata chips. As a direct child after .card-id, keep it anchored to the header's first row when the middle badge group wraps.
*/
.card-size-badge {
align-self: flex-start;
flex-shrink: 0;
box-sizing: border-box;
height: var(--card-chip-height);
min-height: var(--card-chip-height);
max-height: var(--card-chip-height);
letter-spacing: 0.5px;
}
@@ -1689,15 +1686,12 @@ The mobile/short-landscape 28px ⋯ touch target must not expand .card-header-ac
*/
@media (max-width: 768px), (max-height: 480px) {
/*
FNXC:TaskCardLayout 2026-07-26-08:29 (FN-8599):
Narrow and short-landscape cards use the mobile chip rhythm. Keep the size chip first-row anchored instead of centering it over wrapped header badges.
FNXC:TaskCardLayout 2026-08-01-04:48 (FN-8665):
Narrow and short-landscape cards keep the size chip first-row anchored while its shared mobile text-chip rule supplies the same intrinsic height as neighboring badges.
*/
.card-size-badge {
align-self: flex-start;
box-sizing: border-box;
height: var(--card-chip-height-mobile);
min-height: var(--card-chip-height-mobile);
max-height: var(--card-chip-height-mobile);
}
.card-menu-btn {

View File

@@ -169,9 +169,8 @@ describe("TaskCard badge heights (FN-4369)", () => {
}
const sizeStyles = getComputedStyle(sizeBadge!);
expect(sizeStyles.height).toBe("var(--card-chip-height)");
expect(sizeStyles.minHeight).toBe("var(--card-chip-height)");
expect(sizeStyles.maxHeight).toBe("var(--card-chip-height)");
expect(sizeStyles.height).toBe(baselineStyles.height);
expect(sizeStyles.minHeight).toBe(baselineStyles.minHeight);
expect(sizeStyles.paddingTop).toBe(baselineStyles.paddingTop);
expect(sizeStyles.paddingBottom).toBe(baselineStyles.paddingBottom);
expect(sizeStyles.borderTopWidth).toBe(baselineStyles.borderTopWidth);
@@ -180,4 +179,32 @@ describe("TaskCard badge heights (FN-4369)", () => {
cleanupCss();
});
it.each(["S", "M", "L"] as const)("keeps size %s on the status badge box geometry", (size) => {
const cleanupCss = mountCss();
const { container } = render(
<TaskCard
task={makeTask({ id: `FN-8665-${size}`, status: "planning" as Task["status"], size })}
onOpenDetail={noop}
addToast={noop}
/>,
);
const statusBadge = container.querySelector(".card-status-badge");
const sizeBadge = container.querySelector(".card-size-badge");
expect(statusBadge).toBeTruthy();
expect(sizeBadge).toBeTruthy();
const statusStyles = getComputedStyle(statusBadge!);
const sizeStyles = getComputedStyle(sizeBadge!);
expect(sizeStyles.height).toBe(statusStyles.height);
expect(sizeStyles.minHeight).toBe(statusStyles.minHeight);
expect(sizeStyles.paddingTop).toBe(statusStyles.paddingTop);
expect(sizeStyles.paddingBottom).toBe(statusStyles.paddingBottom);
expect(sizeStyles.borderTopWidth).toBe(statusStyles.borderTopWidth);
expect(sizeStyles.borderBottomWidth).toBe(statusStyles.borderBottomWidth);
expect(sizeStyles.lineHeight).toBe(statusStyles.lineHeight);
cleanupCss();
});
});

View File

@@ -193,9 +193,9 @@ function expectSizeBadgeAfterTaskId(container: HTMLElement, expected: boolean) {
expect(sizeStyles.alignItems).toBe("center");
expect(sizeStyles.alignSelf).toBe("flex-start");
expect(sizeStyles.lineHeight).toBe("1");
expect(sizeStyles.height).toMatch(resolvedChipHeightPattern);
expect(sizeStyles.minHeight).toMatch(resolvedChipHeightPattern);
expect(sizeStyles.maxHeight).toMatch(resolvedChipHeightPattern);
expect(sizeStyles.height).toBe("auto");
expect(sizeStyles.minHeight).toBe("auto");
expect(sizeStyles.maxHeight).toBe("none");
expect(sizeBadge!.parentElement).toBe(header);
expect(cardId.nextElementSibling).toBe(sizeBadge);
expect(actions?.contains(sizeBadge)).toBe(false);
@@ -537,15 +537,15 @@ describe("TaskCard badge wrapping (FN-5162)", () => {
expect(sizeBadgeRule).toContain("align-self: flex-start;");
expect(sizeBadgeRule).toContain("box-sizing: border-box;");
expect(sizeBadgeRule).toContain("height: var(--card-chip-height);");
expect(sizeBadgeRule).toContain("min-height: var(--card-chip-height);");
expect(sizeBadgeRule).toContain("max-height: var(--card-chip-height);");
expect(sizeBadgeRule).not.toContain("align-self: center;");
for (const declaration of ["\n height:", "\n min-height:", "\n max-height:"]) {
expectCssRuleNotToContain(loadedCss, ".card-size-badge", declaration);
}
for (const section of [mobileSection, shortLandscapeSection]) {
expectCssRuleToContain(section, ".card-size-badge", "align-self: flex-start;");
expectCssRuleToContain(section, ".card-size-badge", "height: var(--card-chip-height-mobile);");
expectCssRuleToContain(section, ".card-size-badge", "min-height: var(--card-chip-height-mobile);");
expectCssRuleToContain(section, ".card-size-badge", "max-height: var(--card-chip-height-mobile);");
for (const declaration of ["\n height:", "\n min-height:", "\n max-height:"]) {
expectCssRuleNotToContain(section, ".card-size-badge", declaration);
}
}
});