@morya-ui/mcp 0.3.3 → 0.3.5
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/LICENSE +21 -21
- package/README.md +151 -151
- package/bin/morya-ui-mcp.js +2 -2
- package/data/catalog.json +62 -51
- package/data/example-coverage.json +6 -4
- 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 +168 -0
- package/data/golden-pages/list-page-rail.vue +272 -0
- package/data/golden-pages/list-page.vue +222 -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__/page-snippets.test.js +29 -0
- package/dist/__tests__/tools.test.js +94 -1
- package/dist/decisions.d.ts +2 -0
- package/dist/decisions.js +76 -7
- package/dist/golden-pages.d.ts +18 -0
- package/dist/golden-pages.js +76 -22
- package/dist/index.js +9 -3
- package/dist/page-snippets.js +960 -257
- package/dist/patterns.d.ts +5 -3
- package/dist/patterns.js +53 -13
- package/dist/style-presets.d.ts +33 -0
- package/dist/style-presets.js +131 -0
- package/dist/tools.d.ts +12 -0
- package/dist/tools.js +301 -210
- package/package.json +1 -1
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 { resolveListCraftVariant, resolveStyleDirection, 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);
|
|
@@ -64,6 +65,7 @@ function mapDecisionOption(option, locale) {
|
|
|
64
65
|
avoidWhen: zh ? option.avoidWhen : option.avoidWhenEn,
|
|
65
66
|
recipe,
|
|
66
67
|
antiPatterns: zh ? option.antiPatterns : option.antiPatternsEn,
|
|
68
|
+
...(option.relatedSnippets?.length ? { relatedSnippets: option.relatedSnippets } : {}),
|
|
67
69
|
};
|
|
68
70
|
}
|
|
69
71
|
function generatedPageCode(patternId, intent, locale) {
|
|
@@ -92,149 +94,149 @@ function generatedPageCode(patternId, intent, locale) {
|
|
|
92
94
|
const wizardImports = isWizard ? ', MStepper, MSpace' : '';
|
|
93
95
|
const settingsImports = isSettings ? ', MTabs' : '';
|
|
94
96
|
const statusImports = isList || isDetail || isDashboard ? ', MStatus' : '';
|
|
95
|
-
const script = `<script setup lang="ts">
|
|
96
|
-
import { ref } from 'vue'
|
|
97
|
-
import { MButton, MCard, MConfigProvider, MInput, MTag, zhCN${layoutImports}${pageImports}${listImports}${formImports}${dashboardImports}${detailImports}${emptyImports}${wizardImports}${settingsImports}${statusImports} } from 'morya-ui'
|
|
98
|
-
|
|
99
|
-
const loading = ref(false)
|
|
100
|
-
const error = ref('')
|
|
101
|
-
const title = ${JSON.stringify(title)}
|
|
102
|
-
${isList ? `const keyword = ref('')
|
|
103
|
-
const rows = ref<Record<string, unknown>[]>([])
|
|
104
|
-
const columns = [{ key: 'name', label: '${zh ? '名称' : 'Name'}' }, { key: 'status', label: '${zh ? '状态' : 'Status'}' }]
|
|
105
|
-
` : ''}${isForm || isAuth || isWizard ? `const model = ref({ name: '' })
|
|
106
|
-
` : ''}${isDashboard ? `const metrics = ref([
|
|
107
|
-
{ label: '${zh ? '总用户' : 'Users'}', value: '0' },
|
|
108
|
-
{ label: '${zh ? '今日活跃' : 'Active today'}', value: '0' },
|
|
109
|
-
])
|
|
110
|
-
` : ''}${isSettings ? `const activeTab = ref('general')
|
|
111
|
-
const settingTabs = [{ label: '${zh ? '常规' : 'General'}', value: 'general' }]
|
|
112
|
-
` : ''}${isWizard ? `const activeStep = ref(0)
|
|
113
|
-
const wizardSteps = [{ label: '${zh ? '基本信息' : 'Details'}' }, { label: '${zh ? '确认' : 'Confirm'}' }]
|
|
114
|
-
` : ''}
|
|
115
|
-
|
|
116
|
-
async function submit() {
|
|
117
|
-
loading.value = true
|
|
118
|
-
error.value = ''
|
|
119
|
-
try {
|
|
120
|
-
// Replace with the page API request.
|
|
121
|
-
} finally {
|
|
122
|
-
loading.value = false
|
|
123
|
-
}
|
|
124
|
-
}
|
|
97
|
+
const script = `<script setup lang="ts">
|
|
98
|
+
import { ref } from 'vue'
|
|
99
|
+
import { MButton, MCard, MConfigProvider, MInput, MTag, zhCN${layoutImports}${pageImports}${listImports}${formImports}${dashboardImports}${detailImports}${emptyImports}${wizardImports}${settingsImports}${statusImports} } from 'morya-ui'
|
|
100
|
+
|
|
101
|
+
const loading = ref(false)
|
|
102
|
+
const error = ref('')
|
|
103
|
+
const title = ${JSON.stringify(title)}
|
|
104
|
+
${isList ? `const keyword = ref('')
|
|
105
|
+
const rows = ref<Record<string, unknown>[]>([])
|
|
106
|
+
const columns = [{ key: 'name', label: '${zh ? '名称' : 'Name'}' }, { key: 'status', label: '${zh ? '状态' : 'Status'}' }]
|
|
107
|
+
` : ''}${isForm || isAuth || isWizard ? `const model = ref({ name: '' })
|
|
108
|
+
` : ''}${isDashboard ? `const metrics = ref([
|
|
109
|
+
{ label: '${zh ? '总用户' : 'Users'}', value: '0' },
|
|
110
|
+
{ label: '${zh ? '今日活跃' : 'Active today'}', value: '0' },
|
|
111
|
+
])
|
|
112
|
+
` : ''}${isSettings ? `const activeTab = ref('general')
|
|
113
|
+
const settingTabs = [{ label: '${zh ? '常规' : 'General'}', value: 'general' }]
|
|
114
|
+
` : ''}${isWizard ? `const activeStep = ref(0)
|
|
115
|
+
const wizardSteps = [{ label: '${zh ? '基本信息' : 'Details'}' }, { label: '${zh ? '确认' : 'Confirm'}' }]
|
|
116
|
+
` : ''}
|
|
117
|
+
|
|
118
|
+
async function submit() {
|
|
119
|
+
loading.value = true
|
|
120
|
+
error.value = ''
|
|
121
|
+
try {
|
|
122
|
+
// Replace with the page API request.
|
|
123
|
+
} finally {
|
|
124
|
+
loading.value = false
|
|
125
|
+
}
|
|
126
|
+
}
|
|
125
127
|
</script>`;
|
|
126
|
-
const listContent = ` <MPageHeader :title="title">
|
|
127
|
-
<template #actions>
|
|
128
|
-
<MButton severity="primary">${zh ? '新建' : 'Create'}</MButton>
|
|
129
|
-
</template>
|
|
130
|
-
</MPageHeader>
|
|
131
|
-
<MPageFilters variant="filled" :aria-label="${zh ? '筛选' : 'Filters'}">
|
|
132
|
-
<MSpace wrap>
|
|
133
|
-
<MInput v-model="keyword" placeholder="${zh ? '搜索关键词' : 'Search keyword'}" clearable style="width: 14rem" />
|
|
134
|
-
<MButton severity="secondary">${zh ? '查询' : 'Search'}</MButton>
|
|
135
|
-
<MButton severity="secondary">${zh ? '重置' : 'Reset'}</MButton>
|
|
136
|
-
</MSpace>
|
|
137
|
-
</MPageFilters>
|
|
138
|
-
<MTable :columns="columns" :rows="rows" :loading="loading" paginator :rows-per-page="10" striped bordered row-key="id">
|
|
139
|
-
<template #cell-status="{ value }">
|
|
140
|
-
<MStatus :label="String(value ?? '')" :severity="value === 'active' ? 'success' : 'secondary'" />
|
|
141
|
-
</template>
|
|
142
|
-
<template #empty>
|
|
143
|
-
<MEmpty
|
|
144
|
-
:title="${zh ? '暂无数据' : 'No data yet'}"
|
|
145
|
-
:description="${zh ? '创建第一条记录开始使用。' : 'Create your first record to get started.'}"
|
|
146
|
-
>
|
|
147
|
-
<template #extra>
|
|
148
|
-
<MButton severity="primary">${zh ? '新建' : 'Create'}</MButton>
|
|
149
|
-
</template>
|
|
150
|
-
</MEmpty>
|
|
151
|
-
</template>
|
|
128
|
+
const listContent = ` <MPageHeader :title="title">
|
|
129
|
+
<template #actions>
|
|
130
|
+
<MButton severity="primary">${zh ? '新建' : 'Create'}</MButton>
|
|
131
|
+
</template>
|
|
132
|
+
</MPageHeader>
|
|
133
|
+
<MPageFilters variant="filled" :aria-label="${zh ? '筛选' : 'Filters'}">
|
|
134
|
+
<MSpace wrap>
|
|
135
|
+
<MInput v-model="keyword" placeholder="${zh ? '搜索关键词' : 'Search keyword'}" clearable style="width: 14rem" />
|
|
136
|
+
<MButton severity="secondary">${zh ? '查询' : 'Search'}</MButton>
|
|
137
|
+
<MButton severity="secondary">${zh ? '重置' : 'Reset'}</MButton>
|
|
138
|
+
</MSpace>
|
|
139
|
+
</MPageFilters>
|
|
140
|
+
<MTable :columns="columns" :rows="rows" :loading="loading" fill paginator :rows-per-page="10" striped bordered row-key="id">
|
|
141
|
+
<template #cell-status="{ value }">
|
|
142
|
+
<MStatus :label="String(value ?? '')" :severity="value === 'active' ? 'success' : 'secondary'" />
|
|
143
|
+
</template>
|
|
144
|
+
<template #empty>
|
|
145
|
+
<MEmpty
|
|
146
|
+
:title="${zh ? '暂无数据' : 'No data yet'}"
|
|
147
|
+
:description="${zh ? '创建第一条记录开始使用。' : 'Create your first record to get started.'}"
|
|
148
|
+
>
|
|
149
|
+
<template #extra>
|
|
150
|
+
<MButton severity="primary">${zh ? '新建' : 'Create'}</MButton>
|
|
151
|
+
</template>
|
|
152
|
+
</MEmpty>
|
|
153
|
+
</template>
|
|
152
154
|
</MTable>`;
|
|
153
|
-
const formContent = ` <MPageHeader :title="title" :description="${zh ? '填写表单并保存。' : 'Fill in the form and save.'}" />
|
|
154
|
-
<MPageSection variant="form">
|
|
155
|
-
<MForm @submit.prevent="submit">
|
|
156
|
-
<MFormItem label="${zh ? '名称' : 'Name'}" name="name" required>
|
|
157
|
-
<MInput v-model="model.name" fluid />
|
|
158
|
-
</MFormItem>
|
|
159
|
-
<MPageSection variant="actions">
|
|
160
|
-
<MButton native-type="submit" severity="primary" :loading="loading">${zh ? '保存' : 'Save'}</MButton>
|
|
161
|
-
<MButton severity="secondary">${zh ? '取消' : 'Cancel'}</MButton>
|
|
162
|
-
</MPageSection>
|
|
163
|
-
</MForm>
|
|
155
|
+
const formContent = ` <MPageHeader :title="title" :description="${zh ? '填写表单并保存。' : 'Fill in the form and save.'}" />
|
|
156
|
+
<MPageSection variant="form">
|
|
157
|
+
<MForm @submit.prevent="submit">
|
|
158
|
+
<MFormItem label="${zh ? '名称' : 'Name'}" name="name" required>
|
|
159
|
+
<MInput v-model="model.name" fluid />
|
|
160
|
+
</MFormItem>
|
|
161
|
+
<MPageSection variant="actions">
|
|
162
|
+
<MButton native-type="submit" severity="primary" :loading="loading">${zh ? '保存' : 'Save'}</MButton>
|
|
163
|
+
<MButton severity="secondary">${zh ? '取消' : 'Cancel'}</MButton>
|
|
164
|
+
</MPageSection>
|
|
165
|
+
</MForm>
|
|
164
166
|
</MPageSection>`;
|
|
165
|
-
const dashboardContent = ` <MPageHeader :title="title" />
|
|
166
|
-
<MGrid :cols="2" :x-gap="16" :y-gap="16" responsive="screen">
|
|
167
|
-
<MGridItem v-for="metric in metrics" :key="metric.label" :span="1">
|
|
168
|
-
<MPageStat :label="metric.label" :value="metric.value" icon="activity" />
|
|
169
|
-
</MGridItem>
|
|
170
|
-
</MGrid>
|
|
171
|
-
<MCard shadow="always" :title="${zh ? '趋势概览' : 'Trend overview'}">
|
|
172
|
-
<MSkeleton v-if="loading" height="8rem" />
|
|
173
|
-
<MEmpty
|
|
174
|
-
v-else
|
|
175
|
-
:title="${zh ? '暂无图表数据' : 'No chart data yet'}"
|
|
176
|
-
:description="${zh ? '接入图表或业务组件。' : 'Connect charts or business widgets here.'}"
|
|
177
|
-
aria-label="${zh ? '图表占位' : 'Chart placeholder'}"
|
|
178
|
-
/>
|
|
167
|
+
const dashboardContent = ` <MPageHeader :title="title" />
|
|
168
|
+
<MGrid :cols="2" :x-gap="16" :y-gap="16" responsive="screen">
|
|
169
|
+
<MGridItem v-for="metric in metrics" :key="metric.label" :span="1">
|
|
170
|
+
<MPageStat :label="metric.label" :value="metric.value" icon="activity" />
|
|
171
|
+
</MGridItem>
|
|
172
|
+
</MGrid>
|
|
173
|
+
<MCard shadow="always" :title="${zh ? '趋势概览' : 'Trend overview'}">
|
|
174
|
+
<MSkeleton v-if="loading" height="8rem" />
|
|
175
|
+
<MEmpty
|
|
176
|
+
v-else
|
|
177
|
+
:title="${zh ? '暂无图表数据' : 'No chart data yet'}"
|
|
178
|
+
:description="${zh ? '接入图表或业务组件。' : 'Connect charts or business widgets here.'}"
|
|
179
|
+
aria-label="${zh ? '图表占位' : 'Chart placeholder'}"
|
|
180
|
+
/>
|
|
179
181
|
</MCard>`;
|
|
180
|
-
const detailContent = ` <MPageHeader :title="title" :description="${zh ? '查看资源摘要与属性。' : 'Review summary and properties.'}">
|
|
181
|
-
<template #actions>
|
|
182
|
-
<MSpace>
|
|
183
|
-
<MStatus :label="${zh ? '启用' : 'Active'}" severity="success" />
|
|
184
|
-
<MButton severity="primary">${zh ? '编辑' : 'Edit'}</MButton>
|
|
185
|
-
<MButton severity="secondary">${zh ? '返回' : 'Back'}</MButton>
|
|
186
|
-
</MSpace>
|
|
187
|
-
</template>
|
|
188
|
-
</MPageHeader>
|
|
189
|
-
<MCard :title="${zh ? '基本信息' : 'Basics'}">
|
|
190
|
-
<p style="margin:0;color:var(--m-color-text-muted)">${zh ? '用定义列表或网格展示属性;相关列表用 MTable + rows。' : 'Use a definition grid; related lists use MTable + rows.'}</p>
|
|
182
|
+
const detailContent = ` <MPageHeader :title="title" :description="${zh ? '查看资源摘要与属性。' : 'Review summary and properties.'}">
|
|
183
|
+
<template #actions>
|
|
184
|
+
<MSpace>
|
|
185
|
+
<MStatus :label="${zh ? '启用' : 'Active'}" severity="success" />
|
|
186
|
+
<MButton severity="primary">${zh ? '编辑' : 'Edit'}</MButton>
|
|
187
|
+
<MButton severity="secondary">${zh ? '返回' : 'Back'}</MButton>
|
|
188
|
+
</MSpace>
|
|
189
|
+
</template>
|
|
190
|
+
</MPageHeader>
|
|
191
|
+
<MCard :title="${zh ? '基本信息' : 'Basics'}">
|
|
192
|
+
<p style="margin:0;color:var(--m-color-text-muted)">${zh ? '用定义列表或网格展示属性;相关列表用 MTable + rows。' : 'Use a definition grid; related lists use MTable + rows.'}</p>
|
|
191
193
|
</MCard>`;
|
|
192
|
-
const settingsContent = ` <MPageHeader :title="title" :description="${zh ? '按域分组配置偏好。' : 'Grouped preference settings.'}" />
|
|
193
|
-
<MTabs v-model="activeTab" :tabs="settingTabs">
|
|
194
|
-
<template #default="{ activeValue }">
|
|
195
|
-
<MPageSection v-if="activeValue === 'general'" variant="form" :title="${zh ? '常规' : 'General'}">
|
|
196
|
-
<MForm @submit.prevent="submit">
|
|
197
|
-
<MFormItem label="${zh ? '显示名称' : 'Display name'}" name="name" required>
|
|
198
|
-
<MInput v-model="model.name" fluid />
|
|
199
|
-
</MFormItem>
|
|
200
|
-
<MPageSection variant="actions">
|
|
201
|
-
<MButton native-type="submit" severity="primary" :loading="loading">${zh ? '保存' : 'Save'}</MButton>
|
|
202
|
-
</MPageSection>
|
|
203
|
-
</MForm>
|
|
204
|
-
</MPageSection>
|
|
205
|
-
</template>
|
|
194
|
+
const settingsContent = ` <MPageHeader :title="title" :description="${zh ? '按域分组配置偏好。' : 'Grouped preference settings.'}" />
|
|
195
|
+
<MTabs v-model="activeTab" :tabs="settingTabs">
|
|
196
|
+
<template #default="{ activeValue }">
|
|
197
|
+
<MPageSection v-if="activeValue === 'general'" variant="form" :title="${zh ? '常规' : 'General'}">
|
|
198
|
+
<MForm @submit.prevent="submit">
|
|
199
|
+
<MFormItem label="${zh ? '显示名称' : 'Display name'}" name="name" required>
|
|
200
|
+
<MInput v-model="model.name" fluid />
|
|
201
|
+
</MFormItem>
|
|
202
|
+
<MPageSection variant="actions">
|
|
203
|
+
<MButton native-type="submit" severity="primary" :loading="loading">${zh ? '保存' : 'Save'}</MButton>
|
|
204
|
+
</MPageSection>
|
|
205
|
+
</MForm>
|
|
206
|
+
</MPageSection>
|
|
207
|
+
</template>
|
|
206
208
|
</MTabs>`;
|
|
207
|
-
const wizardContent = ` <MPageHeader :title="title" :description="${zh ? '每步一个主任务。' : 'One job per step.'}" />
|
|
208
|
-
<MStepper v-model="activeStep" :steps="wizardSteps" linear />
|
|
209
|
-
<MPageSection variant="form">
|
|
210
|
-
<MForm @submit.prevent="submit">
|
|
211
|
-
<MFormItem label="${zh ? '名称' : 'Name'}" name="name" required>
|
|
212
|
-
<MInput v-model="model.name" fluid />
|
|
213
|
-
</MFormItem>
|
|
214
|
-
<MPageSection variant="actions">
|
|
215
|
-
<MSpace>
|
|
216
|
-
<MButton severity="secondary" text :disabled="activeStep === 0" @click="activeStep = Math.max(activeStep - 1, 0)">${zh ? '上一步' : 'Back'}</MButton>
|
|
217
|
-
<MButton native-type="submit" severity="primary" :loading="loading">${zh ? '下一步' : 'Next'}</MButton>
|
|
218
|
-
</MSpace>
|
|
219
|
-
</MPageSection>
|
|
220
|
-
</MForm>
|
|
209
|
+
const wizardContent = ` <MPageHeader :title="title" :description="${zh ? '每步一个主任务。' : 'One job per step.'}" />
|
|
210
|
+
<MStepper v-model="activeStep" :steps="wizardSteps" linear />
|
|
211
|
+
<MPageSection variant="form">
|
|
212
|
+
<MForm @submit.prevent="submit">
|
|
213
|
+
<MFormItem label="${zh ? '名称' : 'Name'}" name="name" required>
|
|
214
|
+
<MInput v-model="model.name" fluid />
|
|
215
|
+
</MFormItem>
|
|
216
|
+
<MPageSection variant="actions">
|
|
217
|
+
<MSpace>
|
|
218
|
+
<MButton severity="secondary" text :disabled="activeStep === 0" @click="activeStep = Math.max(activeStep - 1, 0)">${zh ? '上一步' : 'Back'}</MButton>
|
|
219
|
+
<MButton native-type="submit" severity="primary" :loading="loading">${zh ? '下一步' : 'Next'}</MButton>
|
|
220
|
+
</MSpace>
|
|
221
|
+
</MPageSection>
|
|
222
|
+
</MForm>
|
|
221
223
|
</MPageSection>`;
|
|
222
224
|
let innerTemplate = '';
|
|
223
225
|
if (isList) {
|
|
224
|
-
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
225
|
-
<MLayout has-sider fill-viewport>
|
|
226
|
-
<MLayoutSider bordered />
|
|
227
|
-
<MLayout>
|
|
228
|
-
<MLayoutHeader :padding="'var(--m-space-4) var(--m-space-6)'">
|
|
229
|
-
<MBreadcrumb :model="[{ label: '${zh ? '首页' : 'Home'}', to: '/' }, { label: '${title}' }]" />
|
|
230
|
-
</MLayoutHeader>
|
|
231
|
-
<MLayoutContent>
|
|
232
|
-
<MPageContent>
|
|
233
|
-
${listContent}
|
|
234
|
-
</MPageContent>
|
|
235
|
-
</MLayoutContent>
|
|
236
|
-
</MLayout>
|
|
237
|
-
</MLayout>
|
|
226
|
+
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
227
|
+
<MLayout has-sider fill-viewport>
|
|
228
|
+
<MLayoutSider bordered />
|
|
229
|
+
<MLayout>
|
|
230
|
+
<MLayoutHeader :padding="'var(--m-space-4) var(--m-space-6)'">
|
|
231
|
+
<MBreadcrumb :model="[{ label: '${zh ? '首页' : 'Home'}', to: '/' }, { label: '${title}' }]" />
|
|
232
|
+
</MLayoutHeader>
|
|
233
|
+
<MLayoutContent>
|
|
234
|
+
<MPageContent fill>
|
|
235
|
+
${listContent}
|
|
236
|
+
</MPageContent>
|
|
237
|
+
</MLayoutContent>
|
|
238
|
+
</MLayout>
|
|
239
|
+
</MLayout>
|
|
238
240
|
</MConfigProvider>`;
|
|
239
241
|
}
|
|
240
242
|
else if (useLayoutShell) {
|
|
@@ -248,76 +250,76 @@ ${listContent}
|
|
|
248
250
|
? wizardContent
|
|
249
251
|
: formContent;
|
|
250
252
|
const pageContentAttrs = isForm || isSettings || isWizard ? ' width="narrow"' : isDashboard ? ' density="spacious"' : '';
|
|
251
|
-
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
252
|
-
<MLayout fill-viewport>
|
|
253
|
-
<MLayoutHeader :padding="'var(--m-space-4) var(--m-space-6)'">
|
|
254
|
-
<MBreadcrumb :model="[{ label: '${zh ? '首页' : 'Home'}', to: '/' }, { label: title }]" />
|
|
255
|
-
</MLayoutHeader>
|
|
256
|
-
<MLayoutContent>
|
|
257
|
-
<MPageContent${pageContentAttrs}>
|
|
258
|
-
${content}
|
|
259
|
-
</MPageContent>
|
|
260
|
-
</MLayoutContent>
|
|
261
|
-
</MLayout>
|
|
253
|
+
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
254
|
+
<MLayout fill-viewport>
|
|
255
|
+
<MLayoutHeader :padding="'var(--m-space-4) var(--m-space-6)'">
|
|
256
|
+
<MBreadcrumb :model="[{ label: '${zh ? '首页' : 'Home'}', to: '/' }, { label: title }]" />
|
|
257
|
+
</MLayoutHeader>
|
|
258
|
+
<MLayoutContent>
|
|
259
|
+
<MPageContent${pageContentAttrs}>
|
|
260
|
+
${content}
|
|
261
|
+
</MPageContent>
|
|
262
|
+
</MLayoutContent>
|
|
263
|
+
</MLayout>
|
|
262
264
|
</MConfigProvider>`;
|
|
263
265
|
}
|
|
264
266
|
else if (isAuth) {
|
|
265
|
-
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
266
|
-
<main class="m-generated-page m-generated-auth">
|
|
267
|
-
<MCard>
|
|
268
|
-
<MForm label-position="top" @submit.prevent="submit">
|
|
269
|
-
<MFormItem label="${zh ? '邮箱' : 'Email'}" name="email">
|
|
270
|
-
<MInput type="email" fluid />
|
|
271
|
-
</MFormItem>
|
|
272
|
-
<MFormItem label="${zh ? '密码' : 'Password'}" name="password">
|
|
273
|
-
<MInput type="password" fluid />
|
|
274
|
-
</MFormItem>
|
|
275
|
-
<MButton native-type="submit" severity="primary" :loading="loading" fluid>${zh ? '登录' : 'Sign in'}</MButton>
|
|
276
|
-
</MForm>
|
|
277
|
-
</MCard>
|
|
278
|
-
</main>
|
|
267
|
+
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
268
|
+
<main class="m-generated-page m-generated-auth">
|
|
269
|
+
<MCard>
|
|
270
|
+
<MForm label-position="top" @submit.prevent="submit">
|
|
271
|
+
<MFormItem label="${zh ? '邮箱' : 'Email'}" name="email">
|
|
272
|
+
<MInput type="email" fluid />
|
|
273
|
+
</MFormItem>
|
|
274
|
+
<MFormItem label="${zh ? '密码' : 'Password'}" name="password">
|
|
275
|
+
<MInput type="password" fluid />
|
|
276
|
+
</MFormItem>
|
|
277
|
+
<MButton native-type="submit" severity="primary" :loading="loading" fluid>${zh ? '登录' : 'Sign in'}</MButton>
|
|
278
|
+
</MForm>
|
|
279
|
+
</MCard>
|
|
280
|
+
</main>
|
|
279
281
|
</MConfigProvider>`;
|
|
280
282
|
}
|
|
281
283
|
else if (isEmpty) {
|
|
282
|
-
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
283
|
-
<main class="m-generated-page">
|
|
284
|
-
<MPageContent>
|
|
285
|
-
<MPageHeader :title="title">
|
|
286
|
-
<template #actions>
|
|
287
|
-
<MButton severity="primary" @click="submit">${zh ? '新建' : 'Create'}</MButton>
|
|
288
|
-
</template>
|
|
289
|
-
</MPageHeader>
|
|
290
|
-
<MEmpty
|
|
291
|
-
:title="${zh ? '暂无内容' : 'Nothing here yet'}"
|
|
292
|
-
:description="${zh ? '创建第一条记录开始使用。' : 'Create your first record to get started.'}"
|
|
293
|
-
icon="database"
|
|
294
|
-
>
|
|
295
|
-
<template #extra>
|
|
296
|
-
<MButton severity="primary" @click="submit">${zh ? '创建' : 'Create'}</MButton>
|
|
297
|
-
</template>
|
|
298
|
-
</MEmpty>
|
|
299
|
-
</MPageContent>
|
|
300
|
-
</main>
|
|
284
|
+
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
285
|
+
<main class="m-generated-page">
|
|
286
|
+
<MPageContent>
|
|
287
|
+
<MPageHeader :title="title">
|
|
288
|
+
<template #actions>
|
|
289
|
+
<MButton severity="primary" @click="submit">${zh ? '新建' : 'Create'}</MButton>
|
|
290
|
+
</template>
|
|
291
|
+
</MPageHeader>
|
|
292
|
+
<MEmpty
|
|
293
|
+
:title="${zh ? '暂无内容' : 'Nothing here yet'}"
|
|
294
|
+
:description="${zh ? '创建第一条记录开始使用。' : 'Create your first record to get started.'}"
|
|
295
|
+
icon="database"
|
|
296
|
+
>
|
|
297
|
+
<template #extra>
|
|
298
|
+
<MButton severity="primary" @click="submit">${zh ? '创建' : 'Create'}</MButton>
|
|
299
|
+
</template>
|
|
300
|
+
</MEmpty>
|
|
301
|
+
</MPageContent>
|
|
302
|
+
</main>
|
|
301
303
|
</MConfigProvider>`;
|
|
302
304
|
}
|
|
303
305
|
else {
|
|
304
|
-
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
305
|
-
<main class="m-generated-page">
|
|
306
|
-
<MCard>
|
|
307
|
-
<p class="m-generated-muted">${zh ? '将此区域替换为页面内容。' : 'Replace this area with page content.'}</p>
|
|
308
|
-
<MTag value="${zh ? '示例' : 'Example'}" severity="info" />
|
|
309
|
-
</MCard>
|
|
310
|
-
</main>
|
|
306
|
+
innerTemplate = `<MConfigProvider :locale="zhCN">
|
|
307
|
+
<main class="m-generated-page">
|
|
308
|
+
<MCard>
|
|
309
|
+
<p class="m-generated-muted">${zh ? '将此区域替换为页面内容。' : 'Replace this area with page content.'}</p>
|
|
310
|
+
<MTag value="${zh ? '示例' : 'Example'}" severity="info" />
|
|
311
|
+
</MCard>
|
|
312
|
+
</main>
|
|
311
313
|
</MConfigProvider>`;
|
|
312
314
|
}
|
|
313
|
-
const template = `<template>
|
|
314
|
-
${innerTemplate}
|
|
315
|
-
<p v-if="error" role="alert" class="m-generated-error">${'{{ error }}'}</p>
|
|
315
|
+
const template = `<template>
|
|
316
|
+
${innerTemplate}
|
|
317
|
+
<p v-if="error" role="alert" class="m-generated-error">${'{{ error }}'}</p>
|
|
316
318
|
</template>`;
|
|
317
|
-
const style = `<style scoped>
|
|
318
|
-
.m-generated-auth { display: grid; place-items: center; padding: var(--m-space-8); max-width: 24rem; margin: 0 auto; min-height: 100vh; }
|
|
319
|
-
.m-generated-empty { display: grid; gap: var(--m-space-2); justify-items: center; padding: var(--m-space-8); text-align: center; }
|
|
320
|
-
.m-generated-error { color: var(--m-color-danger); padding: 0 var(--m-space-6); }
|
|
319
|
+
const style = `<style scoped>
|
|
320
|
+
.m-generated-auth { display: grid; place-items: center; padding: var(--m-space-8); max-width: 24rem; margin: 0 auto; min-height: 100vh; }
|
|
321
|
+
.m-generated-empty { display: grid; gap: var(--m-space-2); justify-items: center; padding: var(--m-space-8); text-align: center; }
|
|
322
|
+
.m-generated-error { color: var(--m-color-danger); padding: 0 var(--m-space-6); }
|
|
321
323
|
</style>`;
|
|
322
324
|
return { script, template, style };
|
|
323
325
|
}
|
|
@@ -729,13 +731,43 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
729
731
|
});
|
|
730
732
|
}
|
|
731
733
|
const locale = resolveLocale(args.mode);
|
|
734
|
+
const styleDirection = resolveStyleDirection({ intent: args.intent, style: args.style });
|
|
735
|
+
const stylePayload = {
|
|
736
|
+
resolution: styleDirection.resolution,
|
|
737
|
+
confidence: styleDirection.confidence,
|
|
738
|
+
summary: styleDirection.summary ?? null,
|
|
739
|
+
guidance: locale === 'en-US' ? styleDirection.guidanceEn : styleDirection.guidanceZh,
|
|
740
|
+
priority: locale === 'en-US' ? styleResolution.priorityEn : styleResolution.priorityZh,
|
|
741
|
+
hardRules: locale === 'en-US' ? styleResolution.hardRulesEn : styleResolution.hardRulesZh,
|
|
742
|
+
note: locale === 'en-US'
|
|
743
|
+
? 'No named style-preset catalog. Follow an explicit user reference/description; if styleDirection.resolution is ask, ask before inventing the look. Prefer snippets for composition; golden pages are optional block-order checks, not aesthetics.'
|
|
744
|
+
: '没有命名风格预设表。有明确参考/描述就跟用户;若 styleDirection.resolution 为 ask,先询问再写完整视觉。优先用 snippets 拼装;黄金样例仅可选核对块顺序,不是审美模板。',
|
|
745
|
+
};
|
|
746
|
+
const craftText = [args.style || '', args.intent || ''].join(' ');
|
|
747
|
+
const resolvedGoldenId = resolveGoldenPageId({
|
|
748
|
+
patternId: best.pattern.id,
|
|
749
|
+
canonicalGoldenId: best.pattern.goldenPage,
|
|
750
|
+
styleId: craftText || null,
|
|
751
|
+
});
|
|
752
|
+
const resolvedGoldenPath = resolvedGoldenId
|
|
753
|
+
? `docs/golden-pages/${resolvedGoldenId}.vue`
|
|
754
|
+
: best.pattern.goldenPage;
|
|
755
|
+
let suggestedSnippets = [...(best.pattern.suggestedSnippets ?? [])];
|
|
756
|
+
if (best.pattern.id === 'admin-list') {
|
|
757
|
+
const listCraft = resolveListCraftVariant(craftText);
|
|
758
|
+
if (listCraft === 'list-page-dense') {
|
|
759
|
+
suggestedSnippets = suggestedSnippets.map((id) => id === 'list-filters-stack' ? 'list-filters-dense' : id);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
732
762
|
const result = {
|
|
733
763
|
intent: args.intent,
|
|
734
764
|
pageType: args.pageType,
|
|
765
|
+
style: args.style,
|
|
735
766
|
matchedPattern: best.pattern.id,
|
|
736
767
|
title: locale === 'en-US' ? best.pattern.titleEn : best.pattern.title,
|
|
737
768
|
confidence: best.score,
|
|
738
|
-
goldenPage:
|
|
769
|
+
goldenPage: resolvedGoldenPath,
|
|
770
|
+
styleDirection: stylePayload,
|
|
739
771
|
components: best.pattern.components,
|
|
740
772
|
structure: best.pattern.structure,
|
|
741
773
|
layout: best.pattern.layout,
|
|
@@ -743,24 +775,39 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
743
775
|
interactionRules: best.pattern.interactionRules,
|
|
744
776
|
avoid: best.pattern.avoid,
|
|
745
777
|
alternatives: ranked.slice(1, 3).filter((item) => item.score > 0).map((item) => ({ id: item.pattern.id, score: item.score })),
|
|
778
|
+
suggestedSnippets,
|
|
746
779
|
nextStep: (() => {
|
|
747
|
-
const goldenId =
|
|
748
|
-
|
|
749
|
-
|
|
780
|
+
const goldenId = resolvedGoldenId;
|
|
781
|
+
const snippets = suggestedSnippets;
|
|
782
|
+
const snippetHint = snippets.length > 0
|
|
783
|
+
? locale === 'en-US'
|
|
784
|
+
? ` Compose with get_page_snippet for: ${snippets.join(', ')}. Use recommend_component for L2 recipes (relatedSnippets).`
|
|
785
|
+
: ` 用 get_page_snippet 拼装:${snippets.join(', ')}。选型用 recommend_component(含 relatedSnippets)。`
|
|
786
|
+
: locale === 'en-US'
|
|
787
|
+
? ' Compose with get_page_snippet + recommend_component (relatedSnippets).'
|
|
788
|
+
: ' 用 get_page_snippet + recommend_component(relatedSnippets)拼装。';
|
|
789
|
+
const styleHint = locale === 'en-US'
|
|
790
|
+
? styleDirection.resolution === 'ask'
|
|
791
|
+
? ' Style is uncertain — ask the user for a short description or reference before inventing the look.'
|
|
792
|
+
: ` Follow styleDirection (${styleDirection.resolution}): “${styleDirection.summary || 'user/reference'}”; honor explicit user words over companions.`
|
|
793
|
+
: styleDirection.resolution === 'ask'
|
|
794
|
+
? ' 风格不确定 — 先请用户说明气质或贴参考,再写完整视觉。'
|
|
795
|
+
: ` 按 styleDirection(${styleDirection.resolution})落实「${styleDirection.summary || '用户参考/描述'}」;用户明确指定优先于 companion。`;
|
|
796
|
+
const goldenHint = goldenId
|
|
797
|
+
? locale === 'en-US'
|
|
798
|
+
? ` Optional: get_golden_page("${goldenId}") only to check whole-page block order (not the default clone target).`
|
|
799
|
+
: ` 可选:仅当需核对整页块顺序时再 get_golden_page("${goldenId}")(默认不要整页克隆)。`
|
|
800
|
+
: locale === 'en-US'
|
|
801
|
+
? ' No golden page for this pattern — follow get_pattern structure + snippets.'
|
|
802
|
+
: ' 该模式暂无黄金样例:按 get_pattern 结构 + snippets 拼装。';
|
|
750
803
|
if (locale === 'en-US') {
|
|
751
|
-
return
|
|
752
|
-
? `Call get_golden_page("${goldenId}") and mirror it. Look up unfamiliar APIs with get_component/get_example, then always run validate_usage and validate_page. includeScaffold returns the golden source when available — not a separate aesthetic template.`
|
|
753
|
-
: `No golden page for this pattern: use get_pattern + get_design_rules, look up APIs with get_component/get_example, then always run validate_usage and validate_page.`;
|
|
804
|
+
return `${snippetHint.trim()}${styleHint}${goldenHint} Look up unfamiliar APIs with get_component/get_example, then always run validate_usage and validate_page.`;
|
|
754
805
|
}
|
|
755
|
-
return
|
|
756
|
-
? `调用 get_golden_page("${goldenId}") 并镜像结构。不熟悉的 API 用 get_component/get_example 核对,然后必须跑 validate_usage 与 validate_page。includeScaffold 有黄金样例时返回样例源码,不是另一套审美模板。`
|
|
757
|
-
: `该模式暂无黄金样例:用 get_pattern + get_design_rules,API 用 get_component/get_example 核对,然后必须跑 validate_usage 与 validate_page。`;
|
|
806
|
+
return `${snippetHint.trim()}${styleHint}${goldenHint} 不熟悉的 API 用 get_component/get_example 核对,然后必须跑 validate_usage 与 validate_page。`;
|
|
758
807
|
})(),
|
|
759
808
|
};
|
|
760
809
|
if (args.includeScaffold) {
|
|
761
|
-
const goldenId =
|
|
762
|
-
listGoldenPages().find((item) => item.patternId === best.pattern.id)?.id ||
|
|
763
|
-
null;
|
|
810
|
+
const goldenId = resolvedGoldenId;
|
|
764
811
|
const golden = goldenId ? readGoldenPageSource(goldenId) : null;
|
|
765
812
|
if (golden) {
|
|
766
813
|
result.scaffold = {
|
|
@@ -769,8 +816,8 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
769
816
|
files: { component: golden.source },
|
|
770
817
|
warnings: [
|
|
771
818
|
locale === 'en-US'
|
|
772
|
-
? 'Scaffold is the golden
|
|
773
|
-
: '
|
|
819
|
+
? 'Scaffold is an optional structure reference from the golden sample. Prefer composing suggestedSnippets; remap domain copy/data only if you use this source. Never invent props. Then validate_usage + validate_page.'
|
|
820
|
+
: '脚手架是黄金样例的可选结构参考。默认优先拼装 suggestedSnippets;若使用本源码只替换域文案与数据。禁止臆造 prop。完成后必须 validate_usage + validate_page。',
|
|
774
821
|
],
|
|
775
822
|
};
|
|
776
823
|
}
|
|
@@ -783,8 +830,8 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
783
830
|
files: { component: componentSource },
|
|
784
831
|
warnings: [
|
|
785
832
|
locale === 'en-US'
|
|
786
|
-
? 'No golden page for this pattern — structural fallback only. Prefer
|
|
787
|
-
: '该模式暂无黄金样例,仅为结构占位。优先
|
|
833
|
+
? 'No golden page for this pattern — structural fallback only. Prefer suggestedSnippets + get_component. Must validate_usage before delivery.'
|
|
834
|
+
: '该模式暂无黄金样例,仅为结构占位。优先 suggestedSnippets + get_component。交付前必须 validate_usage。',
|
|
788
835
|
],
|
|
789
836
|
};
|
|
790
837
|
}
|
|
@@ -805,6 +852,8 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
805
852
|
patternId: payload.record.patternId,
|
|
806
853
|
title: locale === 'en-US' ? payload.record.titleEn : payload.record.title,
|
|
807
854
|
file: payload.record.file,
|
|
855
|
+
style: payload.record.style ?? null,
|
|
856
|
+
variantOf: payload.record.variantOf ?? null,
|
|
808
857
|
source: payload.source,
|
|
809
858
|
nextStep: locale === 'en-US'
|
|
810
859
|
? '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.'
|
|
@@ -819,6 +868,8 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
819
868
|
patternId: item.patternId,
|
|
820
869
|
title: locale === 'en-US' ? item.titleEn : item.title,
|
|
821
870
|
file: item.file,
|
|
871
|
+
style: item.style ?? null,
|
|
872
|
+
variantOf: item.variantOf ?? null,
|
|
822
873
|
})),
|
|
823
874
|
});
|
|
824
875
|
}
|
|
@@ -1033,6 +1084,19 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
1033
1084
|
: '契约:MTable 行数据使用 rows,不要用 data。见黄金样例 list-page / get_component Table。',
|
|
1034
1085
|
});
|
|
1035
1086
|
}
|
|
1087
|
+
if (/fill-viewport|fillViewport/i.test(code)
|
|
1088
|
+
&& /<MTable\b[^>]*\bpaginator\b/i.test(code)
|
|
1089
|
+
&& /<MPageContent\b/i.test(code)
|
|
1090
|
+
&& !(/<MPageContent\b[^>]*\bfill\b/i.test(code)
|
|
1091
|
+
&& /<MTable\b[^>]*\bfill\b/i.test(code))) {
|
|
1092
|
+
suggestions.push({
|
|
1093
|
+
standardId: 'page-sections',
|
|
1094
|
+
type: 'list-fill-height',
|
|
1095
|
+
message: locale === 'en-US'
|
|
1096
|
+
? '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).'
|
|
1097
|
+
: '参考建议:若这是全视口后台主列表且表格是页面主任务,可考虑 MPageContent fill + MTable fill(表体滚动、分页贴底)。嵌入表/短页/整页文档滚动则跳过 fill(见 page-scroll-choice / 黄金样例 list-page)。',
|
|
1098
|
+
});
|
|
1099
|
+
}
|
|
1036
1100
|
if (/<MMessage\b[^>]*\bseverity\b/i.test(code)) {
|
|
1037
1101
|
suggestions.push({
|
|
1038
1102
|
standardId: 'feedback',
|
|
@@ -1097,10 +1161,18 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
1097
1161
|
}
|
|
1098
1162
|
function getDesignRules(args = {}) {
|
|
1099
1163
|
const locale = resolveLocale(args.mode);
|
|
1164
|
+
const styles = {
|
|
1165
|
+
resolution: locale === 'en-US' ? styleResolution.priorityEn : styleResolution.priorityZh,
|
|
1166
|
+
hardRules: locale === 'en-US' ? styleResolution.hardRulesEn : styleResolution.hardRulesZh,
|
|
1167
|
+
note: locale === 'en-US'
|
|
1168
|
+
? 'No named style-preset catalog. Follow user reference/description; ask when uncertain.'
|
|
1169
|
+
: '没有命名风格预设表。跟用户参考/描述;不确定就先问。',
|
|
1170
|
+
};
|
|
1100
1171
|
if (locale === 'zh-CN') {
|
|
1101
1172
|
return textResult({
|
|
1102
1173
|
meta: designRules.meta,
|
|
1103
1174
|
standards: designRules.standards,
|
|
1175
|
+
styles,
|
|
1104
1176
|
tokens: designRules.tokens,
|
|
1105
1177
|
composition: designRules.composition,
|
|
1106
1178
|
actions: designRules.actions,
|
|
@@ -1118,6 +1190,7 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
1118
1190
|
discouraged: item.discouragedEn,
|
|
1119
1191
|
mcp: item.mcp,
|
|
1120
1192
|
})),
|
|
1193
|
+
styles,
|
|
1121
1194
|
tokens: {
|
|
1122
1195
|
colors: ['--m-color-primary', '--m-color-surface', '--m-color-text', '--m-color-border'],
|
|
1123
1196
|
spacing: '--m-space-*',
|
|
@@ -1159,9 +1232,25 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
1159
1232
|
'Form controls should have a visible label or an equivalent accessible name.',
|
|
1160
1233
|
'Overlays teleport to body by default; only change appendTo for a clear layout constraint.',
|
|
1161
1234
|
'Prefer documented component variants over deep CSS overrides.',
|
|
1235
|
+
'Resolve visual style: follow explicit user reference/description first; else infer from clear prompt cues; if uncertain ask once. No named preset catalog. Golden pages lock structure, not aesthetics.',
|
|
1162
1236
|
],
|
|
1163
1237
|
});
|
|
1164
1238
|
}
|
|
1239
|
+
function getStyleDirection(args = {}) {
|
|
1240
|
+
const locale = resolveLocale(args.mode);
|
|
1241
|
+
const direction = resolveStyleDirection({ intent: args.intent, style: args.style });
|
|
1242
|
+
return textResult({
|
|
1243
|
+
resolution: direction.resolution,
|
|
1244
|
+
confidence: direction.confidence,
|
|
1245
|
+
summary: direction.summary ?? null,
|
|
1246
|
+
guidance: locale === 'en-US' ? direction.guidanceEn : direction.guidanceZh,
|
|
1247
|
+
priority: locale === 'en-US' ? styleResolution.priorityEn : styleResolution.priorityZh,
|
|
1248
|
+
hardRules: locale === 'en-US' ? styleResolution.hardRulesEn : styleResolution.hardRulesZh,
|
|
1249
|
+
note: locale === 'en-US'
|
|
1250
|
+
? 'No named style-preset catalog. Pass style as free-text user description when they specified one.'
|
|
1251
|
+
: '没有命名风格预设表。用户有描述时把原文放进 style;不确定时 resolution 为 ask,应先问用户。',
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1165
1254
|
function recommendComponent(args) {
|
|
1166
1255
|
const locale = resolveLocale(args.mode);
|
|
1167
1256
|
if (!args.query && !args.decision) {
|
|
@@ -1380,6 +1469,7 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
1380
1469
|
'get_pattern',
|
|
1381
1470
|
'recommend_page',
|
|
1382
1471
|
'get_design_rules',
|
|
1472
|
+
'get_style_direction',
|
|
1383
1473
|
'recommend_component',
|
|
1384
1474
|
'list_golden_pages',
|
|
1385
1475
|
'get_golden_page',
|
|
@@ -1403,6 +1493,7 @@ export function createToolHandlers(catalog = loadCatalog()) {
|
|
|
1403
1493
|
getPattern,
|
|
1404
1494
|
recommendPage,
|
|
1405
1495
|
getDesignRules,
|
|
1496
|
+
getStyleDirection,
|
|
1406
1497
|
recommendComponent,
|
|
1407
1498
|
listGoldenPageCatalog,
|
|
1408
1499
|
getGoldenPage,
|