Skip to content
Merged
Show file tree
Hide file tree
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 Mar 4, 2026
68e679d
feat(home): migrate homepage into storybook components
georg-schwarz Mar 4, 2026
d922e02
refactor(components): reorganize component folders and local types
georg-schwarz Mar 4, 2026
52de8ff
chore(lint): enforce component boundaries
georg-schwarz Mar 4, 2026
41774b7
chore(storybook): add a11y addon and preview defaults
georg-schwarz Mar 4, 2026
229dcf8
feat(layout): componentize navbar and footer
georg-schwarz Mar 4, 2026
3d9a8e3
fix(storybook): align home template brand type
georg-schwarz Mar 4, 2026
8baf14d
fix(storybook): complete home template seo type
georg-schwarz Mar 4, 2026
5e42fbb
fix(storybook): expand home template brand shape
georg-schwarz Mar 4, 2026
576f6e8
fix(storybook): align home template theme types
georg-schwarz Mar 4, 2026
95d5e8b
chore(storybook): align stories with CSF3 typing
georg-schwarz Mar 4, 2026
1c738e0
chore(storybook): add storybook skill reference
georg-schwarz Mar 4, 2026
2af178b
fix(templates): inline brand color scale type
georg-schwarz Mar 4, 2026
e89da97
chore(storybook): refresh docs and interaction tests
georg-schwarz Mar 4, 2026
023e466
fix(storybook): prevent link navigation in plays
georg-schwarz Mar 4, 2026
f6d94b8
feat(storybook): add brand token gallery
georg-schwarz Mar 4, 2026
e0c7bbb
fix(tsconfig): include storybook in tsconfig
georg-schwarz Mar 4, 2026
1a9bd92
feat(storybook): enforce a11y checks in CI
georg-schwarz Mar 4, 2026
291e0f3
chore(ci): clarify npx usage for storybook tests
georg-schwarz Mar 4, 2026
54b1f0f
fix(button): strip class prop from spreads
georg-schwarz Mar 4, 2026
90483da
docs(storybook): align skill guidance with repo usage
georg-schwarz Mar 4, 2026
998720f
chore(lint): add foundations boundary layer
georg-schwarz Mar 4, 2026
ce6161b
chore(lint): register data and page boundaries
georg-schwarz Mar 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions .agents/skills/storybook/SKILL.md
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 = {};
```
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,18 @@ jobs:
- name: Install dependencies
run: bun install

- name: Install Playwright browsers
run: bun x playwright install --with-deps chromium

- name: Lint
run: bun run lint

- name: Typecheck
run: bun run typecheck

- name: Storybook tests
# Using npx instead of bun x because we had problems with Playwright and bun x.
run: npx vitest --project=storybook --run
Comment thread
georg-schwarz marked this conversation as resolved.

- name: Build
run: bun run build
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ pnpm-debug.log*
.idea/
.vscode/
*.swp

# planning notes (do not commit)
PLAN.md
21 changes: 21 additions & 0 deletions .storybook/main.ts
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;
35 changes: 35 additions & 0 deletions .storybook/preview-head.html
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>
41 changes: 41 additions & 0 deletions .storybook/preview.ts
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;
5 changes: 5 additions & 0 deletions .storybook/vitest.setup.ts
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]);
9 changes: 6 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Idol or Bust is simple website software for research projects that want to under
bun dev # Start dev server at localhost:4321
bun build # Build for production to ./dist
bun preview # Preview production build locally
bun storybook # Start Storybook
```

### Code Quality
Expand All @@ -37,8 +38,10 @@ bun remove <package> # Remove a dependency
```
src/
├── components/ # Reusable UI components
│ ├── ui/ # Generic components (Button, Card)
│ └── features/ # Feature-specific components (Team, SocialLinks)
│ ├── atoms/ # Atomic components (Button)
│ ├── molecules/ # Compound components (Card)
│ ├── organisms/ # Sections (Team, SocialLinks)
│ └── templates/ # Page-level composition (optional)
├── content/ # Content collections (blog posts)
├── data-models/ # Shared TypeScript models for data modules
├── layouts/ # Page layouts (BaseLayout, BlogLayout)
Expand Down Expand Up @@ -97,7 +100,7 @@ import { Button, Card } from "@/components";
import type { CollectionEntry } from "astro:content";

// Avoid
import Button from "@/components/ui/Button.astro";
import { Button } from "@/components/atoms/Button";
```

### Components
Expand Down
40 changes: 33 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ Open [localhost:4321](http://localhost:4321) in your browser.
```
src/
├── components/ # Reusable UI components
│ ├── atoms/ # Atomic components
│ ├── molecules/ # Compound components
│ ├── organisms/ # Section components
│ └── templates/ # Page-level composition (optional)
├── content/ # Blog posts and resources (MDX)
├── data/ # Site-specific page copy and UI content
├── data-models/ # Shared TypeScript models for data modules
Expand All @@ -41,13 +45,35 @@ src/

## Commands

| Command | Description |
| ------------------- | ------------------------ |
| `bun dev` | Start development server |
| `bun build` | Build for production |
| `bun preview` | Preview production build |
| `bun run lint` | Run ESLint |
| `bun run typecheck` | Run TypeScript check |
| Command | Description |
| -------------------------------------- | ----------------------------- |
| `bun dev` | Start development server |
| `bun build` | Build for production |
| `bun preview` | Preview production build |
| `bun run lint` | Run ESLint |
| `bun run typecheck` | Run TypeScript check |
| `bun storybook` | Start Storybook |
| `bun storybook:build` | Build Storybook static site |
| `npx vitest --project=storybook --run` | Run Storybook tests (CI/a11y) |
Comment thread
georg-schwarz marked this conversation as resolved.

## Storybook

Storybook is configured for TSX components under `src/components/`.

```bash
bun storybook
```

Run Storybook tests (including a11y checks) from CI or locally with:

```bash
npx vitest --project=storybook --run
```

Story conventions (early stage):

- Use a single default export title that matches the component group (Atoms, Molecules, Organisms).
- Keep story names short and descriptive (Primary, WithIcon, Dense).

## Customize Branding

Expand Down
3 changes: 2 additions & 1 deletion astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import { defineConfig } from "astro/config";
import tailwind from "@astrojs/tailwind";
import mdx from "@astrojs/mdx";
import sitemap from "@astrojs/sitemap";
import react from "@astrojs/react";

const repo = "idolbust";

export default defineConfig({
site: "https://riehlegroup.github.io",
base: process.env.NODE_ENV === "production" ? `/${repo}/` : "/",
integrations: [tailwind(), mdx(), sitemap()],
integrations: [tailwind(), mdx(), sitemap(), react()],
markdown: {
shikiConfig: {
theme: "github-dark",
Expand Down
Loading
Loading