chore(template): clean-slate template snapshot from bb4a0c7

Curated, product-agnostic snapshot of the post-story-04 tree: demo
content deleted, auth-only reference feature, web-next shell, all gates
green. Product-specific docs, ADRs 027-029, PRDs/epics/archive, editor
library traces, and product naming are curated out; generic template
repairs (coverage provider devDeps, root test:coverage script, live
lint fixes, root-only release-please) are kept. See TEMPLATE.md for
provenance, curation list, and usage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016j8z4VHjedXDTjEDNg7qHK
This commit is contained in:
2026-07-12 20:40:54 +02:00
commit f77e6ea881
1062 changed files with 105156 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
storybook-static
.storybook/storybook-static

1
apps/storybook/.storybook/css.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
declare module "*.css";

View File

@@ -0,0 +1,17 @@
import type { StorybookConfig } from "@storybook/react-vite";
const config: StorybookConfig = {
framework: "@storybook/react-vite",
stories: ["../../../packages/core-ui/src/**/*.stories.@(ts|tsx)"],
addons: ["@storybook/addon-essentials"],
docs: {
autodocs: "tag",
},
async viteFinal(config) {
const tailwindPlugin = await import("@tailwindcss/vite");
config.plugins = [tailwindPlugin.default(), ...(config.plugins || [])];
return config;
},
};
export default config;

View File

@@ -0,0 +1,15 @@
import "./storybook.css";
import type { Preview } from "@storybook/react";
const preview: Preview = {
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
};
export default preview;

View File

@@ -0,0 +1,4 @@
@import "tailwindcss";
@source "../../../packages/core-ui/src";
@import "../../../packages/core-ui/src/styles/theme.css";

137
apps/storybook/AGENTS.md Normal file
View File

@@ -0,0 +1,137 @@
# AGENTS.md — apps/storybook
Centralized Storybook instance for visual component development, documentation, and MCP integration for AI agents. Currently ships with an empty stories list — scaffold `@repo/core-ui` first to populate it.
## Purpose
Visual testing and documentation hub for the design system. When `@repo/core-ui` is scaffolded, stories live colocated with their components there. Storybook serves as the single source of truth for component usage.
> **core-ui is optional.** Scaffold it with `pnpm turbo gen core-package ui`, then add the stories glob and CSS import (see next-steps printed by the generator).
## Port: 6006
```bash
pnpm dev --filter @repo/storybook # http://localhost:6006
```
## Configuration
### `.storybook/main.ts`
Stories are empty by default. After scaffolding `@repo/core-ui`, add the glob:
```typescript
const config: StorybookConfig = {
framework: "@storybook/react-vite",
stories: ["../../../packages/core-ui/src/**/*.stories.@(ts|tsx)"],
addons: ["@storybook/addon-essentials"],
docs: { autodocs: "tag" },
async viteFinal(config) {
const { mergeConfig } = await import("vite");
const tailwindPlugin = await import("@tailwindcss/vite");
return mergeConfig(config, {
plugins: [tailwindPlugin.default()],
});
},
};
```
Key settings:
- **`stories` glob** — empty by default; add `"../../../packages/core-ui/src/**/*.stories.@(ts|tsx)"` after scaffolding core-ui
- **`viteFinal`** — adds Tailwind v4 plugin so classes render in Storybook
- **`autodocs: "tag"`** — auto-generates docs for tagged stories
### `.storybook/preview.ts`
After scaffolding `@repo/core-ui`, import global styles here:
```typescript
import type { Preview } from "@storybook/react";
import "@repo/core-ui/styles/globals.css";
const preview: Preview = {
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
};
```
## Story Organization
Stories are organized by Atomic Design level via the `title` field:
| Level | Title format | Sidebar path |
| -------- | ----------------------------- | ------------------------- |
| Atom | `"Atoms/{ComponentName}"` | Atoms > ComponentName |
| Molecule | `"Molecules/{ComponentName}"` | Molecules > ComponentName |
| Organism | `"Organisms/{ComponentName}"` | Organisms > ComponentName |
| Template | `"Templates/{ComponentName}"` | Templates > ComponentName |
Example story file (after scaffolding core-ui at `packages/core-ui/src/atoms/button/button.stories.tsx`):
```typescript
import type { Meta, StoryObj } from "@storybook/react";
import { Button } from "./button";
const meta = {
title: "Atoms/Button",
component: Button,
tags: ["autodocs"],
} satisfies Meta<typeof Button>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: { children: "Click me" },
};
export const Variant: Story = {
args: { children: "Secondary", variant: "secondary" },
};
```
## MCP Integration
When Storybook runs, the MCP endpoint is available at:
```
http://localhost:6006/mcp
```
### Available tools:
- **`list-all-documentation`** — Lists all component stories and their properties
- **`get-documentation`** — Gets detailed component info (props, variants, usage examples)
- **`run-story-tests`** — Validates story rendering
### Before building new components:
1. Query `list-all-documentation` to check if a similar component exists
2. Query `get-documentation` to understand existing props and variants
3. After creating: `run-story-tests` to validate
## Dependencies
| Dependency | Purpose |
| ----------------------------- | -------------------------------------------------------------------------------------- |
| `@repo/core-ui` | Component source + stories (optional — scaffold with `pnpm turbo gen core-package ui`) |
| `@storybook/react-vite` | Storybook with Vite bundler |
| `@storybook/addon-essentials` | Controls, Actions, Docs, Backgrounds |
| `@tailwindcss/vite` | Vite plugin for Tailwind v4 |
| `storybook` | Storybook CLI + dev server |
| `tailwindcss` | Tailwind CSS v4 |
| `vite` | Build tool |
| `react` / `react-dom` | React 19 |
## Cross-References
- **Component source (when scaffolded):** `packages/core-ui/AGENTS.md`
- **Scaffold core-ui:** `pnpm turbo gen core-package ui`
- **Storybook docs:** `.storybook/` folder

View File

@@ -0,0 +1,3 @@
import baseConfig from "@repo/core-eslint/base";
export default baseConfig;

View File

@@ -0,0 +1,35 @@
{
"name": "@repo/storybook",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"build": "echo 'Storybook build — use pnpm dev for development'",
"build:storybook": "storybook build",
"build-storybook": "storybook build",
"dev": "storybook dev -p 6006",
"lint": "eslint .",
"test-storybook": "test-storybook --url http://localhost:6006",
"test:stories": "concurrently -k -s first -n 'SB,TEST' -c 'magenta,blue' 'pnpm exec http-server storybook-static --port 6006 --silent' 'pnpm exec wait-on tcp:6006 && pnpm test-storybook'"
},
"dependencies": {},
"devDependencies": {
"@playwright/test": "^1.49.0",
"@repo/core-eslint": "workspace:*",
"@repo/core-typescript": "workspace:*",
"@storybook/addon-essentials": "^8.6.0",
"@storybook/react": "^8.6.0",
"@storybook/react-vite": "^8.6.0",
"@storybook/test-runner": "^0.19.1",
"@tailwindcss/vite": "^4.1.0",
"concurrently": "^9.0.0",
"http-server": "^14.1.0",
"playwright": "^1.52.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"storybook": "^8.6.0",
"tailwindcss": "^4.1.0",
"vite": "^6.3.0",
"wait-on": "^8.0.0"
}
}

View File

@@ -0,0 +1,13 @@
import type { TestRunnerConfig } from "@storybook/test-runner";
const config: TestRunnerConfig = {
async preVisit(page) {
page.on("console", (msg) => {
if (msg.type() === "error") {
throw new Error(`Console error in story: ${msg.text()}`);
}
});
},
};
export default config;

View File

@@ -0,0 +1,51 @@
import { test, expect } from "@playwright/test";
/**
* Iterates every story registered in Storybook and takes a screenshot.
*
* Storybook exposes its story manifest at /index.json (Storybook 7+). For
* each entry where `type === "story"`, we navigate to the iframe URL and
* snapshot.
*
* Today the index is empty (no components in the repo). The harness still
* runs — it just finds zero stories. The moment a story lands, the
* baseline is captured on first run and subsequent runs diff against it.
*/
type StoryEntry = {
id: string;
title: string;
name: string;
type: "story" | "docs";
};
async function fetchStoryIndex(baseURL: string): Promise<StoryEntry[]> {
const res = await fetch(`${baseURL}/index.json`);
if (!res.ok) return [];
const json = (await res.json()) as {
entries?: Record<string, StoryEntry>;
};
return Object.values(json.entries ?? {}).filter((e) => e.type === "story");
}
test.describe("Storybook visual regression", () => {
test("captures a screenshot for every registered story", async ({
page,
baseURL,
}) => {
const stories = await fetchStoryIndex(baseURL!);
if (stories.length === 0) {
test.skip(
true,
"No stories registered yet — visual regression harness is inactive until the first story lands.",
);
return;
}
for (const story of stories) {
await test.step(`${story.title}${story.name}`, async () => {
await page.goto(`/iframe.html?id=${story.id}&viewMode=story`);
await page.waitForLoadState("networkidle");
await expect(page).toHaveScreenshot(`${story.id}.png`);
});
}
});
});

View File

@@ -0,0 +1,16 @@
{
"extends": "@repo/core-typescript/react-library.json",
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
".storybook/**/*.ts",
"*.ts",
"*.tsx"
],
"exclude": ["node_modules"]
}

View File

@@ -0,0 +1,4 @@
{
"extends": ["//"],
"tags": ["app"]
}