Files
gt-agent-company/.claude/DESIGN-SYSTEM.md
sexygoat 3c62cc1cd1 first
2026-03-31 18:41:52 +08:00

1005 lines
22 KiB
Markdown

# GT Agent Company - UI/UX Design System
**Project Type**: Mobile-First SaaS Application (UniApp Vue3)
**Tech Stack**: Vue 3 + UnoCSS + uView Plus
**Platforms**: H5 / WeChat Mini Program / Native App
**Last Updated**: 2026-03-18
---
## 🎨 Design Philosophy
**Style Direction**: Modern Professional SaaS with Xiaomi-Inspired Branding
**Primary Pattern**: Glassmorphism + Flat Design + Vibrant & Block-based
**Target Audience**: B2B/B2C professionals seeking agent management solutions
### Core Design Principles
1. **Mobile-First**: Design for 375px viewport first, enhance for larger screens
2. **Performance-Focused**: Minimize animations, optimize images, lazy load
3. **Accessibility-Driven**: WCAG 2.1 AA minimum, touch-friendly targets
4. **Consistent Branding**: Xiaomi-inspired orange (#ff6700) as primary identity
5. **Cross-Platform**: Unified experience across H5, WeChat, and native apps
---
## 🎯 Product Type Recommendations
Based on analysis: **SaaS (General) + B2B Service**
**Recommended Landing Pattern**: Hero + Features + CTA
**Dashboard Style**: Data-Dense + Real-Time Monitoring
**Key Considerations**:
- Balance modern feel with clarity
- Focus on strong CTAs (Call-to-Actions)
- Credibility essential - show clear ROI messaging
- Social proof and trust elements mandatory
---
## 🌈 Color Palette
### Brand Colors (Xiaomi-Inspired)
```scss
// Primary Brand Colors
--brand-orange: #ff6700; // Primary CTA, hover states
--brand-orange-light: #ff8533; // Lighter variant
--brand-orange-dark: #e65a00; // Pressed states
--brand-gray: #333333; // Headings, important text
--brand-gray-light: #757575; // Secondary text
```
### Semantic Colors (Light Mode)
```scss
// Primary Theme Colors
--theme-primary: #ff6700; // Orange (Trust + Energy)
--theme-secondary: #ff8533; // Lighter Orange
--theme-accent: #333333; // Dark Gray
// Status Colors
--theme-success: #3ed268; // Green (Success states)
--theme-warning: #e68815; // Amber (Warnings)
--theme-error: #d31638; // Red (Errors)
// Text Hierarchy
--theme-main-color: #4c484f; // Primary text (slate-900 equivalent)
--theme-content-color: #6b6569; // Body text (slate-700)
--theme-tips-color: #8a8486; // Secondary text (slate-500)
--theme-light-color: #bd9e84; // Muted text (beige)
--theme-disabled-color: #dce0eb; // Disabled states
// Backgrounds
--theme-bg-color: #ffffff; // Main background
--theme-bg-color-secondary: #faf8f7; // Card backgrounds
--theme-bg-gradient-start: #c5dfdf;
--theme-bg-gradient-end: #bd9e84;
// Borders
--theme-border-color: #c5dfdf; // Borders, dividers
```
### Dark Mode Colors
```scss
.theme-dark {
--theme-primary: #3c9cff; // Blue (better for dark mode)
--theme-success: #5ac725;
--theme-warning: #f9ae3d;
--theme-error: #f56c6c;
// Text (High Contrast Required)
--theme-main-color: #ffffff;
--theme-content-color: #b0b8c1;
--theme-tips-color: #8a8f95;
--theme-light-color: #6c757d;
--theme-disabled-color: #495057;
// Backgrounds
--theme-bg-color: #1a1a1a;
--theme-bg-color-secondary: #2d2d2d;
}
```
### UnoCSS Theme Integration
```typescript
// uno.config.ts already configured:
theme: {
colors: {
'primary': 'var(--theme-primary)',
'success': 'var(--theme-success)',
'warning': 'var(--theme-warning)',
'error': 'var(--theme-error)',
'text-main': 'var(--theme-main-color)',
'text-content': 'var(--theme-content-color)',
'text-tips': 'var(--theme-tips-color)',
}
}
// Usage in templates:
<div class="bg-primary text-white">
<p class="text-content">Body text</p>
```
### Color Contrast Requirements
**CRITICAL**: Maintain minimum 4.5:1 contrast ratio for normal text
**Good Combinations**:
- `#4c484f` (text-main) on `#ffffff` → 7.2:1
- `#ffffff` on `#ff6700` (primary) → 4.1:1
- `#333333` on `#ffffff` → 12.6:1
**Bad Combinations**:
- `#bd9e84` (light) on `#ffffff` → 2.4:1 (TOO LOW)
- Use `text-light` only for decorative text, not critical content
---
## 📝 Typography
### Font Pairing: Modern Professional
**Stack**: Plus Jakarta Sans (Sans + Sans)
**Character**: Friendly, modern, SaaS, clean, approachable, professional
```css
/* Import Google Fonts */
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700&display=swap');
/* Fallback for platforms without custom fonts */
font-family: 'Plus Jakarta Sans', 'PingFang SC', 'Microsoft YaHei', sans-serif;
```
### Font Scale (Mobile-First)
```scss
// Base: 16px (rem baseline)
// Headings
--font-h1: 32px; // Hero headings
--font-h2: 28px; // Section titles
--font-h3: 24px; // Card headers
--font-h4: 20px; // Subsection titles
--font-h5: 18px; // Small headings
--font-h6: 16px; // Labels
// Body
--font-body: 16px; // MINIMUM for mobile readability
--font-body-small: 14px;
--font-caption: 12px; // Fine print only
// Line Heights
--line-height-tight: 1.2; // Headings
--line-height-normal: 1.5; // Body text (MANDATORY)
--line-height-relaxed: 1.75; // Long-form content
```
### Typography Hierarchy
```html
<!-- UnoCSS Classes -->
<h1 class="text-32px font-700 leading-tight text-main">
Hero Heading
</h1>
<h2 class="text-28px font-600 leading-tight text-main">
Section Title
</h2>
<p class="text-16px font-400 leading-normal text-content">
Body text content. Minimum 16px on mobile.
</p>
<span class="text-14px text-tips">
Secondary information
</span>
<small class="text-12px text-light">
Fine print only - not for critical content
</small>
```
### Font Weight Usage
- **300 Light**: Decorative text only
- **400 Regular**: Body text, descriptions
- **500 Medium**: Emphasized body text
- **600 SemiBold**: Headings, buttons
- **700 Bold**: Hero titles, important CTAs
**⚠️ RULE**: Never use font weight < 400 for critical content
---
## 📐 Layout & Spacing
### Container Widths
```scss
// Mobile-first breakpoints (UnoCSS)
--container-xs: 100%; // < 640px
--container-sm: 640px; // sm:
--container-md: 768px; // md:
--container-lg: 1024px; // lg:
--container-xl: 1280px; // xl:
// Recommended max-width for content
--max-width-content: 1200px;
```
### Spacing Scale (UnoCSS rem-based)
```scss
// Base: 1rem = 16px (4px increments)
--space-1: 0.25rem; // 4px
--space-2: 0.5rem; // 8px (Minimum touch spacing)
--space-3: 0.75rem; // 12px
--space-4: 1rem; // 16px (Base unit)
--space-6: 1.5rem; // 24px (Section spacing)
--space-8: 2rem; // 32px (Component gaps)
--space-12: 3rem; // 48px (Large sections)
--space-16: 4rem; // 64px (Hero sections)
// UnoCSS Usage:
<div class="p-4"> <!-- 16px padding -->
<div class="gap-2"> <!-- 8px gap -->
<div class="mt-8 mb-6"> <!-- 32px top, 24px bottom -->
```
### Grid System
```html
<!-- 12-column responsive grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div class="col-span-1">Card 1</div>
<div class="col-span-1">Card 2</div>
<div class="col-span-1">Card 3</div>
</div>
<!-- Common layouts -->
<div class="flex flex-col md:flex-row gap-4">
<aside class="w-full md:w-64">Sidebar</aside>
<main class="flex-1">Content</main>
</div>
```
### Safe Area Handling
```scss
// Custom UnoCSS rule already configured:
.pb-safe {
padding-bottom: env(safe-area-inset-bottom);
}
// Use for bottom navigation:
<view class="fixed bottom-0 pb-safe">
Bottom Navigation
</view>
```
---
## 🎯 Components & Patterns
### Touch Targets (CRITICAL)
**MANDATORY**: Minimum 44x44px for all interactive elements
```html
<!-- ✅ GOOD: Proper touch target -->
<button class="min-h-44px min-w-44px center">
<i class="i-mdi-home w-24px h-24px"></i>
</button>
<!-- ❌ BAD: Too small -->
<button class="w-32px h-32px">
<i class="i-mdi-home"></i>
</button>
<!-- Touch spacing between adjacent buttons -->
<div class="flex gap-2"> <!-- Minimum 8px gap -->
<button class="min-h-44px">Button 1</button>
<button class="min-h-44px">Button 2</button>
</div>
```
### Button Styles
```html
<!-- Primary CTA (Orange) -->
<button class="
bg-primary text-white
px-6 py-3 rounded-8px
min-h-44px
font-600 text-16px
transition-colors duration-200
hover:bg-[#e65a00]
active:bg-[#e65a00]
cursor-pointer
">
确认提交
</button>
<!-- Secondary Button -->
<button class="
bg-transparent border-2 border-primary text-primary
px-6 py-3 rounded-8px
min-h-44px
font-600
transition-all duration-200
hover:bg-primary hover:text-white
cursor-pointer
">
取消
</button>
<!-- Disabled State -->
<button class="
bg-text-disabled text-white
px-6 py-3 rounded-8px
cursor-not-allowed
opacity-60
" disabled>
Loading...
</button>
```
### Card Components (Glassmorphism)
```html
<!-- Light Mode Glass Card -->
<view class="
bg-white/80
backdrop-blur-md
border border-gray-200
rounded-16px
p-6
shadow-lg
">
<text class="text-20px font-600 text-main">Card Title</text>
<text class="text-14px text-content mt-2">Card content</text>
</view>
<!-- Dark Mode Glass Card -->
<view class="
dark:bg-white/10
dark:backdrop-blur-md
dark:border-white/20
rounded-16px
p-6
">
Content
</view>
```
### Icon Usage (CRITICAL)
**❌ NEVER use emoji as UI icons** (🎨 🚀 ⚙️)
**✅ ALWAYS use SVG icons from UnoCSS preset-icons**
```html
<!-- ✅ GOOD: SVG icons -->
<i class="i-mdi-home w-24px h-24px text-primary"></i>
<i class="i-mdi-settings w-24px h-24px"></i>
<!-- Custom local icons -->
<i class="i-my-icons-preview-open w-24px h-24px"></i>
<!-- ❌ BAD: Emoji icons -->
<span>🏠 首页</span> <!-- DON'T DO THIS -->
```
### Navigation Bar (Floating)
```html
<!-- ✅ GOOD: Floating navbar with proper spacing -->
<view class="
fixed top-4 left-4 right-4
bg-white/90 backdrop-blur-md
rounded-full
px-6 py-3
shadow-lg
z-50
">
<view class="flex justify-between items-center">
<text class="font-600 text-18px">Logo</text>
<i class="i-mdi-menu w-24px h-24px cursor-pointer"></i>
</view>
</view>
<!-- Account for navbar height in content -->
<view class="pt-72px"> <!-- top-4 + navbar-height + gap -->
Main content starts here
</view>
```
### Form Inputs
```html
<!-- Accessible form input -->
<view class="mb-4">
<label for="email" class="block text-14px font-500 text-main mb-2">
邮箱地址
</label>
<input
id="email"
type="email"
inputmode="email"
class="
w-full px-4 py-3 min-h-44px
bg-white border-2 border-gray-200
rounded-8px
text-16px
focus:border-primary focus:outline-none
transition-colors duration-200
"
placeholder="输入您的邮箱"
/>
<!-- Error state -->
<text class="text-12px text-error mt-1" role="alert">
请输入有效的邮箱地址
</text>
</view>
```
---
## 🎭 Animation & Transitions
### Duration Guidelines
```scss
// Speed mapping (prefer faster)
--duration-instant: 0ms; // No animation
--duration-fast: 150ms; // Micro-interactions (hover, focus)
--duration-normal: 200ms; // Standard transitions
--duration-medium: 300ms; // Maximum for UI (sliding panels)
--duration-slow: 500ms; // AVOID - too sluggish
```
### Recommended Transitions
```html
<!-- ✅ GOOD: Fast color transition -->
<button class="
bg-primary
transition-colors duration-200
hover:bg-[#e65a00]
">
Hover me
</button>
<!-- ✅ GOOD: Transform (GPU-accelerated) -->
<view class="
transition-transform duration-200
hover:scale-105
">
Card
</view>
<!-- ❌ BAD: Slow transition -->
<view class="transition-all duration-1000">
Too slow!
</view>
<!-- ❌ BAD: Animating width/height (causes reflow) -->
<view class="transition-width duration-300">
Use transform instead
</view>
```
### Reduced Motion (CRITICAL)
```css
/* MANDATORY: Respect user preferences */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
```
### Loading States
```html
<!-- Skeleton loader (preferred) -->
<view class="animate-pulse">
<view class="h-20px bg-gray-200 rounded mb-4"></view>
<view class="h-16px bg-gray-200 rounded w-3/4"></view>
</view>
<!-- Spinner (for buttons) -->
<button class="bg-primary text-white px-6 py-3" disabled>
<i class="i-mdi-loading animate-spin w-20px h-20px"></i>
Loading...
</button>
```
### Hover States (CRITICAL)
**❌ RULE**: Never use scale transforms that shift layout
```html
<!-- ✅ GOOD: Stable hover (color change) -->
<view class="
bg-white
transition-colors duration-200
hover:bg-gray-50
cursor-pointer
">
Stable hover
</view>
<!-- ❌ BAD: Layout shift -->
<view class="hover:scale-110">
This shifts adjacent elements!
</view>
```
---
## ♿ Accessibility Requirements
### WCAG 2.1 AA Compliance (MANDATORY)
#### Color Contrast
- **Normal text (16px+)**: Minimum 4.5:1 ratio
- **Large text (24px+ or 18.5px bold)**: Minimum 3:1 ratio
- **UI components**: Minimum 3:1 ratio
```scss
// ✅ Pre-validated combinations:
color: #4c484f; background: #ffffff; // 7.2:1
color: #ffffff; background: #ff6700; // 4.1:1
color: #333333; background: #ffffff; // 12.6:1
// ❌ Avoid:
color: #bd9e84; background: #ffffff; // 2.4:1 - TOO LOW
```
#### Keyboard Navigation
```html
<!-- ✅ GOOD: Proper tab order and focus states -->
<button class="
focus:outline-none
focus:ring-2 focus:ring-primary focus:ring-offset-2
transition-all duration-200
">
Keyboard accessible
</button>
<!-- Custom interactive element -->
<view
tabindex="0"
role="button"
@keydown.enter="handleAction"
@keydown.space="handleAction"
class="
cursor-pointer
focus:ring-2 focus:ring-primary
"
>
Keyboard accessible custom element
</view>
```
#### ARIA Labels
```html
<!-- Icon-only buttons (MANDATORY) -->
<button aria-label="关闭菜单" class="p-2">
<i class="i-mdi-close w-24px h-24px"></i>
</button>
<!-- Loading states -->
<view role="status" aria-live="polite">
<i class="i-mdi-loading animate-spin"></i>
<span class="sr-only">加载中...</span>
</view>
<!-- Error messages -->
<text role="alert" class="text-error">
请填写必填项
</text>
```
#### Form Accessibility
```html
<!-- ✅ GOOD: Proper label association -->
<view>
<label for="username" class="block mb-2">
用户名
</label>
<input
id="username"
type="text"
aria-required="true"
aria-invalid="false"
/>
</view>
<!-- ❌ BAD: Placeholder-only (no label) -->
<input placeholder="用户名" />
```
---
## 📱 Responsive Design
### Mobile-First Breakpoints
```scss
// UnoCSS default breakpoints
xs: 0px // Default (mobile)
sm: 640px // Large mobile
md: 768px // Tablet
lg: 1024px // Desktop
xl: 1280px // Large desktop
2xl: 1536px // Extra large
// Common patterns:
<view class="
grid
grid-cols-1 /* Mobile: 1 column */
sm:grid-cols-2 /* Tablet: 2 columns */
lg:grid-cols-3 /* Desktop: 3 columns */
gap-4
">
```
### Viewport Meta (CRITICAL for H5)
```html
<!-- index.html -->
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
```
### Responsive Typography
```html
<!-- Responsive font sizes -->
<h1 class="
text-24px sm:text-28px md:text-32px
leading-tight
">
Responsive Heading
</h1>
<!-- Responsive spacing -->
<view class="
px-4 sm:px-6 md:px-8
py-6 sm:py-8 md:py-12
">
Responsive padding
</view>
```
### Touch vs Hover
```html
<!-- ✅ GOOD: Click/tap for primary interactions -->
<view @click="handleAction" class="cursor-pointer">
Works on touch and mouse
</view>
<!-- ❌ BAD: Hover-only interactions -->
<view @mouseenter="showTooltip">
Doesn't work on touch devices!
</view>
```
---
## 🚀 Performance Optimization
### Image Optimization
```html
<!-- ✅ GOOD: Lazy loading with placeholder -->
<image
:src="imageUrl"
mode="aspectFill"
lazy-load
class="w-full h-auto"
/>
<!-- Responsive images for H5 -->
<img
:src="imageUrl"
srcset="
image-320w.webp 320w,
image-640w.webp 640w,
image-1280w.webp 1280w
"
sizes="(max-width: 640px) 100vw, 640px"
loading="lazy"
alt="描述性文本"
/>
```
### Animation Performance
```html
<!-- ✅ GOOD: GPU-accelerated properties only -->
<view class="transition-transform transition-opacity duration-200">
Use transform and opacity
</view>
<!-- ❌ BAD: Triggers layout reflow -->
<view class="transition-width transition-height">
Causes performance issues
</view>
```
### Content Jumping Prevention
```html
<!-- ✅ GOOD: Reserve space for async content -->
<view class="min-h-200px">
<template v-if="loading">
<view class="animate-pulse h-200px bg-gray-200"></view>
</template>
<template v-else>
<AsyncContent />
</template>
</view>
```
---
## 🎨 Style Variations
### Glassmorphism (Primary Style)
```html
<view class="
bg-white/80
backdrop-blur-md
border border-white/20
rounded-16px
shadow-lg
">
Glass card content
</view>
```
### Flat Design (Secondary Style)
```html
<view class="
bg-white
border border-gray-200
rounded-8px
shadow-sm
">
Flat card content
</view>
```
### Vibrant Block-based (Accent)
```html
<view class="
bg-primary
text-white
p-6
rounded-12px
shadow-xl
">
<h3 class="text-24px font-700">Feature Title</h3>
<p class="text-16px mt-2">High-contrast content block</p>
</view>
```
---
## 🔧 Vue 3 + UnoCSS Best Practices
### Component Structure
```vue
<script setup lang="ts">
import { ref, computed } from 'vue'
// ✅ GOOD: Use ref for primitives
const count = ref(0)
// ✅ GOOD: Use reactive for objects
const state = reactive({ user: null })
// ✅ GOOD: Computed for derived state
const doubled = computed(() => count.value * 2)
// ✅ GOOD: Define props with types
const props = defineProps<{
title: string
isActive?: boolean
}>()
// ✅ GOOD: Define emits
const emit = defineEmits<{
change: [id: number]
}>()
</script>
<template>
<!-- GOOD: Use UnoCSS utility classes -->
<view class="flex flex-col gap-4 p-4">
<text class="text-20px font-600 text-main">
{{ props.title }}
</text>
<button
class="
bg-primary text-white
px-6 py-3 rounded-8px
min-h-44px
transition-colors duration-200
hover:bg-[#e65a00]
cursor-pointer
"
@click="emit('change', count)"
>
Click me: {{ count }}
</button>
</view>
</template>
```
### UnoCSS Shortcuts (Custom)
```typescript
// uno.config.ts shortcuts already configured:
shortcuts: {
'border-base': 'border border-gray-500/10',
'center': 'flex justify-center items-center',
}
// Usage:
<view class="center">Centered content</view>
```
---
## ✅ Pre-Delivery Checklist
Before committing any UI code, verify:
### Visual Quality
- [ ] No emojis used as icons (use `i-mdi-*` instead)
- [ ] All icons from consistent icon set (MDI via UnoCSS)
- [ ] Hover states don't cause layout shift
- [ ] Use theme colors directly (`bg-primary`, not `bg-[#ff6700]`)
### Interaction
- [ ] All clickable elements have `cursor-pointer`
- [ ] Hover states provide clear visual feedback
- [ ] Transitions are 150-300ms (not slower)
- [ ] Focus states visible for keyboard navigation
### Light/Dark Mode
- [ ] Light mode text contrast ≥ 4.5:1
- [ ] Glass elements visible in light mode (`bg-white/80` minimum)
- [ ] Borders visible in both modes
- [ ] Test both modes before delivery
### Layout
- [ ] Floating elements have spacing from edges (`top-4 left-4 right-4`)
- [ ] No content hidden behind fixed navbars
- [ ] Responsive at 375px, 768px, 1024px
- [ ] No horizontal scroll on mobile
### Accessibility
- [ ] All images have `alt` text
- [ ] Form inputs have `<label>` elements
- [ ] Color is not the only indicator
- [ ] `prefers-reduced-motion` respected
### Performance
- [ ] Images use `lazy-load` attribute
- [ ] No animations > 300ms
- [ ] Only `transform`/`opacity` animations
- [ ] Reserve space for async content
### Touch Targets
- [ ] All interactive elements ≥ 44x44px
- [ ] Minimum 8px gap between buttons
- [ ] Input fields use correct `inputmode`
---
## 📚 Quick Reference Links
### Internal Resources
- Theme Variables: `src/static/styles/theme.scss`
- UnoCSS Config: `uno.config.ts`
- uView Plus Docs: https://uview-plus.jiangruyi.com/
### Design Resources
- MDI Icons: https://icon-sets.iconify.design/mdi/
- UnoCSS Docs: https://unocss.dev/
- WCAG Guidelines: https://www.w3.org/WAI/WCAG21/quickref/
### Color Tools
- Contrast Checker: https://webaim.org/resources/contrastchecker/
- Coolors: https://coolors.co/
---
## 🎯 Common Anti-Patterns to Avoid
### ❌ DON'T
1. **Don't use emoji as icons**
```html
<!-- ❌ BAD -->
<span>🏠 首页</span>
<!-- ✅ GOOD -->
<i class="i-mdi-home"></i> 首页
```
2. **Don't use `bg-white/10` in light mode**
```html
<!-- ❌ BAD: Invisible in light mode -->
<view class="bg-white/10">
<!-- ✅ GOOD -->
<view class="bg-white/80 dark:bg-white/10">
```
3. **Don't use text < 16px for body content on mobile**
```html
<!-- ❌ BAD -->
<text class="text-12px">Important content</text>
<!-- ✅ GOOD -->
<text class="text-16px">Important content</text>
```
4. **Don't forget touch targets**
```html
<!-- ❌ BAD: Only 32px -->
<button class="w-32px h-32px">X</button>
<!-- ✅ GOOD: 44px minimum -->
<button class="min-w-44px min-h-44px center">
<i class="i-mdi-close w-20px h-20px"></i>
</button>
```
5. **Don't use hover-only interactions**
```html
<!-- ❌ BAD: Doesn't work on touch -->
<view @mouseenter="showMenu">
<!-- ✅ GOOD: Works everywhere -->
<view @click="toggleMenu">
```
---
## 📝 Version History
- **v1.0** (2026-03-18): Initial design system based on UI/UX Pro Max analysis
- Added comprehensive mobile-first guidelines
- Integrated existing Xiaomi-inspired brand colors
- Documented UnoCSS + Vue 3 patterns
---
**Last Updated**: 2026-03-18
**Maintained By**: Claude Code (UI/UX Pro Max)