storybook github

storybook — 1thay component workshop

build target: design.1thay.com · port: 6006 · linked files: astro.md, design-tokens.md, CLAUDE.md


overview

storybook is the component development and testing environment for 1thay. components are built, documented, and tested here before integration into astro pages. storybook itself is themed with 1thay tokens (dogfooding).


project config

.storybook/main.ts

import type { StorybookConfig } from '@storybook/react-vite';

const config: StorybookConfig = {
  stories: ['../src/**/*.stories.@(ts|tsx)'],
  addons: [
    '@storybook/addon-links',         // story-to-story linking
    '@storybook/addon-a11y',          // accessibility audit (axe-core)
    '@storybook/addon-docs',          // auto-generated docs + MDX
    './figma-addon.ts',               // custom Figma embed panel
  ],
  framework: {
    name: '@storybook/react-vite',
    options: {},
  },
  staticDirs: ['../public'],          // favicon, static assets
};

.storybook/preview.ts

  • imports src/tokens/tokens.css and src/styles/global.css
  • configures backgrounds: surface (#fff), dim (#f8fafc), dark (#0f172a)
  • default background: surface
  • all stories tagged autodocs

.storybook/manager.ts

  • storybook UI themed with 1thay tokens: colors, fonts, border radius
  • brand title: "1thay design system"
  • brand url: https://1thay.com

package.json scripts

{
  "storybook": "storybook dev -p 6006",
  "build-storybook": "storybook build -o dist-storybook"
}

deploy

setting value
platform cloudflare pages
repo kien-day/1thay-com
branch main
build command npm run build-storybook
output directory dist-storybook/
domain design.1thay.com
preview design.1thay-com.pages.dev

component inventory

completed

component variants stories figma astro
component variants stories figma astro
--- --- --- --- ---
Button primary, secondary, ghost, destructive 11
Card default, flat, raised, bordered 8
Input sm, md, lg + label/helper/invalid 9
Icon lucide (line), carbon (fill) 8
Badge neutral, brand, success, warning, error 6
Toast success, error, info 3

planned

table, chart, modal, select, checkbox, switch, avatar, progress, tooltip, pagination

table, badge, chart, modal, tabs, toast, select, checkbox, switch, avatar, progress, tooltip, pagination


component anatomy

every component follows this structure:

src/components/Name/
├── name.css              # styles using only design tokens
├── Name.tsx              # react component with typescript
├── Name.stories.tsx      # storybook stories with autodocs
└── (optional sub-components)

css rules

  • only use design tokens — never hardcode colors, spacing, radius, shadows
  • import from src/tokens/tokens.css (available globally via preview.ts)
  • use component-level tokens when available (--btn-*, --card-*, --input-*)
  • lowercase text via text-transform: lowercase
  • all interactive elements must have :focus-visible styles

typescript rules

  • use forwardRef for form elements (Input)
  • export types for all props interfaces
  • sub-components exported as named exports alongside root
  • component library is tree-shakeable — each component is a separate import

storybook stories rules

  • tags: ['autodocs'] on meta — auto-generates docs page
  • every variant has its own story
  • every state has its own story
  • at least one interaction test using play() + @storybook/test
  • stories use descriptive vietnamese labels where appropriate
  • use real design token values in story demos

story conventions

title format

components/Button        # top-level component
components/Icon          # icon wrappers

story naming

type pattern example
variant Primary, Secondary export const Primary: Story
size Small, Large export const Small: Story
state Disabled, Loading export const Disabled: Story
composed WithHeaderBodyFooter export const WithHeaderBodyFooter: Story
interactive Clickable, Typing export const Typing: Story

argTypes

argTypes: {
  variant: { control: 'select', options: ['primary', 'secondary', 'ghost', 'destructive'] },
  size: { control: 'select', options: ['sm', 'md', 'lg'] },
  disabled: { control: 'boolean' },
  loading: { control: 'boolean' },
}

interaction testing

every component has at least one play() test:

import { expect, fn, userEvent, within } from '@storybook/test';

export const Clickable: Story = {
  args: { onClick: fn(), children: 'click me' },
  play: async ({ canvasElement, args }) => {
    const canvas = within(canvasElement);
    const btn = canvas.getByRole('button');
    await userEvent.click(btn);
    await expect(args.onClick).toHaveBeenCalled();
  },
};

adding a new component

  1. create src/components/<Name>/ directory
  2. name.css — styles using only design tokens (see design-tokens.md)
  3. Name.tsx — react component with typescript + props interface export
  4. Name.stories.tsx — stories covering all variants, sizes, states + 1 interaction test
  5. npm run build-storybook — verify build passes
  6. create src/pages/components/name.astro — documentation page (see astro.md)
  7. update DocsLayout.astro sidebar
  8. update this file's component inventory
  9. update project-logs.md

dogfooding

storybook itself uses 1thay design tokens:

  • manager UI (sidebar, toolbar): themed with 1thay colors + Inter font
  • preview: imports tokens.css — all stories render with real tokens
  • backgrounds: surface, dim, dark match design token palette
  • docs: autodocs show real token values in use
  • a11y addon: ensures components meet WCAG standards

figma integration

mỗi component story phải có figma link qua parameters.design:

parameters: {
  design: {
    type: 'figma',
    url: 'https://www.figma.com/embed?embed_host=storybook&url=https://www.figma.com/design/OAinJNCk0DZ1p1R1xyPfvx/1thay',
  },
},
  • figma file key: OAinJNCk0DZ1p1R1xyPfvx
  • figma file url: https://www.figma.com/design/OAinJNCk0DZ1p1R1xyPfvx/1thay
  • dùng embed URL format để hiển thị trực tiếp trong Storybook tab "Figma"
  • custom addon tại .storybook/figma-addon.ts (storybook/manager-api, types.PANEL)
  • khi figma có component frames, cập nhật figma.config.json với node IDs và chạy Code Connect

token sync workflow

  1. figma thay đổi tokens → update tokens.css + tokens.js
  2. chạy npm run snapshot-tokens để cập nhật baseline
  3. chạy npm run check-tokens để verify không drift
  4. cập nhật project-logs.md changelog
  5. cập nhật design-tokens.md nếu giá trị thay đổi

figma → code mapping

xem figma.config.json để biết:

  • component mappings (figmaNodeId, codePath, props)
  • token collection mappings (8 collections → tokens.css)
  • style mappings (12 text styles + 4 shadow styles → CSS variables)

deploy

cloudflare pages (2 projects from 1 repo)

project build command output dir domain
1thay-com npm run build dist 1thay.com
1thay-design npm run build-storybook dist-storybook design.1thay.com

deploy workflow

  1. push lên main → cloudflare auto-deploy (nếu build settings đúng trong dashboard)
  2. nếu auto-deploy fail: npx wrangler pages deploy dist --project-name=1thay-com --branch=main
  3. nếu auto-deploy fail: npx wrangler pages deploy dist-storybook --project-name=1thay-design --branch=main

build settings cho 1thay-design (trong cloudflare dashboard)

  • Build command: npm run build-storybook
  • Build output directory: dist-storybook
  • Framework preset: None (disable auto-detect — tránh detect nhầm astro)

verify trước khi deploy

npm run build              # astro build → dist/
npm run build-storybook    # storybook build → dist-storybook/
npm run check-tokens       # token drift check (118 tokens baseline)

current state (2026-05-27)

storybook 10.4.1

category items
framework react-vite, vite 6, react 19
addons links, a11y (axe-core), docs, figma (custom)
stories 6 components + tokens showcase + examples
interaction tests Button (click), Input (typing), Examples (login flow)
themes manager UI themed with 1thay tokens (manager.ts)

components inventory

component stories figma astro page interaction test
Button 11 ✅ (clickable)
Card 8
Input 9 ✅ (typing)
Icon 8
Badge 6
Toast 3
Examples 6 ✅ (login flow)
Tokens 8

key files

file purpose
.storybook/main.ts framework + addons config
.storybook/preview.ts global decorators, backgrounds, controls
.storybook/manager.ts manager UI theme (1thay dogfooding)
.storybook/figma-addon.ts custom Figma embed panel
src/tokens/tokens.css 118 css custom properties (single source of truth)
src/tokens/tokens.js js mirror for programmatic use
figma.config.json figma code connect manifest
scripts/check-token-drift.js ci token drift detection
wrangler.toml astro cloudflare pages config
wrangler.storybook.toml storybook cloudflare pages config

pre-commit checklist

  • npm run build passes
  • npm run build-storybook passes
  • npm run check-tokens passes (no drift)
  • all new components have parameters.design (figma link)
  • all new components have at least 1 play() interaction test
  • all css uses var(--token), không hardcode giá trị
  • story labels dùng tiếng việt lowercase
  • storybook.md component inventory updated
  • project-logs.md changelog updated

linked references