Skip to content

Commit eb1acf4

Browse files
authored
chore: integrate Storybook into the project (#124)
1 parent 804f926 commit eb1acf4

15 files changed

+1159
-5
lines changed

.continue/rules/file-structure-frameworks.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ export const Route = createFileRoute('/users/$id')({
114114
• Use Shadcn components as building blocks rather than reinventing UI
115115
• Create compound components for related UI elements
116116
• Export components with descriptive names
117+
• See the standards rule (`mcp-app-demo-standards.md`) for requirements on colocated Storybook stories for all new components.
117118
118119
## Code Organization
119120
@@ -158,3 +159,7 @@ import { userSchema } from '../../lib/schemas'
158159
• Use kebab-case for route files when appropriate
159160
• Use descriptive names that clearly indicate the file's purpose
160161
• Include the file type in the name when it adds clarity
162+
163+
```
164+
165+
```

.continue/rules/mcp-app-demo-standards.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,38 @@ function useToggle(initialValue = false) {
110110
return [value, toggle] as const
111111
}
112112
```
113+
114+
## Storybook Stories for Components
115+
116+
- All new components **must** have a colocated Storybook story for visual documentation, testing, and design review.
117+
- The story file should be named `SomeComponent.stories.tsx` and placed in the same directory as `SomeComponent.tsx`.
118+
- Example file structure:
119+
120+
```
121+
src/components/
122+
MyComponent.tsx
123+
MyComponent.stories.tsx
124+
```
125+
126+
- See `src/components/ui/button.stories.tsx` for a full example. Minimal example:
127+
128+
```typescript
129+
// MyComponent.stories.tsx
130+
import type { Meta, StoryObj } from '@storybook/react'
131+
import { MyComponent } from './MyComponent'
132+
133+
const meta: Meta<typeof MyComponent> = {
134+
title: 'UI/MyComponent',
135+
component: MyComponent,
136+
tags: ['autodocs'],
137+
}
138+
export default meta
139+
140+
type Story = StoryObj<typeof MyComponent>
141+
142+
export const Default: Story = {
143+
args: {
144+
/* props */
145+
},
146+
}
147+
```

.continue/rules/styling-ui-guidelines.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ You are an expert in Tailwind CSS and Shadcn/ui component development.
1414
• Compose existing Shadcn components rather than creating new ones from scratch
1515
• Follow Shadcn's composition patterns for building complex UI
1616
• Customize Shadcn components through their built-in variant system
17+
• See the standards rule (`mcp-app-demo-standards.md`) for requirements on colocated Storybook stories for all new components.
1718

1819
## Tailwind CSS Best Practices
1920

.cursorrules

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,39 @@ npx shadcn@latest add <component-name>
404404
<div className={cn("base-classes", isActive && "active-classes")}>
405405
```
406406

407+
## Component Storybook Stories
408+
- All new components **must** have a colocated Storybook story for visual documentation, testing, and design review.
409+
- The story file should be named `SomeComponent.stories.tsx` and placed in the same directory as `SomeComponent.tsx`.
410+
- Example file structure:
411+
412+
```
413+
src/components/
414+
MyComponent.tsx
415+
MyComponent.stories.tsx
416+
```
417+
- See [`src/components/ui/button.stories.tsx`](src/components/ui/button.stories.tsx) for a full example. Minimal example:
418+
419+
```typescript
420+
// MyComponent.stories.tsx
421+
import type { Meta, StoryObj } from '@storybook/react'
422+
import { MyComponent } from './MyComponent'
423+
424+
const meta: Meta<typeof MyComponent> = {
425+
title: 'UI/MyComponent',
426+
component: MyComponent,
427+
tags: ['autodocs'],
428+
}
429+
export default meta
430+
431+
type Story = StoryObj<typeof MyComponent>
432+
433+
export const Default: Story = {
434+
args: {
435+
/* props */
436+
},
437+
}
438+
```
439+
407440
## State Management Patterns
408441

409442
**Loader-first approach - avoid redundant React Query:**

.github/copilot-instructions.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,41 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
369369
<div className={cn("base-classes", isActive && "active-classes")}>
370370
```
371371

372+
## Component Storybook Stories
373+
374+
- All new components **must** have a colocated Storybook story for visual documentation, testing, and design review.
375+
- The story file should be named `SomeComponent.stories.tsx` and placed in the same directory as `SomeComponent.tsx`.
376+
- Example file structure:
377+
378+
```
379+
src/components/
380+
MyComponent.tsx
381+
MyComponent.stories.tsx
382+
```
383+
384+
- See [`src/components/ui/button.stories.tsx`](src/components/ui/button.stories.tsx) for a full example. Minimal example:
385+
386+
```typescript
387+
// MyComponent.stories.tsx
388+
import type { Meta, StoryObj } from '@storybook/react'
389+
import { MyComponent } from './MyComponent'
390+
391+
const meta: Meta<typeof MyComponent> = {
392+
title: 'UI/MyComponent',
393+
component: MyComponent,
394+
tags: ['autodocs'],
395+
}
396+
export default meta
397+
398+
type Story = StoryObj<typeof MyComponent>
399+
400+
export const Default: Story = {
401+
args: {
402+
/* props */
403+
},
404+
}
405+
```
406+
372407
## Accessibility Best Practices
373408

374409
### Semantic HTML and ARIA Attributes

.github/workflows/test.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ jobs:
2626

2727
- name: Run tests
2828
run: npm run test:ci
29+
# This can be removed one we deploy to Netlify and Storybook deploying is a check for PRs. See https://github.com/pomerium/mcp-app-demo/issues/123
30+
- name: Build Storybook
31+
run: npm run build-storybook
2932

3033
- name: Set up QEMU
3134
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,6 @@ dist
145145
# Tanstack Start specific files
146146
.tanstack
147147
.nitro
148+
149+
*storybook.log
150+
storybook-static

.storybook/main.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import type { StorybookConfig } from '@storybook/react-vite'
2+
3+
const config: StorybookConfig = {
4+
stories: [
5+
'../src/components/**/*.stories.@(js|jsx|mjs|ts|tsx)',
6+
'../src/components/**/*.mdx',
7+
],
8+
addons: [
9+
'@chromatic-com/storybook',
10+
'@storybook/addon-docs',
11+
'@storybook/addon-onboarding',
12+
'@storybook/addon-a11y',
13+
'@storybook/addon-vitest',
14+
'storybook-dark-mode',
15+
],
16+
framework: {
17+
name: '@storybook/react-vite',
18+
options: {},
19+
},
20+
}
21+
export default config

.storybook/preview.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import React from 'react'
2+
import type { Preview } from '@storybook/react-vite'
3+
import '../src/styles.css'
4+
5+
const preview: Preview = {
6+
parameters: {
7+
darkMode: {
8+
classTarget: 'html',
9+
darkClass: 'dark',
10+
lightClass: '',
11+
stylePreview: true,
12+
},
13+
controls: {
14+
matchers: {
15+
color: /(background|color)$/i,
16+
date: /Date$/i,
17+
},
18+
},
19+
a11y: {
20+
test: 'todo',
21+
},
22+
},
23+
decorators: [
24+
(Story) => (
25+
<div className="p-4">
26+
<Story />
27+
</div>
28+
),
29+
],
30+
}
31+
32+
export default preview

.storybook/vitest.setup.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import * as a11yAddonAnnotations from "@storybook/addon-a11y/preview";
2+
import { setProjectAnnotations } from '@storybook/react-vite';
3+
import * as projectAnnotations from './preview';
4+
5+
// This is an important step to apply the right configuration when testing your stories.
6+
// More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations
7+
setProjectAnnotations([a11yAddonAnnotations, projectAnnotations]);

0 commit comments

Comments
 (0)