Skip to content

Commit b9a30e7

Browse files
samejrclaude
andcommitted
feat(webapp): give the storybook a theme switcher and a categorised sidebar
A System/Light/Dark/White/Black segmented control sits above every story, defaulting to System, so components can be checked in each theme without touching the account preference — leaving the storybook hands the theme back. The sidebar's flat list becomes categories (Foundations, Actions, Forms, Menus & overlays, Feedback, Navigation, Data display, Runs & logs, Settings, Trigger Agent), and StoryKit adds shared page/section/grid scaffolding. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 9ac591f commit b9a30e7

2 files changed

Lines changed: 293 additions & 244 deletions

File tree

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { type CSSProperties, type ReactNode } from "react";
2+
import { Header1, Header2 } from "~/components/primitives/Headers";
3+
import { Paragraph } from "~/components/primitives/Paragraph";
4+
import { cn } from "~/utils/cn";
5+
6+
/* Shared scaffolding for storybook pages: one long scrolling page per component
7+
(or component group), split into titled sections whose samples sit in a
8+
responsive grid of labelled cells. */
9+
10+
export function StoryPage({
11+
title,
12+
description,
13+
children,
14+
className,
15+
}: {
16+
title: string;
17+
description?: string;
18+
children: ReactNode;
19+
className?: string;
20+
}) {
21+
return (
22+
<div className={cn("flex flex-col gap-10 p-8 pb-24", className)}>
23+
<div className="space-y-1">
24+
<Header1>{title}</Header1>
25+
{description && <Paragraph variant="small">{description}</Paragraph>}
26+
</div>
27+
{children}
28+
</div>
29+
);
30+
}
31+
32+
export function StorySection({
33+
title,
34+
description,
35+
children,
36+
className,
37+
}: {
38+
title: string;
39+
description?: string;
40+
children: ReactNode;
41+
className?: string;
42+
}) {
43+
return (
44+
<section className={cn("space-y-3", className)}>
45+
<div className="space-y-0.5 border-b border-grid-dimmed pb-2">
46+
<Header2>{title}</Header2>
47+
{description && <Paragraph variant="extra-small">{description}</Paragraph>}
48+
</div>
49+
{children}
50+
</section>
51+
);
52+
}
53+
54+
/** Responsive auto-fill grid; tune the cell floor with `min`. */
55+
export function StoryGrid({
56+
children,
57+
min = "12rem",
58+
className,
59+
}: {
60+
children: ReactNode;
61+
min?: string;
62+
className?: string;
63+
}) {
64+
return (
65+
<div
66+
className={cn("grid gap-3", className)}
67+
style={{ gridTemplateColumns: `repeat(auto-fill, minmax(${min}, 1fr))` } as CSSProperties}
68+
>
69+
{children}
70+
</div>
71+
);
72+
}
73+
74+
/** One labelled sample. */
75+
export function Story({
76+
label,
77+
children,
78+
className,
79+
contentClassName,
80+
}: {
81+
label: string;
82+
children: ReactNode;
83+
className?: string;
84+
contentClassName?: string;
85+
}) {
86+
return (
87+
<div className={cn("flex flex-col gap-2 rounded-sm border border-grid-dimmed p-3", className)}>
88+
<Paragraph variant="extra-extra-small/caps" className="text-text-dimmed">
89+
{label}
90+
</Paragraph>
91+
<div className={cn("flex min-h-8 flex-1 items-center", contentClassName)}>{children}</div>
92+
</div>
93+
);
94+
}

0 commit comments

Comments
 (0)