22 KiB
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
- Mobile-First: Design for 375px viewport first, enhance for larger screens
- Performance-Focused: Minimize animations, optimize images, lazy load
- Accessibility-Driven: WCAG 2.1 AA minimum, touch-friendly targets
- Consistent Branding: Xiaomi-inspired orange (#ff6700) as primary identity
- 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 (Blue Theme)
// Primary Brand Colors
--brand-primary: #1677ff; // Primary CTA, hover states
--brand-primary-light: #4096ff; // Lighter variant
--brand-primary-dark: #0958d9; // Pressed states
--brand-secondary: #1e293b; // Dark Gray (headings)
--brand-accent: #ffffff; // White (emphasis)
Semantic Colors (Light Mode)
// Primary Theme Colors
--theme-primary: #1677ff; // Blue (Trust + Energy)
--theme-secondary: #1e293b; // Dark Gray
--theme-accent: #ffffff; // White
// Status Colors
--theme-success: #52c41a; // Green (Success states)
--theme-warning: #faad14; // Amber (Warnings)
--theme-error: #ff4d4f; // Red (Errors)
--theme-info: #1677ff; // Info (same as primary)
// Text Hierarchy
--theme-main-color: #212121; // Primary text
--theme-content-color: #666666; // Body text
--theme-tips-color: #999999; // Secondary text
--theme-light-color: #cccccc; // Muted text
--theme-disabled-color: #f5f5f5; // Disabled states
// Backgrounds
--theme-bg-color: #fafafa; // Main background
--theme-bg-color-secondary: #ffffff; // Card backgrounds
--theme-bg-gradient-start: #1677ff;
--theme-bg-gradient-end: #4096ff;
// Borders
--theme-border-color: #e8e8e8; // Borders, dividers
Dark Mode Colors
.theme-dark {
--brand-primary: #4b9cff; // Blue (lighter for dark mode)
--brand-primary-light: #69b1ff;
--brand-primary-dark: #1668dc;
--theme-success: #73d13d;
--theme-warning: #ffc53d;
--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
// 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#ffffffon#ff6700(primary) → 4.1:1#333333on#ffffff→ 12.6:1
❌ Bad Combinations:
#bd9e84(light) on#ffffff→ 2.4:1 (TOO LOW)- Use
text-lightonly for decorative text, not critical content
📝 Typography
Font Pairing: Modern Professional
Stack: Plus Jakarta Sans (Sans + Sans) Character: Friendly, modern, SaaS, clean, approachable, professional
/* 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)
// 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
<!-- 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
// 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)
// 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
<!-- 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
// 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
<!-- ✅ 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
<!-- 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)
<!-- 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
<!-- ✅ 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)
<!-- ✅ 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
<!-- 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
// 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
<!-- ✅ 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)
/* 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
<!-- 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
<!-- ✅ 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
// ✅ 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
<!-- ✅ 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
<!-- 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
<!-- ✅ 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
// 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)
<!-- index.html -->
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
Responsive Typography
<!-- 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
<!-- ✅ 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
<!-- ✅ 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
<!-- ✅ 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
<!-- ✅ 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)
<view class="
bg-white/80
backdrop-blur-md
border border-white/20
rounded-16px
shadow-lg
">
Glass card content
</view>
Flat Design (Secondary Style)
<view class="
bg-white
border border-gray-200
rounded-8px
shadow-sm
">
Flat card content
</view>
Vibrant Block-based (Accent)
<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
<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)
// 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, notbg-[#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/80minimum) - 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
alttext - Form inputs have
<label>elements - Color is not the only indicator
prefers-reduced-motionrespected
Performance
- Images use
lazy-loadattribute - No animations > 300ms
- Only
transform/opacityanimations - 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
-
Don't use emoji as icons
<!-- ❌ BAD --> <span>🏠 首页</span> <!-- ✅ GOOD --> <i class="i-mdi-home"></i> 首页 -
Don't use
bg-white/10in light mode<!-- ❌ BAD: Invisible in light mode --> <view class="bg-white/10"> <!-- ✅ GOOD --> <view class="bg-white/80 dark:bg-white/10"> -
Don't use text < 16px for body content on mobile
<!-- ❌ BAD --> <text class="text-12px">Important content</text> <!-- ✅ GOOD --> <text class="text-16px">Important content</text> -
Don't forget touch targets
<!-- ❌ 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> -
Don't use hover-only interactions
<!-- ❌ 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)