--- name: phase-5-design-system description: | Skill for building platform-independent design systems. Develops consistent component libraries for all UI frameworks. Use proactively when user needs consistent UI components or mentions design tokens. Triggers: design system, component library, design tokens, shadcn, 디자인 시스템, デザインシステム, 设计系统, sistema de diseño, biblioteca de componentes, tokens de diseño, système de design, bibliothèque de composants, jetons de design, Design-System, Komponentenbibliothek, Design-Tokens, sistema di design, libreria di componenti, token di design Do NOT use for: one-off UI changes, backend development, or simple static sites. imports: - ${PLUGIN_ROOT}/templates/pipeline/phase-5-design-system.template.md # hooks: Managed by hooks/hooks.json (unified-write-post.js, unified-stop.js) - GitHub #9354 workaround agent: bkit:pipeline-guide allowed-tools: - Read - Write - Edit - Glob - Bash user-invocable: false next-skill: phase-6-ui-integration pdca-phase: do task-template: "[Phase-5] {feature}" --- # Phase 5: Design System > Build platform-independent design system ## Purpose Build a reusable UI component library. Enable consistent design and fast development. --- ## What is a Design System? ### Definition A design system is **a collection of reusable components and clear standards** that enables building consistent user experiences at scale. ### Why is it Needed? (Framework Agnostic) | Problem | Design System Solution | |---------|----------------------| | Designer-developer mismatch | Single Source of Truth | | Duplicate component development | Reusable component library | | Inconsistent UI/UX | Unified design tokens and rules | | Increased maintenance cost | Centralized change management | | Delayed new member onboarding | Documented component catalog | ### 3 Layers of Design System ``` ┌─────────────────────────────────────────────────────┐ │ Design Tokens │ │ Color, Typography, Spacing, Radius, Shadow, ... │ ├─────────────────────────────────────────────────────┤ │ Core Components │ │ Button, Input, Card, Dialog, Avatar, Badge, ... │ ├─────────────────────────────────────────────────────┤ │ Composite Components │ │ Form, DataTable, Navigation, SearchBar, ... │ └─────────────────────────────────────────────────────┘ ``` ### Platform-specific Implementation Tools | Platform | Recommended Tools | Design Token Method | |----------|------------------|---------------------| | **Web (React/Next.js)** | shadcn/ui, Radix | CSS Variables | | **Web (Vue)** | Vuetify, PrimeVue | CSS Variables | | **Flutter** | Material 3, Custom Theme | ThemeData | | **iOS (SwiftUI)** | Native Components | Asset Catalog, Color Set | | **Android (Compose)** | Material 3 | MaterialTheme | | **React Native** | NativeBase, Tamagui | StyleSheet + Theme | --- ## What to Do in This Phase 1. **Install Base Components**: Button, Input, Card, etc. 2. **Customize**: Adjust to project style 3. **Composite Components**: Combine multiple base components 4. **Documentation**: Document component usage ## Deliverables ``` components/ └── ui/ # shadcn/ui components ├── button.tsx ├── input.tsx ├── card.tsx └── ... lib/ └── utils.ts # Utilities (cn function, etc.) docs/02-design/ └── design-system.md # Design system specification ``` ## PDCA Application - **Plan**: Required component list - **Design**: Component structure, variants design - **Do**: Implement/customize components - **Check**: Review consistency - **Act**: Finalize and proceed to Phase 6 ## Level-wise Application | Level | Application Method | |-------|-------------------| | Starter | Optional (simple projects may skip) | | Dynamic | Required | | Enterprise | Required (including design tokens) | ## shadcn/ui Installation ```bash # Initial setup npx shadcn@latest init # Add components npx shadcn@latest add button npx shadcn@latest add input npx shadcn@latest add card ``` ## Required Component List ### Basic - Button, Input, Textarea - Card, Badge, Avatar - Dialog, Sheet, Popover ### Form - Form, Label, Select - Checkbox, Radio, Switch ### Navigation - Navigation Menu, Tabs - Breadcrumb, Pagination ## Custom Theme Building ### Design Token Override shadcn/ui is CSS variable-based, so customize themes in `globals.css`. ```css /* globals.css */ @layer base { :root { /* ===== Colors ===== */ --background: 0 0% 100%; --foreground: 222.2 84% 4.9%; --primary: 221.2 83.2% 53.3%; /* Brand main color */ --primary-foreground: 210 40% 98%; --secondary: 210 40% 96.1%; --accent: 210 40% 96.1%; --destructive: 0 84.2% 60.2%; --muted: 210 40% 96.1%; --muted-foreground: 215.4 16.3% 46.9%; /* ===== Typography ===== */ --font-sans: 'Pretendard', sans-serif; --font-mono: 'JetBrains Mono', monospace; /* ===== Spacing (rem units) ===== */ --spacing-xs: 0.25rem; /* 4px */ --spacing-sm: 0.5rem; /* 8px */ --spacing-md: 1rem; /* 16px */ --spacing-lg: 1.5rem; /* 24px */ --spacing-xl: 2rem; /* 32px */ /* ===== Border Radius ===== */ --radius: 0.5rem; --radius-sm: 0.25rem; --radius-lg: 0.75rem; --radius-full: 9999px; /* ===== Shadows ===== */ --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05); --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1); --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1); } .dark { --background: 222.2 84% 4.9%; --foreground: 210 40% 98%; --primary: 217.2 91.2% 59.8%; /* ... dark mode overrides */ } } ``` ### Tailwind Config Extension ```js // tailwind.config.js module.exports = { theme: { extend: { colors: { brand: { 50: 'hsl(var(--brand-50))', 500: 'hsl(var(--brand-500))', 900: 'hsl(var(--brand-900))', }, }, fontFamily: { sans: ['var(--font-sans)', 'system-ui'], mono: ['var(--font-mono)', 'monospace'], }, spacing: { 'xs': 'var(--spacing-xs)', 'sm': 'var(--spacing-sm)', 'md': 'var(--spacing-md)', 'lg': 'var(--spacing-lg)', 'xl': 'var(--spacing-xl)', }, borderRadius: { 'sm': 'var(--radius-sm)', 'DEFAULT': 'var(--radius)', 'lg': 'var(--radius-lg)', 'full': 'var(--radius-full)', }, }, }, } ``` ### Design Token Documentation Recommended to create `docs/02-design/design-tokens.md` per project: | Token | Value | Purpose | |-------|-------|---------| | `--primary` | `221.2 83.2% 53.3%` | Brand main color | | `--radius` | `0.5rem` | Default border-radius | | `--font-sans` | `Pretendard` | Body font | ## Component Customization ```tsx // Extend default button to project style const Button = React.forwardRef< HTMLButtonElement, ButtonProps & { isLoading?: boolean } >(({ isLoading, children, ...props }, ref) => { return ( {isLoading ? : children} ); }); ``` --- ## Mobile App Design System ### Flutter: Custom Theme Building Flutter defines design tokens through `ThemeData`. ```dart // lib/theme/app_theme.dart import 'package:flutter/material.dart'; class AppTheme { // ===== Design Tokens ===== // Colors static const Color primary = Color(0xFF3B82F6); static const Color secondary = Color(0xFF64748B); static const Color destructive = Color(0xFFEF4444); static const Color background = Color(0xFFFFFFFF); static const Color foreground = Color(0xFF0F172A); // Spacing static const double spacingXs = 4.0; static const double spacingSm = 8.0; static const double spacingMd = 16.0; static const double spacingLg = 24.0; static const double spacingXl = 32.0; // Border Radius static const double radiusSm = 4.0; static const double radiusMd = 8.0; static const double radiusLg = 12.0; static const double radiusFull = 9999.0; // ===== Theme Data ===== static ThemeData get lightTheme => ThemeData( useMaterial3: true, colorScheme: ColorScheme.fromSeed( seedColor: primary, brightness: Brightness.light, ), fontFamily: 'Pretendard', // Button Theme elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( padding: EdgeInsets.symmetric( horizontal: spacingMd, vertical: spacingSm, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(radiusMd), ), ), ), // Card Theme cardTheme: CardTheme( elevation: 2, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(radiusLg), ), ), // Input Theme inputDecorationTheme: InputDecorationTheme( border: OutlineInputBorder( borderRadius: BorderRadius.circular(radiusMd), ), contentPadding: EdgeInsets.all(spacingSm), ), ); static ThemeData get darkTheme => ThemeData( useMaterial3: true, colorScheme: ColorScheme.fromSeed( seedColor: primary, brightness: Brightness.dark, ), fontFamily: 'Pretendard', // ... dark theme overrides ); } ``` ### Flutter: Reusable Components ```dart // lib/components/app_button.dart import 'package:flutter/material.dart'; import '../theme/app_theme.dart'; enum AppButtonVariant { primary, secondary, destructive, outline } class AppButton extends StatelessWidget { final String label; final VoidCallback? onPressed; final AppButtonVariant variant; final bool isLoading; const AppButton({ required this.label, this.onPressed, this.variant = AppButtonVariant.primary, this.isLoading = false, super.key, }); @override Widget build(BuildContext context) { return ElevatedButton( onPressed: isLoading ? null : onPressed, style: _getStyle(), child: isLoading ? SizedBox( width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2), ) : Text(label), ); } ButtonStyle _getStyle() { switch (variant) { case AppButtonVariant.destructive: return ElevatedButton.styleFrom( backgroundColor: AppTheme.destructive, ); case AppButtonVariant.outline: return ElevatedButton.styleFrom( backgroundColor: Colors.transparent, side: BorderSide(color: AppTheme.primary), ); default: return ElevatedButton.styleFrom(); } } } ``` ### Flutter: Project Structure ``` lib/ ├── theme/ │ ├── app_theme.dart # ThemeData + Design Tokens │ ├── app_colors.dart # Color constants │ ├── app_typography.dart # TextStyle definitions │ └── app_spacing.dart # Spacing constants ├── components/ │ ├── app_button.dart │ ├── app_input.dart │ ├── app_card.dart │ └── app_dialog.dart └── main.dart ``` --- ## Cross-Platform Design Token Sharing ### Design Token JSON (Platform Independent) Centrally manage tokens with Figma Tokens or Style Dictionary. ```json // tokens/design-tokens.json { "color": { "primary": { "value": "#3B82F6" }, "secondary": { "value": "#64748B" }, "destructive": { "value": "#EF4444" } }, "spacing": { "xs": { "value": "4px" }, "sm": { "value": "8px" }, "md": { "value": "16px" }, "lg": { "value": "24px" } }, "radius": { "sm": { "value": "4px" }, "md": { "value": "8px" }, "lg": { "value": "12px" } }, "font": { "family": { "value": "Pretendard" }, "size": { "sm": { "value": "14px" }, "md": { "value": "16px" }, "lg": { "value": "18px" } } } } ``` ### Platform-specific Conversion ```bash # Generate tokens for each platform with Style Dictionary npx style-dictionary build # Output: # - build/css/variables.css (Web) # - build/dart/app_tokens.dart (Flutter) # - build/swift/AppTokens.swift (iOS) # - build/kt/AppTokens.kt (Android) ``` --- ## Design System Checklist (Platform Agnostic) ### Required Items - [ ] **Design Tokens Definition** - [ ] Colors (Primary, Secondary, Semantic) - [ ] Typography (Font Family, Sizes, Weights) - [ ] Spacing (xs, sm, md, lg, xl) - [ ] Border Radius - [ ] Shadows/Elevation - [ ] **Core Components** - [ ] Button (variants: primary, secondary, outline, destructive) - [ ] Input/TextField - [ ] Card - [ ] Dialog/Modal - [ ] Avatar - [ ] Badge - [ ] **Composite Components** - [ ] Form (with validation) - [ ] Navigation (Header, Sidebar, Bottom Nav) - [ ] Data Display (Table, List) - [ ] **Documentation** - [ ] Component catalog (Storybook / Widgetbook) - [ ] Usage guidelines - [ ] Do's and Don'ts --- ## Template See `templates/pipeline/phase-5-design-system.template.md` ## Next Phase Phase 6: UI Implementation + API Integration → Components are ready, now implement actual screens