1005 lines
22 KiB
Markdown
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)
|