FN-8802: contain task cards in narrow layouts

Keep task-card content within its host at narrow desktop and mobile widths.

- Make task-card roots shrinkable, border-box flex items with bounded width
- Cover minimal and populated narrow-card layouts, including badges and controls

Files changed:
 packages/dashboard/app/components/TaskCard.css     |  7 ++++
 .../__tests__/TaskCard.badge-wrap.test.tsx         | 39 ++++++++++++++++++++++
 2 files changed, 46 insertions(+)

Fusion-Task-Id: FN-8802

Fusion-Task-Lineage: 9b0d58ce-4c48-4f3a-89fc-2ef3d603b47e

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-08-05 00:48:35 -07:00
parent 59cfa47b1c
commit fef3a6daf7
2 changed files with 46 additions and 0 deletions

View File

@@ -13,6 +13,13 @@
position: relative;
user-select: none;
touch-action: pan-x pan-y;
/*
FNXC:TaskCardLayout 2026-08-05-07:31 (FN-8802):
Every TaskCard host can become narrower than a card's populated intrinsic content, including pinned desktop docks and mobile columns. Make the shared root a border-box, shrinkable flex item so existing title truncation, badge wrapping, footer-chip wrapping, and visible trailing controls contain themselves without host-specific branches.
*/
box-sizing: border-box;
min-width: 0;
max-width: 100%;
container-type: inline-size;
container-name: task-card;
}

View File

@@ -825,4 +825,43 @@ describe("TaskCard badge wrapping (FN-5162)", () => {
expect(styles.justifyContent).toBe("flex-start");
expect(styles.minWidth).toBe("0px");
});
it("contains minimal and populated cards when a host narrows below the mobile breakpoint", () => {
const { container: minimalContainer } = render(
<TaskCard task={makeTask({ id: "FN-8802-MINIMAL", title: undefined, description: "" })} onOpenDetail={noop} addToast={noop} />,
);
const { container: populatedContainer } = render(
<TaskCard
task={makeTask({
id: "FN-8802-POPULATED",
title: "A deliberately long task title that must shrink inside a very narrow card without moving controls outside its boundary",
priority: "urgent" as Task["priority"],
executionMode: "fast",
size: "L",
sourceType: "agent_heartbeat",
sourceAgentId: "agent-badge-wrap",
noCommitsExpected: true,
})}
onOpenDetail={noop}
addToast={noop}
onMoveTask={async () => makeTask()}
workflowBadge={{ workflowId: "wf-narrow", workflowName: "A workflow badge with an intentionally long name" }}
/>,
);
for (const card of [
minimalContainer.querySelector(".card"),
populatedContainer.querySelector(".card"),
] as HTMLElement[]) {
expect(card).toBeTruthy();
const styles = getComputedStyle(card);
expect(styles.minWidth).toBe("0px");
expect(styles.maxWidth).toBe("100%");
expect(styles.boxSizing).toBe("border-box");
}
expect(populatedContainer.querySelector(".card-menu-btn")).toBeTruthy();
expect(populatedContainer.querySelector(".card-size-badge")).toBeTruthy();
expect(populatedContainer.querySelector(".card-title")).toHaveTextContent("A deliberately long task title");
});
});