ui-guidelines

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

UI Guidelines for Application

应用UI指南

Overview

概述

This skill provides comprehensive UI/UX guidelines for building components in a React/Next.js application using Ant Design, shadcn/ui, and consistent design tokens. It ensures all new components match the existing design system with proper colors, spacing, typography, and interaction patterns.
本技能提供了使用Ant Design、shadcn/ui和统一设计令牌在React/Next.js应用中构建组件的综合UI/UX指南。它确保所有新组件都能匹配现有设计系统,具备合适的颜色、间距、排版和交互模式。

When to Use This Skill

何时使用本技能

Trigger this skill when:
  • Creating UI components: forms, tables, modals, cards, lists
  • Adding new features that require UI elements
  • Building data visualizations or dashboards
  • Implementing loading states or animations
  • Styling components to match the design system
  • User asks to build/create/add any visual component
在以下场景触发本技能:
  • 创建UI组件:表单、表格、模态框、卡片、列表
  • 添加需要UI元素的新功能
  • 构建数据可视化或仪表板
  • 实现加载状态或动画
  • 设置组件样式以匹配设计系统
  • 用户要求构建/创建/添加任何可视化组件

Quick Start

快速开始

Step 1: Identify Component Type

步骤1:确定组件类型

Determine what you're building:
  • Drawer/Side Panel → Read
    references/component-patterns.md
    (Drawer Patterns section) [MANDATORY PATTERN]
  • Data Table → Read
    references/codebase-patterns.md
    (Tables section)
  • Form/Modal → Read
    references/codebase-patterns.md
    (Modal Patterns section)
  • Card/Grid → Read
    references/codebase-patterns.md
    (Card Patterns section)
  • Need colors/spacing → Read
    references/design-tokens.md
  • Need animations/loading → Read
    references/animations.md
明确你要构建的组件类型:
  • 抽屉/侧边面板 → 阅读
    references/component-patterns.md
    (抽屉模式章节)[强制遵循模式]
  • 数据表格 → 阅读
    references/codebase-patterns.md
    (表格章节)
  • 表单/模态框 → 阅读
    references/codebase-patterns.md
    (模态框模式章节)
  • 卡片/网格 → 阅读
    references/codebase-patterns.md
    (卡片模式章节)
  • 需要颜色/间距规范 → 阅读
    references/design-tokens.md
  • 需要动画/加载效果 → 阅读
    references/animations.md

Step 2: Follow the Component Checklist

步骤2:遵循组件检查清单

Every component must:
  • Use Ant Design components as the base
  • Apply consistent spacing (8px, 12px, 16px, 24px)
  • Use theme tokens (
    token.colorText
    ,
    token.colorBgContainer
    )
  • Include proper TypeScript types
  • Handle loading states (Skeleton, Spin, or loading prop)
  • Show feedback with
    message.success()
    /
    message.error()
  • Support responsive design
  • Include proper error handling
每个组件必须满足以下要求:
  • 以Ant Design组件为基础
  • 应用统一间距(8px、12px、16px、24px)
  • 使用主题令牌(
    token.colorText
    token.colorBgContainer
  • 包含合适的TypeScript类型
  • 处理加载状态(Skeleton、Spin或loading属性)
  • 通过
    message.success()
    /
    message.error()
    展示反馈
  • 支持响应式设计
  • 包含完善的错误处理

Step 3: Apply Core Design Tokens

步骤3:应用核心设计令牌

Colors:
  • Brand Orange:
    #F79402
    (primary brand color)
  • Product Owner:
    #7C4DFF
    (purple)
  • Tech Owner:
    #52c41a
    (green)
  • Error/Overdue:
    #ff4d4f
    (red)
  • Always use
    theme.useToken()
    for dynamic colors
Spacing:
  • Small gap:
    8px
  • Medium gap:
    12px
  • Standard padding:
    16px
  • Section margin:
    24px
Typography:
  • Table cells:
    fontSize: 12
  • Secondary text:
    fontSize: '11px'
  • Strong text:
    <Text strong>
  • Secondary:
    <Text type="secondary">
颜色规范:
  • 品牌橙色:
    #F79402
    (主品牌色)
  • 产品负责人:
    #7C4DFF
    (紫色)
  • 技术负责人:
    #52c41a
    (绿色)
  • 错误/逾期:
    #ff4d4f
    (红色)
  • 始终使用
    theme.useToken()
    获取动态颜色
间距规范:
  • 小间距:
    8px
  • 中等间距:
    12px
  • 标准内边距:
    16px
  • 区块外边距:
    24px
排版规范:
  • 表格单元格:
    fontSize: 12
  • 次要文本:
    fontSize: '11px'
  • 加粗文本:
    <Text strong>
  • 次要样式:
    <Text type="secondary">

Core Patterns

核心模式

Pattern 1: Data Tables

模式1:数据表格

All data tables should follow this structure:
tsx
import { Table, Input, Select, ConfigProvider, theme } from "antd";
import { SearchOutlined } from "@ant-design/icons";

export default function DataTable() {
  const { token } = theme.useToken();
  
  return (
    <div style={{ height: "100%", display: "flex", flexDirection: "column" }}>
      {/* Filters row */}
      <div style={{ marginBottom: 16, display: "flex", gap: "8px" }}>
        <Input placeholder="Search..." prefix={<SearchOutlined />} style={{ flex: 1 }} allowClear />
        <Select style={{ flex: 1 }} placeholder="Filter" allowClear />
      </div>

      {/* Table with custom theme */}
      <ConfigProvider theme={{
        components: { Table: { headerBg: token.colorBgContainer, fontSize: 12 } }
      }}>
        <Table
          dataSource={data}
          loading={isLoading}
          rowKey="id"
          size="small"
          pagination={false}
          scroll={{ y: 'calc(100vh - 220px)', x: 'max-content' }}
        />
      </ConfigProvider>
    </div>
  );
}
Key details:
  • Use
    ConfigProvider
    for table theme customization
  • Set
    fontSize: 12
    for compact display
  • Use
    scroll={{ y: 'calc(100vh - 220px)' }}
    for proper scrolling
  • Always include
    rowKey="id"
  • Set
    size="small"
    for compact tables
所有数据表格应遵循以下结构:
tsx
import { Table, Input, Select, ConfigProvider, theme } from "antd";
import { SearchOutlined } from "@ant-design/icons";

export default function DataTable() {
  const { token } = theme.useToken();
  
  return (
    <div style={{ height: "100%", display: "flex", flexDirection: "column" }}>
      {/* Filters row */}
      <div style={{ marginBottom: 16, display: "flex", gap: "8px" }}>
        <Input placeholder="Search..." prefix={<SearchOutlined />} style={{ flex: 1 }} allowClear />
        <Select style={{ flex: 1 }} placeholder="Filter" allowClear />
      </div>

      {/* Table with custom theme */}
      <ConfigProvider theme={{
        components: { Table: { headerBg: token.colorBgContainer, fontSize: 12 } }
      }}>
        <Table
          dataSource={data}
          loading={isLoading}
          rowKey="id"
          size="small"
          pagination={false}
          scroll={{ y: 'calc(100vh - 220px)', x: 'max-content' }}
        />
      </ConfigProvider>
    </div>
  );
}
关键细节:
  • 使用
    ConfigProvider
    自定义表格主题
  • 设置
    fontSize: 12
    以实现紧凑显示
  • 使用
    scroll={{ y: 'calc(100vh - 220px)' }}
    确保正确滚动
  • 始终包含
    rowKey="id"
  • 设置
    size="small"
    以创建紧凑表格

Pattern 2: Forms in Modals

模式2:模态框中的表单

Standard form modal pattern:
tsx
import { Modal, Form, Input, Button, message } from "antd";

export default function AddModal({ isOpen, onClose, onSuccess }) {
  const [form] = Form.useForm();
  const [isSubmitting, setIsSubmitting] = useState(false);

  const handleSubmit = async () => {
    try {
      const values = await form.validateFields();
      setIsSubmitting(true);
      await api.post('/endpoint', values);
      message.success("Created successfully");
      form.resetFields();
      onSuccess();
      onClose();
    } catch (error) {
      message.error(error.response?.data?.error || "Failed to create");
    } finally {
      setIsSubmitting(false);
    }
  };

  return (
    <Modal title="Add Item" open={isOpen} onCancel={onClose} footer={null} maskClosable={true}>
      <Form form={form} layout="vertical" onFinish={handleSubmit}>
        <Form.Item name="name" label="Name" rules={[{ required: true, message: "Please enter name" }]}>
          <Input placeholder="Enter name" />
        </Form.Item>
        
        <Form.Item style={{ marginBottom: 0, marginTop: 16, textAlign: "right" }}>
          <Button onClick={onClose} style={{ marginRight: 8 }}>Cancel</Button>
          <Button htmlType="submit" loading={isSubmitting}>Create</Button>
        </Form.Item>
      </Form>
    </Modal>
  );
}
Key details:
  • Use
    layout="vertical"
    for labels above inputs
  • Include validation rules with clear messages
  • Reset form on success:
    form.resetFields()
  • Show feedback:
    message.success()
    /
    message.error()
  • Set
    maskClosable={true}
    for better UX
标准表单模态框模式:
tsx
import { Modal, Form, Input, Button, message } from "antd";

export default function AddModal({ isOpen, onClose, onSuccess }) {
  const [form] = Form.useForm();
  const [isSubmitting, setIsSubmitting] = useState(false);

  const handleSubmit = async () => {
    try {
      const values = await form.validateFields();
      setIsSubmitting(true);
      await api.post('/endpoint', values);
      message.success("Created successfully");
      form.resetFields();
      onSuccess();
      onClose();
    } catch (error) {
      message.error(error.response?.data?.error || "Failed to create");
    } finally {
      setIsSubmitting(false);
    }
  };

  return (
    <Modal title="Add Item" open={isOpen} onCancel={onClose} footer={null} maskClosable={true}>
      <Form form={form} layout="vertical" onFinish={handleSubmit}>
        <Form.Item name="name" label="Name" rules={[{ required: true, message: "Please enter name" }]}>
          <Input placeholder="Enter name" />
        </Form.Item>
        
        <Form.Item style={{ marginBottom: 0, marginTop: 16, textAlign: "right" }}>
          <Button onClick={onClose} style={{ marginRight: 8 }}>Cancel</Button>
          <Button htmlType="submit" loading={isSubmitting}>Create</Button>
        </Form.Item>
      </Form>
    </Modal>
  );
}
关键细节:
  • 使用
    layout="vertical"
    实现标签在输入框上方的布局
  • 包含带有清晰提示的验证规则
  • 成功后重置表单:
    form.resetFields()
  • 展示反馈:
    message.success()
    /
    message.error()
  • 设置
    maskClosable={true}
    以提升用户体验

Pattern 3: Selectable Card Grids

模式3:可选择的卡片网格

Horizontal scrolling cards with selection:
tsx
import { theme, Typography, Avatar } from "antd";

const { Text } = Typography;
const { token } = theme.useToken();

<div style={{
  display: "flex",
  gap: "12px",
  overflowX: "auto",
  paddingBottom: "4px"
}}>
  {items.map((item) => {
    const isSelected = selectedId === item.id;
    return (
      <div
        key={item.id}
        onClick={() => setSelectedId(isSelected ? null : item.id)}
        style={{
          flex: 1,
          minWidth: '200px',
          maxWidth: '280px',
          padding: '12px',
          cursor: 'pointer',
          borderRadius: '8px',
          border: isSelected ? '1px solid #F79400' : `1px solid ${token.colorBorder}`,
          backgroundColor: isSelected ? token.colorFillSecondary : token.colorBgContainer,
          boxShadow: '0 1px 2px rgba(0, 0, 0, 0.04)',
        }}
      >
        <Text strong style={{ fontSize: '14px' }}>{item.name}</Text>
        {/* Additional content */}
      </div>
    );
  })}
</div>
Key details:
  • Selected state: border with brand primary color
  • Subtle shadow:
    0 1px 2px rgba(0, 0, 0, 0.04)
  • Border radius:
    8px
  • Use
    token.colorBorder
    for unselected state
支持横向滚动的可选择卡片:
tsx
import { theme, Typography, Avatar } from "antd";

const { Text } = Typography;
const { token } = theme.useToken();

<div style={{
  display: "flex",
  gap: "12px",
  overflowX: "auto",
  paddingBottom: "4px"
}}>
  {items.map((item) => {
    const isSelected = selectedId === item.id;
    return (
      <div
        key={item.id}
        onClick={() => setSelectedId(isSelected ? null : item.id)}
        style={{
          flex: 1,
          minWidth: '200px',
          maxWidth: '280px',
          padding: '12px',
          cursor: 'pointer',
          borderRadius: '8px',
          border: isSelected ? '1px solid #F79400' : `1px solid ${token.colorBorder}`,
          backgroundColor: isSelected ? token.colorFillSecondary : token.colorBgContainer,
          boxShadow: '0 1px 2px rgba(0, 0, 0, 0.04)',
        }}
      >
        <Text strong style={{ fontSize: '14px' }}>{item.name}</Text>
        {/* Additional content */}
      </div>
    );
  })}
</div>
关键细节:
  • 选中状态:使用品牌主色作为边框
  • 轻微阴影:
    0 1px 2px rgba(0, 0, 0, 0.04)
  • 圆角:
    8px
  • 未选中状态使用
    token.colorBorder

Pattern 4: Loading States

模式4:加载状态

Always show loading feedback:
tsx
// Table loading
<Table loading={isLoading} dataSource={data} />

// Card loading skeleton
{data === undefined ? (
  <Card loading style={{ minWidth: '200px' }} />
) : (
  <Card>{content}</Card>
)}

// Button loading
<Button htmlType="submit" loading={isSubmitting}>Submit</Button>

// Page content skeleton
<Skeleton active paragraph={{ rows: 4 }} />
始终展示加载反馈:
tsx
// Table loading
<Table loading={isLoading} dataSource={data} />

// Card loading skeleton
{data === undefined ? (
  <Card loading style={{ minWidth: '200px' }} />
) : (
  <Card>{content}</Card>
)}

// Button loading
<Button htmlType="submit" loading={isSubmitting}>Submit</Button>

// Page content skeleton
<Skeleton active paragraph={{ rows: 4 }} />

Pattern 5: Avatars with Fallbacks

模式5:带有回退的头像

tsx
{user.profilePic ? (
  <Avatar size={24} src={getCachedAvatarUrl(user.profilePic)} />
) : (
  <Avatar size={24} style={{ backgroundColor: getAvatarColor(user.name) }}>
    {user.name.charAt(0).toUpperCase()}
  </Avatar>
)}
tsx
{user.profilePic ? (
  <Avatar size={24} src={getCachedAvatarUrl(user.profilePic)} />
) : (
  <Avatar size={24} style={{ backgroundColor: getAvatarColor(user.name) }}>
    {user.name.charAt(0).toUpperCase()}
  </Avatar>
)}

Styling Approach

样式方法

Priority Order

优先级顺序

  1. Ant Design props first (type, size, danger, etc.)
  2. Theme tokens for colors (
    token.colorBgContainer
    )
  3. Inline styles for layout and spacing
  4. Tailwind rarely (only for utility classes)
  1. 优先使用Ant Design属性(type、size、danger等)
  2. 使用主题令牌设置颜色(
    token.colorBgContainer
  3. 内联样式用于布局和间距
  4. 尽量少用Tailwind(仅用于工具类)

DO's ✅

注意事项 ✅

  • Use Ant Design components as base
  • Use
    theme.useToken()
    for colors
  • Apply consistent spacing (8px, 12px, 16px, 24px)
  • Include loading states everywhere
  • Show user feedback with messages
  • Handle errors gracefully
  • Use TypeScript types
  • 以Ant Design组件为基础
  • 使用
    theme.useToken()
    获取颜色
  • 应用统一间距(8px、12px、16px、24px)
  • 所有地方都包含加载状态
  • 通过消息提示向用户展示反馈
  • 优雅处理错误
  • 使用TypeScript类型

DON'Ts ❌

禁止事项 ❌

  • Don't use CSS-in-JS libraries
  • Don't create custom CSS files
  • Don't hardcode colors (use tokens)
  • Don't skip error handling
  • Don't ignore responsive design
  • Don't use excessive shadows
  • 不要使用CSS-in-JS库
  • 不要创建自定义CSS文件
  • 不要硬编码颜色(使用令牌)
  • 不要跳过错误处理
  • 不要忽略响应式设计
  • 不要使用过多阴影

Common Recipes

常用示例

Status Tag

状态标签

tsx
<Tag color={status.color || "#d9d9d9"} style={{ borderRadius: "8px", fontSize: 12 }}>
  {status.name || "Not Set"}
</Tag>
tsx
<Tag color={status.color || "#d9d9d9"} style={{ borderRadius: "8px", fontSize: 12 }}>
  {status.name || "Not Set"}
</Tag>

Clickable Text

可点击文本

tsx
<Text strong style={{ cursor: 'pointer', fontSize: 12 }} onClick={() => router.push(`/path/${id}`)}>
  {title}
</Text>
tsx
<Text strong style={{ cursor: 'pointer', fontSize: 12 }} onClick={() => router.push(`/path/${id}`)}>
  {title}
</Text>

Overdue Indicator

逾期指示器

tsx
{isOverdue && (
  <Tooltip title={`Overdue since ${date}`}>
    <div style={{ width: '6px', height: '6px', borderRadius: '50%', backgroundColor: '#ff4d4f' }} />
  </Tooltip>
)}
tsx
{isOverdue && (
  <Tooltip title={`Overdue since ${date}`}>
    <div style={{ width: '6px', height: '6px', borderRadius: '50%', backgroundColor: '#ff4d4f' }} />
  </Tooltip>
)}

Select with Item Counts

包含项目数量的选择器

tsx
<Select>
  {items.map(item => (
    <Option key={item.id} value={item.id}>
      <div style={{ display: 'flex', justifyContent: 'space-between' }}>
        <span>{item.name}</span>
        <Text type="secondary" style={{ fontSize: '11px' }}>{item.count} items</Text>
      </div>
    </Option>
  ))}
</Select>
tsx
<Select>
  {items.map(item => (
    <Option key={item.id} value={item.id}>
      <div style={{ display: 'flex', justifyContent: 'space-between' }}>
        <span>{item.name}</span>
        <Text type="secondary" style={{ fontSize: '11px' }}>{item.count} items</Text>
      </div>
    </Option>
  ))}
</Select>

Reference Files

参考文件

Read these files for detailed information:
  1. design-tokens.md - Colors, spacing, typography system
  2. codebase-patterns.md - Real patterns from existing code
  3. component-patterns.md - Ant Design component standards
  4. styling-layout.md - Layout patterns and responsive design
  5. animations.md - Loading indicators and transitions
阅读以下文件获取详细信息:
  1. design-tokens.md - 颜色、间距、排版系统
  2. codebase-patterns.md - 现有代码中的实际模式
  3. component-patterns.md - Ant Design组件标准
  4. styling-layout.md - 布局模式和响应式设计
  5. animations.md - 加载指示器和过渡效果

Decision Tree

决策树

Building something new?
  1. Is it a table? → Read
    codebase-patterns.md
    Tables section
  2. Is it a form? → Read
    codebase-patterns.md
    Modal Patterns section
  3. Is it a card grid? → Read
    codebase-patterns.md
    Card Patterns section
  4. Need specific colors? → Read
    design-tokens.md
  5. Need loading animation? → Read
    animations.md
For ANY component:
  • Use TypeScript
  • Handle loading states
  • Show error messages
  • Use theme tokens
  • Test responsiveness
要构建新组件?
  1. 是表格吗? → 阅读
    codebase-patterns.md
    的表格章节
  2. 是表单吗? → 阅读
    codebase-patterns.md
    的模态框模式章节
  3. 是卡片网格吗? → 阅读
    codebase-patterns.md
    的卡片模式章节
  4. 需要特定颜色? → 阅读
    design-tokens.md
  5. 需要加载动画? → 阅读
    animations.md
对于任何组件:
  • 使用TypeScript
  • 处理加载状态
  • 展示错误消息
  • 使用主题令牌
  • 测试响应式效果

Typography Scale

排版层级

tsx
// Strong text (table headers, card titles)
<Text strong style={{ fontSize: '12px' }}>Title</Text>

// Regular text (table cells, body)
<Text style={{ fontSize: '12px' }}>Content</Text>

// Secondary text (subtitles, metadata)
<Text type="secondary" style={{ fontSize: '11px' }}>Metadata</Text>

// Tertiary text (additional info)
<Text style={{ fontSize: '11px', color: token.colorTextTertiary }}>Info</Text>
tsx
// 加粗文本(表格标题、卡片标题)
<Text strong style={{ fontSize: '12px' }}>Title</Text>

// 常规文本(表格单元格、正文)
<Text style={{ fontSize: '12px' }}>Content</Text>

// 次要文本(副标题、元数据)
<Text type="secondary" style={{ fontSize: '11px' }}>Metadata</Text>

// 三级文本(附加信息)
<Text style={{ fontSize: '11px', color: token.colorTextTertiary }}>Info</Text>

Page Layout

页面布局

Standard full-height page layout:
tsx
export default function Page() {
  return (
    <div style={{ 
      height: "100%", 
      display: "flex", 
      flexDirection: "column",
      overflow: "hidden",
      padding: "24px 40px 24px 24px"
    }}>
      {/* Page content with proper scrolling */}
    </div>
  );
}
标准全屏页面布局:
tsx
export default function Page() {
  return (
    <div style={{ 
      height: "100%", 
      display: "flex", 
      flexDirection: "column",
      overflow: "hidden",
      padding: "24px 40px 24px 24px"
    }}>
      {/* Page content with proper scrolling */}
    </div>
  );
}

Data Fetching

数据获取

Use SWR for data fetching:
tsx
import useSWR from "swr";
import { fetcher } from "@/lib/axios";

const { data, error, isLoading, mutate } = useSWR(
  '/api/endpoint',
  fetcher,
  {
    revalidateOnFocus: false,
    revalidateOnReconnect: false,
  }
);
使用SWR进行数据获取:
tsx
import useSWR from "swr";
import { fetcher } from "@/lib/axios";

const { data, error, isLoading, mutate } = useSWR(
  '/api/endpoint',
  fetcher,
  {
    revalidateOnFocus: false,
    revalidateOnReconnect: false,
  }
);

Final Checklist

最终检查清单

Before completing any component:
  • Uses Ant Design as base
  • Applies theme tokens for colors
  • Has consistent spacing
  • Includes loading states
  • Shows error feedback
  • Has TypeScript types
  • Works responsively
  • Matches existing patterns
  • Uses
    fontSize: 12
    for tables
  • Includes proper validation
完成任何组件前,请检查:
  • 以Ant Design为基础
  • 使用主题令牌设置颜色
  • 具备统一间距
  • 包含加载状态
  • 展示错误反馈
  • 具备TypeScript类型
  • 支持响应式
  • 匹配现有模式
  • 表格使用
    fontSize: 12
  • 包含合适的验证