mcpField
P
phase-5-design-system

phase-5-design-system

github.com/ww-w-ai设计与 UI60675 次安装4 周前更新
代码仓库

关于 phase-5-design-system

用于构建平台无关设计系统的技能,帮助建立可复用 UI 组件和统一设计规范。内容涵盖设计令牌、基础与组合组件、自定义及跨 Web 和移动平台的文档实践。

主要功能

  1. 01定义设计令牌
  2. 02规划基础与组合组件
  3. 03自定义组件
  4. 04提供 Web 和移动端实现指引
  5. 05跨平台共享设计令牌
  6. 06编写组件文档

适用场景

  1. 01为项目建立统一 UI 规范
  2. 02构建可复用组件库
  3. 03在多个平台间共享设计令牌

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/ww-w-ai/bkit-claude-code --skill phase-5-design-system

安装后在 Claude Code 中输入/phase-5-design-system确认已加载。

详细介绍

阶段 5:设计系统

构建平台无关的设计系统

目的

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


什么是设计系统?

定义

设计系统是一套可复用的组件和明确的标准,可支持大规模构建一致的用户体验。

为什么需要设计系统?(与框架无关)
问题设计系统解决方案
设计师与开发者之间存在偏差单一事实来源
重复开发组件可复用的组件库
UI/UX 不一致统一的设计令牌和规则
维护成本增加集中式变更管理
新成员入职延迟有文档记录的组件目录
设计系统的 3 个层次
┌─────────────────────────────────────────────────────┐
│              Design Tokens                           │
│   Color, Typography, Spacing, Radius, Shadow, ...   │
├─────────────────────────────────────────────────────┤
│              Core Components                         │
│   Button, Input, Card, Dialog, Avatar, Badge, ...   │
├─────────────────────────────────────────────────────┤
│            Composite Components                      │
│   Form, DataTable, Navigation, SearchBar, ...       │
└─────────────────────────────────────────────────────┘
特定平台的实现工具
平台推荐工具设计令牌方式
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

本阶段要做什么

  1. 安装基础组件:Button、Input、Card 等。
  2. 自定义:调整为符合项目风格。
  3. 组合组件:组合多个基础组件。
  4. 编写文档:记录组件用法。

交付成果

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 应用

  • 计划:所需组件列表
  • 设计:组件结构、变体设计
  • 执行:实现/自定义组件
  • 检查:检查一致性
  • 改进:完成最终调整并进入阶段 6

分级应用

级别应用方式
入门可选(简单项目可跳过)
动态必需
企业级必需(包括设计令牌)

shadcn/ui 安装

# Initial setup
npx shadcn@latest init

# Add components
npx shadcn@latest add button
npx shadcn@latest add input
npx shadcn@latest add card

必需组件列表

基础组件
  • Button、Input、Textarea
  • Card、Badge、Avatar
  • Dialog、Sheet、Popover
表单
  • Form、Label、Select
  • Checkbox、Radio、Switch
导航
  • Navigation Menu、Tabs
  • Breadcrumb、Pagination

构建自定义主题

覆盖设计令牌

shadcn/ui 基于 CSS 变量,因此可在 globals.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 配置
// 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)',
      },
    },
  },
}
设计令牌文档

建议每个项目都创建 docs/02-design/design-tokens.md:

令牌值用途
--primary221.2 83.2% 53.3%品牌主色
--radius0.5rem默认边框圆角
--font-sansPretendard正文字体

自定义组件

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

移动应用设计系统

Flutter:构建自定义主题

Flutter 通过 ThemeData 定义设计令牌。

// 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:可复用组件
// 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:项目结构
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

跨平台共享设计令牌

设计令牌 JSON(与平台无关)

使用 Figma Tokens 或 Style Dictionary 集中管理令牌。

// 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" }
    }
  }
}
特定平台的转换
# 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)

设计系统检查清单(与平台无关)

必需项
  • 设计令牌定义

    • 颜色(主色、辅助色、语义色)
    • 字体排版(字体系列、字号、字重)
    • 间距(xs、sm、md、lg、xl)
    • 边框圆角
    • 阴影/层级
  • 核心组件

    • 按钮(变体:主按钮、次按钮、轮廓按钮、危险按钮)
    • 输入框/文本字段
    • 卡片
    • 对话框/模态框
    • 头像
    • 徽章
  • 组合组件

    • 表单(带验证)
    • 导航(页眉、侧边栏、底部导航)
    • 数据展示(表格、列表)
  • 文档

    • 组件目录(Storybook / Widgetbook)
    • 使用指南
    • 注意事项与禁忌

模板

请参阅 templates/pipeline/phase-5-design-system.template.md

下一阶段

阶段 6:UI 实现 + API 集成 → 组件已就绪,现在开始实现实际界面

评论

支持 Markdown