feat(ui): expand workflow-ready components

This commit is contained in:
2026-03-20 18:11:48 +08:00
parent 36822f05e0
commit a8c1d3f256
27 changed files with 1562 additions and 85 deletions
@@ -26,27 +26,40 @@ function EmptyStateGlyph() {
}
function ReleaseEmptyState({
actionsLayout = "inline",
align = "center",
description = "Adjust the current filters or create a new release to start routing work.",
eyebrow = "No results",
layout = "default",
mediaSize = "default",
tone = "default",
title = "No matching releases"
}: {
actionsLayout?: "inline" | "stack";
align?: "center" | "start";
description?: string;
eyebrow?: string;
layout?: "compact" | "default" | "split";
mediaSize?: "compact" | "default" | "hero";
title?: string;
tone?: "default" | "subtle" | "accent";
}) {
return (
<EmptyState className="w-[min(100%,42rem)]" tone={tone}>
<EmptyStateMedia>
<EmptyState
align={align}
className="w-[min(100%,42rem)]"
layout={layout}
tone={tone}
>
<EmptyStateMedia size={mediaSize}>
<EmptyStateGlyph />
</EmptyStateMedia>
<EmptyStateHeader>
<EmptyStateHeader align={align}>
<EmptyStateEyebrow>{eyebrow}</EmptyStateEyebrow>
<EmptyStateTitle>{title}</EmptyStateTitle>
<EmptyStateDescription>{description}</EmptyStateDescription>
</EmptyStateHeader>
<EmptyStateActions>
<EmptyStateActions layout={actionsLayout}>
<Button>Create release</Button>
<Button variant="ghost">Reset filters</Button>
</EmptyStateActions>
@@ -89,6 +102,55 @@ export const Scenarios: Story = {
)
};
export const CompactQueue: Story = {
parameters: {
docs: {
description: {
story:
"Use the compact layout when an empty state lives inside a dense operational card, list, or queue panel and should preserve surrounding information density."
}
}
},
render: () => (
<div className="w-[720px] rounded-[var(--radius-lg)] border border-[var(--color-border)] bg-[var(--color-card)] p-6 shadow-[var(--shadow-sm)]">
<ReleaseEmptyState
actionsLayout="stack"
align="start"
description="The global queue is clear. Create a task template now or wait for the next dispatch cycle."
eyebrow="Queue clear"
layout="compact"
mediaSize="compact"
title="No blocked work right now"
tone="subtle"
/>
</div>
)
};
export const SplitWorkspace: Story = {
parameters: {
docs: {
description: {
story:
"Use the split layout when the empty state needs more narrative weight, richer actions, or a larger visual anchor inside a dashboard or setup surface."
}
}
},
render: () => (
<div className="w-[940px] rounded-[var(--radius-xl)] border border-[var(--color-border)] bg-[var(--color-background)] p-6">
<ReleaseEmptyState
align="start"
description="Invite operators, connect the first runtime, and define the initial routing lane to turn this empty workspace into an active control surface."
eyebrow="Workspace setup"
layout="split"
mediaSize="hero"
title="This command center needs its first operator"
tone="accent"
/>
</div>
)
};
export const Anatomy: Story = {
render: () => (
<div className="w-[760px] rounded-[var(--radius-lg)] border border-[var(--color-border)] bg-[var(--color-card)] p-6 text-[var(--color-foreground)] shadow-[var(--shadow-sm)]">
@@ -117,6 +179,13 @@ export const Anatomy: Story = {
<code className="text-[var(--color-foreground)]">data-tone</code> exposes whether the
surface stays neutral, subtle, or accent-led.
</p>
<p>
<code className="text-[var(--color-foreground)]">layout</code>,{" "}
<code className="text-[var(--color-foreground)]">align</code>,{" "}
<code className="text-[var(--color-foreground)]">size</code>, and{" "}
<code className="text-[var(--color-foreground)]">actions layout</code> let the same
composition flex between dense cards and broader setup moments.
</p>
</div>
</div>
</div>