mta-mcp 2.16.0 → 2.17.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mta-mcp",
3
- "version": "2.16.0",
3
+ "version": "2.17.0",
4
4
  "description": "MTA - 智能项目分析与编码规范管理 MCP 服务器",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -104,7 +104,7 @@ list_troubleshooting_cases({ framework: "flutter" })
104
104
 
105
105
  ## 📚 案例清单
106
106
 
107
- ### Flutter (11 个案例)
107
+ ### Flutter (13 个案例)
108
108
 
109
109
  | 案例ID | 问题类型 | 关键词 |
110
110
  |--------|----------|--------|
@@ -118,6 +118,8 @@ list_troubleshooting_cases({ framework: "flutter" })
118
118
  | svg-未居中 | SVG未居中 | svg, viewbox, center |
119
119
  | sketch-图标尺寸 | 图标尺寸提取错误 | sketch, icon, group, shape |
120
120
  | sketch-属性未使用 | 属性定义但未使用 | property, unused |
121
+ | sketch-背景层高度 | Frame与_background高度差异 | sketch, frame, background, height, _bg |
122
+ | sketch-列表item区域 | 列表首尾item高度不一致 | sketch, list, menu, padding, divider |
121
123
  | withopacity-弃用 | withOpacity弃用警告 | opacity, deprecated |
122
124
 
123
125
  ### Vue3 (1 个案例)
@@ -194,9 +196,9 @@ list_troubleshooting_cases({ framework: "flutter" })
194
196
 
195
197
  ---
196
198
 
197
- **版本**: v2.14.0
198
- **案例总数**: 12
199
- **最后更新**: 2026-01-17
199
+ **版本**: v2.15.0
200
+ **案例总数**: 14
201
+ **最后更新**: 2026-01-19
200
202
 
201
203
  ---
202
204
 
@@ -0,0 +1,212 @@
1
+ # Sketch 列表 Item 区域高度不一致问题
2
+
3
+ > **问题标签**: `sketch`, `list`, `menu`, `item`, `padding`, `divider`
4
+ > **框架**: Flutter
5
+ > **严重程度**: 中等(导致列表布局细节偏差)
6
+
7
+ ---
8
+
9
+ ## 🔍 问题识别
10
+
11
+ ### 用户描述关键词
12
+ - "第一个/最后一个 item 高度不对"
13
+ - "列表 padding 不均匀"
14
+ - "divider 位置偏移"
15
+ - "底部/顶部留白太多/太少"
16
+
17
+ ### 问题特征
18
+ - [ ] 列表首尾 item 与中间 item 高度不同
19
+ - [ ] 使用统一 padding 导致视觉不平衡
20
+ - [ ] 忽略 divider 在高度计算中的影响
21
+ - [ ] 假设所有 item 高度相同
22
+
23
+ ---
24
+
25
+ ## 🎯 核心原理
26
+
27
+ **根本原因**:设计稿中列表的首个和末尾 item 通常有不同的 padding,以平衡与容器边缘的视觉关系。
28
+
29
+ ### 典型 Sketch 测量结果
30
+
31
+ ```
32
+ Menu Card_background: 350px
33
+
34
+ Divider 位置:
35
+ - Divider 1: y=63
36
+ - Divider 2: y=119
37
+ - Divider 3: y=175
38
+ - Divider 4: y=231
39
+ - Divider 5: y=287
40
+
41
+ 区域高度计算:
42
+ - Item 1: 0 → 63 = 63px
43
+ - Item 2: 63 → 119 = 56px
44
+ - Item 3: 119 → 175 = 56px
45
+ - Item 4: 175 → 231 = 56px
46
+ - Item 5: 231 → 287 = 56px
47
+ - Item 6: 287 → 350 = 63px
48
+ ```
49
+
50
+ **结论**: 首尾 item 63px,中间 item 56px,**不是**统一高度!
51
+
52
+ ---
53
+
54
+ ## ❌ 常见错误
55
+
56
+ ```dart
57
+ // ❌ 错误: 统一 padding
58
+ Padding(
59
+ padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
60
+ child: MenuItem(),
61
+ )
62
+ ```
63
+
64
+ ---
65
+
66
+ ## ✅ 正确解决方案
67
+
68
+ ### 1. 测量 Icon 精确位置
69
+
70
+ ```javascript
71
+ // 测量所有 icon 的 y 坐标
72
+ const icons = sketch.find('[name*="Icon BG"]', menuCard);
73
+ icons.forEach(icon => {
74
+ if (icon.frame.height === 36) {
75
+ console.log(`${icon.name}: y=${icon.frame.y}`);
76
+ }
77
+ });
78
+
79
+ // 结果:
80
+ // Item 1 Icon: y=20
81
+ // Item 2 Icon: y=76
82
+ // Item 3 Icon: y=132
83
+ // ...
84
+ ```
85
+
86
+ ### 2. 计算每个 item 的 padding
87
+
88
+ ```
89
+ Item 1 (区域 0→63):
90
+ - region_start = 0
91
+ - icon_y = 20 → top = 20
92
+ - icon_bottom = 56
93
+ - divider_y = 63 → bottom = 63 - 56 - 1 = 6
94
+ - 验证: 20 + 36 + 6 + 1 = 63 ✅
95
+
96
+ Item 2 (区域 64→119):
97
+ - region_start = 64 (divider1 + 1)
98
+ - icon_y = 76 → top = 76 - 64 = 12
99
+ - icon_bottom = 112
100
+ - divider_y = 119 → bottom = 119 - 112 - 1 = 6
101
+ - 验证: 12 + 36 + 6 + 1 = 55...
102
+
103
+ 等等,56 - 1(divider) = 55,但 12+36+6=54?
104
+ 让我重新计算:区域 = 56px 含 divider
105
+ 内容区 = 55px,12 + 36 + 7 = 55 ✅
106
+ ```
107
+
108
+ ### 3. Flutter 精确实现
109
+
110
+ ```dart
111
+ Widget _buildMenuItem(int index, MenuItem item) {
112
+ // Sketch 测量 (背景层 350px):
113
+ // - Item 1: 区域 63px = top:20 + icon:36 + bottom:6 + divider:1
114
+ // - Item 2-5: 区域 56px = top:12 + icon:36 + bottom:7 + divider:1
115
+ // - Item 6: 区域 63px = top:12 + icon:36 + bottom:15 (无 divider)
116
+
117
+ final isFirst = index == 0;
118
+ final isLast = index == 5; // 6 个 item
119
+
120
+ return Column(
121
+ mainAxisSize: MainAxisSize.min,
122
+ children: [
123
+ Padding(
124
+ padding: EdgeInsets.fromLTRB(
125
+ 16,
126
+ isFirst ? 20 : 12, // 首 item top 更大
127
+ 16,
128
+ isFirst ? 6 : (isLast ? 15 : 7), // 尾 item bottom 更大
129
+ ),
130
+ child: Row(
131
+ children: [
132
+ Icon(size: 36),
133
+ SizedBox(width: 16),
134
+ Expanded(child: Text(item.title)),
135
+ ArrowIcon(),
136
+ ],
137
+ ),
138
+ ),
139
+
140
+ // Divider (最后一个不需要)
141
+ if (!isLast)
142
+ Container(
143
+ margin: EdgeInsets.only(left: 68, right: 20),
144
+ height: 1,
145
+ color: Color(0x0F1C2B45),
146
+ ),
147
+ ],
148
+ );
149
+ }
150
+ ```
151
+
152
+ ---
153
+
154
+ ## 🔑 关键公式
155
+
156
+ ### 从 Sketch 测量计算 padding
157
+
158
+ ```
159
+ top_padding = icon.y - region_start
160
+ bottom_padding = region_end - icon.bottom - divider_height
161
+ ```
162
+
163
+ 其中:
164
+ - `region_start` = 上一个 divider.y + 1 (首 item 为 0)
165
+ - `region_end` = 当前 divider.y (尾 item 为 background.height)
166
+ - `icon.bottom` = icon.y + icon.height
167
+ - `divider_height` = 1 (尾 item 为 0)
168
+
169
+ ### 验证公式
170
+
171
+ ```
172
+ 区域高度 = top_padding + icon_height + bottom_padding + divider_height
173
+ ```
174
+
175
+ ---
176
+
177
+ ## 📊 真实案例数据
178
+
179
+ ### Profile Menu Card (350px)
180
+
181
+ | Item | 区域 | Top | Icon | Bottom | Divider | 总计 |
182
+ |------|------|-----|------|--------|---------|------|
183
+ | 1 | 0→63 | 20 | 36 | 6 | 1 | 63 |
184
+ | 2 | 63→119 | 12 | 36 | 7 | 1 | 56 |
185
+ | 3 | 119→175 | 12 | 36 | 7 | 1 | 56 |
186
+ | 4 | 175→231 | 12 | 36 | 7 | 1 | 56 |
187
+ | 5 | 231→287 | 12 | 36 | 7 | 1 | 56 |
188
+ | 6 | 287→350 | 12 | 36 | 15 | 0 | 63 |
189
+
190
+ **总计**: 63 + 56×4 + 63 = 350px ✅
191
+
192
+ ---
193
+
194
+ ## ⚠️ 预防措施
195
+
196
+ 1. **不要假设统一高度**: 始终测量首、中、尾三种 item
197
+ 2. **测量 icon 实际 y 坐标**: 不要只看区域高度
198
+ 3. **区分有无 divider**: 尾 item 通常无 divider
199
+ 4. **使用背景层边界**: 不要用 Frame 高度
200
+
201
+ ---
202
+
203
+ ## 🔗 相关问题
204
+
205
+ - [sketch-背景层高度.md](./sketch-背景层高度.md) - 背景层 vs Frame 高度
206
+ - [layout-尺寸不匹配.md](./layout-尺寸不匹配.md) - 通用布局问题
207
+
208
+ ---
209
+
210
+ **创建日期**: 2026-01-19
211
+ **最后更新**: 2026-01-19
212
+ **来源**: Profile 页面 Menu Item 布局调试实战
@@ -0,0 +1,264 @@
1
+ # Sketch Frame 与 Background 层高度差异问题
2
+
3
+ > **问题标签**: `sketch`, `frame`, `background`, `height`, `_background`, `_bg`
4
+ > **框架**: Flutter
5
+ > **严重程度**: 高(导致布局错位和多轮返工)
6
+
7
+ ---
8
+
9
+ ## 🔍 问题识别
10
+
11
+ ### 用户描述关键词
12
+ - "间距不对"
13
+ - "高度算错了"
14
+ - "内边距有问题"
15
+ - "最后一个 item 高度不对"
16
+ - "卡片高度不匹配"
17
+
18
+ ### 问题特征
19
+ - [ ] 计算的间距与设计稿视觉效果不符
20
+ - [ ] 使用 Frame 高度计算,但结果总是差几像素
21
+ - [ ] Menu/List 的第一个或最后一个 item 高度异常
22
+ - [ ] 多个卡片之间的 gap 计算错误
23
+
24
+ ---
25
+
26
+ ## 🎯 核心原理
27
+
28
+ **根本原因**:Sketch 的 Frame(组/画板)高度与其内部 `_background` 或 `_bg` 层高度可能不同。
29
+
30
+ ### Sketch 层级结构示例
31
+
32
+ ```
33
+ Menu Card (Frame) ← height: 336px ❌ 错误值
34
+ ├── Menu Card_background ← height: 350px ✅ 正确值
35
+ ├── Menu Item 1
36
+ ├── Divider 1
37
+ ├── Menu Item 2
38
+ ...
39
+
40
+ Warning Card (Frame) ← height: 100px ❌ 错误值
41
+ ├── Warning Card_bg ← height: 127px ✅ 正确值
42
+ ├── Warning Text
43
+ ├── Button
44
+ ```
45
+
46
+ | 元素 | Frame 高度 | _background 高度 | 差异 |
47
+ |------|------------|------------------|------|
48
+ | Menu Card | 336px | 350px | +14px |
49
+ | Warning Card | 100px | 127px | +27px |
50
+
51
+ ### 为什么会这样?
52
+
53
+ 1. **Auto Layout**: Frame 可能使用 Hug Contents 或固定高度
54
+ 2. **阴影/装饰**: _background 层包含了内边距、阴影区域
55
+ 3. **Padding 内含**: 背景层可能比 Frame 更大以提供视觉边距
56
+
57
+ ---
58
+
59
+ ## ❌ 常见错误排查路线(避免重复)
60
+
61
+ | 尝试方向 | 为什么无效 | 浪费时间 |
62
+ |----------|-----------|---------|
63
+ | 使用 Frame 高度计算 gap | 背景层实际更大 | 3-5 轮对话 |
64
+ | 反复调整 padding | 不知道正确的参考值 | 4-6 轮对话 |
65
+ | 假设最后 item 与其他相同 | 底部 padding 通常不同 | 2-3 轮对话 |
66
+ | 只测量 divider 位置 | 忽略了背景层边界 | 2-3 轮对话 |
67
+
68
+ **总计浪费**: 10-15 轮对话
69
+
70
+ ---
71
+
72
+ ## ✅ 正确解决方案
73
+
74
+ ### 解决步骤
75
+
76
+ #### 1. 必须同时测量 Frame 和 _background 层
77
+
78
+ ```javascript
79
+ // Sketch 测量脚本 - 比较 Frame 与背景层高度
80
+ const sketch = require('sketch');
81
+ const doc = sketch.getSelectedDocument();
82
+ const page = doc.selectedPage;
83
+ const target = sketch.find('[name="Profile Page"]', page)[0]; // 替换为目标
84
+
85
+ function measureBackgroundLayers(container) {
86
+ const results = {};
87
+
88
+ sketch.find('*', container).forEach(layer => {
89
+ const name = layer.name;
90
+
91
+ // 查找 Frame 和对应的 _background/_bg 层
92
+ if (name.includes('Card') || name.includes('Panel')) {
93
+ results[name] = {
94
+ type: layer.type,
95
+ frameHeight: layer.frame.height,
96
+ y: layer.frame.y
97
+ };
98
+ }
99
+
100
+ // 单独记录 _background 和 _bg 层
101
+ if (name.includes('_background') || name.includes('_bg')) {
102
+ results[name] = {
103
+ type: layer.type,
104
+ height: layer.frame.height,
105
+ y: layer.frame.y
106
+ };
107
+ }
108
+ });
109
+
110
+ console.log(JSON.stringify(results, null, 2));
111
+ }
112
+
113
+ measureBackgroundLayers(target);
114
+ ```
115
+
116
+ #### 2. 使用 _background 层高度计算布局
117
+
118
+ ```dart
119
+ // ❌ 错误: 使用 Frame 高度
120
+ const warningCardHeight = 100; // Frame 高度
121
+ const menuCardY = 274;
122
+ const gap = menuCardY - (warningCardY + warningCardHeight);
123
+ // gap = 274 - (130 + 100) = 44px ❌
124
+
125
+ // ✅ 正确: 使用 _background 层高度
126
+ const warningCardHeight = 127; // _bg 层高度
127
+ const gap = menuCardY - (warningCardY + warningCardHeight);
128
+ // gap = 274 - (130 + 127) = 17px ✅
129
+ ```
130
+
131
+ #### 3. 区分列表首尾 item 的 padding
132
+
133
+ Menu/List 类组件中,首尾 item 通常与背景边缘有特殊间距:
134
+
135
+ ```javascript
136
+ // 测量 divider 位置和背景层边界
137
+ const dividers = sketch.find('[name*="Divider"]', menuCard);
138
+ const background = sketch.find('[name*="_background"]', menuCard)[0];
139
+
140
+ dividers.forEach(d => {
141
+ console.log(`${d.name}: y=${d.frame.y}`);
142
+ });
143
+ console.log(`Background height: ${background.frame.height}`);
144
+
145
+ // 计算每个区域高度
146
+ // Item 1: 0 → divider1.y
147
+ // Item 2-N-1: divider[i-1].y → divider[i].y
148
+ // Item N: divider[N-1].y + 1 → background.height
149
+ ```
150
+
151
+ #### 4. Flutter 实现:区分首尾 item
152
+
153
+ ```dart
154
+ Widget _buildMenuItem(int index, MenuItem item) {
155
+ // Sketch 精确测量 (Menu Card_background = 350px):
156
+ // - Item 1: 区域63px = top:20 + icon:36 + bottom:6 + divider:1
157
+ // - Item 2-5: 区域56px = top:12 + icon:36 + bottom:7 + divider:1
158
+ // - Item 6: 区域63px = top:12 + icon:36 + bottom:15 (无divider)
159
+
160
+ return Padding(
161
+ padding: EdgeInsets.fromLTRB(
162
+ 16,
163
+ index == 0 ? 20 : 12, // 首 item top 更大
164
+ 16,
165
+ index == 0 ? 6 : (index == 5 ? 15 : 7), // 尾 item bottom 更大
166
+ ),
167
+ child: Row(...),
168
+ );
169
+ }
170
+ ```
171
+
172
+ ---
173
+
174
+ ## 🔑 关键公式
175
+
176
+ ### 卡片间距计算
177
+
178
+ ```
179
+ 实际 gap = 下一卡片.y - (当前卡片.y + 当前卡片._background.height)
180
+ ```
181
+
182
+ ### 列表 item 区域计算
183
+
184
+ ```
185
+ 区域[0] = divider[0].y // 首 item
186
+ 区域[i] = divider[i].y - divider[i-1].y // 中间 items (含 divider)
187
+ 区域[N] = background.height - divider[N-1].y - 1 // 尾 item (无 divider)
188
+ ```
189
+
190
+ ### Icon 垂直 padding 计算
191
+
192
+ ```
193
+ top_padding = icon.y - region_start
194
+ bottom_padding = region_end - (icon.y + icon.height) - divider_height
195
+ ```
196
+
197
+ ---
198
+
199
+ ## ⚠️ 预防措施
200
+
201
+ ### 提取 Sketch 时的检查清单
202
+
203
+ - [ ] 是否同时读取了 Frame 高度和 _background/_bg 层高度?
204
+ - [ ] 两者是否相同?如果不同,使用哪个?
205
+ - [ ] 卡片之间的 gap 是否基于视觉边界(_background)计算?
206
+ - [ ] 列表的首尾 item 是否有特殊的 padding?
207
+
208
+ ### 命名约定识别
209
+
210
+ | 后缀 | 含义 | 使用场景 |
211
+ |------|------|----------|
212
+ | `_background` | 完整背景层 | 用于计算实际高度 |
213
+ | `_bg` | 简化背景层 | 同上 |
214
+ | `_shadow` | 阴影层 | 可能影响视觉边界 |
215
+ | `_border` | 边框层 | 不影响高度计算 |
216
+
217
+ ---
218
+
219
+ ## 📊 真实案例
220
+
221
+ ### 案例: Profile 页面卡片间距
222
+
223
+ **问题**: Warning Card 到 Menu Card 的间距应该是 17px,但计算得到 44px
224
+
225
+ **错误分析**:
226
+ ```
227
+ Menu Card.y = 274
228
+ Warning Card.y = 130
229
+ Warning Card Frame.height = 100 ← 使用了错误的值
230
+
231
+ gap = 274 - (130 + 100) = 44px ❌
232
+ ```
233
+
234
+ **正确分析**:
235
+ ```
236
+ Menu Card.y = 274
237
+ Warning Card.y = 130
238
+ Warning Card_bg.height = 127 ← 使用 _bg 层高度
239
+
240
+ gap = 274 - (130 + 127) = 17px ✅
241
+ ```
242
+
243
+ **修复代码**:
244
+ ```dart
245
+ // 修改前
246
+ SizedBox(height: 44),
247
+
248
+ // 修改后
249
+ SizedBox(height: 17),
250
+ ```
251
+
252
+ ---
253
+
254
+ ## 🔗 相关问题
255
+
256
+ - [layout-尺寸不匹配.md](./layout-尺寸不匹配.md) - 通用布局问题
257
+ - [sketch-完整提取.md](./sketch-完整提取.md) - 完整提取脚本
258
+ - [sketch-图标尺寸.md](./sketch-图标尺寸.md) - SVG 尺寸问题
259
+
260
+ ---
261
+
262
+ **创建日期**: 2026-01-19
263
+ **最后更新**: 2026-01-19
264
+ **来源**: Profile 页面 Menu Card 布局调试实战