Skip to content

Commit 53de768

Browse files
authored
Merge pull request #807 from Chris0Jeky/feature/storybook-baseline
Add Storybook baseline for UI primitives
2 parents d6ef4f7 + 1610d04 commit 53de768

25 files changed

+3189
-21
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# ADR-0030: Storybook Baseline with Vite 8 Compatibility
2+
3+
- **Status**: Accepted
4+
- **Date**: 2026-04-09
5+
- **Deciders**: Taskdeck maintainers
6+
7+
## Context
8+
9+
Taskdeck uses Vite 8 in the frontend workspace. The Storybook baseline issue requested Storybook 8.x, but Storybook 8 does not support the Vite 8 toolchain used by the app.
10+
11+
The team still needs a stable, reviewable component catalogue for the 17 `Td*` primitives, plus a place to validate visual variants without touching the production app.
12+
13+
## Decision
14+
15+
Use Storybook 10.3.x for the frontend Storybook baseline.
16+
17+
Reasons:
18+
19+
- Storybook 10.3.x supports `vite@^8.0.0`.
20+
- The CSF3 story format remains the same, so the story authoring model stays familiar.
21+
- The preview should import the app stylesheet so Storybook reflects the production component look and spacing as closely as practical.
22+
- Story files live in `src/stories/` to keep the component directory focused on runtime code.
23+
24+
## Alternatives Considered
25+
26+
- Storybook 8.x: rejected because it is not compatible with Vite 8.
27+
- Deferring Storybook entirely: rejected because the component library needs a reviewable baseline now.
28+
- Co-locating stories with components: workable, but rejected for this baseline because a centralized story directory keeps the setup simpler.
29+
30+
## Consequences
31+
32+
- Storybook can be built and maintained without downgrading Vite.
33+
- Visual review of `Td*` primitives is available through `npm run storybook` and `npm run storybook:build`.
34+
- Story files are excluded from the app typecheck, so production compilation stays focused on runtime code.
35+
- Future contributors have a recorded rationale for the Storybook version choice.
36+
37+
## References
38+
39+
- PR #807
40+
- Issue #251
41+
- `frontend/taskdeck-web/.storybook/main.ts`
42+
- `frontend/taskdeck-web/.storybook/preview.ts`
43+
- `frontend/taskdeck-web/src/stories/`

docs/decisions/INDEX.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@
3131
| [0027](ADR-0027-cloud-target-topology-autoscaling.md) | Cloud Target Topology and Autoscaling Reference Architecture | Accepted | 2026-04-09 |
3232
| [0028](ADR-0028-staged-deployment-bluegreen-canary.md) | Staged Deployment - Blue/Green with Canary Verification | Accepted | 2026-04-09 |
3333
| [0029](ADR-0029-oidc-mfa-pluggable-identity.md) | OIDC/SSO Integration with Optional TOTP MFA | Accepted | 2026-04-09 |
34+
| [0030](ADR-0030-storybook-baseline-vite-8-compatibility.md) | Storybook Baseline with Vite 8 Compatibility | Accepted | 2026-04-09 |

frontend/taskdeck-web/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ lerna-debug.log*
1010
node_modules
1111
dist
1212
dist-ssr
13+
storybook-static
1314
*.local
1415

1516
# Editor directories and files
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import type { StorybookConfig } from '@storybook/vue3-vite'
2+
3+
function isPwaPlugin(plugin: unknown): boolean {
4+
if (plugin && typeof plugin === 'object' && 'name' in plugin) {
5+
const name = String((plugin as { name?: unknown }).name ?? '').toLowerCase()
6+
return name.includes('pwa') || name.includes('workbox')
7+
}
8+
return false
9+
}
10+
11+
function stripPwaPlugins(plugins: unknown[]): unknown[] {
12+
const filtered: unknown[] = []
13+
14+
for (const plugin of plugins) {
15+
if (Array.isArray(plugin)) {
16+
// Recursively filter nested arrays but preserve the array structure
17+
const filteredNested = stripPwaPlugins(plugin)
18+
if (filteredNested.length > 0) {
19+
filtered.push(filteredNested)
20+
}
21+
continue
22+
}
23+
if (!isPwaPlugin(plugin)) {
24+
filtered.push(plugin)
25+
}
26+
}
27+
28+
return filtered
29+
}
30+
31+
const config: StorybookConfig = {
32+
stories: ['../src/**/*.stories.@(ts|tsx)'],
33+
framework: {
34+
name: '@storybook/vue3-vite',
35+
options: {
36+
docgen: 'vue-component-meta',
37+
},
38+
},
39+
async viteFinal(viteConfig) {
40+
// Strip PWA plugin — it is app-specific and breaks the Storybook build
41+
// because the Storybook output includes large JS bundles that exceed
42+
// the workbox precache size limit.
43+
return {
44+
...viteConfig,
45+
plugins: viteConfig.plugins
46+
? (stripPwaPlugins(viteConfig.plugins as unknown[]) as typeof viteConfig.plugins)
47+
: viteConfig.plugins,
48+
}
49+
},
50+
}
51+
52+
export default config
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import type { Preview } from '@storybook/vue3-vite'
2+
import '../src/style.css'
3+
4+
const preview: Preview = {
5+
parameters: {
6+
controls: { expanded: true },
7+
backgrounds: {
8+
default: 'obsidian',
9+
values: [
10+
{ name: 'obsidian', value: '#131313' },
11+
{ name: 'light', value: '#f5f3f1' },
12+
],
13+
},
14+
},
15+
decorators: [
16+
(story) => ({
17+
components: { story },
18+
template: `
19+
<div style="padding: 1rem;">
20+
<story />
21+
</div>
22+
`,
23+
}),
24+
],
25+
}
26+
27+
export default preview

0 commit comments

Comments
 (0)