Skip to content

Commit 305c8b3

Browse files
samejrclaude
andcommitted
feat(webapp): show a story's component file names, copyable on hover
Each story now names the component files it covers under the title, using CopyableText so the name can be lifted straight into a search. StoryKit also gains a section-level name for pages covering several files, and a sub-section heading. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 267ab71 commit 305c8b3

1 file changed

Lines changed: 48 additions & 3 deletions

File tree

apps/webapp/app/routes/storybook/StoryKit.tsx

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,46 @@
11
import { type CSSProperties, type ReactNode } from "react";
2-
import { Header1, Header2 } from "~/components/primitives/Headers";
2+
import { CopyableText } from "~/components/primitives/CopyableText";
3+
import { Header1, Header2, Header3 } from "~/components/primitives/Headers";
34
import { Paragraph } from "~/components/primitives/Paragraph";
45
import { cn } from "~/utils/cn";
56

67
/* Shared scaffolding for storybook pages: one long scrolling page per component
78
(or component group), split into titled sections whose samples sit in a
89
responsive grid of labelled cells. */
910

11+
/**
12+
* The component's own file name, copyable on hover, so a story can be traced
13+
* back to source without hunting. Pass every file a page covers.
14+
*/
15+
export function ComponentNames({ names }: { names: string[] }) {
16+
return (
17+
<div className="flex flex-wrap items-center gap-x-4 gap-y-1">
18+
{names.map((name) => (
19+
<CopyableText key={name} value={name} className="font-mono text-xs text-text-dimmed" />
20+
))}
21+
</div>
22+
);
23+
}
24+
1025
export function StoryPage({
1126
title,
27+
componentNames,
1228
description,
1329
children,
1430
className,
1531
}: {
1632
title: string;
33+
/** File names of the components shown, e.g. ["Buttons.tsx"]. */
34+
componentNames?: string[];
1735
description?: string;
1836
children: ReactNode;
1937
className?: string;
2038
}) {
2139
return (
2240
<div className={cn("flex flex-col gap-10 p-8 pb-24", className)}>
23-
<div className="space-y-1">
41+
<div className="space-y-1.5">
2442
<Header1>{title}</Header1>
43+
{componentNames && componentNames.length > 0 && <ComponentNames names={componentNames} />}
2544
{description && <Paragraph variant="small">{description}</Paragraph>}
2645
</div>
2746
{children}
@@ -31,26 +50,52 @@ export function StoryPage({
3150

3251
export function StorySection({
3352
title,
53+
componentName,
3454
description,
3555
children,
3656
className,
3757
}: {
3858
title: string;
59+
/** Shown beside the heading when a page covers several component files. */
60+
componentName?: string;
3961
description?: string;
4062
children: ReactNode;
4163
className?: string;
4264
}) {
4365
return (
4466
<section className={cn("space-y-3", className)}>
4567
<div className="space-y-0.5 border-b border-grid-dimmed pb-2">
46-
<Header2>{title}</Header2>
68+
<div className="flex flex-wrap items-baseline gap-x-3">
69+
<Header2>{title}</Header2>
70+
{componentName && (
71+
<CopyableText value={componentName} className="font-mono text-xs text-text-dimmed" />
72+
)}
73+
</div>
4774
{description && <Paragraph variant="extra-small">{description}</Paragraph>}
4875
</div>
4976
{children}
5077
</section>
5178
);
5279
}
5380

81+
/** Sub-heading inside a section, for grouping variants of one component. */
82+
export function StorySubSection({
83+
title,
84+
children,
85+
className,
86+
}: {
87+
title: string;
88+
children: ReactNode;
89+
className?: string;
90+
}) {
91+
return (
92+
<div className={cn("space-y-2", className)}>
93+
<Header3 className="text-text-dimmed">{title}</Header3>
94+
{children}
95+
</div>
96+
);
97+
}
98+
5499
/** Responsive auto-fill grid; tune the cell floor with `min`. */
55100
export function StoryGrid({
56101
children,

0 commit comments

Comments
 (0)