first
This commit is contained in:
666
.claude/COMPONENT-PATTERNS.md
Normal file
666
.claude/COMPONENT-PATTERNS.md
Normal file
@@ -0,0 +1,666 @@
|
||||
# Common Component Patterns
|
||||
|
||||
Quick copy-paste patterns for frequent UI components.
|
||||
|
||||
## 🔘 Buttons
|
||||
|
||||
### Primary CTA Button
|
||||
|
||||
```vue
|
||||
<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
|
||||
disabled:opacity-60 disabled:cursor-not-allowed
|
||||
"
|
||||
:disabled="loading"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
<i v-if="loading" class="i-mdi-loading animate-spin w-20px h-20px mr-2"></i>
|
||||
{{ loading ? '提交中...' : '确认提交' }}
|
||||
</button>
|
||||
```
|
||||
|
||||
### Secondary/Outline Button
|
||||
|
||||
```vue
|
||||
<button
|
||||
class="
|
||||
bg-transparent border-2 border-primary text-primary
|
||||
px-6 py-3 rounded-8px
|
||||
min-h-44px
|
||||
font-600 text-16px
|
||||
transition-all duration-200
|
||||
hover:bg-primary hover:text-white
|
||||
cursor-pointer
|
||||
"
|
||||
@click="handleCancel"
|
||||
>
|
||||
取消
|
||||
</button>
|
||||
```
|
||||
|
||||
### Icon Button (Accessible)
|
||||
|
||||
```vue
|
||||
<button
|
||||
aria-label="关闭"
|
||||
class="
|
||||
min-h-44px min-w-44px
|
||||
center
|
||||
rounded-full
|
||||
transition-colors duration-200
|
||||
hover:bg-gray-100
|
||||
cursor-pointer
|
||||
"
|
||||
@click="handleClose"
|
||||
>
|
||||
<i class="i-mdi-close w-24px h-24px text-gray-600"></i>
|
||||
</button>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Cards
|
||||
|
||||
### Glass Card (Primary Style)
|
||||
|
||||
```vue
|
||||
<view
|
||||
class="
|
||||
bg-white/80 dark:bg-white/10
|
||||
backdrop-blur-md
|
||||
border border-gray-200 dark:border-white/20
|
||||
rounded-16px
|
||||
p-6
|
||||
shadow-lg
|
||||
"
|
||||
>
|
||||
<text class="text-20px font-600 text-main block mb-2">
|
||||
Card Title
|
||||
</text>
|
||||
<text class="text-14px text-content block">
|
||||
Card description content goes here.
|
||||
</text>
|
||||
</view>
|
||||
```
|
||||
|
||||
### Flat Card (Secondary Style)
|
||||
|
||||
```vue
|
||||
<view
|
||||
class="
|
||||
bg-white dark:bg-[#2d2d2d]
|
||||
border border-gray-200 dark:border-gray-700
|
||||
rounded-8px
|
||||
p-4
|
||||
shadow-sm
|
||||
"
|
||||
>
|
||||
<view class="flex items-center gap-3">
|
||||
<i class="i-mdi-information w-24px h-24px text-primary"></i>
|
||||
<text class="text-16px text-main">Information</text>
|
||||
</view>
|
||||
</view>
|
||||
```
|
||||
|
||||
### Interactive Card (Clickable)
|
||||
|
||||
```vue
|
||||
<view
|
||||
class="
|
||||
bg-white/80 dark:bg-white/10
|
||||
backdrop-blur-md
|
||||
border border-gray-200 dark:border-white/20
|
||||
rounded-16px
|
||||
p-6
|
||||
shadow-lg
|
||||
transition-colors duration-200
|
||||
hover:bg-white/90 dark:hover:bg-white/15
|
||||
cursor-pointer
|
||||
"
|
||||
@click="handleCardClick"
|
||||
>
|
||||
<view class="flex items-center justify-between">
|
||||
<text class="text-18px font-600 text-main">Clickable Card</text>
|
||||
<i class="i-mdi-chevron-right w-24px h-24px text-gray-400"></i>
|
||||
</view>
|
||||
</view>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Forms
|
||||
|
||||
### Form Input (Accessible)
|
||||
|
||||
```vue
|
||||
<view class="mb-4">
|
||||
<label
|
||||
for="email-input"
|
||||
class="block text-14px font-500 text-main mb-2"
|
||||
>
|
||||
邮箱地址 <span class="text-error">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="email-input"
|
||||
v-model="email"
|
||||
type="email"
|
||||
inputmode="email"
|
||||
class="
|
||||
w-full px-4 py-3 min-h-44px
|
||||
bg-white dark:bg-[#2d2d2d]
|
||||
border-2 border-gray-200 dark:border-gray-700
|
||||
rounded-8px
|
||||
text-16px text-main
|
||||
focus:border-primary focus:outline-none
|
||||
transition-colors duration-200
|
||||
placeholder:text-gray-400
|
||||
"
|
||||
placeholder="输入您的邮箱"
|
||||
:aria-invalid="!!errors.email"
|
||||
:aria-describedby="errors.email ? 'email-error' : undefined"
|
||||
/>
|
||||
<text
|
||||
v-if="errors.email"
|
||||
id="email-error"
|
||||
role="alert"
|
||||
class="text-12px text-error mt-1 block"
|
||||
>
|
||||
{{ errors.email }}
|
||||
</text>
|
||||
</view>
|
||||
```
|
||||
|
||||
### Select/Dropdown
|
||||
|
||||
```vue
|
||||
<view class="mb-4">
|
||||
<label
|
||||
for="category-select"
|
||||
class="block text-14px font-500 text-main mb-2"
|
||||
>
|
||||
选择分类
|
||||
</label>
|
||||
<select
|
||||
id="category-select"
|
||||
v-model="selectedCategory"
|
||||
class="
|
||||
w-full px-4 py-3 min-h-44px
|
||||
bg-white dark:bg-[#2d2d2d]
|
||||
border-2 border-gray-200 dark:border-gray-700
|
||||
rounded-8px
|
||||
text-16px text-main
|
||||
cursor-pointer
|
||||
focus:border-primary focus:outline-none
|
||||
"
|
||||
>
|
||||
<option value="">请选择...</option>
|
||||
<option value="1">分类一</option>
|
||||
<option value="2">分类二</option>
|
||||
</select>
|
||||
</view>
|
||||
```
|
||||
|
||||
### Checkbox (Accessible)
|
||||
|
||||
```vue
|
||||
<view class="flex items-center gap-2 min-h-44px">
|
||||
<input
|
||||
id="agree-terms"
|
||||
v-model="agreedToTerms"
|
||||
type="checkbox"
|
||||
class="
|
||||
w-20px h-20px
|
||||
accent-primary
|
||||
cursor-pointer
|
||||
"
|
||||
/>
|
||||
<label
|
||||
for="agree-terms"
|
||||
class="text-14px text-content cursor-pointer"
|
||||
>
|
||||
我同意 <text class="text-primary">服务条款</text> 和 <text class="text-primary">隐私政策</text>
|
||||
</label>
|
||||
</view>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧭 Navigation
|
||||
|
||||
### Floating Top Navbar
|
||||
|
||||
```vue
|
||||
<view
|
||||
class="
|
||||
fixed top-4 left-4 right-4
|
||||
bg-white/90 dark:bg-[#1a1a1a]/90
|
||||
backdrop-blur-md
|
||||
border border-gray-200 dark:border-white/20
|
||||
rounded-full
|
||||
px-6 py-3
|
||||
shadow-lg
|
||||
z-50
|
||||
"
|
||||
>
|
||||
<view class="flex justify-between items-center">
|
||||
<view class="flex items-center gap-2">
|
||||
<i class="i-mdi-home w-24px h-24px text-primary"></i>
|
||||
<text class="font-600 text-18px text-main">GT Agent</text>
|
||||
</view>
|
||||
|
||||
<button
|
||||
aria-label="打开菜单"
|
||||
class="min-h-44px min-w-44px center cursor-pointer"
|
||||
@click="toggleMenu"
|
||||
>
|
||||
<i class="i-mdi-menu w-24px h-24px text-main"></i>
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Account for navbar height -->
|
||||
<view class="pt-72px">
|
||||
<!-- Main content -->
|
||||
</view>
|
||||
```
|
||||
|
||||
### Bottom Navigation (Safe Area)
|
||||
|
||||
```vue
|
||||
<view
|
||||
class="
|
||||
fixed bottom-0 left-0 right-0
|
||||
bg-white/90 dark:bg-[#1a1a1a]/90
|
||||
backdrop-blur-md
|
||||
border-t border-gray-200 dark:border-white/20
|
||||
pb-safe
|
||||
z-50
|
||||
"
|
||||
>
|
||||
<view class="flex justify-around items-center py-2">
|
||||
<button
|
||||
v-for="item in navItems"
|
||||
:key="item.id"
|
||||
:aria-label="item.label"
|
||||
:class="{
|
||||
'text-primary': currentRoute === item.route,
|
||||
'text-gray-400': currentRoute !== item.route,
|
||||
}"
|
||||
class="
|
||||
flex flex-col items-center gap-1
|
||||
min-h-44px min-w-44px
|
||||
center
|
||||
cursor-pointer
|
||||
transition-colors duration-200
|
||||
"
|
||||
@click="navigateTo(item.route)"
|
||||
>
|
||||
<i :class="item.icon" class="w-24px h-24px"></i>
|
||||
<text class="text-12px">{{ item.label }}</text>
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<script setup lang="ts">
|
||||
const navItems = [
|
||||
{ id: 1, label: '首页', icon: 'i-mdi-home', route: '/home' },
|
||||
{ id: 2, label: '我的', icon: 'i-mdi-account', route: '/profile' },
|
||||
]
|
||||
</script>
|
||||
```
|
||||
|
||||
### Breadcrumbs
|
||||
|
||||
```vue
|
||||
<nav aria-label="面包屑导航" class="mb-6">
|
||||
<ol class="flex items-center gap-2 text-14px">
|
||||
<li>
|
||||
<a href="/" class="text-primary hover:underline">首页</a>
|
||||
</li>
|
||||
<li class="text-gray-400">
|
||||
<i class="i-mdi-chevron-right w-16px h-16px"></i>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/products" class="text-primary hover:underline">产品</a>
|
||||
</li>
|
||||
<li class="text-gray-400">
|
||||
<i class="i-mdi-chevron-right w-16px h-16px"></i>
|
||||
</li>
|
||||
<li class="text-content" aria-current="page">产品详情</li>
|
||||
</ol>
|
||||
</nav>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Data Display
|
||||
|
||||
### List Item (Interactive)
|
||||
|
||||
```vue
|
||||
<view
|
||||
class="
|
||||
flex items-center justify-between
|
||||
p-4
|
||||
bg-white dark:bg-[#2d2d2d]
|
||||
border-b border-gray-200 dark:border-gray-700
|
||||
min-h-44px
|
||||
transition-colors duration-200
|
||||
hover:bg-gray-50 dark:hover:bg-gray-800
|
||||
cursor-pointer
|
||||
"
|
||||
@click="handleItemClick(item)"
|
||||
>
|
||||
<view class="flex items-center gap-3 flex-1">
|
||||
<i class="i-mdi-file-document w-24px h-24px text-primary"></i>
|
||||
<view class="flex-1">
|
||||
<text class="text-16px font-500 text-main block">{{ item.title }}</text>
|
||||
<text class="text-12px text-tips block mt-1">{{ item.subtitle }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<i class="i-mdi-chevron-right w-24px h-24px text-gray-400"></i>
|
||||
</view>
|
||||
```
|
||||
|
||||
### Badge/Tag
|
||||
|
||||
```vue
|
||||
<!-- Status badge -->
|
||||
<span
|
||||
:class="{
|
||||
'bg-success/10 text-success': status === 'active',
|
||||
'bg-warning/10 text-warning': status === 'pending',
|
||||
'bg-error/10 text-error': status === 'inactive',
|
||||
}"
|
||||
class="
|
||||
inline-flex items-center gap-1
|
||||
px-3 py-1
|
||||
rounded-full
|
||||
text-12px font-500
|
||||
"
|
||||
>
|
||||
<i
|
||||
:class="{
|
||||
'i-mdi-check-circle': status === 'active',
|
||||
'i-mdi-clock': status === 'pending',
|
||||
'i-mdi-alert-circle': status === 'inactive',
|
||||
}"
|
||||
class="w-14px h-14px"
|
||||
></i>
|
||||
{{ statusText }}
|
||||
</span>
|
||||
```
|
||||
|
||||
### Empty State
|
||||
|
||||
```vue
|
||||
<view class="center flex-col py-16">
|
||||
<i class="i-mdi-inbox w-64px h-64px text-gray-300 mb-4"></i>
|
||||
<text class="text-18px font-500 text-main mb-2">暂无数据</text>
|
||||
<text class="text-14px text-tips mb-6">
|
||||
当前没有可显示的内容
|
||||
</text>
|
||||
<button
|
||||
class="
|
||||
bg-primary text-white
|
||||
px-6 py-3 rounded-8px
|
||||
min-h-44px
|
||||
cursor-pointer
|
||||
"
|
||||
@click="handleRefresh"
|
||||
>
|
||||
刷新
|
||||
</button>
|
||||
</view>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚡ Loading States
|
||||
|
||||
### Skeleton Loader
|
||||
|
||||
```vue
|
||||
<view class="animate-pulse space-y-4 p-4">
|
||||
<!-- Title skeleton -->
|
||||
<view class="h-20px bg-gray-200 dark:bg-gray-700 rounded w-3/4"></view>
|
||||
|
||||
<!-- Content skeletons -->
|
||||
<view class="space-y-2">
|
||||
<view class="h-16px bg-gray-200 dark:bg-gray-700 rounded"></view>
|
||||
<view class="h-16px bg-gray-200 dark:bg-gray-700 rounded w-5/6"></view>
|
||||
<view class="h-16px bg-gray-200 dark:bg-gray-700 rounded w-4/6"></view>
|
||||
</view>
|
||||
|
||||
<!-- Image skeleton -->
|
||||
<view class="h-200px bg-gray-200 dark:bg-gray-700 rounded"></view>
|
||||
</view>
|
||||
```
|
||||
|
||||
### Loading Spinner
|
||||
|
||||
```vue
|
||||
<!-- Inline spinner -->
|
||||
<view class="center py-8">
|
||||
<i class="i-mdi-loading animate-spin w-32px h-32px text-primary"></i>
|
||||
</view>
|
||||
|
||||
<!-- With text -->
|
||||
<view class="center flex-col gap-2 py-8">
|
||||
<i class="i-mdi-loading animate-spin w-32px h-32px text-primary"></i>
|
||||
<text class="text-14px text-tips">加载中...</text>
|
||||
</view>
|
||||
|
||||
<!-- Full screen overlay -->
|
||||
<view
|
||||
v-if="loading"
|
||||
class="
|
||||
fixed inset-0
|
||||
bg-black/50
|
||||
center flex-col gap-3
|
||||
z-999
|
||||
"
|
||||
>
|
||||
<i class="i-mdi-loading animate-spin w-48px h-48px text-white"></i>
|
||||
<text class="text-16px text-white">加载中...</text>
|
||||
</view>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔔 Alerts & Toasts
|
||||
|
||||
### Alert Box
|
||||
|
||||
```vue
|
||||
<view
|
||||
role="alert"
|
||||
:class="{
|
||||
'bg-success/10 border-success/30 text-success': type === 'success',
|
||||
'bg-warning/10 border-warning/30 text-warning': type === 'warning',
|
||||
'bg-error/10 border-error/30 text-error': type === 'error',
|
||||
'bg-primary/10 border-primary/30 text-primary': type === 'info',
|
||||
}"
|
||||
class="
|
||||
flex items-start gap-3
|
||||
p-4
|
||||
border-l-4
|
||||
rounded-8px
|
||||
mb-4
|
||||
"
|
||||
>
|
||||
<i
|
||||
:class="{
|
||||
'i-mdi-check-circle': type === 'success',
|
||||
'i-mdi-alert': type === 'warning',
|
||||
'i-mdi-alert-circle': type === 'error',
|
||||
'i-mdi-information': type === 'info',
|
||||
}"
|
||||
class="w-24px h-24px flex-shrink-0 mt-0.5"
|
||||
></i>
|
||||
|
||||
<view class="flex-1">
|
||||
<text class="text-16px font-600 block mb-1">{{ title }}</text>
|
||||
<text class="text-14px opacity-80">{{ message }}</text>
|
||||
</view>
|
||||
|
||||
<button
|
||||
aria-label="关闭"
|
||||
class="min-h-44px min-w-44px center cursor-pointer"
|
||||
@click="handleClose"
|
||||
>
|
||||
<i class="i-mdi-close w-20px h-20px"></i>
|
||||
</button>
|
||||
</view>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Modal/Dialog
|
||||
|
||||
### Modal Overlay
|
||||
|
||||
```vue
|
||||
<!-- Modal -->
|
||||
<view
|
||||
v-if="isOpen"
|
||||
class="fixed inset-0 z-999 center p-4"
|
||||
@click.self="handleClose"
|
||||
>
|
||||
<!-- Backdrop -->
|
||||
<view
|
||||
class="absolute inset-0 bg-black/50"
|
||||
@click="handleClose"
|
||||
></view>
|
||||
|
||||
<!-- Modal Content -->
|
||||
<view
|
||||
class="
|
||||
relative
|
||||
bg-white dark:bg-[#1a1a1a]
|
||||
rounded-16px
|
||||
p-6
|
||||
max-w-md w-full
|
||||
shadow-2xl
|
||||
animate-fade-in
|
||||
"
|
||||
role="dialog"
|
||||
aria-labelledby="modal-title"
|
||||
aria-modal="true"
|
||||
>
|
||||
<!-- Close button -->
|
||||
<button
|
||||
aria-label="关闭"
|
||||
class="
|
||||
absolute top-4 right-4
|
||||
min-h-44px min-w-44px
|
||||
center
|
||||
cursor-pointer
|
||||
"
|
||||
@click="handleClose"
|
||||
>
|
||||
<i class="i-mdi-close w-24px h-24px text-gray-400"></i>
|
||||
</button>
|
||||
|
||||
<!-- Title -->
|
||||
<text id="modal-title" class="text-24px font-700 text-main block mb-4">
|
||||
Modal Title
|
||||
</text>
|
||||
|
||||
<!-- Content -->
|
||||
<text class="text-16px text-content block mb-6">
|
||||
Modal content goes here.
|
||||
</text>
|
||||
|
||||
<!-- Actions -->
|
||||
<view class="flex gap-3">
|
||||
<button
|
||||
class="
|
||||
flex-1
|
||||
bg-transparent border-2 border-gray-200
|
||||
text-gray-600
|
||||
px-6 py-3 rounded-8px
|
||||
min-h-44px
|
||||
cursor-pointer
|
||||
"
|
||||
@click="handleClose"
|
||||
>
|
||||
取消
|
||||
</button>
|
||||
<button
|
||||
class="
|
||||
flex-1
|
||||
bg-primary text-white
|
||||
px-6 py-3 rounded-8px
|
||||
min-h-44px
|
||||
cursor-pointer
|
||||
"
|
||||
@click="handleConfirm"
|
||||
>
|
||||
确认
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📐 Layout Utilities
|
||||
|
||||
### Container
|
||||
|
||||
```vue
|
||||
<view class="container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl">
|
||||
<!-- Centered content with responsive padding -->
|
||||
</view>
|
||||
```
|
||||
|
||||
### Responsive Grid
|
||||
|
||||
```vue
|
||||
<view class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<view v-for="item in items" :key="item.id">
|
||||
<!-- Grid item -->
|
||||
</view>
|
||||
</view>
|
||||
```
|
||||
|
||||
### Flex Layouts
|
||||
|
||||
```vue
|
||||
<!-- Horizontal stack -->
|
||||
<view class="flex items-center gap-4">
|
||||
<div>Item 1</div>
|
||||
<div>Item 2</div>
|
||||
</view>
|
||||
|
||||
<!-- Vertical stack -->
|
||||
<view class="flex flex-col gap-4">
|
||||
<div>Item 1</div>
|
||||
<div>Item 2</div>
|
||||
</view>
|
||||
|
||||
<!-- Space between -->
|
||||
<view class="flex items-center justify-between">
|
||||
<div>Left</div>
|
||||
<div>Right</div>
|
||||
</view>
|
||||
|
||||
<!-- Centered -->
|
||||
<view class="center">
|
||||
<div>Centered content</div>
|
||||
</view>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Full Documentation**: See `.claude/DESIGN-SYSTEM.md`
|
||||
Reference in New Issue
Block a user