phase-5-design-system

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Phase 5: Design System

第五阶段:设计系统

Build platform-independent design system
构建跨平台设计系统

Purpose

目标

Build a reusable UI component library. Enable consistent design and fast development.

构建可复用的UI组件库,实现一致性设计与快速开发。

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)

为何需要设计系统?(框架无关)

ProblemDesign System Solution
Designer-developer mismatchSingle Source of Truth
Duplicate component developmentReusable component library
Inconsistent UI/UXUnified design tokens and rules
Increased maintenance costCentralized change management
Delayed new member onboardingDocumented component catalog
问题设计系统解决方案
设计师与开发者认知偏差单一事实来源
组件重复开发可复用组件库
UI/UX不一致统一的设计令牌与规则
维护成本增加集中式变更管理
新成员上手缓慢文档化组件目录

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, ...       │
└─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│              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

各平台推荐实现工具

PlatformRecommended ToolsDesign Token Method
Web (React/Next.js)shadcn/ui, RadixCSS Variables
Web (Vue)Vuetify, PrimeVueCSS Variables
FlutterMaterial 3, Custom ThemeThemeData
iOS (SwiftUI)Native ComponentsAsset Catalog, Color Set
Android (Compose)Material 3MaterialTheme
React NativeNativeBase, TamaguiStyleSheet + Theme

平台推荐工具设计令牌实现方式
Web(React/Next.js)shadcn/ui, RadixCSS Variables
Web(Vue)Vuetify, PrimeVueCSS Variables
FlutterMaterial 3, 自定义主题ThemeData
iOS(SwiftUI)原生组件Asset Catalog, Color Set
Android(Compose)Material 3MaterialTheme
React NativeNativeBase, TamaguiStyleSheet + 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
  1. 安装基础组件:Button、Input、Card等
  2. 自定义配置:根据项目风格调整组件
  3. 组合组件开发:将多个基础组件组合为复合组件
  4. 文档编写:记录组件使用方法

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
components/
└── ui/                     # shadcn/ui组件
    ├── button.tsx
    ├── input.tsx
    ├── card.tsx
    └── ...

lib/
└── utils.ts                # 工具函数(如cn函数)

docs/02-design/
└── design-system.md        # 设计系统规范文档

PDCA Application

PDCA循环应用

  • 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

分场景应用建议

LevelApplication Method
StarterOptional (simple projects may skip)
DynamicRequired
EnterpriseRequired (including design tokens)
项目规模应用方式
入门项目可选(简单项目可跳过)
动态项目必需
企业级项目必需(包含设计令牌)

shadcn/ui Installation

shadcn/ui 安装步骤

bash
undefined
bash
undefined

Initial setup

初始化配置

npx shadcn@latest init
npx shadcn@latest init

Add components

添加组件

npx shadcn@latest add button npx shadcn@latest add input npx shadcn@latest add card
undefined
npx shadcn@latest add button npx shadcn@latest add input npx shadcn@latest add card
undefined

Required Component List

必需组件列表

Basic

基础组件

  • Button, Input, Textarea
  • Card, Badge, Avatar
  • Dialog, Sheet, Popover
  • Button、Input、Textarea
  • Card、Badge、Avatar
  • Dialog、Sheet、Popover

Form

表单组件

  • Form, Label, Select
  • Checkbox, Radio, Switch
  • Form、Label、Select
  • Checkbox、Radio、Switch

Navigation

导航组件

  • Navigation Menu, Tabs
  • Breadcrumb, Pagination
  • 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 */
  }
}
shadcn/ui 基于CSS变量实现,可在
globals.css
中自定义主题。
css
/* globals.css */
@layer base {
  :root {
    /* ===== 颜色 ===== */
    --background: 0 0% 100%;
    --foreground: 222.2 84% 4.9%;
    --primary: 221.2 83.2% 53.3%;      /* 品牌主色 */
    --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%;

    /* ===== 排版 ===== */
    --font-sans: 'Pretendard', sans-serif;
    --font-mono: 'JetBrains Mono', monospace;

    /* ===== 间距(rem单位) ===== */
    --spacing-xs: 0.25rem;   /* 4px */
    --spacing-sm: 0.5rem;    /* 8px */
    --spacing-md: 1rem;      /* 16px */
    --spacing-lg: 1.5rem;    /* 24px */
    --spacing-xl: 2rem;      /* 32px */

    /* ===== 圆角 ===== */
    --radius: 0.5rem;
    --radius-sm: 0.25rem;
    --radius-lg: 0.75rem;
    --radius-full: 9999px;

    /* ===== 阴影 ===== */
    --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%;
    /* ... 深色模式覆盖配置 */
  }
}

Tailwind Config Extension

Tailwind 配置扩展

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)',
      },
    },
  },
}
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:
TokenValuePurpose
--primary
221.2 83.2% 53.3%
Brand main color
--radius
0.5rem
Default border-radius
--font-sans
Pretendard
Body font
建议为每个项目创建
docs/02-design/design-tokens.md
令牌用途
--primary
221.2 83.2% 53.3%
品牌主色
--radius
0.5rem
默认圆角
--font-sans
Pretendard
正文字体

Component Customization

组件自定义示例

tsx
// Extend default button to project style
const Button = React.forwardRef<
  HTMLButtonElement,
  ButtonProps & { isLoading?: boolean }
>(({ isLoading, children, ...props }, ref) => {
  return (
    <ButtonPrimitive ref={ref} {...props}>
      {isLoading ? <Spinner /> : children}
    </ButtonPrimitive>
  );
});

tsx
// 扩展默认按钮以适配项目风格
const Button = React.forwardRef<
  HTMLButtonElement,
  ButtonProps & { isLoading?: boolean }
>(({ isLoading, children, ...props }, ref) => {
  return (
    <ButtonPrimitive ref={ref} {...props}>
      {isLoading ? <Spinner /> : children}
    </ButtonPrimitive>
  );
});

Mobile App Design System

移动端应用设计系统

Flutter: Custom Theme Building

Flutter:自定义主题构建

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 通过
ThemeData
定义设计令牌。
dart
// lib/theme/app_theme.dart
import 'package:flutter/material.dart';

class AppTheme {
  // ===== 设计令牌 =====

  // 颜色
  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);

  // 间距
  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;

  // 圆角
  static const double radiusSm = 4.0;
  static const double radiusMd = 8.0;
  static const double radiusLg = 12.0;
  static const double radiusFull = 9999.0;

  // ===== 主题数据 =====

  static ThemeData get lightTheme => ThemeData(
    useMaterial3: true,
    colorScheme: ColorScheme.fromSeed(
      seedColor: primary,
      brightness: Brightness.light,
    ),
    fontFamily: 'Pretendard',

    // 按钮主题
    elevatedButtonTheme: ElevatedButtonThemeData(
      style: ElevatedButton.styleFrom(
        padding: EdgeInsets.symmetric(
          horizontal: spacingMd,
          vertical: spacingSm,
        ),
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(radiusMd),
        ),
      ),
    ),

    // 卡片主题
    cardTheme: CardTheme(
      elevation: 2,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(radiusLg),
      ),
    ),

    // 输入框主题
    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',
    // ... 深色主题覆盖配置
  );
}

Flutter: Reusable Components

Flutter:可复用组件示例

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,
  });

  
  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();
    }
  }
}
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,
  });

  
  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

Flutter:项目结构

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

lib/
├── theme/
│   ├── app_theme.dart          # ThemeData + 设计令牌
│   ├── app_colors.dart         # 颜色常量
│   ├── app_typography.dart     # 文本样式定义
│   └── app_spacing.dart        # 间距常量
├── 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)

平台无关的设计令牌JSON

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" }
    }
  }
}
通过Figma Tokens或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
undefined
bash
undefined

Generate tokens for each platform with Style Dictionary

使用Style Dictionary为各平台生成令牌

npx style-dictionary build
npx style-dictionary build

Output:

输出文件:

- build/css/variables.css (Web)

- build/css/variables.css (Web)

- build/dart/app_tokens.dart (Flutter)

- build/dart/app_tokens.dart (Flutter)

- build/swift/AppTokens.swift (iOS)

- build/swift/AppTokens.swift (iOS)

- build/kt/AppTokens.kt (Android)

- 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

  • 设计令牌定义
    • 颜色(主色、辅助色、语义色)
    • 排版(字体、字号、字重)
    • 间距(xs、sm、md、lg、xl)
    • 圆角
    • 阴影/层级
  • 核心组件
    • Button(变体:主按钮、辅助按钮、轮廓按钮、危险按钮)
    • Input/TextField
    • Card
    • Dialog/Modal
    • Avatar
    • Badge
  • 复合组件
    • Form(带校验)
    • Navigation(头部、侧边栏、底部导航)
    • 数据展示(Table、List)
  • 文档
    • 组件目录(Storybook / Widgetbook)
    • 使用指南
    • 注意事项

Template

模板

See
templates/pipeline/phase-5-design-system.template.md
请查看
templates/pipeline/phase-5-design-system.template.md

Next Phase

下一阶段

Phase 6: UI Implementation + API Integration → Components are ready, now implement actual screens
第六阶段:UI实现 + API集成 → 组件已就绪,开始实现实际页面