feat: add custom storybook for design system#784
feat: add custom storybook for design system#784edwche10 wants to merge 7 commits intocjpais:mainfrom
Conversation
Adds a lightweight custom storybook showcasing Handy's UI components, icons, shared components, and design tokens (colors + typography). Supports light and dark mode. Run with `bun run storybook`. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
VirenMohindra
left a comment
There was a problem hiding this comment.
hey edward, appreciate the effort here — having a component playground is really valuable for the team. i have some structural feedback that i think will make this much easier to maintain long-term. the main themes are~
- using the actual storybook library instead of a custom one,
- colocating stories next to components, and
- only show tokens / styles that actually exist in the app today
There was a problem hiding this comment.
this is a custom ~750-line react app reimplementing what https://storybook.js.org/ gives us out of the box. with real storybook we get: interactive controls panel for tweaking props, auto-generated prop docs from typescript interfaces, a11y auditing, viewport testing, and a standard story format (CSF) that's well-documented
for a tauri app, the setup involves configuring vite aliases to mock the native bridge, but that's straightforward and you've already written the mock files (they just aren't wired up)
i would recommend using @storybook/react-vite with the existing vite config as a base. each component then gets a ComponentName.stories.tsx file colocated next to it like so~
src/components/ui/
├── Button.tsx
├── Button.stories.tsx
├── Input.tsx
├── Input.stories.tsx
└── ...
this makes stories discoverable, keeps them in sync with component changes, and scales much better than a single monolith file
src/components/ui/IconButton.tsx
Outdated
There was a problem hiding this comment.
this is a new component introduced in this PR but it's not used anywhere in the actual app — only in the react storybook. a storybook PR shouldn't introduce new components that aren't consumed by the app yet. i'd recommend either removing this from this PR (and adding it in a separate PR where app code actually uses it) or updating existing app code to use it here
leaning towards the latter
screenshots would be super important here!
There was a problem hiding this comment.
Removed IconButton from this PR to keep the scope focused. I noticed the existing ResetButton does a similar job — once the real Storybook setup is in place, we can revisit consolidating them into IconButton in a follow-up PR.
I had an image of the ResetButton that exists today in the app, but at the end, it's an icon bottom.
There was a problem hiding this comment.
this file defines ~50+ CSS custom properties (--color-error, --color-warning, --color-info, --color-success, all the --color-primary-alpha-, --color-gray-alpha-, --color-text-alpha-* variants) that don't exist in the app's actual App.css. no component in src/components/ui/ uses these tokens either — they use hardcoded tailwind classes (e.g. Alert.tsx uses bg-red-500/10, not var(--color-error-bg))
showing these in the storybook's color palette is misleading — someone would think these tokens exist in the design system when they don't. the storybook should either
@importthe app's actual CSS and only add its own chrome tokens(--sb-*), or- just use tailwind classes
if we want to adopt semantic design tokens, that should be a separate effort where we update App.css and migrate components to use them
storybook/storybook.tsx
Outdated
| id: "typography", | ||
| name: "Typography", | ||
| group: "Design Tokens", | ||
| render: () => { | ||
| const typeScale = [ | ||
| { label: "Display", size: "28px", weight: "700", lineHeight: "1.2", sample: "Handy — Voice to Text" }, | ||
| { label: "Heading 1", size: "22px", weight: "600", lineHeight: "1.3", sample: "Settings & Preferences" }, | ||
| { label: "Heading 2", size: "18px", weight: "600", lineHeight: "1.3", sample: "General Settings" }, | ||
| { label: "Heading 3", size: "15px", weight: "600", lineHeight: "1.4", sample: "Recording Options" }, | ||
| { label: "Body", size: "14px", weight: "400", lineHeight: "1.5", sample: "Select your preferred microphone and configure how recordings are handled." }, | ||
| { label: "Body Medium", size: "14px", weight: "500", lineHeight: "1.5", sample: "Push to talk is enabled" }, | ||
| { label: "Small", size: "13px", weight: "400", lineHeight: "1.5", sample: "Choose an audio input device from the list below." }, | ||
| { label: "Small Medium", size: "13px", weight: "500", lineHeight: "1.5", sample: "Model downloaded successfully" }, | ||
| { label: "Caption", size: "12px", weight: "400", lineHeight: "1.4", sample: "Last updated 3 minutes ago" }, | ||
| { label: "Label", size: "11px", weight: "600", lineHeight: "1.4", sample: "AUDIO INPUT", style: "uppercase" as const, letterSpacing: "0.05em" }, | ||
| { label: "Mono", size: "13px", weight: "400", lineHeight: "1.5", sample: "sk-ant-api03-xxxxxxxxxxxxxx", fontFamily: "monospace" }, | ||
| ]; |
There was a problem hiding this comment.
similar to the color tokens issue — this type scale (display 28px/700, heading 1 22px/600, etc) isn't defined or enforced anywhere in the codebase. there are no tailwind config entries, css classes, or utility tokens backing these values. this presents aspirational design as the current reality, which can cause confusion
storybook/mocks/useSettings.ts
Outdated
There was a problem hiding this comment.
this file (along with settingsStore.ts, modelStore.ts, and all 9 tauri-plugin-*.ts mock files) is never imported anywhere in the storybook. that's ~270 lines of dead code across 11 files. the only mock files actually used are data.ts and bindings.ts
i'd remove all the unused ones to keep the PR lean
There was a problem hiding this comment.
Done. Removed all unused Storybook mock files and kept only data.ts and bindings.ts.
There was a problem hiding this comment.
we only removed a single mock, we need to remove all the unused ones
There was a problem hiding this comment.
Removed all 13 unused mock files. Only data.ts and bindings.ts remain — these are the only two actually used by the storybook.
There was a problem hiding this comment.
the tauri plugin mock files exist in storybook/mocks/ but they're never aliased here, so they don't actually intercept any tauri imports. if any component further down the import chain tries to call @tauri-apps/api/core or @tauri-apps/plugin-os, it'll hit the real (missing) native bridge and crash. with real storybook + proper vite aliases, this would look something like~
alias: {
"@tauri-apps/api/core": resolve(__dirname, "./storybook/mocks/tauri-apps-api-core.ts"),
"@tauri-apps/api/event": resolve(__dirname, "./storybook/mocks/tauri-apps-api-event.ts"),
// ... etc
}There was a problem hiding this comment.
this references http://localhost:1422/HandyMain/storybook/ but the actual URL is http://localhost:1422/
minor but would confuse someone opening the html file directly
this will anyway get removed once we use storybook properly
There was a problem hiding this comment.
Fixed! The URL now correctly points to http://localhost:1422/
| "test:playwright:ui": "playwright test --ui", | ||
| "check:translations": "bun scripts/check-translations.ts" | ||
| "check:translations": "bun scripts/check-translations.ts", | ||
| "storybook": "vite --config vite.storybook.config.ts" |
There was a problem hiding this comment.
README.md and CLAUDE.md should be updated to document this new command and how to use the storybook. right now the only mention is in the PR description
There was a problem hiding this comment.
Added the bun run storybook command to both README.md and CLAUDE.md with a short description of what it does and the URL to open.
| }, | ||
| ]; | ||
| return ( | ||
| <div style={{ display: "flex", flexDirection: "column", gap: 32 }}> |
There was a problem hiding this comment.
the color swatches and typography grid use heavy inline style={{}} props while the rest of the file (and the app) uses tailwind. worth keeping consistent — with real storybook this is less of an issue since each story file is small and self-contained
this will also be fixed once we move to storybook!
Removes 13 unused mock files from storybook/mocks/. Only data.ts and bindings.ts are actually imported by the storybook — the rest were dead code. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
a0597dd to
7b5fac5
Compare
URL was pointing to /HandyMain/storybook/ instead of the correct /. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
IconButton is not yet used in the app. Removing from this PR to keep scope focused — will be added in a follow-up PR once the real Storybook setup is in place and the component is adopted in the app (e.g. replacing ResetButton). Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Removed Semantic, Primary Alpha, Gray Alpha and Text Alpha color groups from the storybook color palette and storybook.css. These variables do not exist in App.css or anywhere in the app — only the 7 real tokens (text, background, background-ui, logo-primary, logo-stroke, text-stroke, mid-gray) are now shown. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The type scale (Display, Heading 1-3, Body, Caption, Label, Mono) is not defined or enforced anywhere in the app. Components use standard Tailwind utilities (text-xs, text-sm etc.) directly. Removing to avoid presenting aspirational design as current reality. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
@VirenMohindra @virenpepper is this more or less good to go? I'm focusing mainly on issues/fixes right now, or tiny obvious mergable changes |
Adds a lightweight custom storybook showcasing Handy's UI components, icons, shared components, and design tokens (colors + typography). Supports light and dark mode. Run with
bun run storybook.Before Submitting This PR
Please confirm you have done the following:
If this is a feature or change that was previously closed/rejected:
Summary
Adds a custom storybook under
storybook/to preview Handy's UI components in isolation.Human Written Description
I noticed the project didn't have a way to preview UI components in isolation, which makes it hard to work on the design system. I built a custom storybook that shows all the UI components, icons, and design tokens (colors + typography) with light and dark mode support. This makes it easier for the team to reference and work with the components without needing to run the full app.
How to run
bun install
bun run storybook
Then open http://localhost:1422
What's included
Related Issues/Discussions
Fixes #
Discussion:
Community Feedback
Testing
Screenshots/Videos (if applicable)
AI Assistance
If AI was used:
Helped build the storybook structure, fix Tailwind configuration, and set up the Vite config