---
name: dev-storybook
description: Comprehensive Storybook skill for Vue 3 - story creation, auditing, component discovery, visual testing, and CI integration. Merged from dev-storybook, storybook-audit, and storybook-master.
---
# dev-storybook
BUILD, AUDIT, and AUTOMATE Storybook stories for Vue 3 components with TypeScript. This comprehensive skill covers story creation, auditing existing stories for issues, component discovery and inventory, and CI/CD integration. Use when creating component documentation, fixing story compilation errors, auditing for display issues, or setting up automated testing workflows.
## Core Responsibilities
1. **Story Creation**: Write well-structured Storybook stories for Vue 3 components
2. **Error Resolution**: Fix TypeScript and Vue compilation errors in stories
3. **Styling Patterns**: Apply CSS correctly in Storybook without runtime template errors
4. **Component Props**: Ensure correct prop types and event handlers
5. **Story Auditing**: Detect and fix cutoff modals, store dependencies, design token violations
6. **Component Discovery**: Scan codebase for components and generate inventory reports
7. **Automated Testing**: Visual regression testing and accessibility compliance
8. **Story Streamlining**: Ensure stories match the actual app appearance exactly
---
## Story Streamlining (CRITICAL)
**Trigger Keywords**: "streamline", "streamlined", "match app", "looks different", "visual fidelity"
When user asks to **"streamline"** a Storybook story, they mean: **Make the story look EXACTLY like the component appears in the actual app.**
### What "Streamlined" Means in This Project
**CRITICAL**: In FlowState, "streamlined" specifically means using **glass morphism** instead of solid black backgrounds.
- ❌ **NOT streamlined**: Solid black/opaque backgrounds (`--glass-bg-solid`, `rgba(0,0,0,0.95)`)
- ✅ **Streamlined**: Semi-transparent backgrounds with blur so the purple gradient shows through
```css
/* Streamlined = Glass Morphism */
background: rgba(30, 32, 45, 0.75);
backdrop-filter: blur(24px) saturate(180%);
```
**The app's signature look is glass panels floating over a purple/indigo gradient. If a component looks like a flat black box, it's NOT streamlined.**
### Streamlining Checklist
When streamlining a story, verify ALL of the following:
| Check | Requirement | How to Fix |
|-------|-------------|------------|
| **1. Use Actual Components** | Story imports and renders the REAL Vue component, not a mockup | Import from `@/components/...` |
| **2. App Background** | Story background matches app's purple/indigo gradient | Use `background: var(--app-background-gradient)` |
| **3. Glass Morphism** | Modals/overlays use semi-transparent bg with blur, NOT solid black | Use `rgba(30, 32, 45, 0.75)` + `backdrop-filter: blur(24px)` |
| **4. Design Tokens** | All styling uses CSS variables, no hardcoded values | Replace `#hex` and `rgba()` with `var(--token)` |
| **5. Correct Props** | Story passes the same props the component expects | Check `defineProps` in component |
| **6. Event Handlers** | All emitted events have handlers | Add `@event="handler"` |
| **7. Mock Data** | Data looks realistic, matches production patterns | Use actual Task/Project types |
### Streamlining Workflow
```
1. IDENTIFY the component being streamlined
└── Find the actual .vue component file
└── Read its props, emits, and slots
2. COMPARE story vs app
└── What does the story currently show?
└── What does the actual app show?
└── List the differences
3. FIX each difference:
a. Background: Use var(--app-background-gradient)
b. Components: Import actual components, not mockups
c. Tokens: Replace hardcoded colors with CSS variables
d. Props: Match component's defineProps interface
e. Data: Use realistic mock data
4. VERIFY with user
└── Ask user to check Storybook matches app
```
### Background Color Reference
**CRITICAL**: The app uses a purple/indigo gradient, NOT neutral gray.
```typescript
// ❌ WRONG - neutral gray (doesn't match app)
background: var(--surface-primary);
background: hsl(0, 0%, 12%);
// ✅ CORRECT - app's purple/indigo gradient
background: var(--app-background-gradient);
```
The `--app-background-gradient` is defined in `design-tokens.css`:
```css
--app-background-gradient: linear-gradient(135deg,
hsl(220, 13%, 9%) 0%,
hsl(240, 21%, 15%) 25%,
hsl(250, 24%, 12%) 50%,
hsl(260, 20%, 14%) 75%,
hsl(220, 13%, 11%) 100%);
```
### Example: Before/After Streamlining
**Before (mockup, wrong background):**
```typescript
export const Default: Story = {
render: () => ({
template: `
`
})
}
```
**After (streamlined, matches app):**
```typescript
import QuickSortCard from '@/components/QuickSortCard.vue'
import { useTaskStore } from '@/stores/tasks'
export const Default: Story = {
render: () => ({
components: { QuickSortCard },
setup() {
const mockTask = { id: '1', title: 'Real Task', priority: 'high', ... }
return { mockTask }
},
template: `
`
})
}
```
### Glass Morphism vs Solid Black (CRITICAL)
**Problem**: Components using `--glass-bg-solid` or opaque black backgrounds look wrong because they block the app's purple gradient from showing through.
**Solution**: Use semi-transparent backgrounds with blur so the gradient is visible through the glass effect.
```css
/* ❌ WRONG - Solid black, no glass effect */
background: var(--glass-bg-solid); /* rgba(0, 0, 0, 0.95) */
background: rgba(0, 0, 0, 0.95);
background: #121214;
/* ✅ CORRECT - Semi-transparent with blur (glass morphism) */
background: rgba(30, 32, 45, 0.75);
backdrop-filter: blur(24px) saturate(180%);
-webkit-backdrop-filter: blur(24px) saturate(180%);
border: 1px solid var(--glass-border-medium);
```
**Glass Morphism Recipe**:
| Property | Value | Purpose |
|----------|-------|---------|
| `background` | `rgba(30, 32, 45, 0.75)` | Semi-transparent dark with slight purple tint |
| `backdrop-filter` | `blur(24px) saturate(180%)` | Blur + color boost for depth |
| `border` | `1px solid var(--glass-border-medium)` | Subtle edge definition |
| `box-shadow` | `inset 0 1px 0 rgba(255, 255, 255, 0.1)` | Top highlight for polish |
**When to use glass morphism**:
- Modals and overlays
- Command palettes
- Dropdown menus
- Floating panels
- Any component that appears over the app background
### Common Streamlining Issues
| Issue | Symptom | Fix |
|-------|---------|-----|
| **Mockup instead of component** | Story shows different UI than app | Import actual component |
| **Wrong background color** | Black/gray instead of purple gradient | Use `var(--app-background-gradient)` |
| **Solid black modal** | Modal looks flat, no depth | Use glass morphism with `rgba()` + `backdrop-filter` |
| **Hardcoded colors** | Colors don't match design system | Use CSS variables |
| **Missing components** | Card missing buttons/badges | Import child components |
| **Wrong spacing** | Elements too cramped/spread | Use `var(--space-X)` tokens |
## Critical Rules
### Vue 3 Template Restrictions
**NEVER use `
`
// ✅ CORRECT - Apply styles globally or use inline styles
template: `
`
```
### Component Prop Verification
**ALWAYS verify component props before writing stories**:
```bash
# Check component interface
grep -A 5 "interface Props" src/components/MyComponent.vue
grep -A 5 "defineProps" src/components/MyComponent.vue
```
Example fix:
```typescript
// Component expects: { isOpen: boolean, taskIds: string[] }
// ❌ WRONG story args
args: {
isVisible: true, // Wrong prop name
selectedTasks: [] // Wrong prop name
}
// ✅ CORRECT story args
args: {
isOpen: true,
taskIds: ['1', '2', '3']
}
```
### Import Requirements
**ALWAYS include required Vue imports**:
```typescript
import type { Meta, StoryObj } from '@storybook/vue3'
import { ref, reactive, computed } from 'vue' // Include all Vue APIs you use
import MyComponent from '@/components/MyComponent.vue'
```
Common missing imports:
- `ref` - For reactive state
- `reactive` - For reactive objects
- `computed` - For computed properties
- `watch` - For watchers
- `onMounted`, `onUnmounted` - For lifecycle hooks
## Story Structure Pattern
### Basic Story Template
```typescript
import type { Meta, StoryObj } from '@storybook/vue3'
import { ref } from 'vue'
import MyComponent from '@/components/MyComponent.vue'
const meta = {
component: MyComponent,
title: '📁 Category/MyComponent',
tags: ['autodocs'],
parameters: {
layout: 'centered', // or 'fullscreen'
docs: {
description: {
component: 'Component description here'
}
}
}
} satisfies Meta
export default meta
type Story = StoryObj
export const Default: Story = {
args: {
// Component props here
isOpen: true,
title: 'Example'
},
render: (args) => ({
components: { MyComponent },
setup() {
const isOpen = ref(args.isOpen)
const handleClose = () => {
isOpen.value = false
}
return {
isOpen,
handleClose,
args
}
},
template: `
`
})
}
```
### Modal/Overlay Story Pattern
```typescript
export const ModalExample: Story = {
parameters: {
layout: 'fullscreen' // Modal needs full screen
},
args: {
isOpen: true,
title: 'Modal Title'
},
render: (args) => ({
components: { MyModal },
setup() {
const isOpen = ref(args.isOpen)
return {
isOpen,
args,
handleClose: () => { isOpen.value = false },
handleConfirm: () => { console.log('Confirmed') }
}
},
template: `
`
})
}
```
## Story Organization Standards
### CRITICAL: Consolidate, Don't Duplicate
**Problem**: Too many similar stories create confusion and make components harder to understand.
**Solution**: Use focused, well-documented stories with clear purpose.
### Recommended Story Structure (5-Story Pattern)
Every component story file should follow this organization:
#### 1. **Default Story** (Primary with interactive controls)
```typescript
export const Default: Story = {
args: {
variant: 'default',
hoverable: false,
// ... all props with defaults
},
render: (args) => ({
components: { MyComponent },
setup() {
return { args }
},
template: `
Default Component
Usage guidance explaining when/where to use this component.
`
})
}
```
**Purpose**: Interactive playground for testing all prop combinations via Controls panel.
#### 2. **Variants Story** (Consolidated comparison)
```typescript
export const Variants: Story = {
parameters: {
docs: {
description: {
story: `**Visual variants for different contexts:**
- **Variant A**: When to use this variant
- **Variant B**: When to use this variant
- **Variant C**: When to use this variant`
}
}
},
render: () => ({
components: { MyComponent },
template: `
Variant A
Use when [specific context]
Variant B
Use when [specific context]
`
})
}
```
**Purpose**: Show all visual variants **side by side** with usage guidance.
**Anti-pattern**: Don't create separate stories for each variant (VariantA, VariantB, VariantC). Consolidate!
#### 3. **Effects/States Story** (Realistic contexts)
```typescript
export const Effects: Story = {
parameters: {
layout: 'fullscreen',
docs: {
description: {
story: `**Effects for interaction and visual hierarchy:**
- **Hoverable**: Use when components are clickable
- **Glass**: Use on colorful/gradient backgrounds
- **Elevated**: Use to emphasize important content`
}
}
},
render: () => ({
components: { MyComponent },
template: `
Hoverable Component
Use when components are clickable. Hover to see the effect.
Content here
Glass Effect
Use on colorful or gradient backgrounds.
Glass effect shown on actual gradient!
`
})
}
```
**Purpose**: Show effects/states in **realistic visual contexts** (e.g., glass on gradient, not plain background).
**Critical**: Always show effects where they actually make sense visually.
#### 4. **WithSlots/Structure Story** (Slot patterns)
```typescript
export const WithSlots: Story = {
parameters: {
docs: {
description: {
story: `**Component supports slots for structured content:**
- **Header**: For titles, actions, or badges
- **Footer**: For metadata, timestamps, or action buttons
- Use slots to create consistent, structured layouts`
}
}
},
render: () => ({
components: { MyComponent },
template: `
Header Content
Main content
Main content
Footer actions
Header
Main content
Footer
`
})
}
```
**Purpose**: Show slot usage patterns side by side.
#### 5. **Real-World Example** (Production-ready)
```typescript
export const TaskCardExample: Story = {
parameters: {
docs: {
description: {
story: 'A realistic example showing how to combine variants, effects, and slots for production use.'
}
}
},
render: () => ({
components: { MyComponent },
template: `
`
})
}
```
**Purpose**: Show production-ready example combining multiple features.
### Usage Guidance Requirements
**EVERY story must include usage guidance**. Never show a variant without explaining when to use it.
#### Component-Level Documentation
```typescript
const meta = {
component: MyComponent,
title: '🧩 Components/🔘 Base/MyComponent',
tags: ['autodocs'],
parameters: {
layout: 'centered',
docs: {
description: {
component: `Component description explaining its purpose.
**When to use:**
- Specific use case 1
- Specific use case 2
- Specific use case 3`
}
}
},
argTypes: {
variant: {
control: 'select',
options: ['default', 'outlined', 'filled'],
description: 'Visual style variant',
table: {
type: { summary: 'string' },
defaultValue: { summary: 'default' }
}
}
}
}
```
#### Story-Level Documentation
```typescript
export const Variants: Story = {
parameters: {
docs: {
description: {
story: `**Visual variants for different contexts:**
- **Default**: Standard style (use for X)
- **Outlined**: Transparent background (use for Y)
- **Filled**: Solid background (use for Z)`
}
}
}
}
```
### Visual Context Best Practices
#### ✅ GOOD: Show effects in realistic contexts
```typescript
// Glass effect on gradient
Now the glass effect actually makes sense!
// Elevated card on page
Extra shadow creates depth on the page
```
#### ❌ BAD: Show effects on plain backgrounds
```typescript
// Glass effect on plain background (can't see blur!)
Glass effect is invisible here
// Elevated without context (shadow purpose unclear)
Why is this elevated?
```
### ArgTypes Standards
Always include comprehensive argTypes with descriptions:
```typescript
argTypes: {
variant: {
control: 'select',
options: ['default', 'outlined', 'filled'],
description: 'Visual style variant',
table: {
type: { summary: 'string' },
defaultValue: { summary: 'default' }
}
},
hoverable: {
control: 'boolean',
description: 'Add hover effects (elevation & transform)',
table: {
type: { summary: 'boolean' },
defaultValue: { summary: 'false' }
}
}
}
```
### Story Consolidation Checklist
Before creating multiple similar stories, ask:
- [ ] Can these variants be shown side by side in one story?
- [ ] Does each story explain WHEN to use it?
- [ ] Are effects shown in realistic visual contexts?
- [ ] Is the Default story using args for interactivity?
- [ ] Does the documentation include "When to use" guidance?
**Target**: 5-7 focused stories per component, NOT 12+ redundant stories.
## CSS Styling Patterns
### Option 1: Inline Styles (Preferred for simple cases)
```typescript
template: `
`
```
### Option 2: CSS Variables (Use design tokens)
```typescript
template: `
`
```
### Option 3: Global Styling (For component-wide changes)
Modify the component's scoped styles directly in the `.vue` file instead of trying to override in stories.
## Common Errors and Fixes
### Error: "Tags with side effect (