mta-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +818 -0
- package/agents/_TEMPLATE.md +153 -0
- package/agents/flutter.agent.md +222 -0
- package/agents/i18n.agent.md +78 -0
- package/agents/logicflow.agent.md +97 -0
- package/agents/vue3.agent.md +176 -0
- package/agents/wechat-miniprogram.agent.md +89 -0
- package/bin/mta.cjs +132 -0
- package/common/i18n.md +385 -0
- package/common/typescript-strict.md +186 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.js +6493 -0
- package/dist/index.js.map +1 -0
- package/package.json +81 -0
- package/standards/README.md +194 -0
- package/standards/core/code-generation.md +421 -0
- package/standards/core/code-style.md +308 -0
- package/standards/core/dart-base.md +572 -0
- package/standards/core/mandatory-rules.md +103 -0
- package/standards/core/typescript-base.md +179 -0
- package/standards/frameworks/flutter-ui-system.md +497 -0
- package/standards/frameworks/flutter.md +1268 -0
- package/standards/frameworks/pinia.md +172 -0
- package/standards/frameworks/vue3-composition.md +779 -0
- package/standards/frameworks/wechat-miniprogram.md +2177 -0
- package/standards/libraries/element-plus.md +1128 -0
- package/standards/libraries/i18n.md +360 -0
- package/standards/libraries/logicflow.md +1007 -0
- package/standards/patterns/api-layer.md +187 -0
- package/standards/patterns/component-design.md +200 -0
- package/standards/patterns/design-system-restoration.md +570 -0
- package/standards/patterns/vue-api-mock-layer.md +958 -0
- package/standards/patterns/vue-css-nesting.md +604 -0
- package/standards/troubleshooting-cases/flutter/textfield-vertical-centering.md +107 -0
- package/standards/workflows/design-restoration-guide.md +164 -0
- package/standards/workflows/large-project-split.md +359 -0
- package/standards/workflows/problem-diagnosis.md +280 -0
- package/standards/workflows/textfield-centering-guide.md +157 -0
- package/templates/README.md +144 -0
- package/templates/common/types/_CONFIG.md +12 -0
- package/templates/common/types/api.ts +39 -0
- package/templates/common/types/common.ts +70 -0
- package/templates/config-templates/agents-section.md +9 -0
- package/templates/config-templates/custom-section.md +6 -0
- package/templates/config-templates/header.md +29 -0
- package/templates/config-templates/workflow-minimal.md +44 -0
- package/templates/copilot-instructions-mcp-optimized.md +158 -0
- package/templates/vue/api-layer/_CONFIG.md +145 -0
- package/templates/vue/api-layer/index.ts +58 -0
- package/templates/vue/api-layer/mock/index.ts +122 -0
- package/templates/vue/api-layer/modules/_template.ts +109 -0
- package/templates/vue/api-layer/modules/index.ts +16 -0
- package/templates/vue/api-layer/request.ts +279 -0
- package/templates/vue/api-layer/types.ts +80 -0
- package/troubleshooting/README.md +368 -0
- package/troubleshooting/USAGE_GUIDE.md +289 -0
- package/troubleshooting/flutter/clip-/351/230/264/345/275/261/350/243/201/345/211/252.md +244 -0
- package/troubleshooting/flutter/component-/351/200/232/347/224/250/345/214/226/346/217/220/345/217/226.md +269 -0
- package/troubleshooting/flutter/input-/345/255/227/346/256/265/347/274/272/345/244/261.md +240 -0
- package/troubleshooting/flutter/input-/350/276/271/346/241/206/351/227/256/351/242/230.md +236 -0
- package/troubleshooting/flutter/layout-/345/260/272/345/257/270/344/270/215/345/214/271/351/205/215.md +214 -0
- package/troubleshooting/flutter/shadow-/351/200/217/345/207/272/351/227/256/351/242/230.md +172 -0
- package/troubleshooting/flutter/sketch-/345/210/227/350/241/250item/345/214/272/345/237/237.md +212 -0
- package/troubleshooting/flutter/sketch-/345/233/276/346/240/207/345/260/272/345/257/270.md +135 -0
- package/troubleshooting/flutter/sketch-/345/256/214/346/225/264/346/217/220/345/217/226.md +201 -0
- package/troubleshooting/flutter/sketch-/345/261/236/346/200/247/346/234/252/344/275/277/347/224/250.md +139 -0
- package/troubleshooting/flutter/sketch-/350/203/214/346/231/257/345/261/202/351/253/230/345/272/246.md +264 -0
- package/troubleshooting/flutter/svg-/346/234/252/345/261/205/344/270/255.md +120 -0
- package/troubleshooting/flutter/svg-/351/242/234/350/211/262/345/274/202/345/270/270.md +117 -0
- package/troubleshooting/flutter/tabbar-/345/212/250/347/224/273/345/220/214/346/255/245.md +107 -0
- package/troubleshooting/flutter/withopacity-/345/274/203/347/224/250.md +81 -0
- package/troubleshooting/vue3/cascader-/350/257/257/346/233/277/346/215/242.md +130 -0
- package/troubleshooting/vue3/drawer-input-/346/240/267/345/274/217.md +181 -0
- package/troubleshooting/vue3/table-/347/274/226/350/276/221/345/217/226/346/266/210.md +148 -0
- package/troubleshooting/vue3/table-/350/276/271/346/241/206/351/227/256/351/242/230.md +178 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# TypeScript 基础规范
|
|
2
|
+
|
|
3
|
+
## 核心要求
|
|
4
|
+
|
|
5
|
+
1. **类型优先** - 所有变量、参数、返回值都应有类型
|
|
6
|
+
2. **避免 any** - 使用 `unknown` 或更具体的类型
|
|
7
|
+
3. **严格模式** - 启用所有严格检查选项
|
|
8
|
+
|
|
9
|
+
## 基本类型使用
|
|
10
|
+
|
|
11
|
+
### 原始类型
|
|
12
|
+
```typescript
|
|
13
|
+
// ✅ 好
|
|
14
|
+
const name: string = 'John'
|
|
15
|
+
const age: number = 25
|
|
16
|
+
const isActive: boolean = true
|
|
17
|
+
|
|
18
|
+
// ❌ 坏 - 不需要显式类型(可推断)
|
|
19
|
+
const name: string = 'John' // 过度标注
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 数组类型
|
|
23
|
+
```typescript
|
|
24
|
+
// ✅ 好
|
|
25
|
+
const numbers: number[] = [1, 2, 3]
|
|
26
|
+
const users: User[] = []
|
|
27
|
+
|
|
28
|
+
// 或使用泛型
|
|
29
|
+
const items: Array<string> = ['a', 'b']
|
|
30
|
+
|
|
31
|
+
// ❌ 坏
|
|
32
|
+
const numbers: any[] = [1, 2, 3]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 对象类型
|
|
36
|
+
```typescript
|
|
37
|
+
// ✅ 好 - 使用 interface
|
|
38
|
+
interface User {
|
|
39
|
+
id: number
|
|
40
|
+
name: string
|
|
41
|
+
email?: string // 可选属性
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const user: User = {
|
|
45
|
+
id: 1,
|
|
46
|
+
name: 'John'
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ❌ 坏
|
|
50
|
+
const user: any = { id: 1 }
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 函数类型
|
|
54
|
+
|
|
55
|
+
### 函数声明
|
|
56
|
+
```typescript
|
|
57
|
+
// ✅ 好 - 明确的参数和返回类型
|
|
58
|
+
function add(a: number, b: number): number {
|
|
59
|
+
return a + b
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 箭头函数
|
|
63
|
+
const multiply = (a: number, b: number): number => a * b
|
|
64
|
+
|
|
65
|
+
// ❌ 坏 - 缺少返回类型
|
|
66
|
+
function add(a: number, b: number) {
|
|
67
|
+
return a + b
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 异步函数
|
|
72
|
+
```typescript
|
|
73
|
+
// ✅ 好
|
|
74
|
+
async function fetchUser(id: number): Promise<User | null> {
|
|
75
|
+
const response = await fetch(`/api/users/${id}`)
|
|
76
|
+
if (!response.ok) return null
|
|
77
|
+
return response.json()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ❌ 坏
|
|
81
|
+
async function fetchUser(id: number) {
|
|
82
|
+
return await fetch(`/api/users/${id}`)
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 可选参数
|
|
87
|
+
```typescript
|
|
88
|
+
// ✅ 好
|
|
89
|
+
function greet(name: string, title?: string): string {
|
|
90
|
+
return title ? `${title} ${name}` : name
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// 默认参数
|
|
94
|
+
function createUser(name: string, role: string = 'user'): User {
|
|
95
|
+
return { name, role }
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## 联合类型与类型守卫
|
|
100
|
+
|
|
101
|
+
### 联合类型
|
|
102
|
+
```typescript
|
|
103
|
+
// ✅ 好
|
|
104
|
+
type Status = 'pending' | 'success' | 'error'
|
|
105
|
+
type ID = string | number
|
|
106
|
+
|
|
107
|
+
function setStatus(status: Status) {
|
|
108
|
+
// ...
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### 类型守卫
|
|
113
|
+
```typescript
|
|
114
|
+
// ✅ 好
|
|
115
|
+
function isString(value: unknown): value is string {
|
|
116
|
+
return typeof value === 'string'
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function processValue(value: string | number) {
|
|
120
|
+
if (typeof value === 'string') {
|
|
121
|
+
return value.toUpperCase()
|
|
122
|
+
}
|
|
123
|
+
return value.toFixed(2)
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## 泛型
|
|
128
|
+
|
|
129
|
+
### 基本泛型
|
|
130
|
+
```typescript
|
|
131
|
+
// ✅ 好
|
|
132
|
+
function identity<T>(value: T): T {
|
|
133
|
+
return value
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const result = identity<string>('hello')
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### 泛型约束
|
|
140
|
+
```typescript
|
|
141
|
+
// ✅ 好
|
|
142
|
+
interface HasId {
|
|
143
|
+
id: number
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function findById<T extends HasId>(items: T[], id: number): T | undefined {
|
|
147
|
+
return items.find(item => item.id === id)
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## 类型断言
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
// ✅ 好 - 必要时使用 as
|
|
155
|
+
const input = document.querySelector('input') as HTMLInputElement
|
|
156
|
+
input.value = 'hello'
|
|
157
|
+
|
|
158
|
+
// ❌ 坏 - 避免使用 as any
|
|
159
|
+
const data = fetchData() as any
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## 实用类型
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
// Partial - 所有属性可选
|
|
166
|
+
type PartialUser = Partial<User>
|
|
167
|
+
|
|
168
|
+
// Required - 所有属性必填
|
|
169
|
+
type RequiredUser = Required<User>
|
|
170
|
+
|
|
171
|
+
// Pick - 选择部分属性
|
|
172
|
+
type UserPreview = Pick<User, 'id' | 'name'>
|
|
173
|
+
|
|
174
|
+
// Omit - 排除部分属性
|
|
175
|
+
type UserWithoutEmail = Omit<User, 'email'>
|
|
176
|
+
|
|
177
|
+
// Record - 键值对类型
|
|
178
|
+
type UserMap = Record<string, User>
|
|
179
|
+
```
|
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
# Flutter UI 开发规范 - Design Token 系统
|
|
2
|
+
|
|
3
|
+
> 基于 Design Token 和 Flex 组件系统的 Flutter UI 开发规范
|
|
4
|
+
|
|
5
|
+
## 🎯 核心原则
|
|
6
|
+
|
|
7
|
+
1. **Token 驱动** - 所有样式值必须通过 Design Token 系统获取
|
|
8
|
+
2. **一致性优先** - 使用统一的组件和样式,禁止硬编码样式值
|
|
9
|
+
3. **可扩展设计** - 支持快速响应 UI 设计变更
|
|
10
|
+
4. **Figma 友好** - 支持从设计工具直接导入 Token
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 📦 系统架构
|
|
15
|
+
|
|
16
|
+
### 双轨主题系统
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
lib/core/themes/
|
|
20
|
+
├── theme_config.dart # 基础配置类
|
|
21
|
+
├── style_presets.dart # 5种预设风格
|
|
22
|
+
├── theme_manager.dart # 主题管理器 (GetX)
|
|
23
|
+
├── styled_widgets.dart # 风格感知组件
|
|
24
|
+
├── design_tokens.dart # Design Token 定义
|
|
25
|
+
├── token_manager.dart # Token 管理器 + 全局快捷方式
|
|
26
|
+
├── flex_widgets.dart # 灵活组件库
|
|
27
|
+
└── themes.dart # 统一导出
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Token 层级
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
DesignTokens
|
|
34
|
+
├── TokenColors # 颜色系统
|
|
35
|
+
│ ├── primary/secondary/tertiary # 主题色
|
|
36
|
+
│ ├── neutral[50-950] # 中性色阶
|
|
37
|
+
│ ├── text (primary/secondary/...) # 文本颜色
|
|
38
|
+
│ ├── background (primary/elevated/...) # 背景颜色
|
|
39
|
+
│ ├── border (default/strong/...) # 边框颜色
|
|
40
|
+
│ └── fill (primary/secondary/...) # 填充颜色
|
|
41
|
+
├── TokenTypography # 排版系统
|
|
42
|
+
├── TokenSpacing # 间距系统
|
|
43
|
+
├── TokenRadius # 圆角系统
|
|
44
|
+
├── TokenShadows # 阴影系统
|
|
45
|
+
├── TokenBorders # 边框系统
|
|
46
|
+
├── TokenOpacity # 透明度系统
|
|
47
|
+
└── TokenDuration # 动画时长系统
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## ⚠️ 强制规范
|
|
53
|
+
|
|
54
|
+
### 1. 禁止硬编码样式值
|
|
55
|
+
|
|
56
|
+
```dart
|
|
57
|
+
// ❌ 禁止 - 硬编码颜色
|
|
58
|
+
Container(
|
|
59
|
+
color: Color(0xFF3B82F6),
|
|
60
|
+
padding: EdgeInsets.all(16),
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
// ✅ 正确 - 使用 Token
|
|
64
|
+
Container(
|
|
65
|
+
color: $c.primary,
|
|
66
|
+
padding: EdgeInsets.all($s.md),
|
|
67
|
+
)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 2. 必须使用全局快捷方式
|
|
71
|
+
|
|
72
|
+
| 快捷方式 | 用途 | 示例 |
|
|
73
|
+
|---------|------|------|
|
|
74
|
+
| `$c` | 颜色 | `$c.primary`, `$c.text.primary`, `$c.neutral[100]` |
|
|
75
|
+
| `$t` | 排版 | `$t.displayLarge`, `$t.bodyMedium` |
|
|
76
|
+
| `$s` | 间距 | `$s.sm`, `$s.md`, `$s.lg`, `$s.px(14)` |
|
|
77
|
+
| `$r` | 圆角 | `$r.sm`, `$r.md`, `$r.full` |
|
|
78
|
+
| `$shadow` | 阴影 | `$shadow.sm`, `$shadow.md` |
|
|
79
|
+
| `$b` | 边框 | `$b.thin`, `$b.medium` |
|
|
80
|
+
| `$o` | 透明度 | `$o.disabled`, `$o.hover` |
|
|
81
|
+
| `$d` | 动画时长 | `$d.fast`, `$d.normal` |
|
|
82
|
+
|
|
83
|
+
### 3. 必须使用 Flex 组件
|
|
84
|
+
|
|
85
|
+
```dart
|
|
86
|
+
// ❌ 禁止 - 直接使用 Flutter 原生组件并硬编码样式
|
|
87
|
+
ElevatedButton(
|
|
88
|
+
style: ElevatedButton.styleFrom(
|
|
89
|
+
backgroundColor: Colors.blue,
|
|
90
|
+
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
|
91
|
+
),
|
|
92
|
+
onPressed: () {},
|
|
93
|
+
child: Text('按钮'),
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
// ✅ 正确 - 使用 Flex 组件
|
|
97
|
+
FlexButton(
|
|
98
|
+
text: '按钮',
|
|
99
|
+
onPressed: () {},
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
// ✅ 正确 - 需要自定义时覆盖属性
|
|
103
|
+
FlexButton(
|
|
104
|
+
text: '自定义按钮',
|
|
105
|
+
color: $c.secondary,
|
|
106
|
+
radius: $r.lg,
|
|
107
|
+
padding: EdgeInsets.symmetric(horizontal: $s.xl, vertical: $s.md),
|
|
108
|
+
onPressed: () {},
|
|
109
|
+
)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 🎨 颜色使用规范
|
|
115
|
+
|
|
116
|
+
### 语义化颜色
|
|
117
|
+
|
|
118
|
+
```dart
|
|
119
|
+
// 文本颜色 - 按重要性选择
|
|
120
|
+
Text('主标题', style: TextStyle(color: $c.text.primary)) // 最重要
|
|
121
|
+
Text('副标题', style: TextStyle(color: $c.text.secondary)) // 次要
|
|
122
|
+
Text('辅助文字', style: TextStyle(color: $c.text.tertiary)) // 辅助
|
|
123
|
+
Text('禁用文字', style: TextStyle(color: $c.text.disabled)) // 禁用态
|
|
124
|
+
|
|
125
|
+
// 背景颜色 - 按层级选择
|
|
126
|
+
Container(color: $c.background.primary) // 主背景
|
|
127
|
+
Container(color: $c.background.secondary) // 次级背景
|
|
128
|
+
Container(color: $c.background.elevated) // 悬浮/卡片背景
|
|
129
|
+
|
|
130
|
+
// 边框颜色
|
|
131
|
+
Container(
|
|
132
|
+
decoration: BoxDecoration(
|
|
133
|
+
border: Border.all(color: $c.border.default_), // 默认边框
|
|
134
|
+
),
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
// 填充颜色 - 用于交互元素
|
|
138
|
+
Container(color: $c.fill.primary) // 主要填充(按钮等)
|
|
139
|
+
Container(color: $c.fill.hover) // 悬停态
|
|
140
|
+
Container(color: $c.fill.pressed) // 按下态
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### 中性色阶
|
|
144
|
+
|
|
145
|
+
```dart
|
|
146
|
+
// 使用数字索引访问中性色
|
|
147
|
+
$c.neutral[50] // 最浅
|
|
148
|
+
$c.neutral[100]
|
|
149
|
+
$c.neutral[200]
|
|
150
|
+
$c.neutral[300]
|
|
151
|
+
$c.neutral[400]
|
|
152
|
+
$c.neutral[500] // 中间
|
|
153
|
+
$c.neutral[600]
|
|
154
|
+
$c.neutral[700]
|
|
155
|
+
$c.neutral[800]
|
|
156
|
+
$c.neutral[900]
|
|
157
|
+
$c.neutral[950] // 最深
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## 📏 间距使用规范
|
|
163
|
+
|
|
164
|
+
### 预设间距
|
|
165
|
+
|
|
166
|
+
```dart
|
|
167
|
+
$s.none // 0
|
|
168
|
+
$s.xxs // 2
|
|
169
|
+
$s.xs // 4
|
|
170
|
+
$s.sm // 8
|
|
171
|
+
$s.md // 16 (默认)
|
|
172
|
+
$s.lg // 24
|
|
173
|
+
$s.xl // 32
|
|
174
|
+
$s.xxl // 48
|
|
175
|
+
$s.xxxl // 64
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### 自定义间距
|
|
179
|
+
|
|
180
|
+
```dart
|
|
181
|
+
// 当设计稿有非标准间距时
|
|
182
|
+
Padding(
|
|
183
|
+
padding: EdgeInsets.all($s.px(14)), // 14px
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
// 使用 Gap 组件
|
|
187
|
+
Row(
|
|
188
|
+
children: [
|
|
189
|
+
Icon(Icons.star),
|
|
190
|
+
Gap($s.sm), // 8px 间隔
|
|
191
|
+
Text('评分'),
|
|
192
|
+
],
|
|
193
|
+
)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## 🔲 组件使用规范
|
|
199
|
+
|
|
200
|
+
### FlexButton
|
|
201
|
+
|
|
202
|
+
```dart
|
|
203
|
+
// 基础用法
|
|
204
|
+
FlexButton(
|
|
205
|
+
text: '确认',
|
|
206
|
+
onPressed: () {},
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
// 次要按钮
|
|
210
|
+
FlexButton.secondary(
|
|
211
|
+
text: '取消',
|
|
212
|
+
onPressed: () {},
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
// 文本按钮
|
|
216
|
+
FlexButton.text(
|
|
217
|
+
text: '了解更多',
|
|
218
|
+
onPressed: () {},
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
// 完全自定义
|
|
222
|
+
FlexButton(
|
|
223
|
+
text: '渐变按钮',
|
|
224
|
+
gradient: LinearGradient(
|
|
225
|
+
colors: [$c.primary, $c.secondary],
|
|
226
|
+
),
|
|
227
|
+
width: double.infinity,
|
|
228
|
+
height: 56,
|
|
229
|
+
radius: $r.lg,
|
|
230
|
+
textStyle: $t.labelLarge.copyWith(color: Colors.white),
|
|
231
|
+
onPressed: () {},
|
|
232
|
+
)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### FlexCard
|
|
236
|
+
|
|
237
|
+
```dart
|
|
238
|
+
// 基础卡片
|
|
239
|
+
FlexCard(
|
|
240
|
+
child: Text('内容'),
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
// 玻璃态卡片
|
|
244
|
+
FlexCard(
|
|
245
|
+
blur: 10,
|
|
246
|
+
color: $c.background.elevated.withOpacity(0.8),
|
|
247
|
+
child: Text('毛玻璃效果'),
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
// 自定义卡片
|
|
251
|
+
FlexCard(
|
|
252
|
+
padding: EdgeInsets.all($s.lg),
|
|
253
|
+
radius: $r.xl,
|
|
254
|
+
shadow: $shadow.lg,
|
|
255
|
+
border: Border.all(color: $c.border.default_),
|
|
256
|
+
child: Column(
|
|
257
|
+
children: [
|
|
258
|
+
Text('标题', style: $t.titleLarge),
|
|
259
|
+
Gap($s.sm),
|
|
260
|
+
Text('描述内容'),
|
|
261
|
+
],
|
|
262
|
+
),
|
|
263
|
+
)
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### FlexInput
|
|
267
|
+
|
|
268
|
+
```dart
|
|
269
|
+
// 基础输入框
|
|
270
|
+
FlexInput(
|
|
271
|
+
hint: '请输入用户名',
|
|
272
|
+
controller: _controller,
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
// 带图标
|
|
276
|
+
FlexInput(
|
|
277
|
+
hint: '搜索',
|
|
278
|
+
prefixIcon: Icon(Icons.search),
|
|
279
|
+
suffixIcon: IconButton(
|
|
280
|
+
icon: Icon(Icons.clear),
|
|
281
|
+
onPressed: () => _controller.clear(),
|
|
282
|
+
),
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
// 自定义样式
|
|
286
|
+
FlexInput(
|
|
287
|
+
hint: '自定义输入框',
|
|
288
|
+
fillColor: $c.background.secondary,
|
|
289
|
+
radius: $r.full,
|
|
290
|
+
borderColor: Colors.transparent,
|
|
291
|
+
)
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### FlexBox (Row/Column with Gap)
|
|
295
|
+
|
|
296
|
+
```dart
|
|
297
|
+
// 水平布局带间距
|
|
298
|
+
FlexBox.row(
|
|
299
|
+
gap: $s.md,
|
|
300
|
+
children: [
|
|
301
|
+
Icon(Icons.star),
|
|
302
|
+
Text('评分'),
|
|
303
|
+
Text('4.5'),
|
|
304
|
+
],
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
// 垂直布局带间距
|
|
308
|
+
FlexBox.column(
|
|
309
|
+
gap: $s.sm,
|
|
310
|
+
crossAxisAlignment: CrossAxisAlignment.start,
|
|
311
|
+
children: [
|
|
312
|
+
Text('标题', style: $t.titleMedium),
|
|
313
|
+
Text('描述文字'),
|
|
314
|
+
FlexButton(text: '操作', onPressed: () {}),
|
|
315
|
+
],
|
|
316
|
+
)
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Gap
|
|
320
|
+
|
|
321
|
+
```dart
|
|
322
|
+
// 简单间隔
|
|
323
|
+
Column(
|
|
324
|
+
children: [
|
|
325
|
+
Text('第一行'),
|
|
326
|
+
Gap($s.md), // 16px 垂直间隔
|
|
327
|
+
Text('第二行'),
|
|
328
|
+
],
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
Row(
|
|
332
|
+
children: [
|
|
333
|
+
Icon(Icons.info),
|
|
334
|
+
Gap($s.sm), // 8px 水平间隔
|
|
335
|
+
Text('提示信息'),
|
|
336
|
+
],
|
|
337
|
+
)
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## 🎭 主题切换
|
|
343
|
+
|
|
344
|
+
### 可用风格
|
|
345
|
+
|
|
346
|
+
```dart
|
|
347
|
+
// 5 种预设风格
|
|
348
|
+
AppStyleType.neumorphic // 拟物新态(iOS 26 风格)
|
|
349
|
+
AppStyleType.material3 // Material Design 3
|
|
350
|
+
AppStyleType.flat // 扁平化
|
|
351
|
+
AppStyleType.glassmorphism // 玻璃态
|
|
352
|
+
AppStyleType.cyberpunk // 赛博朋克
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### 切换风格
|
|
356
|
+
|
|
357
|
+
```dart
|
|
358
|
+
// 通过 ThemeManager 切换
|
|
359
|
+
final themeManager = Get.find<ThemeManager>();
|
|
360
|
+
|
|
361
|
+
// 切换风格
|
|
362
|
+
themeManager.switchStyle(AppStyleType.glassmorphism);
|
|
363
|
+
|
|
364
|
+
// 切换深色/浅色模式
|
|
365
|
+
themeManager.toggleDarkMode();
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
## 📥 从设计工具导入
|
|
371
|
+
|
|
372
|
+
### 导入 Figma Token
|
|
373
|
+
|
|
374
|
+
```dart
|
|
375
|
+
// 1. 从 Figma 导出 JSON
|
|
376
|
+
// 2. 加载到 TokenManager
|
|
377
|
+
final tokenManager = Get.find<TokenManager>();
|
|
378
|
+
|
|
379
|
+
await tokenManager.loadFromJson({
|
|
380
|
+
'colors': {
|
|
381
|
+
'primary': '#3B82F6',
|
|
382
|
+
'secondary': '#8B5CF6',
|
|
383
|
+
'neutral': {
|
|
384
|
+
'50': '#FAFAFA',
|
|
385
|
+
'100': '#F4F4F5',
|
|
386
|
+
// ...
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
'spacing': {
|
|
390
|
+
'base': 4,
|
|
391
|
+
'scale': [0, 0.5, 1, 2, 4, 6, 8, 12, 16],
|
|
392
|
+
},
|
|
393
|
+
'radius': {
|
|
394
|
+
'none': 0,
|
|
395
|
+
'sm': 4,
|
|
396
|
+
'md': 8,
|
|
397
|
+
'lg': 16,
|
|
398
|
+
'xl': 24,
|
|
399
|
+
'full': 9999,
|
|
400
|
+
},
|
|
401
|
+
});
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
## 📋 UI 还原检查清单
|
|
407
|
+
|
|
408
|
+
当从设计稿还原 UI 时,按以下顺序检查:
|
|
409
|
+
|
|
410
|
+
### 1. 颜色
|
|
411
|
+
- [ ] 使用 `$c.xxx` 获取颜色,禁止硬编码
|
|
412
|
+
- [ ] 文本颜色使用 `$c.text.xxx`
|
|
413
|
+
- [ ] 背景颜色使用 `$c.background.xxx`
|
|
414
|
+
- [ ] 如有特殊颜色,先添加到 Token 系统
|
|
415
|
+
- [ ] **注意透明度**:设计稿颜色 `#RRGGBBAA` 最后两位是透明度
|
|
416
|
+
|
|
417
|
+
### 2. 间距
|
|
418
|
+
- [ ] 使用 `$s.xxx` 获取间距
|
|
419
|
+
- [ ] 非标准间距使用 `$s.px(n)`
|
|
420
|
+
- [ ] 元素间隔使用 `Gap()` 组件
|
|
421
|
+
- [ ] **Row 内使用 `SizedBox(width:)` 或 `Gap.h()`**
|
|
422
|
+
|
|
423
|
+
### 3. 排版
|
|
424
|
+
- [ ] 使用 `$t.xxx` 获取文本样式
|
|
425
|
+
- [ ] 自定义时用 `.copyWith()` 扩展
|
|
426
|
+
|
|
427
|
+
### 4. 组件
|
|
428
|
+
- [ ] 按钮使用 `FlexButton`
|
|
429
|
+
- [ ] 卡片使用 `FlexCard`
|
|
430
|
+
- [ ] 输入框使用 `FlexInput`
|
|
431
|
+
- [ ] 列表布局使用 `FlexBox`
|
|
432
|
+
|
|
433
|
+
### 5. 圆角和阴影
|
|
434
|
+
- [ ] 圆角使用 `$r.xxx`
|
|
435
|
+
- [ ] 阴影使用 `$shadow.xxx`
|
|
436
|
+
- [ ] 边框使用 `$b.xxx`
|
|
437
|
+
|
|
438
|
+
### 6. SVG 图标(重要!)
|
|
439
|
+
- [ ] **禁止使用 Material Icons**,必须从设计稿导出 SVG
|
|
440
|
+
- [ ] SVG viewBox 与使用尺寸一致(避免额外居中处理)
|
|
441
|
+
- [ ] **不使用 ColorFilter 覆盖 SVG 颜色**,保留原有样式
|
|
442
|
+
- [ ] 仅在外部明确指定颜色时才覆盖
|
|
443
|
+
|
|
444
|
+
```dart
|
|
445
|
+
// ❌ 错误 - ColorFilter 覆盖了 SVG 原有颜色和透明度
|
|
446
|
+
SvgPicture.asset(
|
|
447
|
+
'assets/icons/icon.svg',
|
|
448
|
+
colorFilter: ColorFilter.mode(someColor, BlendMode.srcIn),
|
|
449
|
+
)
|
|
450
|
+
|
|
451
|
+
// ✅ 正确 - 保留 SVG 原有样式
|
|
452
|
+
SvgPicture.asset(
|
|
453
|
+
'assets/icons/icon.svg',
|
|
454
|
+
width: 12,
|
|
455
|
+
height: 12,
|
|
456
|
+
// 不使用 colorFilter,保留 SVG 原有颜色和透明度
|
|
457
|
+
)
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
## 🚫 禁止事项
|
|
463
|
+
|
|
464
|
+
1. **禁止** 直接使用 `Color(0xFFxxxxxx)` 硬编码颜色
|
|
465
|
+
2. **禁止** 直接使用 `EdgeInsets.all(16)` 硬编码间距
|
|
466
|
+
3. **禁止** 在组件中直接使用 `Colors.blue` 等 Material 颜色
|
|
467
|
+
4. **禁止** 使用 `SizedBox(width: 16)` 作为间隔(用 `Gap`)
|
|
468
|
+
5. **禁止** 跳过 Token 系统直接访问 `Theme.of(context)`
|
|
469
|
+
6. **禁止** 在单个文件中定义局部样式常量
|
|
470
|
+
7. **禁止** 使用 Material Icons 代替设计稿图标(必须导出 SVG)
|
|
471
|
+
8. **禁止** 使用 ColorFilter 覆盖 SVG 原有颜色(会丢失透明度)
|
|
472
|
+
9. **禁止** 忽略设计稿颜色的透明度(`#RRGGBBAA` 最后两位)
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
## ✅ 推荐做法
|
|
477
|
+
|
|
478
|
+
1. **优先** 使用 Flex 组件库
|
|
479
|
+
2. **优先** 使用语义化 Token(如 `$c.text.primary` 而非 `$c.neutral[900]`)
|
|
480
|
+
3. **优先** 使用预设间距(`$s.md`)而非自定义(`$s.px(16)`)
|
|
481
|
+
4. **始终** 考虑深色模式兼容性
|
|
482
|
+
5. **始终** 从组件级别开始构建,而非页面级别
|
|
483
|
+
6. **始终** 在修改 Token 时考虑全局影响
|
|
484
|
+
|
|
485
|
+
---
|
|
486
|
+
|
|
487
|
+
## 📚 相关文件
|
|
488
|
+
|
|
489
|
+
- `lib/core/themes/design_tokens.dart` - Token 定义
|
|
490
|
+
- `lib/core/themes/token_manager.dart` - Token 管理
|
|
491
|
+
- `lib/core/themes/flex_widgets.dart` - 组件库
|
|
492
|
+
- `lib/presentation/pages/showcase/style_showcase_page.dart` - 示例页面
|
|
493
|
+
|
|
494
|
+
---
|
|
495
|
+
|
|
496
|
+
**维护团队**: MTA工作室
|
|
497
|
+
**最后更新**: 2026-01-01
|