@loom-framework/core 0.1.0-alpha.101 → 0.1.0-alpha.102
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/builtin-skills/loom/SKILL.md +26 -9
- package/builtin-skills/loom/references/dashboard.md +22 -22
- package/builtin-skills/loom/references/data-model.md +32 -13
- package/dist/cli/templates/frontend-entry.d.ts.map +1 -1
- package/dist/cli/templates/frontend-entry.js +11 -3
- package/dist/cli/templates/frontend-entry.js.map +1 -1
- package/package.json +1 -1
|
@@ -143,50 +143,67 @@ import { defineConfig } from '@loom-framework/core';
|
|
|
143
143
|
export default defineConfig({
|
|
144
144
|
project: {
|
|
145
145
|
name: 'my-app', // 必填
|
|
146
|
-
description: '
|
|
146
|
+
description: { 'zh-CN': '我的应用', 'en-US': 'My App' }, // 可选,支持多语言
|
|
147
147
|
},
|
|
148
148
|
data: {
|
|
149
149
|
defaultAdapter: 'filesystem', // 'filesystem' | 'sqlite'
|
|
150
150
|
models: [{
|
|
151
151
|
name: 'items', // 将作为 React 组件名生成页面,字母开头,字母/数字/下划线
|
|
152
|
-
description: '
|
|
152
|
+
description: { 'zh-CN': '数据项', 'en-US': 'Items' }, // 可选:支持多语言
|
|
153
153
|
fields: [{
|
|
154
154
|
name: 'status', // 字母/下划线开头,字母数字下划线
|
|
155
155
|
type: 'string', // 'string' | 'number' | 'boolean' | 'date' | 'string[]' | 'number[]' | 'json'
|
|
156
156
|
required: true, // 可选,默认 false
|
|
157
|
-
description: '
|
|
157
|
+
description: { 'zh-CN': '状态', 'en-US': 'Status' }, // 可选:支持多语言
|
|
158
158
|
default: 'active', // 可选:写入时自动填充
|
|
159
|
-
enum: ['active', 'inactive'], //
|
|
159
|
+
enum: ['active', 'inactive'], // 可选:限制可选值(存储值,不随语言变化)
|
|
160
|
+
enumLabels: { // 可选:enum 值的多语言显示标签
|
|
161
|
+
active: { 'zh-CN': '激活', 'en-US': 'Active' },
|
|
162
|
+
inactive: { 'zh-CN': '停用', 'en-US': 'Inactive' },
|
|
163
|
+
},
|
|
160
164
|
}],
|
|
161
165
|
}],
|
|
162
166
|
},
|
|
163
167
|
aiButtons: [{ // 可选
|
|
164
168
|
id: 'summarize', // 必填:唯一标识
|
|
165
|
-
label: '总结',
|
|
169
|
+
label: { 'zh-CN': '总结', 'en-US': 'Summarize' }, // 必填:支持多语言
|
|
166
170
|
prompt: '请总结以下内容', // 必填:支持 {{var}} 引用当前行字段值
|
|
167
171
|
},
|
|
168
172
|
{
|
|
169
173
|
id: 'analyze', // 带变量的示例
|
|
170
|
-
label: '分析',
|
|
174
|
+
label: { 'zh-CN': '分析', 'en-US': 'Analyze' },
|
|
171
175
|
prompt: '分析{{questionContent}},错误答案:{{wrongAnswer}}',
|
|
172
176
|
placement: 'wrong_questions', // 可选:限制按钮只出现在指定模型页面,逗号分隔多个模型名;省略则出现在所有页面
|
|
173
177
|
}],
|
|
174
178
|
dashboards: [{ // 可选:Dashboard 定义
|
|
175
179
|
name: 'overview', // 必填:唯一标识,同命名规则
|
|
176
|
-
description: '数据概览',
|
|
180
|
+
description: { 'zh-CN': '数据概览', 'en-US': 'Overview' }, // 可选
|
|
177
181
|
models: ['items'], // 必填:关联的数据模型
|
|
178
|
-
layout: [{ row: [{ type: 'stat', title: '总数', model: 'items', aggregate: 'count', span: 6 }] }],
|
|
182
|
+
layout: [{ row: [{ type: 'stat', title: { 'zh-CN': '总数', 'en-US': 'Total' }, model: 'items', aggregate: 'count', span: 6 }] }],
|
|
179
183
|
}],
|
|
180
184
|
});
|
|
181
185
|
```
|
|
182
186
|
|
|
187
|
+
### 多语言(i18n)
|
|
188
|
+
|
|
189
|
+
所有面向用户的展示字段均支持 `LocaleString` 格式:`string | Record<string, string>`。
|
|
190
|
+
|
|
191
|
+
- **简单写法**:`description: '科目'` — 所有语言显示相同文本
|
|
192
|
+
- **多语言写法**:`description: { 'zh-CN': '科目', 'en-US': 'Subject' }` — 切换语言时自动翻译
|
|
193
|
+
- **enum 值**:`enum` 始终是存储值(不分语言),显示文本通过 `enumLabels` 翻译
|
|
194
|
+
- **回退规则**:请求的 locale → `'zh-CN'` → 第一个可用值
|
|
195
|
+
|
|
196
|
+
支持的 LocaleString 字段:`project.description`、`ModelSchema.description`、`FieldDefinition.description`、`AIButtonConfig.label`、`DashboardConfig.description`、`DashboardWidget.title`、`RelationConfig.label`
|
|
197
|
+
|
|
198
|
+
生成页面会自动通过 `registerMessages()` 注册 i18n key,并使用 `t()` 调用引用,无需手动处理。
|
|
199
|
+
|
|
183
200
|
高级配置(`ai.claudeCode`、`server`、按模型 `adapters`、`indexes`)见 `references/data-model.md`。
|
|
184
201
|
|
|
185
202
|
## API 路由格式
|
|
186
203
|
|
|
187
204
|
后端 REST API 路径为 `/api/v1/data/<model-name>`,支持:`GET`(列表)、`GET /:id`(单条)、`POST`(创建)、`PUT /:id`(更新)、`DELETE /:id`(删除)、`GET /schema`(模型 Schema + AI 按钮)。
|
|
188
205
|
AI 相关:`POST /api/v1/chat`(SSE 流式对话)、`GET /api/v1/sessions`(会话列表)。
|
|
189
|
-
前端通过 `useData('<model-name>')` 自动访问,无需手动拼接。`useSchema('<model-name>')` 获取模型字段和 AI
|
|
206
|
+
前端通过 `useData('<model-name>')` 自动访问,无需手动拼接。`useSchema('<model-name>')` 获取模型字段和 AI 按钮定义,自动根据当前 locale 请求服务端 resolved 数据。`filterOptions(schema, fieldName)` 和 `selectOptions(schema, fieldName)` 将 enum 值转为 antd 组件格式(使用 resolved 的 enumLabels)。`enumLabel(schema, fieldName, value)` 获取单个 enum 值的显示标签。
|
|
190
207
|
|
|
191
208
|
## 常见问题
|
|
192
209
|
|
|
@@ -14,10 +14,10 @@ export default defineConfig({
|
|
|
14
14
|
data: { /* ... */ },
|
|
15
15
|
dashboards: [{
|
|
16
16
|
name: 'overview',
|
|
17
|
-
description: '数据概览',
|
|
17
|
+
description: { 'zh-CN': '数据概览', 'en-US': 'Overview' },
|
|
18
18
|
models: ['items'],
|
|
19
19
|
layout: [
|
|
20
|
-
{ row: [{ type: 'stat', title: '总数', model: 'items', aggregate: 'count', span: 6 }] },
|
|
20
|
+
{ row: [{ type: 'stat', title: { 'zh-CN': '总数', 'en-US': 'Total' }, model: 'items', aggregate: 'count', span: 6 }] },
|
|
21
21
|
],
|
|
22
22
|
}],
|
|
23
23
|
});
|
|
@@ -35,12 +35,12 @@ export default defineConfig({
|
|
|
35
35
|
```typescript
|
|
36
36
|
{
|
|
37
37
|
name: 'overview', // 必填:Dashboard 标识(同模型命名规则)
|
|
38
|
-
description: '数据概览',
|
|
38
|
+
description: { 'zh-CN': '数据概览', 'en-US': 'Overview' }, // 可选:支持多语言
|
|
39
39
|
models: ['model_a'], // 必填:关联的数据模型名列表
|
|
40
40
|
layout: [{ // 必填:布局定义,数组每项代表一行
|
|
41
41
|
row: [{ // 每行包含一组 widget
|
|
42
42
|
type: 'stat', // 图表类型,见下方图表类型表
|
|
43
|
-
title: '总数',
|
|
43
|
+
title: { 'zh-CN': '总数', 'en-US': 'Total' }, // 支持多语言
|
|
44
44
|
model: 'model_a', // 数据模型名
|
|
45
45
|
span: 6, // 可选:Col 宽度(1-24),省略则自动均分
|
|
46
46
|
aggregate: 'count', // 可选:count|sum|avg|min|max|ratio(默认 count)
|
|
@@ -142,48 +142,48 @@ export default defineConfig({
|
|
|
142
142
|
data: { /* ... */ },
|
|
143
143
|
dashboards: [{
|
|
144
144
|
name: 'overview',
|
|
145
|
-
description: '错题数据概览',
|
|
145
|
+
description: { 'zh-CN': '错题数据概览', 'en-US': 'Overview' },
|
|
146
146
|
models: ['wrong_questions', 'review_plans'],
|
|
147
147
|
layout: [
|
|
148
148
|
{
|
|
149
149
|
row: [
|
|
150
|
-
{ type: 'stat', title: '错题总数', model: 'wrong_questions', aggregate: 'count', span: 4 },
|
|
151
|
-
{ type: 'stat', title: '掌握率', model: 'wrong_questions', aggregate: 'ratio', filter: { isMastered: true }, span: 4 },
|
|
152
|
-
{ type: 'gauge', title: '掌握率仪表盘', model: 'wrong_questions', aggregate: 'ratio', filter: { isMastered: true }, span: 6 },
|
|
153
|
-
{ type: 'liquid', title: '掌握率水波图', model: 'wrong_questions', aggregate: 'ratio', filter: { isMastered: true }, span: 5 },
|
|
154
|
-
{ type: 'stat', title: '平均复习次数', model: 'wrong_questions', aggregate: 'avg', field: 'reviewCount', span: 5 }
|
|
150
|
+
{ type: 'stat', title: { 'zh-CN': '错题总数', 'en-US': 'Total Questions' }, model: 'wrong_questions', aggregate: 'count', span: 4 },
|
|
151
|
+
{ type: 'stat', title: { 'zh-CN': '掌握率', 'en-US': 'Mastery Rate' }, model: 'wrong_questions', aggregate: 'ratio', filter: { isMastered: true }, span: 4 },
|
|
152
|
+
{ type: 'gauge', title: { 'zh-CN': '掌握率仪表盘', 'en-US': 'Mastery Gauge' }, model: 'wrong_questions', aggregate: 'ratio', filter: { isMastered: true }, span: 6 },
|
|
153
|
+
{ type: 'liquid', title: { 'zh-CN': '掌握率水波图', 'en-US': 'Mastery Liquid' }, model: 'wrong_questions', aggregate: 'ratio', filter: { isMastered: true }, span: 5 },
|
|
154
|
+
{ type: 'stat', title: { 'zh-CN': '平均复习次数', 'en-US': 'Avg Reviews' }, model: 'wrong_questions', aggregate: 'avg', field: 'reviewCount', span: 5 }
|
|
155
155
|
]
|
|
156
156
|
},
|
|
157
157
|
{
|
|
158
158
|
row: [
|
|
159
|
-
{ type: 'pie', title: '科目分布', model: 'wrong_questions', groupBy: 'subject', span: 8 },
|
|
160
|
-
{ type: 'ring', title: '难度分布', model: 'wrong_questions', groupBy: 'difficulty', span: 8 },
|
|
161
|
-
{ type: 'bar', title: '错误类型分布', model: 'wrong_questions', groupBy: 'errorType', span: 8 }
|
|
159
|
+
{ type: 'pie', title: { 'zh-CN': '科目分布', 'en-US': 'By Subject' }, model: 'wrong_questions', groupBy: 'subject', span: 8 },
|
|
160
|
+
{ type: 'ring', title: { 'zh-CN': '难度分布', 'en-US': 'By Difficulty' }, model: 'wrong_questions', groupBy: 'difficulty', span: 8 },
|
|
161
|
+
{ type: 'bar', title: { 'zh-CN': '错误类型分布', 'en-US': 'By Error Type' }, model: 'wrong_questions', groupBy: 'errorType', span: 8 }
|
|
162
162
|
]
|
|
163
163
|
},
|
|
164
164
|
{
|
|
165
165
|
row: [
|
|
166
|
-
{ type: 'line', title: '错题录入趋势', model: 'wrong_questions', groupBy: 'createdAt', interval: 'month', span: 12 },
|
|
167
|
-
{ type: 'area', title: '复习计划趋势', model: 'review_plans', groupBy: 'createdAt', interval: 'month', span: 12 }
|
|
166
|
+
{ type: 'line', title: { 'zh-CN': '错题录入趋势', 'en-US': 'Questions Trend' }, model: 'wrong_questions', groupBy: 'createdAt', interval: 'month', span: 12 },
|
|
167
|
+
{ type: 'area', title: { 'zh-CN': '复习计划趋势', 'en-US': 'Review Plans Trend' }, model: 'review_plans', groupBy: 'createdAt', interval: 'month', span: 12 }
|
|
168
168
|
]
|
|
169
169
|
},
|
|
170
170
|
{
|
|
171
171
|
row: [
|
|
172
|
-
{ type: 'radar', title: '各科目概览', model: 'wrong_questions', groupBy: 'subject', span: 8 },
|
|
173
|
-
{ type: 'stacked_bar', title: '科目×错误类型', model: 'wrong_questions', groupBy: 'subject', crossGroupBy: 'errorType', span: 8 },
|
|
174
|
-
{ type: 'grouped_bar', title: '科目×难度', model: 'wrong_questions', groupBy: 'subject', crossGroupBy: 'difficulty', span: 8 }
|
|
172
|
+
{ type: 'radar', title: { 'zh-CN': '各科目概览', 'en-US': 'Subject Overview' }, model: 'wrong_questions', groupBy: 'subject', span: 8 },
|
|
173
|
+
{ type: 'stacked_bar', title: { 'zh-CN': '科目×错误类型', 'en-US': 'Subject × Error Type' }, model: 'wrong_questions', groupBy: 'subject', crossGroupBy: 'errorType', span: 8 },
|
|
174
|
+
{ type: 'grouped_bar', title: { 'zh-CN': '科目×难度', 'en-US': 'Subject × Difficulty' }, model: 'wrong_questions', groupBy: 'subject', crossGroupBy: 'difficulty', span: 8 }
|
|
175
175
|
]
|
|
176
176
|
},
|
|
177
177
|
{
|
|
178
178
|
row: [
|
|
179
|
-
{ type: 'scatter', title: '科目分布散点', model: 'wrong_questions', groupBy: 'subject', span: 8 },
|
|
180
|
-
{ type: 'funnel', title: '错误类型漏斗', model: 'wrong_questions', groupBy: 'errorType', span: 8 },
|
|
181
|
-
{ type: 'treemap', title: '科目×难度树图', model: 'wrong_questions', groupBy: 'subject', crossGroupBy: 'difficulty', span: 8 }
|
|
179
|
+
{ type: 'scatter', title: { 'zh-CN': '科目分布散点', 'en-US': 'Subject Scatter' }, model: 'wrong_questions', groupBy: 'subject', span: 8 },
|
|
180
|
+
{ type: 'funnel', title: { 'zh-CN': '错误类型漏斗', 'en-US': 'Error Type Funnel' }, model: 'wrong_questions', groupBy: 'errorType', span: 8 },
|
|
181
|
+
{ type: 'treemap', title: { 'zh-CN': '科目×难度树图', 'en-US': 'Subject × Difficulty Tree' }, model: 'wrong_questions', groupBy: 'subject', crossGroupBy: 'difficulty', span: 8 }
|
|
182
182
|
]
|
|
183
183
|
},
|
|
184
184
|
{
|
|
185
185
|
row: [
|
|
186
|
-
{ type: 'heatmap', title: '科目×年级热力图', model: 'wrong_questions', groupBy: 'subject', crossGroupBy: 'grade', span: 24 }
|
|
186
|
+
{ type: 'heatmap', title: { 'zh-CN': '科目×年级热力图', 'en-US': 'Subject × Grade Heatmap' }, model: 'wrong_questions', groupBy: 'subject', crossGroupBy: 'grade', span: 24 }
|
|
187
187
|
]
|
|
188
188
|
}
|
|
189
189
|
]
|
|
@@ -9,9 +9,14 @@ Advanced configuration for `loom.config.ts`. Full type definitions from `package
|
|
|
9
9
|
name: 'status', // ^[a-zA-Z_][a-zA-Z0-9_]*$
|
|
10
10
|
type: 'string', // 'string' | 'number' | 'boolean' | 'date' | 'string[]' | 'number[]' | 'json'
|
|
11
11
|
required: true, // optional, default false
|
|
12
|
-
description: '
|
|
12
|
+
description: { 'zh-CN': '状态', 'en-US': 'Status' }, // optional: LocaleString, shown in generated forms
|
|
13
13
|
default: 'active', // optional: auto-filled on write if not provided
|
|
14
|
-
enum: ['active', 'inactive', 'archived'], // optional: restrict string field to allowed values
|
|
14
|
+
enum: ['active', 'inactive', 'archived'], // optional: restrict string field to allowed values (storage values)
|
|
15
|
+
enumLabels: { // optional: display labels per locale for each enum value
|
|
16
|
+
active: { 'zh-CN': '激活', 'en-US': 'Active' },
|
|
17
|
+
inactive: { 'zh-CN': '停用', 'en-US': 'Inactive' },
|
|
18
|
+
archived: { 'zh-CN': '归档', 'en-US': 'Archived' },
|
|
19
|
+
},
|
|
15
20
|
}
|
|
16
21
|
```
|
|
17
22
|
|
|
@@ -20,7 +25,7 @@ Advanced configuration for `loom.config.ts`. Full type definitions from `package
|
|
|
20
25
|
```typescript
|
|
21
26
|
{
|
|
22
27
|
name: 'orders', // ^[a-zA-Z][a-zA-Z0-9_]*$, will be used as React component name
|
|
23
|
-
description: 'Order
|
|
28
|
+
description: { 'zh-CN': '订单记录', 'en-US': 'Order Records' }, // optional: LocaleString, shown in page heading
|
|
24
29
|
fields: [...],
|
|
25
30
|
indexes?: [{ fields: ['userId', 'status'], unique: false }],
|
|
26
31
|
adapters?: { // optional: per-model adapter override
|
|
@@ -35,7 +40,7 @@ Advanced configuration for `loom.config.ts`. Full type definitions from `package
|
|
|
35
40
|
```typescript
|
|
36
41
|
aiButtons: [{
|
|
37
42
|
id: 'summarize', // required: unique identifier
|
|
38
|
-
label: '总结',
|
|
43
|
+
label: { 'zh-CN': '总结', 'en-US': 'Summarize' }, // required: LocaleString, button text
|
|
39
44
|
icon: 'FileTextOutlined', // optional: Ant Design icon component name
|
|
40
45
|
prompt: '请总结以下内容', // required: supports {{var}} placeholders, replaced with current row field values
|
|
41
46
|
placement: 'wrong_questions', // optional: limit to specific model pages, comma-separated; omit for all pages
|
|
@@ -82,12 +87,12 @@ data: {
|
|
|
82
87
|
```typescript
|
|
83
88
|
dashboards: [{
|
|
84
89
|
name: 'overview', // ^[a-zA-Z][a-zA-Z0-9_]*$, same naming rules as model
|
|
85
|
-
description: '数据概览',
|
|
90
|
+
description: { 'zh-CN': '数据概览', 'en-US': 'Overview' }, // optional: LocaleString, shown in sidebar
|
|
86
91
|
models: ['items'], // required: data models included in this dashboard
|
|
87
92
|
layout: [{ // required: at least one row
|
|
88
93
|
row: [{ // at least one widget per row
|
|
89
94
|
type: 'stat' | 'pie' | 'ring' | 'bar' | 'line' | 'area' | 'scatter' | 'radar' | 'funnel' | 'treemap' | 'gauge' | 'liquid' | 'heatmap' | 'stacked_bar' | 'grouped_bar',
|
|
90
|
-
title: '任务总数',
|
|
95
|
+
title: { 'zh-CN': '任务总数', 'en-US': 'Total Tasks' }, // required: LocaleString, display title
|
|
91
96
|
model: 'items', // required: data model name
|
|
92
97
|
span: 6, // optional: Ant Design Grid Col span (1-24), auto-equal-split if omitted
|
|
93
98
|
groupBy: 'status', // optional: group by field for aggregation
|
|
@@ -103,14 +108,28 @@ dashboards: [{
|
|
|
103
108
|
|
|
104
109
|
## useSchema Runtime API
|
|
105
110
|
|
|
106
|
-
Generated pages use `useSchema(model)` to fetch model schema and AI buttons at runtime:
|
|
111
|
+
Generated pages use `useSchema(model)` to fetch model schema and AI buttons at runtime. Schema is auto-resolved by current locale:
|
|
107
112
|
|
|
108
113
|
```typescript
|
|
109
114
|
const { schema, loading, error } = useSchema('items');
|
|
110
|
-
// schema.fields — field definitions with
|
|
111
|
-
// schema.
|
|
115
|
+
// schema.fields — field definitions with resolved LocaleString (e.g. description is string, not LocaleString)
|
|
116
|
+
// schema.fields[].enumLabels — resolved to { [enumValue]: displayLabel } for current locale
|
|
117
|
+
// schema.aiButtons — AI buttons filtered by placement, label resolved to current locale
|
|
118
|
+
|
|
119
|
+
// Convert schema enum to antd formats (uses resolved enumLabels):
|
|
120
|
+
filterOptions(schema, 'status') // → [{ text: '激活', value: 'active' }, ...]
|
|
121
|
+
selectOptions(schema, 'status') // → [{ label: '激活', value: 'active' }, ...]
|
|
122
|
+
|
|
123
|
+
// Get display label for a single enum value:
|
|
124
|
+
enumLabel(schema, 'status', 'active') // → '激活'
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## LocaleString
|
|
128
|
+
|
|
129
|
+
All user-facing string fields support `LocaleString` format: `string | Record<string, string>`.
|
|
130
|
+
|
|
131
|
+
- **Simple**: `description: '科目'` — same text for all locales
|
|
132
|
+
- **Multi-locale**: `description: { 'zh-CN': '科目', 'en-US': 'Subject' }` — auto-translated on locale switch
|
|
133
|
+
- **Fallback**: requested locale → `'zh-CN'` → first available value
|
|
112
134
|
|
|
113
|
-
|
|
114
|
-
filterOptions(schema, 'status') // → [{ text: 'active', value: 'active' }, ...]
|
|
115
|
-
selectOptions(schema, 'status') // → [{ label: 'active', value: 'active' }, ...]
|
|
116
|
-
```
|
|
135
|
+
Supported fields: `project.description`, `ModelSchema.description`, `FieldDefinition.description`, `AIButtonConfig.label`, `DashboardConfig.description`, `DashboardWidget.title`, `RelationConfig.label`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frontend-entry.d.ts","sourceRoot":"","sources":["../../../src/cli/templates/frontend-entry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,4BAA4B;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,aAAa,IAAI,MAAM,CAWtC;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,4BAA4B,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"frontend-entry.d.ts","sourceRoot":"","sources":["../../../src/cli/templates/frontend-entry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,4BAA4B;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,aAAa,IAAI,MAAM,CAWtC;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,4BAA4B,GAAG,MAAM,CAiE1E;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,4BAA4B,GAAG,MAAM,CAc7E"}
|
|
@@ -15,7 +15,7 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
|
15
15
|
}
|
|
16
16
|
export function createAppTsx(options) {
|
|
17
17
|
return `import React, { useState } from 'react';
|
|
18
|
-
import { AppShell,
|
|
18
|
+
import { AppShell, useLocale, registerMessages, LoomConfigProvider } from '@loom-framework/frontend-antd';
|
|
19
19
|
import type { BreadcrumbItem } from '@loom-framework/frontend-antd';
|
|
20
20
|
|
|
21
21
|
// Register i18n keys for nav items and breadcrumbs
|
|
@@ -28,7 +28,7 @@ registerMessages('en-US', {
|
|
|
28
28
|
'nav.skill-management': 'Skill Management',
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
function AppContent() {
|
|
32
32
|
const [selectedKey, setSelectedKey] = useState('');
|
|
33
33
|
const { t } = useLocale();
|
|
34
34
|
|
|
@@ -48,7 +48,7 @@ export default function App() {
|
|
|
48
48
|
default:
|
|
49
49
|
return (
|
|
50
50
|
<div style={{ padding: 24 }}>
|
|
51
|
-
<h2
|
|
51
|
+
<h2>{t('nav.home')}</h2>
|
|
52
52
|
<p>${options.description || 'A Loom application.'}</p>
|
|
53
53
|
<p>运行 <code>loom generate page <Name> --model <model></code> 生成页面。</p>
|
|
54
54
|
</div>
|
|
@@ -69,6 +69,14 @@ export default function App() {
|
|
|
69
69
|
</AppShell>
|
|
70
70
|
);
|
|
71
71
|
}
|
|
72
|
+
|
|
73
|
+
export default function App() {
|
|
74
|
+
return (
|
|
75
|
+
<LoomConfigProvider>
|
|
76
|
+
<AppContent />
|
|
77
|
+
</LoomConfigProvider>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
72
80
|
`;
|
|
73
81
|
}
|
|
74
82
|
export function createIndexHtml(options) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frontend-entry.js","sourceRoot":"","sources":["../../../src/cli/templates/frontend-entry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,MAAM,UAAU,aAAa;IAC3B,OAAO;;;;;;;;;CASR,CAAC;AACF,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAqC;IAChE,OAAO;;;;;;iBAMQ,OAAO,CAAC,IAAI;;;;iBAIZ,OAAO,CAAC,IAAI
|
|
1
|
+
{"version":3,"file":"frontend-entry.js","sourceRoot":"","sources":["../../../src/cli/templates/frontend-entry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,MAAM,UAAU,aAAa;IAC3B,OAAO;;;;;;;;;CASR,CAAC;AACF,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAqC;IAChE,OAAO;;;;;;iBAMQ,OAAO,CAAC,IAAI;;;;iBAIZ,OAAO,CAAC,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;iBAyBZ,OAAO,CAAC,WAAW,IAAI,qBAAqB;;;;;;;;;eAS9C,OAAO,CAAC,IAAI;;;;;;;;;;;;;;;;;;;CAmB1B,CAAC;AACF,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAqC;IACnE,OAAO;;;;;aAKI,OAAO,CAAC,IAAI;;;;;;;CAOxB,CAAC;AACF,CAAC"}
|
package/package.json
CHANGED