-
Notifications
You must be signed in to change notification settings - Fork 1
feat(storybook): introduce Storybook UI #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
3f249bb
chore(storybook): init storybook
georg-schwarz 68e679d
feat(home): migrate homepage into storybook components
georg-schwarz d922e02
refactor(components): reorganize component folders and local types
georg-schwarz 52de8ff
chore(lint): enforce component boundaries
georg-schwarz 41774b7
chore(storybook): add a11y addon and preview defaults
georg-schwarz 229dcf8
feat(layout): componentize navbar and footer
georg-schwarz 3d9a8e3
fix(storybook): align home template brand type
georg-schwarz 8baf14d
fix(storybook): complete home template seo type
georg-schwarz 5e42fbb
fix(storybook): expand home template brand shape
georg-schwarz 576f6e8
fix(storybook): align home template theme types
georg-schwarz 95d5e8b
chore(storybook): align stories with CSF3 typing
georg-schwarz 1c738e0
chore(storybook): add storybook skill reference
georg-schwarz 2af178b
fix(templates): inline brand color scale type
georg-schwarz e89da97
chore(storybook): refresh docs and interaction tests
georg-schwarz 023e466
fix(storybook): prevent link navigation in plays
georg-schwarz f6d94b8
feat(storybook): add brand token gallery
georg-schwarz e0c7bbb
fix(tsconfig): include storybook in tsconfig
georg-schwarz 1a9bd92
feat(storybook): enforce a11y checks in CI
georg-schwarz 291e0f3
chore(ci): clarify npx usage for storybook tests
georg-schwarz 54b1f0f
fix(button): strip class prop from spreads
georg-schwarz 90483da
docs(storybook): align skill guidance with repo usage
georg-schwarz 998720f
chore(lint): add foundations boundary layer
georg-schwarz ce6161b
chore(lint): register data and page boundaries
georg-schwarz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| --- | ||
| name: storybook-component | ||
| description: Create, review, and edit components in the component library, the design system, and storybook | ||
| license: MIT | ||
| compatibility: opencode | ||
| --- | ||
|
|
||
| ## What I do | ||
|
|
||
| - Create new components in the component library, design system, and storybook in a consistent way | ||
| - Review existing component library, design system, and storybook for consistency and best practices | ||
| - Update existing component library, design system, and storybook in a consistent way | ||
|
|
||
| ## When to use me | ||
|
|
||
| Use this skill for any Storybook-related work in this repo, including: | ||
|
|
||
| - Reviewing the component library or Storybook setup for best practices. | ||
| - Auditing story coverage, controls, docs, or interactions. | ||
| - Creating or editing components and their stories in `src/components`. | ||
|
|
||
| If the user asks to “review the component library in terms of Storybook best practices,” load this skill. | ||
|
|
||
| ## Domain knowledge: Storybook basics | ||
|
|
||
| - A story is a focused, deterministic example of a component state. | ||
| - Stories should be isolated from app routing, API calls, and global state. | ||
| - Prefer args/controls over hard-coded props to keep stories interactive. | ||
| - Favor realistic content and edge cases (long strings, empty states, errors). | ||
| - Use `parameters` for layout, backgrounds, and viewport-specific cases. | ||
| - Keep stories fast: avoid heavy network requests or long-running effects. | ||
|
|
||
| ## Best practices | ||
|
|
||
| - One component per story file, co-located with the component. | ||
| - Export a single `meta` default (or `export default`) and named stories. | ||
| - Use concise story names that reflect the user-facing state. | ||
| - Keep stories deterministic (no random data without a seeded generator). | ||
| - Use `argTypes` for clear control labels and documentation. | ||
| - Avoid coupling stories to app-specific context unless the component requires it. | ||
| - Prefer minimal decorators; if needed, document why they exist. | ||
| - Interaction tests should include at least one assertion so failures are meaningful; use them for behaviors, not purely visual states. | ||
| - Add play functions when user interactions change the UI, trigger callbacks, or guard accessibility flows; skip for static-only components. | ||
| - For links in play functions, prevent default navigation before clicking to avoid browser disconnects during Vitest runs. | ||
|
|
||
| ## Repo-specific conventions | ||
|
|
||
| - Components live in `src/components` following atoms/molecules/organisms/templates. | ||
| - Use kebab-case filenames and PascalCase component names. | ||
| - Keep stories alongside components as `*.stories.tsx` or `*.stories.astro`. | ||
| - If a component has a separate types file, place it in the same folder and export | ||
| types via the local barrel `index.ts`. | ||
| - Always import components from the component's local barrel (e.g. | ||
| `@/components/organisms/Navbar`) rather than deep relative paths. | ||
| - Use the `@/` alias for any imports within `src/`. | ||
| - Do not import from `src/pages` or `src/layouts` in stories. | ||
| - Always set `parameters.docs.description.component` with a concise usage note for every component story. | ||
|
|
||
| ## Standard workflow | ||
|
|
||
| 1. Create or update the component in `src/components/...`. | ||
| 2. Add or update the story file in the same folder. | ||
| 3. If new props or types are added, update the local `index.ts` barrel. | ||
| 4. Verify stories render in Storybook and controls behave as expected. | ||
|
|
||
| ## Story templates | ||
|
|
||
| ### React/TSX story | ||
|
|
||
| ```ts | ||
| import type { Meta, StoryObj } from "@storybook/react"; | ||
| import { Button } from "@/components"; | ||
|
|
||
| const meta: Meta<typeof Button> = { | ||
| title: "Atoms/Button", | ||
| component: Button, | ||
| args: { | ||
| label: "Click me", | ||
| variant: "primary", | ||
| }, | ||
| }; | ||
|
|
||
| export default meta; | ||
| type Story = StoryObj<typeof Button>; | ||
|
|
||
| export const Default: Story = {}; | ||
| ``` | ||
|
|
||
| ### Astro story (when using `.astro` components) | ||
|
|
||
| ```ts | ||
| import type { Meta, StoryObj } from "@storybook/astro"; | ||
| import { Hero } from "@/components"; | ||
|
|
||
| const meta: Meta<typeof Hero> = { | ||
| title: "Organisms/Hero", | ||
| component: Hero, | ||
| args: { | ||
| title: "Research that ships", | ||
| subtitle: "A short, descriptive subtitle", | ||
| }, | ||
| parameters: { | ||
| layout: "fullscreen", | ||
| }, | ||
| }; | ||
|
|
||
| export default meta; | ||
| type Story = StoryObj<typeof Hero>; | ||
|
|
||
| export const Default: Story = {}; | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,3 +21,6 @@ pnpm-debug.log* | |
| .idea/ | ||
| .vscode/ | ||
| *.swp | ||
|
|
||
| # planning notes (do not commit) | ||
| PLAN.md | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| import type { StorybookConfig } from "@storybook/react-vite"; | ||
|
|
||
| const config: StorybookConfig = { | ||
| framework: "@storybook/react-vite", | ||
| stories: ["../src/components/**/*.stories.@(ts|tsx|mdx)"], | ||
| addons: [ | ||
| "@storybook/addon-a11y", | ||
| "@storybook/addon-docs", | ||
| "@storybook/addon-vitest", | ||
| ], | ||
| viteFinal: async (config) => { | ||
| config.resolve = config.resolve ?? {}; | ||
| config.resolve.alias = { | ||
| ...(config.resolve.alias ?? {}), | ||
| "@": "/src", | ||
| }; | ||
| return config; | ||
| }, | ||
| }; | ||
|
|
||
| export default config; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| <style> | ||
| :root { | ||
| --color-primary-50: 239 246 255; | ||
| --color-primary-100: 219 234 254; | ||
| --color-primary-200: 191 219 254; | ||
| --color-primary-300: 147 197 253; | ||
| --color-primary-400: 96 165 250; | ||
| --color-primary-500: 59 130 246; | ||
| --color-primary-600: 37 99 235; | ||
| --color-primary-700: 29 78 216; | ||
| --color-primary-800: 30 64 175; | ||
| --color-primary-900: 30 58 138; | ||
| --color-primary-950: 23 37 84; | ||
|
|
||
| --color-secondary-50: 248 250 252; | ||
| --color-secondary-100: 241 245 249; | ||
| --color-secondary-200: 226 232 240; | ||
| --color-secondary-300: 203 213 225; | ||
| --color-secondary-400: 148 163 184; | ||
| --color-secondary-500: 100 116 139; | ||
| --color-secondary-600: 71 85 105; | ||
| --color-secondary-700: 51 65 85; | ||
| --color-secondary-800: 30 41 59; | ||
| --color-secondary-900: 15 23 42; | ||
| --color-secondary-950: 2 6 23; | ||
|
|
||
| --font-sans: Inter, system-ui, sans-serif; | ||
| --font-mono: "JetBrains Mono", monospace; | ||
| --color-theme: #2563eb; | ||
| } | ||
|
|
||
| body { | ||
| font-family: var(--font-sans); | ||
| } | ||
| </style> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| import type { Preview } from "@storybook/react"; | ||
|
|
||
| import "@/styles/global.css"; | ||
|
|
||
| const preview: Preview = { | ||
| parameters: { | ||
| a11y: { | ||
| test: "error", | ||
| }, | ||
| layout: "padded", | ||
| backgrounds: { | ||
| default: "Light", | ||
| values: [ | ||
| { name: "Light", value: "#f8fafc" }, | ||
| { name: "Dark", value: "#0f172a" }, | ||
| { name: "Brand", value: "#e0e7ff" }, | ||
| ], | ||
| }, | ||
| actions: { argTypesRegex: "^on[A-Z].*" }, | ||
| controls: { | ||
| matchers: { | ||
| color: /(background|color)$/i, | ||
| date: /Date$/i, | ||
| }, | ||
| }, | ||
| options: { | ||
| storySort: { | ||
| order: [ | ||
| "Foundations", | ||
| "Atoms", | ||
| "Molecules", | ||
| "Organisms", | ||
| "Templates", | ||
| "Pages", | ||
| ], | ||
| }, | ||
| }, | ||
| }, | ||
| }; | ||
|
|
||
| export default preview; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import { setProjectAnnotations } from "@storybook/react"; | ||
| import * as a11yAddonAnnotations from "@storybook/addon-a11y/preview"; | ||
| import * as previewAnnotations from "./preview"; | ||
|
|
||
| setProjectAnnotations([a11yAddonAnnotations, previewAnnotations]); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.