@morya-ui/mcp 0.3.2 → 0.3.4
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 +151 -149
- package/bin/morya-ui-mcp.js +2 -2
- package/data/catalog.json +70 -53
- package/data/example-coverage.json +8 -6
- package/data/golden-pages/dashboard-page.vue +138 -138
- package/data/golden-pages/detail-page.vue +178 -178
- package/data/golden-pages/empty-state.vue +56 -56
- package/data/golden-pages/form-in-dialog.vue +166 -166
- package/data/golden-pages/form-page.vue +107 -107
- package/data/golden-pages/landing-page.vue +358 -358
- package/data/golden-pages/list-page-dense.vue +166 -0
- package/data/golden-pages/list-page-rail.vue +270 -0
- package/data/golden-pages/list-page.vue +220 -216
- package/data/golden-pages/login-page.vue +231 -231
- package/data/golden-pages/result-page.vue +84 -84
- package/data/golden-pages/settings-page.vue +163 -163
- package/data/golden-pages/wizard-form.vue +182 -182
- package/dist/__tests__/tools.test.js +93 -1
- package/dist/decisions.d.ts +14 -0
- package/dist/decisions.js +818 -41
- package/dist/golden-pages.d.ts +13 -0
- package/dist/golden-pages.js +55 -2
- package/dist/index.js +9 -3
- package/dist/page-snippets.js +254 -225
- package/dist/patterns.d.ts +2 -2
- package/dist/patterns.js +20 -9
- package/dist/style-presets.d.ts +52 -0
- package/dist/style-presets.js +322 -0
- package/dist/tools.d.ts +20 -0
- package/dist/tools.js +336 -216
- package/package.json +16 -12
- package/LICENSE +0 -21
package/dist/tools.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { findComponent, findGuide, loadCatalog, normalizeName, resolveLocale, textResult, toKebab, } from './catalog.js';
|
|
2
2
|
import { componentDecisions, findDecision, scoreDecision } from './decisions.js';
|
|
3
|
-
import { listGoldenPages, readGoldenPageSource } from './golden-pages.js';
|
|
3
|
+
import { listGoldenPages, readGoldenPageSource, resolveGoldenPageId } from './golden-pages.js';
|
|
4
4
|
import { filterPageSnippets, findPageSnippet, pageSnippets, scorePageSnippet } from './page-snippets.js';
|
|
5
5
|
import { designRules, findPattern, pagePatterns, scorePattern } from './patterns.js';
|
|
6
6
|
import { countCatalogResources, countCatalogResourceTemplates } from './resources.js';
|
|
7
|
+
import { findStylePreset, resolveStyleDirection, stylePresets, styleResolution, } from './style-presets.js';
|
|
7
8
|
function inspectButtonIconOnlyUsage(code, issues) {
|
|
8
9
|
const pairedTagRe = /<MButton\b([^>]*)>([\s\S]*?)<\/MButton>/gi;
|
|
9
10
|
let match = pairedTagRe.exec(code);
|
|
@@ -47,6 +48,25 @@ function pickLocale(record, locale) {
|
|
|
47
48
|
function vueName(name) {
|
|
48
49
|
return `M${name}`;
|
|
49
50
|
}
|
|
51
|
+
function mapDecisionOption(option, locale) {
|
|
52
|
+
const zh = locale !== 'en-US';
|
|
53
|
+
const recipe = {
|
|
54
|
+
props: zh ? option.recipe.props : option.recipe.propsEn,
|
|
55
|
+
...(option.recipe.slots?.length
|
|
56
|
+
? { slots: zh ? option.recipe.slots : option.recipe.slotsEn }
|
|
57
|
+
: {}),
|
|
58
|
+
...(option.recipe.events?.length
|
|
59
|
+
? { events: zh ? option.recipe.events : option.recipe.eventsEn }
|
|
60
|
+
: {}),
|
|
61
|
+
};
|
|
62
|
+
return {
|
|
63
|
+
component: option.component,
|
|
64
|
+
when: zh ? option.when : option.whenEn,
|
|
65
|
+
avoidWhen: zh ? option.avoidWhen : option.avoidWhenEn,
|
|
66
|
+
recipe,
|
|
67
|
+
antiPatterns: zh ? option.antiPatterns : option.antiPatternsEn,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
50
70
|
function generatedPageCode(patternId, intent, locale) {
|
|
51
71
|
const zh = locale === 'zh-CN';
|
|
52
72
|
const isList = patternId === 'admin-list';
|
|
@@ -73,149 +93,149 @@ function generatedPageCode(patternId, intent, locale) {
|
|
|
73
93
|
const wizardImports = isWizard ? ', MStepper, MSpace' : '';
|
|
74
94
|
const settingsImports = isSettings ? ', MTabs' : '';
|
|
75
95
|
const statusImports = isList || isDetail || isDashboard ? ', MStatus' : '';
|
|
76
|
-
const script = `<script setup lang="ts">
|
|
77
|
-
import { ref } from 'vue'
|
|
78
|
-
import { MButton, MCard, MConfigProvider, MInput, MTag, zhCN${layoutImports}${pageImports}${listImports}${formImports}${dashboardImports}${detailImports}${emptyImports}${wizardImports}${settingsImports}${statusImports} } from 'morya-ui'
|
|
79
|
-
|
|
80
|
-
const loading = ref(false)
|
|
81
|
-
const error = ref('')
|
|
82
|
-
const title = ${JSON.stringify(title)}
|
|
83
|
-
${isList ? `const keyword = ref('')
|
|
84
|
-
const rows = ref<Record<string, unknown>[]>([])
|
|
85
|
-
const columns = [{ key: 'name', label: '${zh ? '名称' : 'Name'}' }, { key: 'status', label: '${zh ? '状态' : 'Status'}' }]
|
|
86
|
-
` : ''}${isForm || isAuth || isWizard ? `const model = ref({ name: '' })
|
|
87
|
-
` : ''}${isDashboard ? `const metrics = ref([
|
|
88
|
-
{ label: '${zh ? '总用户' : 'Users'}', value: '0' },
|
|
89
|
-
{ label: '${zh ? '今日活跃' : 'Active today'}', value: '0' },
|
|
90
|
-
])
|
|
91
|
-
` : ''}${isSettings ? `const activeTab = ref('general')
|
|
92
|
-
const settingTabs = [{ label: '${zh ? '常规' : 'General'}', value: 'general' }]
|
|
93
|
-
` : ''}${isWizard ? `const activeStep = ref(0)
|
|
94
|
-
const wizardSteps = [{ label: '${zh ? '基本信息' : 'Details'}' }, { label: '${zh ? '确认' : 'Confirm'}' }]
|
|
95
|
-
` : ''}
|
|
96
|
-
|
|
97
|
-
async function submit() {
|
|
98
|
-
loading.value = true
|
|
99
|
-
error.value = ''
|
|
100
|
-
try {
|
|
101
|
-
// Replace with the page API request.
|
|
102
|
-
} finally {
|
|
103
|
-
loading.value = false
|
|
104
|
-
}
|
|
105
|
-
}
|
|
96
|
+
const script = `<script setup lang="ts">
|
|
97
|
+
import { ref } from 'vue'
|
|
98
|
+
import { MButton, MCard, MConfigProvider, MInput, MTag, zhCN${layoutImports}${pageImports}${listImports}${formImports}${dashboardImports}${detailImports}${emptyImports}${wizardImports}${settingsImports}${statusImports} } from 'morya-ui'
|
|
99
|
+
|
|
100
|
+
const loading = ref(false)
|
|
101
|
+
const error = ref('')
|
|
102
|
+
const title = ${JSON.stringify(title)}
|
|
103
|
+
${isList ? `const keyword = ref('')
|
|
104
|
+
const rows = ref<Record<string, unknown>[]>([])
|
|
105
|
+
const columns = [{ key: 'name', label: '${zh ? '名称' : 'Name'}' }, { key: 'status', label: '${zh ? '状态' : 'Status'}' }]
|
|
106
|
+
` : ''}${isForm || isAuth || isWizard ? `const model = ref({ name: '' })
|
|
107
|
+
` : ''}${isDashboard ? `const metrics = ref([
|
|
108
|
+
{ label: '${zh ? '总用户' : 'Users'}', value: '0' },
|
|
109
|
+
{ label: '${zh ? '今日活跃' : 'Active today'}', value: '0' },
|
|
110
|
+
])
|
|
111
|
+
` : ''}${isSettings ? `const activeTab = ref('general')
|
|
112
|
+
const settingTabs = [{ label: '${zh ? '常规' : 'General'}', value: 'general' }]
|
|
113
|
+
` : ''}${isWizard ? `const activeStep = ref(0)
|
|
114
|
+
const wizardSteps = [{ label: '${zh ? '基本信息' : 'Details'}' }, { label: '${zh ? '确认' : 'Confirm'}' }]
|
|
115
|
+
` : ''}
|
|
116
|
+
|
|
117
|
+
async function submit() {
|
|
118
|
+
loading.value = true
|
|
119
|
+
error.value = ''
|
|
120
|
+
try {
|
|
121
|
+
// Replace with the page API request.
|
|
122
|
+
} finally {
|
|
123
|
+
loading.value = false
|
|
124
|
+
}
|
|
125
|
+
}
|
|
106
126
|
</script>`;
|
|
107
|
-
const listContent = ` <MPageHeader :title="title">
|
|
108
|
-
<template #actions>
|
|
109
|
-
<MButton severity="primary">${zh ? '新建' : 'Create'}</MButton>
|
|
110
|
-
</template>
|
|
111
|
-
</MPageHeader>
|
|
112
|
-
<MPageFilters variant="filled" :aria-label="${zh ? '筛选' : 'Filters'}">
|
|
113
|
-
<MSpace wrap>
|
|
114
|
-
<MInput v-model="keyword" placeholder="${zh ? '搜索关键词' : 'Search keyword'}" clearable style="width: 14rem" />
|
|
115
|
-
<MButton severity="secondary">${zh ? '查询' : 'Search'}</MButton>
|
|
116
|
-
<MButton severity="secondary">${zh ? '重置' : 'Reset'}</MButton>
|
|
117
|
-
</MSpace>
|
|
118
|
-
</MPageFilters>
|
|
119
|
-
<MTable :columns="columns" :rows="rows" :loading="loading" paginator :rows-per-page="10" striped bordered row-key="id">
|
|
120
|
-
<template #cell-status="{ value }">
|
|
121
|
-
<MStatus :label="String(value ?? '')" :severity="value === 'active' ? 'success' : 'secondary'" />
|
|
122
|
-
</template>
|
|
123
|
-
<template #empty>
|
|
124
|
-
<MEmpty
|
|
125
|
-
:title="${zh ? '暂无数据' : 'No data yet'}"
|
|
126
|
-
:description="${zh ? '创建第一条记录开始使用。' : 'Create your first record to get started.'}"
|
|
127
|
-
>
|
|
128
|
-
<template #extra>
|
|
129
|
-
<MButton severity="primary">${zh ? '新建' : 'Create'}</MButton>
|
|
130
|
-
</template>
|
|
131
|
-
</MEmpty>
|
|
132
|
-
</template>
|
|
127
|
+
const listContent = ` <MPageHeader :title="title">
|
|
128
|
+
<template #actions>
|
|
129
|
+
<MButton severity="primary">${zh ? '新建' : 'Create'}</MButton>
|
|
130
|
+
</template>
|
|
131
|
+
</MPageHeader>
|
|
132
|
+
<MPageFilters variant="filled" :aria-label="${zh ? '筛选' : 'Filters'}">
|
|
133
|
+
<MSpace wrap>
|
|
134
|
+
<MInput v-model="keyword" placeholder="${zh ? '搜索关键词' : 'Search keyword'}" clearable style="width: 14rem" />
|
|
135
|
+
<MButton severity="secondary">${zh ? '查询' : 'Search'}</MButton>
|
|
136
|
+
<MButton severity="secondary">${zh ? '重置' : 'Reset'}</MButton>
|
|
137
|
+
</MSpace>
|
|
138
|
+
</MPageFilters>
|
|
139
|
+
<MTable :columns="columns" :rows="rows" :loading="loading" fill paginator :rows-per-page="10" striped bordered row-key="id">
|
|
140
|
+
<template #cell-status="{ value }">
|
|
141
|
+
<MStatus :label="String(value ?? '')" :severity="value === 'active' ? 'success' : 'secondary'" />
|
|
142
|
+
</template>
|
|
143
|
+
<template #empty>
|
|
144
|
+
<MEmpty
|
|
145
|
+
:title="${zh ? '暂无数据' : 'No data yet'}"
|
|
146
|
+
:description="${zh ? '创建第一条记录开始使用。' : 'Create your first record to get started.'}"
|
|
147
|
+
>
|
|
148
|
+
<template #extra>
|
|
149
|
+
<MButton severity="primary">${zh ? '新建' : 'Create'}</MButton>
|
|
150
|
+
</template>
|
|
151
|
+
</MEmpty>
|
|
152
|
+
</template>
|
|
133
153
|
</MTable>`;
|
|
134
|
-
const formContent = ` <MPageHeader :title="title" :description="${zh ? '填写表单并保存。' : 'Fill in the form and save.'}" />
|
|
135
|
-
<MPageSection variant="form">
|
|
136
|
-
<MForm @submit.prevent="submit">
|
|
137
|
-
<MFormItem label="${zh ? '名称' : 'Name'}" name="name" required>
|
|
138
|
-
<MInput v-model="model.name" fluid />
|
|
139
|
-
</MFormItem>
|
|
140
|
-
<MPageSection variant="actions">
|
|
141
|
-
<MButton native-type="submit" severity="primary" :loading="loading">${zh ? '保存' : 'Save'}</MButton>
|
|
142
|
-
<MButton severity="secondary">${zh ? '取消' : 'Cancel'}</MButton>
|
|
143
|
-
</MPageSection>
|
|
144
|
-
</MForm>
|
|
154
|
+
const formContent = ` <MPageHeader :title="title" :description="${zh ? '填写表单并保存。' : 'Fill in the form and save.'}" />
|
|
155
|
+
<MPageSection variant="form">
|
|
156
|
+
<MForm @submit.prevent="submit">
|
|
157
|
+
<MFormItem label="${zh ? '名称' : 'Name'}" name="name" required>
|
|
158
|
+
<MInput v-model="model.name" fluid />
|
|
159
|
+
</MFormItem>
|
|
160
|
+
<MPageSection variant="actions">
|
|
161
|
+
<MButton native-type="submit" severity="primary" :loading="loading">${zh ? '保存' : 'Save'}</MButton>
|
|
162
|
+
<MButton severity="secondary">${zh ? '取消' : 'Cancel'}</MButton>
|
|
163
|
+
</MPageSection>
|
|
164
|
+
</MForm>
|
|
145
165
|
</MPageSection>`;
|
|
146
|
-
const dashboardContent = ` <MPageHeader :title="title" />
|
|
147
|
-
<MGrid :cols="2" :x-gap="16" :y-gap="16" responsive="screen">
|
|
148
|
-
<MGridItem v-for="metric in metrics" :key="metric.label" :span="1">
|
|
149
|
-
<MPageStat :label="metric.label" :value="metric.value" icon="activity" />
|
|
150
|
-
</MGridItem>
|
|
151
|
-
</MGrid>
|
|
152
|
-
<MCard shadow="always" :title="${zh ? '趋势概览' : 'Trend overview'}">
|
|
153
|
-
<MSkeleton v-if="loading" height="8rem" />
|
|
154
|
-
<MEmpty
|
|
155
|
-
v-else
|
|
156
|
-
:title="${zh ? '暂无图表数据' : 'No chart data yet'}"
|
|
157
|
-
:description="${zh ? '接入图表或业务组件。' : 'Connect charts or business widgets here.'}"
|
|
158
|
-
aria-label="${zh ? '图表占位' : 'Chart placeholder'}"
|
|
159
|
-
/>
|
|
166
|
+
const dashboardContent = ` <MPageHeader :title="title" />
|
|
167
|
+
<MGrid :cols="2" :x-gap="16" :y-gap="16" responsive="screen">
|
|
168
|
+
<MGridItem v-for="metric in metrics" :key="metric.label" :span="1">
|
|
169
|
+
<MPageStat :label="metric.label" :value="metric.value" icon="activity" />
|
|
170
|
+
</MGridItem>
|
|
171
|
+
</MGrid>
|
|
172
|
+
<MCard shadow="always" :title="${zh ? '趋势概览' : 'Trend overview'}">
|
|
173
|
+
<MSkeleton v-if="loading" height="8rem" />
|
|
174
|
+
<MEmpty
|
|
175
|
+
v-else
|
|
176
|
+
:title="${zh ? '暂无图表数据' : 'No chart data yet'}"
|
|
177
|
+
:description="${zh ? '接入图表或业务组件。' : 'Connect charts or business widgets here.'}"
|
|
178
|
+
aria-label="${zh ? '图表占位' : 'Chart placeholder'}"
|
|
179
|
+
/>
|
|
160
180
|
</MCard>`;
|
|
161
|
-
const detailContent = ` <MPageHeader :title="title" :description="${zh ? '查看资源摘要与属性。' : 'Review summary and properties.'}">
|
|
162
|
-
<template #actions>
|
|
163
|
-
<MSpace>
|
|
164
|
-
<MStatus :label="${zh ? '启用' : 'Active'}" severity="success" />
|
|
165
|
-
<MButton severity="primary">${zh ? '编辑' : 'Edit'}</MButton>
|
|
166
|
-
<MButton severity="secondary">${zh ? '返回' : 'Back'}</MButton>
|
|
167
|
-
</MSpace>
|
|
168
|
-
</template>
|
|
169
|
-
</MPageHeader>
|
|
170
|
-
<MCard :title="${zh ? '基本信息' : 'Basics'}">
|
|
171
|
-
<p style="margin:0;color:var(--m-color-text-muted)">${zh ? '用定义列表或网格展示属性;相关列表用 MTable + rows。' : 'Use a definition grid; related lists use MTable + rows.'}</p>
|
|
181
|
+
const detailContent = ` <MPageHeader :title="title" :description="${zh ? '查看资源摘要与属性。' : 'Review summary and properties.'}">
|
|
182
|
+
<template #actions>
|
|
183
|
+
<MSpace>
|
|
184
|
+
<MStatus :label="${zh ? '启用' : 'Active'}" severity="success" />
|
|
185
|
+
<MButton severity="primary">${zh ? '编辑' : 'Edit'}</MButton>
|
|
186
|
+
<MButton severity="secondary">${zh ? '返回' : 'Back'}</MButton>
|
|
187
|
+
</MSpace>
|
|
188
|
+
</template>
|
|
189
|
+
</MPageHeader>
|
|
190
|
+
<MCard :title="${zh ? '基本信息' : 'Basics'}">
|
|
191
|
+
<p style="margin:0;color:var(--m-color-text-muted)">${zh ? '用定义列表或网格展示属性;相关列表用 MTable + rows。' : 'Use a definition grid; related lists use MTable + rows.'}</p>
|
|
172
192
|
</MCard>`;
|
|
173
|
-
const settingsContent = ` <MPageHeader :title="title" :description="${zh ? '按域分组配置偏好。' : 'Grouped preference settings.'}" />
|
|
174
|
-
<MTabs v-model="activeTab" :tabs="settingTabs">
|
|
175
|
-
<template #default="{ activeValue }">
|
|
176
|
-
<MPageSection v-if="activeValue === 'general'" variant="form" :title="${zh ? '常规' : 'General'}">
|
|
177
|
-
<MForm @submit.prevent="submit">
|
|
178
|
-
<MFormItem label="${zh ? '显示名称' : 'Display name'}" name="name" required>
|
|
179
|
-
<MInput v-model="model.name" fluid />
|
|
180
|
-
</MFormItem>
|
|
181
|
-
<MPageSection variant="actions">
|
|
182
|
-
<MButton native-type="submit" severity="primary" :loading="loading">${zh ? '保存' : 'Save'}</MButton>
|
|
183
|
-
</MPageSection>
|
|
184
|
-
</MForm>
|
|
185
|
-
</MPageSection>
|
|
186
|
-
</template>
|
|
193
|
+
const settingsContent = ` <MPageHeader :title="title" :description="${zh ? '按域分组配置偏好。' : 'Grouped preference settings.'}" />
|
|
194
|
+
<MTabs v-model="activeTab" :tabs="settingTabs">
|
|
195
|
+
<template #default="{ activeValue }">
|
|
196
|
+
<MPageSection v-if="activeValue === 'general'" variant="form" :title="${zh ? '常规' : 'General'}">
|
|
197
|
+
<MForm @submit.prevent="submit">
|
|
198
|
+
<MFormItem label="${zh ? '显示名称' : 'Display name'}" name="name" required>
|
|
199
|
+
<MInput v-model="model.name" fluid />
|
|
200
|
+
</MFormItem>
|
|
201
|
+
<MPageSection variant="actions">
|
|
202
|
+
<MButton native-type="submit" severity="primary" :loading="loading">${zh ? '保存' : 'Save'}</MButton>
|
|
203
|
+
</MPageSection>
|
|
204
|
+
</MForm>
|
|
205
|
+
</MPageSection>
|
|
206
|
+
</template>
|
|
187
207
|
</MTabs>`;
|
|
188
|
-
const wizardContent = ` <MPageHeader :title="title" :description="${zh ? '每步一个主任务。' : 'One job per step.'}" />
|
|
189
|
-
<MStepper v-model="activeStep" :steps="wizardSteps" linear />
|
|
190
|
-
<MPageSection variant="form">
|
|
191
|
-
<MForm @submit.prevent="submit">
|
|
192
|
-
<MFormItem label="${zh ? '名称' : 'Name'}" name="name" required>
|
|
193
|
-
<MInput v-model="model.name" fluid />
|
|
194
|
-
</MFormItem>
|
|
195
|
-
<MPageSection variant="actions">
|
|
196
|
-
<MSpace>
|
|
197
|
-
<MButton severity="secondary" text :disabled="activeStep === 0" @click="activeStep = Math.max(activeStep - 1, 0)">${zh ? '上一步' : 'Back'}</MButton>
|
|
198
|
-
<MButton native-type="submit" severity="primary" :loading="loading">${zh ? '下一步' : 'Next'}</MButton>
|
|
199
|
-
</MSpace>
|
|
200
|
-
</MPageSection>
|
|
201
|
-
</MForm>
|
|
208
|
+
const wizardContent = ` <MPageHeader :title="title" :description="${zh ? '每步一个主任务。' : 'One job per step.'}" />
|
|
209
|
+
<MStepper v-model="activeStep" :steps="wizardSteps" linear />
|
|
210
|
+
<MPageSection variant="form">
|
|
211
|
+
<MForm @submit.prevent="submit">
|
|
212
|
+
<MFormItem label="${zh ? '名称' : 'Name'}" name="name" required>
|
|
213
|
+
<MInput v-model="model.name" fluid />
|
|
214
|
+
</MFormItem>
|
|
215
|
+
<MPageSection variant="actions">
|
|
216
|
+
<MSpace>
|
|
217
|
+
<MButton severity="secondary" text :disabled="activeStep === 0" @click="activeStep = Math.max(activeStep - 1, 0)">${zh ? '上一步' : 'Back'}</MButton>
|
|
218
|
+
<MButton native-type="submit" severity="primary" :loading="loading">${zh ? '下一步' : 'Next'}</MButton>
|
|
219
|
+
</MSpace>
|
|
220
|
+
</MPageSection>
|
|
221
|
+
</MForm>
|
|
202
222
|
</MPageSection>`;
|
|
203
223
|
let innerTemplate = '';
|
|
204
224
|
if (isList) {
|
|
205
|
-
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
206
|
-
<MLayout has-sider fill-viewport>
|
|
207
|
-
<MLayoutSider bordered />
|
|
208
|
-
<MLayout>
|
|
209
|
-
<MLayoutHeader :padding="'var(--m-space-4) var(--m-space-6)'">
|
|
210
|
-
<MBreadcrumb :model="[{ label: '${zh ? '首页' : 'Home'}', to: '/' }, { label: '${title}' }]" />
|
|
211
|
-
</MLayoutHeader>
|
|
212
|
-
<MLayoutContent>
|
|
213
|
-
<MPageContent>
|
|
214
|
-
${listContent}
|
|
215
|
-
</MPageContent>
|
|
216
|
-
</MLayoutContent>
|
|
217
|
-
</MLayout>
|
|
218
|
-
</MLayout>
|
|
225
|
+
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
226
|
+
<MLayout has-sider fill-viewport>
|
|
227
|
+
<MLayoutSider bordered />
|
|
228
|
+
<MLayout>
|
|
229
|
+
<MLayoutHeader :padding="'var(--m-space-4) var(--m-space-6)'">
|
|
230
|
+
<MBreadcrumb :model="[{ label: '${zh ? '首页' : 'Home'}', to: '/' }, { label: '${title}' }]" />
|
|
231
|
+
</MLayoutHeader>
|
|
232
|
+
<MLayoutContent>
|
|
233
|
+
<MPageContent fill>
|
|
234
|
+
${listContent}
|
|
235
|
+
</MPageContent>
|
|
236
|
+
</MLayoutContent>
|
|
237
|
+
</MLayout>
|
|
238
|
+
</MLayout>
|
|
219
239
|
</MConfigProvider>`;
|
|
220
240
|
}
|
|
221
241
|
else if (useLayoutShell) {
|
|
@@ -229,76 +249,76 @@ ${listContent}
|
|
|
229
249
|
? wizardContent
|
|
230
250
|
: formContent;
|
|
231
251
|
const pageContentAttrs = isForm || isSettings || isWizard ? ' width="narrow"' : isDashboard ? ' density="spacious"' : '';
|
|
232
|
-
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
233
|
-
<MLayout fill-viewport>
|
|
234
|
-
<MLayoutHeader :padding="'var(--m-space-4) var(--m-space-6)'">
|
|
235
|
-
<MBreadcrumb :model="[{ label: '${zh ? '首页' : 'Home'}', to: '/' }, { label: title }]" />
|
|
236
|
-
</MLayoutHeader>
|
|
237
|
-
<MLayoutContent>
|
|
238
|
-
<MPageContent${pageContentAttrs}>
|
|
239
|
-
${content}
|
|
240
|
-
</MPageContent>
|
|
241
|
-
</MLayoutContent>
|
|
242
|
-
</MLayout>
|
|
252
|
+
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
253
|
+
<MLayout fill-viewport>
|
|
254
|
+
<MLayoutHeader :padding="'var(--m-space-4) var(--m-space-6)'">
|
|
255
|
+
<MBreadcrumb :model="[{ label: '${zh ? '首页' : 'Home'}', to: '/' }, { label: title }]" />
|
|
256
|
+
</MLayoutHeader>
|
|
257
|
+
<MLayoutContent>
|
|
258
|
+
<MPageContent${pageContentAttrs}>
|
|
259
|
+
${content}
|
|
260
|
+
</MPageContent>
|
|
261
|
+
</MLayoutContent>
|
|
262
|
+
</MLayout>
|
|
243
263
|
</MConfigProvider>`;
|
|
244
264
|
}
|
|
245
265
|
else if (isAuth) {
|
|
246
|
-
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
247
|
-
<main class="m-generated-page m-generated-auth">
|
|
248
|
-
<MCard>
|
|
249
|
-
<MForm label-position="top" @submit.prevent="submit">
|
|
250
|
-
<MFormItem label="${zh ? '邮箱' : 'Email'}" name="email">
|
|
251
|
-
<MInput type="email" fluid />
|
|
252
|
-
</MFormItem>
|
|
253
|
-
<MFormItem label="${zh ? '密码' : 'Password'}" name="password">
|
|
254
|
-
<MInput type="password" fluid />
|
|
255
|
-
</MFormItem>
|
|
256
|
-
<MButton native-type="submit" severity="primary" :loading="loading" fluid>${zh ? '登录' : 'Sign in'}</MButton>
|
|
257
|
-
</MForm>
|
|
258
|
-
</MCard>
|
|
259
|
-
</main>
|
|
266
|
+
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
267
|
+
<main class="m-generated-page m-generated-auth">
|
|
268
|
+
<MCard>
|
|
269
|
+
<MForm label-position="top" @submit.prevent="submit">
|
|
270
|
+
<MFormItem label="${zh ? '邮箱' : 'Email'}" name="email">
|
|
271
|
+
<MInput type="email" fluid />
|
|
272
|
+
</MFormItem>
|
|
273
|
+
<MFormItem label="${zh ? '密码' : 'Password'}" name="password">
|
|
274
|
+
<MInput type="password" fluid />
|
|
275
|
+
</MFormItem>
|
|
276
|
+
<MButton native-type="submit" severity="primary" :loading="loading" fluid>${zh ? '登录' : 'Sign in'}</MButton>
|
|
277
|
+
</MForm>
|
|
278
|
+
</MCard>
|
|
279
|
+
</main>
|
|
260
280
|
</MConfigProvider>`;
|
|
261
281
|
}
|
|
262
282
|
else if (isEmpty) {
|
|
263
|
-
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
264
|
-
<main class="m-generated-page">
|
|
265
|
-
<MPageContent>
|
|
266
|
-
<MPageHeader :title="title">
|
|
267
|
-
<template #actions>
|
|
268
|
-
<MButton severity="primary" @click="submit">${zh ? '新建' : 'Create'}</MButton>
|
|
269
|
-
</template>
|
|
270
|
-
</MPageHeader>
|
|
271
|
-
<MEmpty
|
|
272
|
-
:title="${zh ? '暂无内容' : 'Nothing here yet'}"
|
|
273
|
-
:description="${zh ? '创建第一条记录开始使用。' : 'Create your first record to get started.'}"
|
|
274
|
-
icon="database"
|
|
275
|
-
>
|
|
276
|
-
<template #extra>
|
|
277
|
-
<MButton severity="primary" @click="submit">${zh ? '创建' : 'Create'}</MButton>
|
|
278
|
-
</template>
|
|
279
|
-
</MEmpty>
|
|
280
|
-
</MPageContent>
|
|
281
|
-
</main>
|
|
283
|
+
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
284
|
+
<main class="m-generated-page">
|
|
285
|
+
<MPageContent>
|
|
286
|
+
<MPageHeader :title="title">
|
|
287
|
+
<template #actions>
|
|
288
|
+
<MButton severity="primary" @click="submit">${zh ? '新建' : 'Create'}</MButton>
|
|
289
|
+
</template>
|
|
290
|
+
</MPageHeader>
|
|
291
|
+
<MEmpty
|
|
292
|
+
:title="${zh ? '暂无内容' : 'Nothing here yet'}"
|
|
293
|
+
:description="${zh ? '创建第一条记录开始使用。' : 'Create your first record to get started.'}"
|
|
294
|
+
icon="database"
|
|
295
|
+
>
|
|
296
|
+
<template #extra>
|
|
297
|
+
<MButton severity="primary" @click="submit">${zh ? '创建' : 'Create'}</MButton>
|
|
298
|
+
</template>
|
|
299
|
+
</MEmpty>
|
|
300
|
+
</MPageContent>
|
|
301
|
+
</main>
|
|
282
302
|
</MConfigProvider>`;
|
|
283
303
|
}
|
|
284
304
|
else {
|
|
285
|
-
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
286
|
-
<main class="m-generated-page">
|
|
287
|
-
<MCard>
|
|
288
|
-
<p class="m-generated-muted">${zh ? '将此区域替换为页面内容。' : 'Replace this area with page content.'}</p>
|
|
289
|
-
<MTag value="${zh ? '示例' : 'Example'}" severity="info" />
|
|
290
|
-
</MCard>
|
|
291
|
-
</main>
|
|
305
|
+
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
306
|
+
<main class="m-generated-page">
|
|
307
|
+
<MCard>
|
|
308
|
+
<p class="m-generated-muted">${zh ? '将此区域替换为页面内容。' : 'Replace this area with page content.'}</p>
|
|
309
|
+
<MTag value="${zh ? '示例' : 'Example'}" severity="info" />
|
|
310
|
+
</MCard>
|
|
311
|
+
</main>
|
|
292
312
|
</MConfigProvider>`;
|
|
293
313
|
}
|
|
294
|
-
const template = `<template>
|
|
295
|
-
${innerTemplate}
|
|
296
|
-
<p v-if="error" role="alert" class="m-generated-error">${'{{ error }}'}</p>
|
|
314
|
+
const template = `<template>
|
|
315
|
+
${innerTemplate}
|
|
316
|
+
<p v-if="error" role="alert" class="m-generated-error">${'{{ error }}'}</p>
|
|
297
317
|
</template>`;
|
|
298
|
-
const style = `<style scoped>
|
|
299
|
-
.m-generated-auth { display: grid; place-items: center; padding: var(--m-space-8); max-width: 24rem; margin: 0 auto; min-height: 100vh; }
|
|
300
|
-
.m-generated-empty { display: grid; gap: var(--m-space-2); justify-items: center; padding: var(--m-space-8); text-align: center; }
|
|
301
|
-
.m-generated-error { color: var(--m-color-danger); padding: 0 var(--m-space-6); }
|
|
318
|
+
const style = `<style scoped>
|
|
319
|
+
.m-generated-auth { display: grid; place-items: center; padding: var(--m-space-8); max-width: 24rem; margin: 0 auto; min-height: 100vh; }
|
|
320
|
+
.m-generated-empty { display: grid; gap: var(--m-space-2); justify-items: center; padding: var(--m-space-8); text-align: center; }
|
|
321
|
+
.m-generated-error { color: var(--m-color-danger); padding: 0 var(--m-space-6); }
|
|
302
322
|
</style>`;
|
|
303
323
|
return { script, template, style };
|
|
304
324
|
}
|
|
@@ -710,13 +730,47 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
710
730
|
});
|
|
711
731
|
}
|
|
712
732
|
const locale = resolveLocale(args.mode);
|
|
733
|
+
const styleDirection = resolveStyleDirection({ intent: args.intent, style: args.style });
|
|
734
|
+
const stylePayload = {
|
|
735
|
+
resolution: styleDirection.resolution,
|
|
736
|
+
confidence: styleDirection.confidence,
|
|
737
|
+
preset: styleDirection.preset
|
|
738
|
+
? {
|
|
739
|
+
id: styleDirection.preset.id,
|
|
740
|
+
title: locale === 'en-US' ? styleDirection.preset.titleEn : styleDirection.preset.title,
|
|
741
|
+
summary: locale === 'en-US' ? styleDirection.preset.summaryEn : styleDirection.preset.summary,
|
|
742
|
+
apply: locale === 'en-US' ? styleDirection.preset.applyEn : styleDirection.preset.apply,
|
|
743
|
+
avoid: locale === 'en-US' ? styleDirection.preset.avoidEn : styleDirection.preset.avoid,
|
|
744
|
+
}
|
|
745
|
+
: null,
|
|
746
|
+
candidates: styleDirection.candidates.map((item) => ({
|
|
747
|
+
id: item.id,
|
|
748
|
+
title: locale === 'en-US' ? item.titleEn : item.title,
|
|
749
|
+
score: item.score,
|
|
750
|
+
})),
|
|
751
|
+
guidance: locale === 'en-US' ? styleDirection.guidanceEn : styleDirection.guidanceZh,
|
|
752
|
+
priority: locale === 'en-US' ? styleResolution.priorityEn : styleResolution.priorityZh,
|
|
753
|
+
note: locale === 'en-US'
|
|
754
|
+
? 'If the user supplied a visual reference, follow that first (map to --m-* + M*). Golden pages lock structure, not the only aesthetic.'
|
|
755
|
+
: '若用户提供了参考样式,优先跟参考(映射到 --m-* + M*)。黄金样例锁结构,不是唯一审美。',
|
|
756
|
+
};
|
|
757
|
+
const resolvedGoldenId = resolveGoldenPageId({
|
|
758
|
+
patternId: best.pattern.id,
|
|
759
|
+
canonicalGoldenId: best.pattern.goldenPage,
|
|
760
|
+
styleId: styleDirection.preset?.id || args.style || null,
|
|
761
|
+
});
|
|
762
|
+
const resolvedGoldenPath = resolvedGoldenId
|
|
763
|
+
? `docs/golden-pages/${resolvedGoldenId}.vue`
|
|
764
|
+
: best.pattern.goldenPage;
|
|
713
765
|
const result = {
|
|
714
766
|
intent: args.intent,
|
|
715
767
|
pageType: args.pageType,
|
|
768
|
+
style: args.style,
|
|
716
769
|
matchedPattern: best.pattern.id,
|
|
717
770
|
title: locale === 'en-US' ? best.pattern.titleEn : best.pattern.title,
|
|
718
771
|
confidence: best.score,
|
|
719
|
-
goldenPage:
|
|
772
|
+
goldenPage: resolvedGoldenPath,
|
|
773
|
+
styleDirection: stylePayload,
|
|
720
774
|
components: best.pattern.components,
|
|
721
775
|
structure: best.pattern.structure,
|
|
722
776
|
layout: best.pattern.layout,
|
|
@@ -725,23 +779,26 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
725
779
|
avoid: best.pattern.avoid,
|
|
726
780
|
alternatives: ranked.slice(1, 3).filter((item) => item.score > 0).map((item) => ({ id: item.pattern.id, score: item.score })),
|
|
727
781
|
nextStep: (() => {
|
|
728
|
-
const goldenId =
|
|
729
|
-
|
|
730
|
-
|
|
782
|
+
const goldenId = resolvedGoldenId;
|
|
783
|
+
const styleHint = locale === 'en-US'
|
|
784
|
+
? styleDirection.resolution === 'offer'
|
|
785
|
+
? ' Resolve style first (reference → preset → ask among quiet/soft/dense/rail/studio/ink).'
|
|
786
|
+
: ` Apply styleDirection preset "${styleDirection.preset?.id || 'n/a'}".`
|
|
787
|
+
: styleDirection.resolution === 'offer'
|
|
788
|
+
? ' 先定风格(参考 → 预设 → 请用户从 quiet/soft/dense/rail/studio/ink 选)。'
|
|
789
|
+
: ` 套用 styleDirection 预设「${styleDirection.preset?.id || 'n/a'}」。`;
|
|
731
790
|
if (locale === 'en-US') {
|
|
732
791
|
return goldenId
|
|
733
|
-
? `Call get_golden_page("${goldenId}") and mirror
|
|
734
|
-
: `No golden page for this pattern: use get_pattern + get_design_rules
|
|
792
|
+
? `Call get_golden_page("${goldenId}") and mirror structure.${styleHint} Look up unfamiliar APIs with get_component/get_example, then always run validate_usage and validate_page.`
|
|
793
|
+
: `No golden page for this pattern: use get_pattern + get_design_rules.${styleHint} Look up APIs with get_component/get_example, then always run validate_usage and validate_page.`;
|
|
735
794
|
}
|
|
736
795
|
return goldenId
|
|
737
|
-
? `调用 get_golden_page("${goldenId}")
|
|
738
|
-
: `该模式暂无黄金样例:用 get_pattern + get_design_rules
|
|
796
|
+
? `调用 get_golden_page("${goldenId}") 并镜像结构。${styleHint} 不熟悉的 API 用 get_component/get_example 核对,然后必须跑 validate_usage 与 validate_page。`
|
|
797
|
+
: `该模式暂无黄金样例:用 get_pattern + get_design_rules。${styleHint} API 用 get_component/get_example 核对,然后必须跑 validate_usage 与 validate_page。`;
|
|
739
798
|
})(),
|
|
740
799
|
};
|
|
741
800
|
if (args.includeScaffold) {
|
|
742
|
-
const goldenId =
|
|
743
|
-
listGoldenPages().find((item) => item.patternId === best.pattern.id)?.id ||
|
|
744
|
-
null;
|
|
801
|
+
const goldenId = resolvedGoldenId;
|
|
745
802
|
const golden = goldenId ? readGoldenPageSource(goldenId) : null;
|
|
746
803
|
if (golden) {
|
|
747
804
|
result.scaffold = {
|
|
@@ -786,6 +843,8 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
786
843
|
patternId: payload.record.patternId,
|
|
787
844
|
title: locale === 'en-US' ? payload.record.titleEn : payload.record.title,
|
|
788
845
|
file: payload.record.file,
|
|
846
|
+
style: payload.record.style ?? null,
|
|
847
|
+
variantOf: payload.record.variantOf ?? null,
|
|
789
848
|
source: payload.source,
|
|
790
849
|
nextStep: locale === 'en-US'
|
|
791
850
|
? 'Mirror this structure and replace business data. Look up unfamiliar APIs with get_component/get_example, then always run validate_usage and validate_page. See get_design_rules for page standards.'
|
|
@@ -800,6 +859,8 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
800
859
|
patternId: item.patternId,
|
|
801
860
|
title: locale === 'en-US' ? item.titleEn : item.title,
|
|
802
861
|
file: item.file,
|
|
862
|
+
style: item.style ?? null,
|
|
863
|
+
variantOf: item.variantOf ?? null,
|
|
803
864
|
})),
|
|
804
865
|
});
|
|
805
866
|
}
|
|
@@ -1014,6 +1075,19 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
1014
1075
|
: '契约:MTable 行数据使用 rows,不要用 data。见黄金样例 list-page / get_component Table。',
|
|
1015
1076
|
});
|
|
1016
1077
|
}
|
|
1078
|
+
if (/fill-viewport|fillViewport/i.test(code)
|
|
1079
|
+
&& /<MTable\b[^>]*\bpaginator\b/i.test(code)
|
|
1080
|
+
&& /<MPageContent\b/i.test(code)
|
|
1081
|
+
&& !(/<MPageContent\b[^>]*\bfill\b/i.test(code)
|
|
1082
|
+
&& /<MTable\b[^>]*\bfill\b/i.test(code))) {
|
|
1083
|
+
suggestions.push({
|
|
1084
|
+
standardId: 'page-sections',
|
|
1085
|
+
type: 'list-fill-height',
|
|
1086
|
+
message: locale === 'en-US'
|
|
1087
|
+
? 'Advisory: for a full-viewport admin list whose main job is one table, consider MPageContent fill + MTable fill so the body scrolls and pagination stays at the page bottom. Skip fill for embedded/short/document-scroll tables (see page-scroll-choice / golden list-page).'
|
|
1088
|
+
: '参考建议:若这是全视口后台主列表且表格是页面主任务,可考虑 MPageContent fill + MTable fill(表体滚动、分页贴底)。嵌入表/短页/整页文档滚动则跳过 fill(见 page-scroll-choice / 黄金样例 list-page)。',
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1017
1091
|
if (/<MMessage\b[^>]*\bseverity\b/i.test(code)) {
|
|
1018
1092
|
suggestions.push({
|
|
1019
1093
|
standardId: 'feedback',
|
|
@@ -1078,10 +1152,21 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
1078
1152
|
}
|
|
1079
1153
|
function getDesignRules(args = {}) {
|
|
1080
1154
|
const locale = resolveLocale(args.mode);
|
|
1155
|
+
const styles = {
|
|
1156
|
+
resolution: locale === 'en-US' ? styleResolution.priorityEn : styleResolution.priorityZh,
|
|
1157
|
+
hardRules: locale === 'en-US' ? styleResolution.hardRulesEn : styleResolution.hardRulesZh,
|
|
1158
|
+
presets: stylePresets.map((preset) => ({
|
|
1159
|
+
id: preset.id,
|
|
1160
|
+
title: locale === 'en-US' ? preset.titleEn : preset.title,
|
|
1161
|
+
summary: locale === 'en-US' ? preset.summaryEn : preset.summary,
|
|
1162
|
+
lanes: preset.lanes,
|
|
1163
|
+
})),
|
|
1164
|
+
};
|
|
1081
1165
|
if (locale === 'zh-CN') {
|
|
1082
1166
|
return textResult({
|
|
1083
1167
|
meta: designRules.meta,
|
|
1084
1168
|
standards: designRules.standards,
|
|
1169
|
+
styles,
|
|
1085
1170
|
tokens: designRules.tokens,
|
|
1086
1171
|
composition: designRules.composition,
|
|
1087
1172
|
actions: designRules.actions,
|
|
@@ -1099,6 +1184,7 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
1099
1184
|
discouraged: item.discouragedEn,
|
|
1100
1185
|
mcp: item.mcp,
|
|
1101
1186
|
})),
|
|
1187
|
+
styles,
|
|
1102
1188
|
tokens: {
|
|
1103
1189
|
colors: ['--m-color-primary', '--m-color-surface', '--m-color-text', '--m-color-border'],
|
|
1104
1190
|
spacing: '--m-space-*',
|
|
@@ -1140,9 +1226,47 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
1140
1226
|
'Form controls should have a visible label or an equivalent accessible name.',
|
|
1141
1227
|
'Overlays teleport to body by default; only change appendTo for a clear layout constraint.',
|
|
1142
1228
|
'Prefer documented component variants over deep CSS overrides.',
|
|
1229
|
+
'Resolve visual style via reference → preset → prompt cues → offer quiet/soft/dense/rail/studio/ink; golden pages lock structure, not aesthetics.',
|
|
1143
1230
|
],
|
|
1144
1231
|
});
|
|
1145
1232
|
}
|
|
1233
|
+
function listStylePresets(args = {}) {
|
|
1234
|
+
const locale = resolveLocale(args.mode);
|
|
1235
|
+
return textResult({
|
|
1236
|
+
resolution: locale === 'en-US' ? styleResolution.priorityEn : styleResolution.priorityZh,
|
|
1237
|
+
hardRules: locale === 'en-US' ? styleResolution.hardRulesEn : styleResolution.hardRulesZh,
|
|
1238
|
+
presets: stylePresets.map((preset) => ({
|
|
1239
|
+
id: preset.id,
|
|
1240
|
+
title: locale === 'en-US' ? preset.titleEn : preset.title,
|
|
1241
|
+
summary: locale === 'en-US' ? preset.summaryEn : preset.summary,
|
|
1242
|
+
lanes: preset.lanes,
|
|
1243
|
+
keywords: preset.keywords,
|
|
1244
|
+
listGoldenPage: preset.listGoldenPage ?? null,
|
|
1245
|
+
})),
|
|
1246
|
+
});
|
|
1247
|
+
}
|
|
1248
|
+
function getStylePreset(args) {
|
|
1249
|
+
const locale = resolveLocale(args.mode);
|
|
1250
|
+
const preset = findStylePreset(args.style);
|
|
1251
|
+
if (!preset) {
|
|
1252
|
+
return textResult({
|
|
1253
|
+
error: `Style preset not found: ${args.style}`,
|
|
1254
|
+
available: stylePresets.map((item) => item.id),
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
return textResult({
|
|
1258
|
+
id: preset.id,
|
|
1259
|
+
title: locale === 'en-US' ? preset.titleEn : preset.title,
|
|
1260
|
+
summary: locale === 'en-US' ? preset.summaryEn : preset.summary,
|
|
1261
|
+
lanes: preset.lanes,
|
|
1262
|
+
keywords: preset.keywords,
|
|
1263
|
+
listGoldenPage: preset.listGoldenPage ?? null,
|
|
1264
|
+
cues: locale === 'en-US' ? preset.cuesEn : preset.cues,
|
|
1265
|
+
apply: locale === 'en-US' ? preset.applyEn : preset.apply,
|
|
1266
|
+
avoid: locale === 'en-US' ? preset.avoidEn : preset.avoid,
|
|
1267
|
+
resolution: locale === 'en-US' ? styleResolution.priorityEn : styleResolution.priorityZh,
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1146
1270
|
function recommendComponent(args) {
|
|
1147
1271
|
const locale = resolveLocale(args.mode);
|
|
1148
1272
|
if (!args.query && !args.decision) {
|
|
@@ -1170,11 +1294,7 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
1170
1294
|
title: locale === 'en-US' ? decision.titleEn : decision.title,
|
|
1171
1295
|
question: locale === 'en-US' ? decision.questionEn : decision.question,
|
|
1172
1296
|
keywords: decision.keywords,
|
|
1173
|
-
options: decision.options.map((option) => (
|
|
1174
|
-
component: option.component,
|
|
1175
|
-
when: locale === 'en-US' ? option.whenEn : option.when,
|
|
1176
|
-
avoidWhen: locale === 'en-US' ? option.avoidWhenEn : option.avoidWhen,
|
|
1177
|
-
})),
|
|
1297
|
+
options: decision.options.map((option) => mapDecisionOption(option, locale)),
|
|
1178
1298
|
});
|
|
1179
1299
|
}
|
|
1180
1300
|
if (!args.query) {
|
|
@@ -1194,14 +1314,10 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
1194
1314
|
decision: matched.id,
|
|
1195
1315
|
title: locale === 'en-US' ? matched.titleEn : matched.title,
|
|
1196
1316
|
question: locale === 'en-US' ? matched.questionEn : matched.question,
|
|
1197
|
-
recommendations: matched.options.map((option) => (
|
|
1198
|
-
component: option.component,
|
|
1199
|
-
when: locale === 'en-US' ? option.whenEn : option.when,
|
|
1200
|
-
avoidWhen: locale === 'en-US' ? option.avoidWhenEn : option.avoidWhen,
|
|
1201
|
-
})),
|
|
1317
|
+
recommendations: matched.options.map((option) => mapDecisionOption(option, locale)),
|
|
1202
1318
|
nextStep: locale === 'en-US'
|
|
1203
|
-
? '
|
|
1204
|
-
: '
|
|
1319
|
+
? 'Apply the recipe props/slots/events, then use get_component and get_example before implementing. Run validate_usage before delivery.'
|
|
1320
|
+
: '先按 recipe 的 props/slots/events 落地,再用 get_component / get_example 核对 API;交付前跑 validate_usage。',
|
|
1205
1321
|
});
|
|
1206
1322
|
}
|
|
1207
1323
|
function getSetup(args) {
|
|
@@ -1369,6 +1485,8 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
1369
1485
|
'get_pattern',
|
|
1370
1486
|
'recommend_page',
|
|
1371
1487
|
'get_design_rules',
|
|
1488
|
+
'list_style_presets',
|
|
1489
|
+
'get_style_preset',
|
|
1372
1490
|
'recommend_component',
|
|
1373
1491
|
'list_golden_pages',
|
|
1374
1492
|
'get_golden_page',
|
|
@@ -1392,6 +1510,8 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
1392
1510
|
getPattern,
|
|
1393
1511
|
recommendPage,
|
|
1394
1512
|
getDesignRules,
|
|
1513
|
+
listStylePresets,
|
|
1514
|
+
getStylePreset,
|
|
1395
1515
|
recommendComponent,
|
|
1396
1516
|
listGoldenPageCatalog,
|
|
1397
1517
|
getGoldenPage,
|