apps/storybook (@datler/storybook) shows components in isolation under the token system: Storybook 10 on the Vite builder (@storybook/react-vite), with the accessibility and docs addons. pnpm run storybook serves it on port 6006, and pnpm run storybook:build builds the static site.

Wiring

  • Theme axes. .storybook/preview.tsx builds its globalTypes from datlerThemeAxes in @datler/design-tokens (Design Tokens), so there is one toolbar control per axis (mode, palette, accent, radius, density and font) and the options cannot differ from the CSS. Its decorator writes each axis as its data-* attribute on <html> and wraps every story in bg-background text-foreground p-6. A mode of system is resolved to dark or light against prefers-color-scheme before it reaches the attribute, by @jeliroco-multimedia/blunt-tokens’ resolveMode, the resolver the app’s theme runtime applies, because system is a preference, not a value the CSS knows.
  • CSS. .storybook/preview.css reproduces the renderer’s CSS entry in the same order: Tailwind, datler-theme.css (which owns the attribute-keyed dark: variant), the library’s bridge.css and the library’s styles.css. Without the last two, library components render with their utility classes compiling to nothing, and the file says not to re-declare the dark: variant after the tokens, since a class-based one would win and no story adds a .dark class.
  • Tailwind v4 runs as a Vite plugin added in viteFinal. Tailwind scans from its CSS file’s own directory, which would cover only apps/storybook, so @source points it at apps/renderer/src, packages/ and apps/storybook/src. The @ alias resolves to the renderer’s src, as the renderer’s own Vite config does, so stories beside renderer components import as the components do.
  • Stories live next to the components they show (*.stories.tsx in apps/renderer/src), with the foundations and a Welcome page in apps/storybook/src; the stories globs cover those trees and packages/.

What has stories

wherestories
apps/storybook/src/foundations/Color, Typography, Spacing, Radius, Motion, Icons, and JelirocoContract, which reads every contract token off the live document and lists any that resolve to nothing
apps/renderer/src/components/the quick-add palette, the entry panel, the trackable card, the trackable calendar, the shared charts, the Term component, the Series editor, the primitives (icon, add and text buttons, the wordmark, icon tiles, colour dots, eyebrows), the form section, the save error, a catalog item’s attribute values, the note controls, and the reading picker

A component earns a story when more than one route uses it, or when it draws a state a screen rarely reaches (an error, an empty list, a farewell), and the story shows those states (empty, filled, error) so the toolbar has something to re-skin. A component used once, inside one route, does not. A story is a component and a few props: one that needs the database is the wrong candidate, which is why the entry dialog, the Achievement toast and the getting-started farewell, all of which read it, have none yet.

Design Tokens · Theming System · Jeliroco Components · Monorepo Layout