Storybook Migration: Ready-to-Execute Commands
Complete step-by-step commands to transform your 168 design screens into interactive Storybook components
🎯 Overview​
This document provides copy-paste commands to set up your Storybook design system. You're ready for Phase 2 of your migration plan!
Current Status: ✅ Design system docs complete, ✅ Repository created
Next Goal: Interactive Storybook with first 5 components
🚀 Step 1: Initialize Project Structure​
1.1 Navigate to Design System Repository​
cd juniro-design-system
1.2 Initialize Modern React + TypeScript Project​
# Initialize package.json
npm init -y
# Update package.json with proper details
cat > package.json << 'EOF'
{
"name": "@juniro/design-system",
"version": "0.1.0",
"description": "Juniro Design System - Interactive component library",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "vite build",
"dev": "vite",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"chromatic": "chromatic --exit-zero-on-changes"
},
"keywords": ["design-system", "react", "typescript", "storybook"],
"author": "Juniro Team",
"license": "Private",
"peerDependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
EOF
1.3 Install Core Dependencies​
# React and TypeScript
npm install react react-dom typescript @types/react @types/react-dom
# Build tools
npm install -D vite @vitejs/plugin-react
# Styling (Tailwind CSS for consistency with your current setup)
npm install -D tailwindcss postcss autoprefixer
npm install -D @tailwindcss/forms @tailwindcss/typography
# Storybook (latest version)
npm install -D @storybook/react-vite @storybook/addon-essentials
npm install -D @storybook/addon-controls @storybook/addon-docs
npm install -D @storybook/addon-a11y @storybook/addon-viewport
npm install -D storybook
# Design tokens and utilities
npm install clsx class-variance-authority
npm install -D @types/node
# Cross-browser compatibility
npm install -D autoprefixer browserslist
npm install -D @playwright/test
# Performance and UX enhancements
npm install framer-motion
npm install react-hook-form @hookform/resolvers zod
🎨 Step 2: Configure Build Tools​
2.1 Create Vite Configuration​
cat > vite.config.ts << 'EOF'
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { resolve } from 'path'
export default defineConfig({
plugins: [react()],
build: {
lib: {
entry: resolve(__dirname, 'src/index.ts'),
name: 'JuniroDesignSystem',
fileName: (format) => `index.${format}.js`,
},
rollupOptions: {
external: ['react', 'react-dom'],
output: {
globals: {
react: 'React',
'react-dom': 'ReactDOM',
},
},
},
},
resolve: {
alias: {
'@': resolve(__dirname, 'src'),
},
},
})
EOF
2.2 Create TypeScript Configuration​
cat > tsconfig.json << 'EOF'
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}
EOF
cat > tsconfig.node.json << 'EOF'
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}
EOF
2.3 Initialize Tailwind CSS​
npx tailwindcss init -p
# Update tailwind.config.js with Juniro brand tokens
cat > tailwind.config.js << 'EOF'
/** @type {import('tailwindcss').Config} */
export default {
content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'],
theme: {
extend: {
colors: {
// Juniro Brand Colors (extracted from your designs)
primary: {
50: '#eff6ff',
100: '#dbeafe',
500: '#3b82f6',
600: '#2563eb',
700: '#1d4ed8',
900: '#1e3a8a',
},
success: {
50: '#ecfdf5',
500: '#10b981',
700: '#047857',
},
warning: {
50: '#fffbeb',
500: '#f59e0b',
700: '#b45309',
},
error: {
50: '#fef2f2',
500: '#ef4444',
700: '#c53030',
}
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
},
spacing: {
'18': '4.5rem',
'88': '22rem',
}
},
},
plugins: [
require('@tailwindcss/forms'),
require('@tailwindcss/typography'),
],
}
EOF
📚 Step 3: Initialize Storybook​
3.1 Create Storybook Configuration​
mkdir -p .storybook
cat > .storybook/main.ts << 'EOF'
import type { StorybookConfig } from '@storybook/react-vite'
const config: StorybookConfig = {
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx|mdx)'],
addons: [
'@storybook/addon-essentials',
'@storybook/addon-controls',
'@storybook/addon-docs',
'@storybook/addon-a11y',
'@storybook/addon-viewport',
],
framework: {
name: '@storybook/react-vite',
options: {},
},
typescript: {
reactDocgen: 'react-docgen-typescript',
},
docs: {
autodocs: 'tag',
},
}
export default config
EOF
cat > .storybook/preview.ts << 'EOF'
import type { Preview } from '@storybook/react'
import '../src/styles/globals.css'
const preview: Preview = {
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
docs: {
description: {
component: 'Juniro Design System Components',
},
},
viewport: {
viewports: {
mobile: {
name: 'Mobile',
styles: { width: '375px', height: '667px' },
},
tablet: {
name: 'Tablet',
styles: { width: '768px', height: '1024px' },
},
desktop: {
name: 'Desktop',
styles: { width: '1440px', height: '900px' },
},
},
},
},
}
export default preview
EOF
3.2 Create Base Styles​
mkdir -p src/styles
cat > src/styles/globals.css << 'EOF'
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
html {
font-family: 'Inter', system-ui, sans-serif;
}
body {
@apply text-gray-900 bg-white;
}
}
@layer components {
/* Juniro-specific component styles */
.juniro-focus {
@apply focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 focus:outline-none;
}
.juniro-transition {
@apply transition-all duration-200 ease-in-out;
}
}
EOF
🧩 Step 4: Create First Components​
4.1 Create Component Structure​
mkdir -p src/components/{Button,Input,Card,Badge,Typography}
mkdir -p src/types
mkdir -p src/utils
4.2 Create Design Tokens​
cat > src/types/index.ts << 'EOF'
export interface BaseComponent {
className?: string
children?: React.ReactNode
}
export type Size = 'sm' | 'md' | 'lg'
export type Variant = 'primary' | 'secondary' | 'ghost' | 'danger'
export type Color = 'primary' | 'success' | 'warning' | 'error' | 'gray'
EOF
cat > src/utils/cn.ts << 'EOF'
import { clsx, type ClassValue } from 'clsx'
export function cn(...inputs: ClassValue[]) {
return clsx(inputs)
}
EOF
4.3 Create Button Component (Your First Component)​
cat > src/components/Button/Button.tsx << 'EOF'
import React from 'react'
import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/utils/cn'
const buttonVariants = cva(
'inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors juniro-focus disabled:pointer-events-none disabled:opacity-50',
{
variants: {
variant: {
primary: 'bg-primary-600 text-white hover:bg-primary-700',
secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200',
ghost: 'hover:bg-gray-100 hover:text-gray-900',
danger: 'bg-error-600 text-white hover:bg-error-700',
},
size: {
sm: 'h-9 rounded-md px-3',
md: 'h-10 px-4 py-2',
lg: 'h-11 rounded-md px-8',
},
},
defaultVariants: {
variant: 'primary',
size: 'md',
},
}
)
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
return (
<button
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = 'Button'
export { Button, buttonVariants }
EOF
4.4 Create Button Story​
cat > src/components/Button/Button.stories.tsx << 'EOF'
import type { Meta, StoryObj } from '@storybook/react'
import { Button } from './Button'
const meta: Meta<typeof Button> = {
title: 'Core/Button',
component: Button,
parameters: {
layout: 'centered',
docs: {
description: {
component: 'Primary action button component used throughout Juniro platform.',
},
},
},
tags: ['autodocs'],
argTypes: {
variant: {
control: { type: 'select' },
options: ['primary', 'secondary', 'ghost', 'danger'],
},
size: {
control: { type: 'select' },
options: ['sm', 'md', 'lg'],
},
},
}
export default meta
type Story = StoryObj<typeof meta>
export const Primary: Story = {
args: {
variant: 'primary',
children: 'Book Activity',
},
}
export const Secondary: Story = {
args: {
variant: 'secondary',
children: 'View Details',
},
}
export const Ghost: Story = {
args: {
variant: 'ghost',
children: 'Cancel',
},
}
export const Danger: Story = {
args: {
variant: 'danger',
children: 'Delete Account',
},
}
export const Sizes: Story = {
render: () => (
<div className="flex items-center gap-4">
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
</div>
),
}
export const AllVariants: Story = {
render: () => (
<div className="flex flex-col gap-4">
<div className="flex gap-4">
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="danger">Danger</Button>
</div>
<div className="flex gap-4">
<Button disabled variant="primary">Disabled Primary</Button>
<Button disabled variant="secondary">Disabled Secondary</Button>
</div>
</div>
),
}
EOF
4.5 Create Main Export File​
cat > src/components/Button/index.ts << 'EOF'
export { Button, type ButtonProps } from './Button'
EOF
cat > src/index.ts << 'EOF'
// Components
export { Button } from './components/Button'
// Types
export type { BaseComponent, Size, Variant, Color } from './types'
// Utilities
export { cn } from './utils/cn'
EOF
🚀 Step 5: Launch Storybook​
5.1 Start Development Server​
# Install dependencies
npm install
# Start Storybook
npm run storybook
This will open Storybook at http://localhost:6006 with your first interactive Button component!
📋 Step 6: Next 4 Components (Week 3-4)​
After Button is working, add these components using the same pattern:
Priority Order:​
- ✅ Button (Done above)
- Input - Text inputs used across all portals
- Card - Activity cards, provider profiles
- Badge - Status indicators, categories
- Typography - Headings, body text, links
Quick Component Templates:​
Input Component:
# Create Input component with variants: text, email, password, search
# Include proper labels, validation states, and accessibility
Card Component:
# Create Card component for ActivityCard and ProviderProfile
# Include image, title, description, actions, ratings
Badge Component:
# Create Badge component for status and categories
# Include colors: success, warning, error, info, neutral
Typography Component:
# Create Typography component for headings and body text
# Include proper hierarchy and responsive sizing
🎯 Success Criteria​
After completing these steps, you'll have:
- ✅ Interactive Storybook running locally
- ✅ 5 core components with variants and documentation
- ✅ Design tokens from your Figma designs
- ✅ TypeScript + Tailwind setup matching your current tech stack
- ✅ Accessibility testing built-in
- ✅ Mobile responsive testing
🔗 Integration with Current Workflow​
Link from Documentation:​
Update your docs/design-system/index.md to include:
## 🎮 Interactive Components
- **[Live Storybook](http://localhost:6006)** - Interactive component playground
- **[Button Component](http://localhost:6006/?path=/story/core-button--primary)** - See all button variants
Share with Team:​
Once working, deploy Storybook to Vercel:
npm run build-storybook
# Deploy /storybook-static to design.juniro.com
Ready to start? Copy and paste the commands above to transform your design system from static screenshots to interactive components! 🚀