@morya-ui/mcp 0.2.7 → 0.2.9
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 +1 -1
- package/data/catalog.json +448 -96
- package/data/example-coverage.json +40 -5
- package/data/golden-pages/dashboard-page.vue +41 -8
- package/data/golden-pages/empty-state.vue +22 -1
- package/data/golden-pages/form-page.vue +1 -1
- package/data/golden-pages/landing-page.vue +31 -1
- package/data/golden-pages/list-page.vue +25 -12
- package/data/golden-pages/login-page.vue +44 -4
- package/dist/__tests__/tools.test.js +10 -0
- package/dist/decisions.js +205 -1
- package/dist/page-snippets.js +27 -17
- package/dist/patterns.d.ts +4 -2
- package/dist/patterns.js +11 -9
- package/dist/tools.js +25 -5
- package/package.json +1 -1
package/dist/decisions.js
CHANGED
|
@@ -136,7 +136,7 @@ export const componentDecisions = [
|
|
|
136
136
|
titleEn: 'Choosing a selection control',
|
|
137
137
|
question: '选项是平面少量、层级结构、多选标签,还是需要输入搜索?',
|
|
138
138
|
questionEn: 'Are options a small flat set, a hierarchy, multi-select tags, or searchable input?',
|
|
139
|
-
keywords: ['选择', '下拉', '多选', '树选择', '搜索选择', 'select', 'treeselect', 'autocomplete', 'dropdown'],
|
|
139
|
+
keywords: ['选择', '下拉', '多选', '树选择', '搜索选择', '级联', '列表选择', '按钮组', 'select', 'treeselect', 'autocomplete', 'cascadeselect', 'listbox', 'selectbutton', 'radio', 'dropdown'],
|
|
140
140
|
options: [
|
|
141
141
|
{
|
|
142
142
|
component: 'Select',
|
|
@@ -159,6 +159,34 @@ export const componentDecisions = [
|
|
|
159
159
|
avoidWhen: ['用户只能从固定枚举中选择', '不应该允许自由输入'],
|
|
160
160
|
avoidWhenEn: ['Users must choose from a fixed enum', 'Free input must not be allowed'],
|
|
161
161
|
},
|
|
162
|
+
{
|
|
163
|
+
component: 'SelectButton',
|
|
164
|
+
when: ['选项很少且需要全部露出', '单选或多选都适合按钮组'],
|
|
165
|
+
whenEn: ['Only a few options, and all of them should stay visible', 'Single or multiple selection works as a button group'],
|
|
166
|
+
avoidWhen: ['选项超过大约 5 个', '选项很长或来自远程搜索'],
|
|
167
|
+
avoidWhenEn: ['More than about five options', 'Labels are long or options come from remote search'],
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
component: 'Radio',
|
|
171
|
+
when: ['少量互斥选项需要和表单文案一起阅读', '一次只能选一个'],
|
|
172
|
+
whenEn: ['A few mutually exclusive options should be read with the form copy', 'Only one value can be selected'],
|
|
173
|
+
avoidWhen: ['多选', '选项很多需要收进弹出层'],
|
|
174
|
+
avoidWhenEn: ['Multiple selection', 'Too many options for an always-visible list'],
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
component: 'Listbox',
|
|
178
|
+
when: ['选项需要始终以列表展示', '可筛选,但不希望收成下拉框'],
|
|
179
|
+
whenEn: ['Options should stay visible as a list', 'Filtering is useful, but a collapsed dropdown is not'],
|
|
180
|
+
avoidWhen: ['页面空间紧、只需要一个闭合的选择框'],
|
|
181
|
+
avoidWhenEn: ['Space is tight and a closed select is enough'],
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
component: 'CascadeSelect',
|
|
185
|
+
when: ['值要按多级分栏逐级点选', '层级是路径而不是可勾选的树'],
|
|
186
|
+
whenEn: ['The value is chosen column by column through levels', 'The hierarchy is a path, not a checkable tree'],
|
|
187
|
+
avoidWhen: ['需要勾选树节点或搜索整棵树'],
|
|
188
|
+
avoidWhenEn: ['Users need to check tree nodes or search the whole tree'],
|
|
189
|
+
},
|
|
162
190
|
],
|
|
163
191
|
},
|
|
164
192
|
{
|
|
@@ -383,6 +411,182 @@ export const componentDecisions = [
|
|
|
383
411
|
},
|
|
384
412
|
],
|
|
385
413
|
},
|
|
414
|
+
{
|
|
415
|
+
id: 'loading-choice',
|
|
416
|
+
title: '如何选择加载反馈',
|
|
417
|
+
titleEn: 'Choosing a loading indicator',
|
|
418
|
+
question: '这是区域或全屏等待、已知布局的占位、可量化进度,还是只需要阻止交互?',
|
|
419
|
+
questionEn: 'Is this a region or fullscreen wait, a placeholder for a known layout, measurable progress, or interaction blocking without a loading message?',
|
|
420
|
+
keywords: [
|
|
421
|
+
'加载',
|
|
422
|
+
'等待',
|
|
423
|
+
'遮罩',
|
|
424
|
+
'骨架',
|
|
425
|
+
'进度',
|
|
426
|
+
'loading',
|
|
427
|
+
'spinner',
|
|
428
|
+
'skeleton',
|
|
429
|
+
'progress',
|
|
430
|
+
'v-loading',
|
|
431
|
+
'mloading',
|
|
432
|
+
],
|
|
433
|
+
options: [
|
|
434
|
+
{
|
|
435
|
+
component: 'Loading',
|
|
436
|
+
when: [
|
|
437
|
+
'一块区域或整页正在等待,用户暂时不能操作这块内容',
|
|
438
|
+
'需要加载文案、多种动效,或用 v-loading / loading.service 盖住已有节点',
|
|
439
|
+
'全屏提交、保存、跳转前的短暂等待',
|
|
440
|
+
],
|
|
441
|
+
whenEn: [
|
|
442
|
+
'A region or the whole page is waiting and that content should not be operated',
|
|
443
|
+
'A caption, effect, v-loading, or loading.service mask over an existing node is needed',
|
|
444
|
+
'A short fullscreen wait before submit, save, or navigation',
|
|
445
|
+
],
|
|
446
|
+
avoidWhen: ['布局已知、希望用占位块避免跳动', '进度可以量化', '只是按钮自己的 loading 状态'],
|
|
447
|
+
avoidWhenEn: [
|
|
448
|
+
'The layout is known and a placeholder should prevent jump',
|
|
449
|
+
'Progress can be measured',
|
|
450
|
+
'Only the button’s own loading state is needed',
|
|
451
|
+
],
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
component: 'Skeleton',
|
|
455
|
+
when: ['内容结构已知,用占位块表示即将出现的卡片、文本或列表', '仪表盘或详情初次进入'],
|
|
456
|
+
whenEn: ['The content structure is known and placeholders stand in for cards, text, or lists', 'First paint of a dashboard or detail view'],
|
|
457
|
+
avoidWhen: ['需要明确的“正在加载”遮罩', '进度可量化'],
|
|
458
|
+
avoidWhenEn: ['An explicit loading mask is required', 'Progress can be measured'],
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
component: 'ProgressBar',
|
|
462
|
+
when: ['进度有百分比或可估算完成度', '上传、导入等长任务'],
|
|
463
|
+
whenEn: ['Progress has a percentage or an estimated completion', 'Long tasks such as upload or import'],
|
|
464
|
+
avoidWhen: ['不知道还要等多久', '只是挡住一块区域'],
|
|
465
|
+
avoidWhenEn: ['Duration is unknown', 'The only goal is to cover a region'],
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
component: 'ProgressSpinner',
|
|
469
|
+
when: ['行内或控件旁需要一个很小的转圈,不盖住内容'],
|
|
470
|
+
whenEn: ['A small inline spinner beside a control, without covering content'],
|
|
471
|
+
avoidWhen: ['区域遮罩、全屏等待或带文案的加载态'],
|
|
472
|
+
avoidWhenEn: ['A region mask, fullscreen wait, or loading state with a caption'],
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
component: 'BlockUI',
|
|
476
|
+
when: ['只需要阻止点击,不需要表达“正在加载”'],
|
|
477
|
+
whenEn: ['Interaction should be blocked without saying that something is loading'],
|
|
478
|
+
avoidWhen: ['用户需要知道正在等待结果'],
|
|
479
|
+
avoidWhenEn: ['The user needs to know a result is still pending'],
|
|
480
|
+
},
|
|
481
|
+
],
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
id: 'status-label-choice',
|
|
485
|
+
title: '如何选择状态与标签',
|
|
486
|
+
titleEn: 'Choosing status, tag, chip, or badge',
|
|
487
|
+
question: '这是行内业务状态、分类标签、可移除实体,还是挂在控件上的数量?',
|
|
488
|
+
questionEn: 'Is this an inline business status, a category label, a removable entity, or a count on another control?',
|
|
489
|
+
keywords: ['行内状态', '状态点', '角标', '徽章', '可关闭标签', '芯片', 'status', 'badge', 'chip', 'tag', 'closable'],
|
|
490
|
+
options: [
|
|
491
|
+
{
|
|
492
|
+
component: 'Status',
|
|
493
|
+
when: ['表格单元格或标题旁的业务状态', '需要圆点或语义图标加短文案'],
|
|
494
|
+
whenEn: ['Business status in a table cell or beside a title', 'A dot or semantic icon plus a short label'],
|
|
495
|
+
avoidWhen: ['可关闭的分类标签', '挂在按钮上的数字'],
|
|
496
|
+
avoidWhenEn: ['A closable category label', 'A count attached to a button'],
|
|
497
|
+
},
|
|
498
|
+
{
|
|
499
|
+
component: 'Tag',
|
|
500
|
+
when: ['分类、筛选结果或可关闭标签', '需要比 Status 更像芯片的表面'],
|
|
501
|
+
whenEn: ['A category, filter result, or closable label', 'A chip-like surface rather than an inline status'],
|
|
502
|
+
avoidWhen: ['只是一行里的轻量状态', '带图片且代表一个可移除实体'],
|
|
503
|
+
avoidWhenEn: ['A lightweight inline status', 'An entity with an image that can be removed'],
|
|
504
|
+
},
|
|
505
|
+
{
|
|
506
|
+
component: 'Chip',
|
|
507
|
+
when: ['短实体信息,可带图标、图片和移除'],
|
|
508
|
+
whenEn: ['A short entity that may include an icon, image, and remove action'],
|
|
509
|
+
avoidWhen: ['纯状态色点', '只是分类色块'],
|
|
510
|
+
avoidWhenEn: ['A status dot only', 'A category color block only'],
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
component: 'Badge',
|
|
514
|
+
when: ['角标数量或圆点,附着在按钮、头像等控件上'],
|
|
515
|
+
whenEn: ['A count or dot attached to a button, avatar, or other control'],
|
|
516
|
+
avoidWhen: ['独立成行的状态文案'],
|
|
517
|
+
avoidWhenEn: ['A standalone status sentence'],
|
|
518
|
+
},
|
|
519
|
+
],
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
id: 'empty-result-choice',
|
|
523
|
+
title: '空态还是结果页',
|
|
524
|
+
titleEn: 'Empty state vs result page',
|
|
525
|
+
question: '这是没有数据,还是流程已经结束的成功、失败或 HTTP 状态?',
|
|
526
|
+
questionEn: 'Is there simply no data, or has a flow ended in success, failure, or an HTTP status?',
|
|
527
|
+
keywords: ['空状态', '无数据', '首次使用', '筛选无结果', '结果页', '404', '403', '500', 'empty', 'result'],
|
|
528
|
+
options: [
|
|
529
|
+
{
|
|
530
|
+
component: 'Empty',
|
|
531
|
+
when: ['列表没有行', '筛选没有命中', '首次使用,需要引导创建'],
|
|
532
|
+
whenEn: ['A list has no rows', 'Filters matched nothing', 'First use, and the next step is to create something'],
|
|
533
|
+
avoidWhen: ['接口失败', '无权限', '页面不存在', '提交成功回执'],
|
|
534
|
+
avoidWhenEn: ['The request failed', 'Permission was denied', 'The page does not exist', 'A submit-success receipt'],
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
component: 'Result',
|
|
538
|
+
when: ['提交成功或失败的终点页', '403 / 404 / 500 等阻断状态', '需要明确的下一步(返回、重试、回首页)'],
|
|
539
|
+
whenEn: ['A terminal success or failure page', 'A blocking 403 / 404 / 500 state', 'The next step must be explicit (back, retry, home)'],
|
|
540
|
+
avoidWhen: ['正常的无数据', '表格内部的空行'],
|
|
541
|
+
avoidWhenEn: ['A normal empty collection', 'The empty slot inside a table'],
|
|
542
|
+
},
|
|
543
|
+
],
|
|
544
|
+
},
|
|
545
|
+
{
|
|
546
|
+
id: 'action-menu-choice',
|
|
547
|
+
title: '如何选择菜单',
|
|
548
|
+
titleEn: 'Choosing a menu',
|
|
549
|
+
question: '这是按钮上的操作项、侧栏导航、右键菜单,还是全局命令搜索?',
|
|
550
|
+
questionEn: 'Is this an action menu on a trigger, sider navigation, a context menu, or a global command search?',
|
|
551
|
+
keywords: ['动作菜单', '右键', '右键菜单', '命令面板', '导航菜单', 'context menu', 'command menu', 'menubar', '上下文菜单'],
|
|
552
|
+
options: [
|
|
553
|
+
{
|
|
554
|
+
component: 'Dropdown',
|
|
555
|
+
when: ['从按钮或图标打开一组操作', '编辑、删除、更多'],
|
|
556
|
+
whenEn: ['Actions open from a button or icon', 'Edit, delete, or more'],
|
|
557
|
+
avoidWhen: ['表单里选一个枚举值', '常驻侧栏导航'],
|
|
558
|
+
avoidWhenEn: ['Choosing an enum in a form', 'Persistent sider navigation'],
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
component: 'Menu',
|
|
562
|
+
when: ['后台侧栏或页面内的常驻导航', '需要选中项与路由同步'],
|
|
563
|
+
whenEn: ['Persistent navigation in an admin sider or page', 'Selection should stay in sync with the route'],
|
|
564
|
+
avoidWhen: ['一次性操作菜单', '右键弹出'],
|
|
565
|
+
avoidWhenEn: ['A one-shot action menu', 'A right-click popup'],
|
|
566
|
+
},
|
|
567
|
+
{
|
|
568
|
+
component: 'ContextMenu',
|
|
569
|
+
when: ['在指针位置弹出,通常由右键触发'],
|
|
570
|
+
whenEn: ['The menu opens at the pointer, usually from a right-click'],
|
|
571
|
+
avoidWhen: ['可见的导航', '表单选择'],
|
|
572
|
+
avoidWhenEn: ['Visible navigation', 'Form selection'],
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
component: 'CommandMenu',
|
|
576
|
+
when: ['全局搜索命令或跳转', '键盘优先,例如 Cmd/Ctrl+K'],
|
|
577
|
+
whenEn: ['Global command search or jump', 'Keyboard-first, such as Cmd/Ctrl+K'],
|
|
578
|
+
avoidWhen: ['少量固定操作放在按钮旁即可'],
|
|
579
|
+
avoidWhenEn: ['A few fixed actions fit next to a button'],
|
|
580
|
+
},
|
|
581
|
+
{
|
|
582
|
+
component: 'Menubar',
|
|
583
|
+
when: ['顶部应用菜单,项很多且分组'],
|
|
584
|
+
whenEn: ['A top application menu with many grouped items'],
|
|
585
|
+
avoidWhen: ['侧栏只有一层链接'],
|
|
586
|
+
avoidWhenEn: ['The sider is a single level of links'],
|
|
587
|
+
},
|
|
588
|
+
],
|
|
589
|
+
},
|
|
386
590
|
];
|
|
387
591
|
export function findDecision(name) {
|
|
388
592
|
const key = name.trim().toLowerCase().replace(/[-_\s]/g, '');
|
package/dist/page-snippets.js
CHANGED
|
@@ -61,7 +61,7 @@ const statusOptions = [
|
|
|
61
61
|
descriptionEn: 'Standard MTable placed directly in MPageContent without an extra Card wrapper.',
|
|
62
62
|
pageTypes: ['list'],
|
|
63
63
|
keywords: ['表格', 'table', 'pagination', 'paginator', 'empty', 'columns', 'rows'],
|
|
64
|
-
imports: ['MTable'],
|
|
64
|
+
imports: ['MTable', 'MEmpty', 'MButton'],
|
|
65
65
|
scriptSetup: `const columns = [
|
|
66
66
|
{ key: 'name', label: '名称' },
|
|
67
67
|
{ key: 'status', label: '状态' },
|
|
@@ -82,13 +82,19 @@ const loading = ref(false)`,
|
|
|
82
82
|
aria-label="数据列表"
|
|
83
83
|
>
|
|
84
84
|
<template #empty>
|
|
85
|
-
<
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
<MEmpty
|
|
86
|
+
title="还没有数据"
|
|
87
|
+
description="创建第一条记录后,这里会列出结果。"
|
|
88
|
+
icon="inbox"
|
|
89
|
+
>
|
|
90
|
+
<template #extra>
|
|
91
|
+
<MButton severity="primary">新建</MButton>
|
|
92
|
+
</template>
|
|
93
|
+
</MEmpty>
|
|
88
94
|
</template>
|
|
89
95
|
</MTable>`,
|
|
90
|
-
rules: ['表格直接放在 MPageContent 内', '空态用
|
|
91
|
-
rulesEn: ['Place the table directly in MPageContent', 'Use
|
|
96
|
+
rules: ['表格直接放在 MPageContent 内', '空态用 MEmpty,不要留空白或单行灰字'],
|
|
97
|
+
rulesEn: ['Place the table directly in MPageContent', 'Use MEmpty for zero-data states, not a blank or muted sentence'],
|
|
92
98
|
avoid: ['不要用 MCard 包裹 bordered MTable'],
|
|
93
99
|
avoidEn: ['Do not wrap a bordered MTable with MCard'],
|
|
94
100
|
},
|
|
@@ -103,12 +109,12 @@ const loading = ref(false)`,
|
|
|
103
109
|
imports: ['MSpace', 'MButton'],
|
|
104
110
|
template: `<template #cell-actions>
|
|
105
111
|
<MSpace>
|
|
106
|
-
<MButton severity="secondary" size="small">编辑</MButton>
|
|
107
|
-
<MButton severity="danger" size="small">删除</MButton>
|
|
112
|
+
<MButton severity="secondary" size="small" text>编辑</MButton>
|
|
113
|
+
<MButton severity="danger" size="small" text>删除</MButton>
|
|
108
114
|
</MSpace>
|
|
109
115
|
</template>`,
|
|
110
|
-
rules: ['行内操作用 size="small"', '危险操作使用 severity="danger" 并配合确认弹窗'],
|
|
111
|
-
rulesEn: ['Use size="small"
|
|
116
|
+
rules: ['行内操作用 size="small" + text/outlined,避免一排实心按钮', '危险操作使用 severity="danger" 并配合确认弹窗'],
|
|
117
|
+
rulesEn: ['Use size="small" with text/outlined row actions', 'Use severity="danger" with confirmation for destructive actions'],
|
|
112
118
|
avoid: ['不要用 Dropdown 代替明确的行内按钮组,除非操作很多'],
|
|
113
119
|
avoidEn: ['Do not replace explicit row buttons with Dropdown unless there are many actions'],
|
|
114
120
|
},
|
|
@@ -116,8 +122,8 @@ const loading = ref(false)`,
|
|
|
116
122
|
id: 'list-status-tag',
|
|
117
123
|
title: '表格状态列 Tag',
|
|
118
124
|
titleEn: 'Table status tag cell',
|
|
119
|
-
description: '在 #cell-status 中用 MTag
|
|
120
|
-
descriptionEn: 'Render
|
|
125
|
+
description: '在 #cell-status 中用 MTag 展示分类标签(业务状态优先用 list-status-dot / MStatus)。',
|
|
126
|
+
descriptionEn: 'Render category labels with MTag in #cell-status (prefer MStatus for business status).',
|
|
121
127
|
pageTypes: ['list'],
|
|
122
128
|
keywords: ['状态', 'tag', 'status', 'cell-status'],
|
|
123
129
|
imports: ['MTag'],
|
|
@@ -313,18 +319,22 @@ const submitting = ref(false)`,
|
|
|
313
319
|
descriptionEn: 'Recent records in a small MTable inside MCard.',
|
|
314
320
|
pageTypes: ['dashboard'],
|
|
315
321
|
keywords: ['recent', '最近', 'table', 'card', 'list'],
|
|
316
|
-
imports: ['MCard', 'MTable', '
|
|
322
|
+
imports: ['MCard', 'MTable', 'MStatus'],
|
|
317
323
|
scriptSetup: `const recentColumns = [
|
|
318
324
|
{ key: 'id', label: '工单号', width: 96 },
|
|
319
325
|
{ key: 'title', label: '标题' },
|
|
320
|
-
{ key: 'status', label: '状态', width:
|
|
326
|
+
{ key: 'status', label: '状态', width: 110 },
|
|
321
327
|
]
|
|
322
328
|
const recentRows = ref<Record<string, unknown>[]>([])`,
|
|
323
329
|
template: `<MCard title="最近工单">
|
|
324
|
-
<MTable :columns="recentColumns" :rows="recentRows" size="small" :paginator="false" bordered
|
|
330
|
+
<MTable :columns="recentColumns" :rows="recentRows" size="small" :paginator="false" bordered row-key="id">
|
|
331
|
+
<template #cell-status="{ value }">
|
|
332
|
+
<MStatus :label="String(value ?? '')" severity="secondary" />
|
|
333
|
+
</template>
|
|
334
|
+
</MTable>
|
|
325
335
|
</MCard>`,
|
|
326
|
-
rules: ['明细列表放 MCard 内合理', 'size="small" 适合卡片内表格'],
|
|
327
|
-
rulesEn: ['Detail lists inside MCard are appropriate', 'Use size="small" for in-card tables'],
|
|
336
|
+
rules: ['明细列表放 MCard 内合理', 'size="small" 适合卡片内表格', '行内业务状态用 MStatus'],
|
|
337
|
+
rulesEn: ['Detail lists inside MCard are appropriate', 'Use size="small" for in-card tables', 'Use MStatus for row business status'],
|
|
328
338
|
avoid: ['卡片内表格不要再外包一层 MPageContent'],
|
|
329
339
|
avoidEn: ['Do not wrap in-card tables with another MPageContent'],
|
|
330
340
|
},
|
package/dist/patterns.d.ts
CHANGED
|
@@ -92,13 +92,15 @@ export declare const designRules: {
|
|
|
92
92
|
readonly status: {
|
|
93
93
|
readonly preferred: "MStatus";
|
|
94
94
|
readonly chip: "MTag";
|
|
95
|
+
readonly badge: "MBadge";
|
|
96
|
+
readonly entity: "MChip";
|
|
95
97
|
readonly mapping: {
|
|
96
98
|
readonly active: "success";
|
|
97
99
|
readonly pending: "warn";
|
|
98
100
|
readonly disabled: "secondary";
|
|
99
101
|
readonly error: "danger";
|
|
100
102
|
};
|
|
101
|
-
readonly note: "行内轻量状态用 MStatus
|
|
103
|
+
readonly note: "行内轻量状态用 MStatus;分类或可关闭标签用 MTag;数量角标用 MBadge;可移除实体用 MChip";
|
|
102
104
|
};
|
|
103
105
|
readonly feedback: {
|
|
104
106
|
readonly default: "message";
|
|
@@ -126,7 +128,7 @@ export declare const designRules: {
|
|
|
126
128
|
readonly api: "field errorMessage | token-styled role=alert";
|
|
127
129
|
readonly when: readonly ["登录/表单区常驻错误:优先字段 errorMessage", "表单级总结:使用 --m-* 样式的 role=alert 条(见 login-page 黄金样例)", "MMessage 组件当前主要为 message 服务宿主,勿臆造 severity 子节点 API"];
|
|
128
130
|
};
|
|
129
|
-
readonly doc: "
|
|
131
|
+
readonly doc: "design-kit/.agents/skills/morya-ui-pages/references/feedback.md";
|
|
130
132
|
};
|
|
131
133
|
readonly global: readonly ["优先使用组件库组件和 --m-* Token", "操作反馈默认 message;仅一行文案时优先于 toast", "空态用 MEmpty;结果/阻断页用 MResult;行内状态优先 MStatus", "图标按钮建议提供 aria-label;表单字段建议有可见 label", "浮层默认 Teleport 到 body;有明确布局约束时再改 appendTo", "优先使用组件 documented variant,少写深层 CSS 覆盖"];
|
|
132
134
|
};
|
package/dist/patterns.js
CHANGED
|
@@ -5,7 +5,7 @@ export const pagePatterns = [
|
|
|
5
5
|
titleEn: 'Admin list page',
|
|
6
6
|
description: '用于资源管理、设备管理、用户管理等带筛选和行操作的数据列表。',
|
|
7
7
|
descriptionEn: 'A resource-management list with filters, actions, row operations, and pagination.',
|
|
8
|
-
goldenPage: '
|
|
8
|
+
goldenPage: 'list-page',
|
|
9
9
|
keywords: [
|
|
10
10
|
'列表',
|
|
11
11
|
'表格',
|
|
@@ -93,7 +93,7 @@ export const pagePatterns = [
|
|
|
93
93
|
titleEn: 'Create or edit form page',
|
|
94
94
|
description: '用于创建或编辑业务对象,包含分组字段、校验和提交状态。',
|
|
95
95
|
descriptionEn: 'A create or edit page with grouped fields, validation, and submit states.',
|
|
96
|
-
goldenPage: '
|
|
96
|
+
goldenPage: 'form-page',
|
|
97
97
|
keywords: ['表单', '新增', '编辑', '创建', '配置', '设置', 'form', 'create', 'edit', 'settings'],
|
|
98
98
|
components: [
|
|
99
99
|
{ component: 'ConfigProvider', role: '应用根包裹' },
|
|
@@ -216,7 +216,7 @@ export const pagePatterns = [
|
|
|
216
216
|
{ component: 'Button', role: '刷新、查看详情和快捷操作', required: false },
|
|
217
217
|
{ component: 'Skeleton', role: '初始加载占位', required: false },
|
|
218
218
|
],
|
|
219
|
-
goldenPage: '
|
|
219
|
+
goldenPage: 'dashboard-page',
|
|
220
220
|
structure: [
|
|
221
221
|
'ConfigProvider',
|
|
222
222
|
'└── Layout',
|
|
@@ -267,7 +267,7 @@ export const pagePatterns = [
|
|
|
267
267
|
titleEn: 'Empty state / no results page',
|
|
268
268
|
description: '用于首次使用、搜索无结果、资源已清空或暂时没有内容的场景。',
|
|
269
269
|
descriptionEn: 'For first use, no search results, empty resources, or temporarily unavailable content.',
|
|
270
|
-
goldenPage: '
|
|
270
|
+
goldenPage: 'empty-state',
|
|
271
271
|
keywords: ['空状态', '无数据', '无结果', '首次使用', 'empty', 'no results', 'no data', 'zero state'],
|
|
272
272
|
components: [
|
|
273
273
|
{ component: 'PageContent', role: '承载空态的内容区', required: false },
|
|
@@ -297,7 +297,7 @@ export const pagePatterns = [
|
|
|
297
297
|
titleEn: 'Login / authentication page',
|
|
298
298
|
description: '用于登录、注册、找回密码和二次认证流程。',
|
|
299
299
|
descriptionEn: 'For login, registration, password recovery, and second-factor authentication flows.',
|
|
300
|
-
goldenPage: '
|
|
300
|
+
goldenPage: 'login-page',
|
|
301
301
|
keywords: ['登录', '注册', '认证', '密码', '验证码', 'login', 'register', 'authentication', 'password', 'otp'],
|
|
302
302
|
components: [
|
|
303
303
|
{ component: 'ConfigProvider', role: '应用根包裹' },
|
|
@@ -329,7 +329,7 @@ export const pagePatterns = [
|
|
|
329
329
|
titleEn: 'Marketing landing page',
|
|
330
330
|
description: '用于产品官网、发布页、定价前导等公开营销表面;首屏单一任务,控件仍用 morya-ui。',
|
|
331
331
|
descriptionEn: 'Public marketing surfaces (product home, launch, pre-pricing). One job in the first viewport; controls still use morya-ui.',
|
|
332
|
-
goldenPage: '
|
|
332
|
+
goldenPage: 'landing-page',
|
|
333
333
|
keywords: [
|
|
334
334
|
'落地页',
|
|
335
335
|
'营销',
|
|
@@ -432,7 +432,7 @@ export const pagePatterns = [
|
|
|
432
432
|
'不使用大面积自定义背景色覆盖组件库 surface Token',
|
|
433
433
|
],
|
|
434
434
|
interactionRules: [
|
|
435
|
-
'
|
|
435
|
+
'已知布局用 Skeleton 占位;区域或全屏等待用 Loading(MLoading / v-loading / loading.service)',
|
|
436
436
|
'资源不存在用 MResult status="404";列表空数据用 MEmpty,不要混用',
|
|
437
437
|
'危险操作必须确认并在成功后刷新或离开当前详情页',
|
|
438
438
|
],
|
|
@@ -693,8 +693,10 @@ export const designRules = {
|
|
|
693
693
|
status: {
|
|
694
694
|
preferred: 'MStatus',
|
|
695
695
|
chip: 'MTag',
|
|
696
|
+
badge: 'MBadge',
|
|
697
|
+
entity: 'MChip',
|
|
696
698
|
mapping: { active: 'success', pending: 'warn', disabled: 'secondary', error: 'danger' },
|
|
697
|
-
note: '行内轻量状态用 MStatus
|
|
699
|
+
note: '行内轻量状态用 MStatus;分类或可关闭标签用 MTag;数量角标用 MBadge;可移除实体用 MChip',
|
|
698
700
|
},
|
|
699
701
|
feedback: {
|
|
700
702
|
default: 'message',
|
|
@@ -726,7 +728,7 @@ export const designRules = {
|
|
|
726
728
|
'MMessage 组件当前主要为 message 服务宿主,勿臆造 severity 子节点 API',
|
|
727
729
|
],
|
|
728
730
|
},
|
|
729
|
-
doc: '
|
|
731
|
+
doc: 'design-kit/.agents/skills/morya-ui-pages/references/feedback.md',
|
|
730
732
|
},
|
|
731
733
|
global: [
|
|
732
734
|
'优先使用组件库组件和 --m-* Token',
|
package/dist/tools.js
CHANGED
|
@@ -933,8 +933,8 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
933
933
|
standardId: 'layout-shell',
|
|
934
934
|
type: 'height-chain',
|
|
935
935
|
message: locale === 'en-US'
|
|
936
|
-
? 'Prefer layout-app-shell / golden pages:
|
|
937
|
-
: '对齐 layout-app-shell /
|
|
936
|
+
? 'Prefer layout-app-shell / golden pages: with MLayout, set html, body, #app { height: 100% } when the shell is not using fillViewport.'
|
|
937
|
+
: '对齐 layout-app-shell / 黄金样例:未使用 fillViewport 时,配合 MLayout 设置 html, body, #app { height: 100% }。',
|
|
938
938
|
});
|
|
939
939
|
}
|
|
940
940
|
if (/<MMenu\b/i.test(code)) {
|
|
@@ -1003,13 +1003,25 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
1003
1003
|
destructive: { component: 'MButton', props: ['severity="danger"'], requiresConfirmation: true },
|
|
1004
1004
|
cancel: { component: 'MButton', props: ['severity="secondary"', 'text'] },
|
|
1005
1005
|
},
|
|
1006
|
-
status: {
|
|
1006
|
+
status: {
|
|
1007
|
+
preferred: 'MStatus',
|
|
1008
|
+
chip: 'MTag',
|
|
1009
|
+
badge: 'MBadge',
|
|
1010
|
+
entity: 'MChip',
|
|
1011
|
+
mapping: { active: 'success', pending: 'warn', disabled: 'secondary', error: 'danger' },
|
|
1012
|
+
note: 'Inline status uses MStatus; category or closable labels use MTag; counts use MBadge.',
|
|
1013
|
+
},
|
|
1007
1014
|
feedback: {
|
|
1008
1015
|
default: 'message',
|
|
1009
1016
|
message: { when: ['single-line action result', 'save/delete/create confirmations'] },
|
|
1010
1017
|
toast: { when: ['summary + detail', 'async or background notifications'] },
|
|
1011
|
-
|
|
1012
|
-
|
|
1018
|
+
empty: { component: 'MEmpty', when: ['no rows', 'no filter matches', 'first use'] },
|
|
1019
|
+
result: { component: 'MResult', when: ['terminal success/failure', '403 / 404 / 500'] },
|
|
1020
|
+
inlineMessage: {
|
|
1021
|
+
api: 'field errorMessage | token-styled role=alert',
|
|
1022
|
+
when: ['persistent form/auth errors; MMessage is the message host, not an inline alert'],
|
|
1023
|
+
},
|
|
1024
|
+
doc: 'design-kit/.agents/skills/morya-ui-pages/references/feedback.md',
|
|
1013
1025
|
},
|
|
1014
1026
|
global: [
|
|
1015
1027
|
'Prefer library components and --m-* tokens.',
|
|
@@ -1104,6 +1116,14 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
1104
1116
|
install: 'pnpm add morya-ui',
|
|
1105
1117
|
peer: 'vue@^3.3.0',
|
|
1106
1118
|
styles: "import 'morya-ui/styles.css'",
|
|
1119
|
+
aiSetup: {
|
|
1120
|
+
command: 'npx @morya-ui/setup',
|
|
1121
|
+
skill: 'morya-ui-pages',
|
|
1122
|
+
mcp: 'npx -y @morya-ui/mcp',
|
|
1123
|
+
note: locale === 'en-US'
|
|
1124
|
+
? 'setup installs the library, copies the page skill and Cursor rules, and merges MCP. Table data uses the rows prop. MMessage is the message host, not an inline alert.'
|
|
1125
|
+
: 'setup 会安装组件库、复制页面 skill 与 Cursor 规则,并合并 MCP。表格数据用 rows。MMessage 是 message 宿主,不是内嵌 Alert。',
|
|
1126
|
+
},
|
|
1107
1127
|
guides: {
|
|
1108
1128
|
introduction: pickMarkdown(intro),
|
|
1109
1129
|
quickStart: pickMarkdown(quickStart),
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@morya-ui/mcp",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.9",
|
|
5
5
|
"description": "MCP server for morya-ui — component docs, examples, and usage guidance for AI coding agents.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://github.com/morya-space/morya-ui/tree/main/packages/ui-mcp#readme",
|