@morya-ui/setup 0.3.3 → 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 +103 -103
- package/bin/morya-ui-setup.js +14 -14
- package/catalog/skills.json +46 -46
- package/package.json +5 -3
- package/src/cli.mjs +335 -335
- package/src/copy-template.mjs +78 -78
- package/src/fs-utils.mjs +24 -24
- package/src/install.mjs +63 -63
- package/src/mcp.mjs +50 -50
- package/src/package-json.mjs +30 -30
- package/src/skills.mjs +223 -223
- package/src/styles.mjs +119 -119
- package/template/.agents/skills/morya-ui-pages/SKILL.md +184 -164
- package/template/.agents/skills/morya-ui-pages/evals/evals.json +89 -89
- package/template/.agents/skills/morya-ui-pages/references/component-index.md +99 -99
- package/template/.agents/skills/morya-ui-pages/references/decision-recipes.md +32 -0
- package/template/.agents/skills/morya-ui-pages/references/design-system.md +101 -100
- package/template/.agents/skills/morya-ui-pages/references/feedback.md +68 -68
- package/template/.agents/skills/morya-ui-pages/references/optional-companions.md +107 -34
- package/template/.agents/skills/morya-ui-pages/references/page-layouts.md +141 -119
- package/template/.agents/skills/morya-ui-pages/references/review-checklist.md +64 -61
- package/template/.agents/skills/morya-ui-pages/references/style-presets.md +73 -0
- package/template/.agents/skills/morya-ui-pages/references/surfaces.md +91 -89
- package/template/.agents/skills/morya-ui-pages/references/visual-craft.md +221 -196
- package/template/.cursor/rules/coding-style.mdc +41 -41
- package/template/.cursor/rules/component-usage.mdc +41 -41
- package/template/.cursor/rules/design-system.mdc +17 -17
- package/template/.cursor/rules/page-layout.mdc +97 -78
- package/template/DESIGN.md +59 -59
- package/template/scripts/check-raw-colors.mjs +74 -74
- package/LICENSE +0 -21
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Vue 3 + TypeScript 业务代码风格(Morya UI 项目)
|
|
3
|
-
globs: "**/*.{ts,vue}"
|
|
4
|
-
alwaysApply: false
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# 编码风格
|
|
8
|
-
|
|
9
|
-
## Vue
|
|
10
|
-
|
|
11
|
-
- 使用 `<script setup lang="ts">`。
|
|
12
|
-
- 组件名 PascalCase;模板中用 `M*` 前缀组件。
|
|
13
|
-
- `v-model` 与组件库 emit 对齐(如 `v-model:page`)。
|
|
14
|
-
- 页面级样式 `scoped`;仅使用 `--m-*` 与设计令牌。
|
|
15
|
-
|
|
16
|
-
## TypeScript
|
|
17
|
-
|
|
18
|
-
- Props/emit 显式类型;避免 `any`。
|
|
19
|
-
- 异步提交:`loading` ref + `try/finally`。
|
|
20
|
-
|
|
21
|
-
## 文件组织
|
|
22
|
-
|
|
23
|
-
```text
|
|
24
|
-
src/
|
|
25
|
-
views/ # 路由页面
|
|
26
|
-
components/ # 业务组件
|
|
27
|
-
composables/ # 复用逻辑
|
|
28
|
-
api/ # 请求层
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## 命名
|
|
32
|
-
|
|
33
|
-
- 页面:`UserListView.vue` / `UserFormView.vue`
|
|
34
|
-
- 路由 path kebab-case:`/users/create`
|
|
35
|
-
|
|
36
|
-
## 检查
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
pnpm check:colors # 裸色值扫描
|
|
40
|
-
pnpm typecheck
|
|
41
|
-
```
|
|
1
|
+
---
|
|
2
|
+
description: Vue 3 + TypeScript 业务代码风格(Morya UI 项目)
|
|
3
|
+
globs: "**/*.{ts,vue}"
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 编码风格
|
|
8
|
+
|
|
9
|
+
## Vue
|
|
10
|
+
|
|
11
|
+
- 使用 `<script setup lang="ts">`。
|
|
12
|
+
- 组件名 PascalCase;模板中用 `M*` 前缀组件。
|
|
13
|
+
- `v-model` 与组件库 emit 对齐(如 `v-model:page`)。
|
|
14
|
+
- 页面级样式 `scoped`;仅使用 `--m-*` 与设计令牌。
|
|
15
|
+
|
|
16
|
+
## TypeScript
|
|
17
|
+
|
|
18
|
+
- Props/emit 显式类型;避免 `any`。
|
|
19
|
+
- 异步提交:`loading` ref + `try/finally`。
|
|
20
|
+
|
|
21
|
+
## 文件组织
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
src/
|
|
25
|
+
views/ # 路由页面
|
|
26
|
+
components/ # 业务组件
|
|
27
|
+
composables/ # 复用逻辑
|
|
28
|
+
api/ # 请求层
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## 命名
|
|
32
|
+
|
|
33
|
+
- 页面:`UserListView.vue` / `UserFormView.vue`
|
|
34
|
+
- 路由 path kebab-case:`/users/create`
|
|
35
|
+
|
|
36
|
+
## 检查
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pnpm check:colors # 裸色值扫描
|
|
40
|
+
pnpm typecheck
|
|
41
|
+
```
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Morya UI 组件用法与选型(Vue 业务代码)
|
|
3
|
-
globs: src/**/*.vue
|
|
4
|
-
alwaysApply: false
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# 组件用法
|
|
8
|
-
|
|
9
|
-
## 引入
|
|
10
|
-
|
|
11
|
-
```ts
|
|
12
|
-
import { MButton, MInput } from 'morya-ui'
|
|
13
|
-
// 按需:import MButton from 'morya-ui/button'
|
|
14
|
-
// import 'morya-ui/button/style'
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## 必选模式
|
|
18
|
-
|
|
19
|
-
- 表单:`MForm` + `MFormItem` + 字段组件;提交用 `@submit` + `type="submit"`。
|
|
20
|
-
- 表格:`MTable` 的 `columns` + `rows` + `row-key`;单元格用 `#cell-{key}` 插槽。没有 `data` prop。
|
|
21
|
-
- 浮层:详情/编辑 `MDialog`;侧栏 `MDrawer`;删除确认 `MConfirmDialog`。
|
|
22
|
-
- 反馈(**默认 Message**):
|
|
23
|
-
- 单行操作结果 → `message.success/info/warn/error('…')`
|
|
24
|
-
- 有标题 + 详情 / 异步通知 → `toast.*({ summary, detail })`
|
|
25
|
-
- 表单区常驻错误 → 字段 `errorMessage`,或 token 样式的 `role="alert"`(`<MMessage>` 只是 message 宿主,不是内嵌 Alert)
|
|
26
|
-
- 详见 skill `references/feedback.md`
|
|
27
|
-
|
|
28
|
-
## Props 约定
|
|
29
|
-
|
|
30
|
-
- 尺寸:`size="small" | "large"`(默认 medium)。
|
|
31
|
-
- 危险:`severity="danger"` 或 `invalid` + `errorMessage`。
|
|
32
|
-
- 清除:优先 `clearable`(Select 亦支持 `showClear` 别名)。
|
|
33
|
-
- 宽度:表单字段 `fluid`;页面级宽度用 layout CSS + `max-width`。
|
|
34
|
-
|
|
35
|
-
## 禁止
|
|
36
|
-
|
|
37
|
-
- 同一页面混用其他 UI 库。
|
|
38
|
-
- 用 `MDropdown` 代替 Select 做枚举选择。
|
|
39
|
-
- 手写 table/modal 替代 `MTable` / `MDialog`。
|
|
40
|
-
|
|
41
|
-
完整清单:MCP `recommend_component`(含 recipe),或 skill `references/decision-recipes.md` / `component-index.md`。
|
|
1
|
+
---
|
|
2
|
+
description: Morya UI 组件用法与选型(Vue 业务代码)
|
|
3
|
+
globs: src/**/*.vue
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 组件用法
|
|
8
|
+
|
|
9
|
+
## 引入
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { MButton, MInput } from 'morya-ui'
|
|
13
|
+
// 按需:import MButton from 'morya-ui/button'
|
|
14
|
+
// import 'morya-ui/button/style'
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 必选模式
|
|
18
|
+
|
|
19
|
+
- 表单:`MForm` + `MFormItem` + 字段组件;提交用 `@submit` + `type="submit"`。
|
|
20
|
+
- 表格:`MTable` 的 `columns` + `rows` + `row-key`;单元格用 `#cell-{key}` 插槽。没有 `data` prop。
|
|
21
|
+
- 浮层:详情/编辑 `MDialog`;侧栏 `MDrawer`;删除确认 `MConfirmDialog`。
|
|
22
|
+
- 反馈(**默认 Message**):
|
|
23
|
+
- 单行操作结果 → `message.success/info/warn/error('…')`
|
|
24
|
+
- 有标题 + 详情 / 异步通知 → `toast.*({ summary, detail })`
|
|
25
|
+
- 表单区常驻错误 → 字段 `errorMessage`,或 token 样式的 `role="alert"`(`<MMessage>` 只是 message 宿主,不是内嵌 Alert)
|
|
26
|
+
- 详见 skill `references/feedback.md`
|
|
27
|
+
|
|
28
|
+
## Props 约定
|
|
29
|
+
|
|
30
|
+
- 尺寸:`size="small" | "large"`(默认 medium)。
|
|
31
|
+
- 危险:`severity="danger"` 或 `invalid` + `errorMessage`。
|
|
32
|
+
- 清除:优先 `clearable`(Select 亦支持 `showClear` 别名)。
|
|
33
|
+
- 宽度:表单字段 `fluid`;页面级宽度用 layout CSS + `max-width`。
|
|
34
|
+
|
|
35
|
+
## 禁止
|
|
36
|
+
|
|
37
|
+
- 同一页面混用其他 UI 库。
|
|
38
|
+
- 用 `MDropdown` 代替 Select 做枚举选择。
|
|
39
|
+
- 手写 table/modal 替代 `MTable` / `MDialog`。
|
|
40
|
+
|
|
41
|
+
完整清单:MCP `recommend_component`(含 recipe),或 skill `references/decision-recipes.md` / `component-index.md`。
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Morya UI 设计系统第一信源。生成或修改 UI 前必读 DESIGN.md。
|
|
3
|
-
alwaysApply: true
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Morya UI 设计系统
|
|
7
|
-
|
|
8
|
-
1. **先读** 项目根目录 `DESIGN.md`。组件选型用 MCP `recommend_component`(含 recipe),或 skill `references/decision-recipes.md` / `component-index.md`。
|
|
9
|
-
2. **只用** `morya-ui` 的 `M*` 组件;全局样式 `morya-ui/styles.css`。
|
|
10
|
-
3. **颜色/间距/圆角** 使用 `--m-*` CSS 变量,禁止裸 hex/rgb(见 `scripts/check-raw-colors.mjs`)。
|
|
11
|
-
4. **页面结构** 用 MCP `get_golden_page
|
|
12
|
-
5. **表单选项** 用 `MSelect` / `MTreeSelect`;**动作菜单** 用 `MDropdown`。
|
|
13
|
-
6. 不确定 API 时查文档站或 MCP `get_component`,**禁止臆造 prop**;写完后必须 `validate_usage`。
|
|
14
|
-
7. 根节点用 `MConfigProvider`;后台布局用 `MLayout` 系列。
|
|
15
|
-
8. **操作反馈默认 `message` API**;仅 `summary + detail` 或异步通知用 `toast`;表单常驻错误用字段 `errorMessage` 或 token 样式的 `role="alert"`(`<MMessage>` 只是 message 宿主)。见 skill `references/feedback.md`。
|
|
16
|
-
|
|
17
|
-
Token
|
|
1
|
+
---
|
|
2
|
+
description: Morya UI 设计系统第一信源。生成或修改 UI 前必读 DESIGN.md。
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Morya UI 设计系统
|
|
7
|
+
|
|
8
|
+
1. **先读** 项目根目录 `DESIGN.md`。组件选型用 MCP `recommend_component`(含 recipe),或 skill `references/decision-recipes.md` / `component-index.md`。
|
|
9
|
+
2. **只用** `morya-ui` 的 `M*` 组件;全局样式 `morya-ui/styles.css`。
|
|
10
|
+
3. **颜色/间距/圆角** 使用 `--m-*` CSS 变量,禁止裸 hex/rgb(见 `scripts/check-raw-colors.mjs`)。
|
|
11
|
+
4. **页面结构** 用 MCP `get_golden_page` 对齐区块顺序与 API;**视觉方向**按参考样式 / 用户指定风格 / 提示词推断(`list_style_presets`:quiet、soft、dense、rail、studio、ink)。已安装 `frontend-design` / `impeccable` 时只加深审美与抛光,**不得**换组件库或推翻黄金结构。
|
|
12
|
+
5. **表单选项** 用 `MSelect` / `MTreeSelect`;**动作菜单** 用 `MDropdown`。
|
|
13
|
+
6. 不确定 API 时查文档站或 MCP `get_component`,**禁止臆造 prop**;写完后必须 `validate_usage`。
|
|
14
|
+
7. 根节点用 `MConfigProvider`;后台布局用 `MLayout` 系列。
|
|
15
|
+
8. **操作反馈默认 `message` API**;仅 `summary + detail` 或异步通知用 `toast`;表单常驻错误用字段 `errorMessage` 或 token 样式的 `role="alert"`(`<MMessage>` 只是 message 宿主)。见 skill `references/feedback.md`。
|
|
16
|
+
|
|
17
|
+
Token / 风格 / companion:MCP `get_design_rules`、`list_style_presets`;skill `optional-companions.md`(运行时以 `morya-ui/styles.css` 为准)
|
|
@@ -1,78 +1,97 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: 生成 Morya UI 业务页面(列表/表单/仪表盘)时的布局规范
|
|
3
|
-
alwaysApply: false
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# 页面布局(Agent Requested)
|
|
7
|
-
|
|
8
|
-
生成完整页面时,先确定类型并 **复制黄金样例结构**:
|
|
9
|
-
|
|
10
|
-
| 类型 | MCP `get_golden_page` |
|
|
11
|
-
| --- | --- |
|
|
12
|
-
| 列表页 | `list-page` |
|
|
13
|
-
| 表单页 | `form-page`(仅长表单 / 独立配置页) |
|
|
14
|
-
| 列表内弹窗表单 | `form-in-dialog` |
|
|
15
|
-
| 详情页 | `detail-page` |
|
|
16
|
-
| 结果 / 阻断页 | `result-page` |
|
|
17
|
-
| 设置页 | `settings-page` |
|
|
18
|
-
| 分步向导 | `wizard-form` |
|
|
19
|
-
| 仪表盘 | `dashboard-page` |
|
|
20
|
-
| 登录页 | `login-page` |
|
|
21
|
-
| 营销落地 | `landing-page` |
|
|
22
|
-
| 空状态 | `empty-state` |
|
|
23
|
-
|
|
24
|
-
## 列表内新建 / 编辑(默认)
|
|
25
|
-
|
|
26
|
-
后台 CRUD **优先**:列表页 + `MDialog`(或 `MDrawer`)内 `MForm`,不要把「新建用户 / 编辑角色」做成单独路由,除非字段很多或多步骤。
|
|
27
|
-
|
|
28
|
-
## 列表页区块顺序
|
|
29
|
-
|
|
30
|
-
1. `MLayout fillViewport` + 可选 `MLayoutSider bordered`
|
|
31
|
-
2. 侧栏 `MMenu`
|
|
32
|
-
3. `MLayoutHeader` → `MBreadcrumb`
|
|
33
|
-
4. `MLayoutContent` → `MPageContent`
|
|
34
|
-
5. `MPageHeader`(页面标题 + `#actions` 主操作;视口内 **唯一** filled primary)
|
|
35
|
-
6. `MPageFilters`(可选 `variant="filled"`、`collapsible` + `#advanced`;查询/重置用 secondary)
|
|
36
|
-
7. 可选 `MPageFilterChips` + 可关闭 `MTag`(有已选条件时,放在筛选与表格之间)
|
|
37
|
-
8. 可选 `MPageToolbar`(仅批量操作,**不要**页面标题)
|
|
38
|
-
9. `MTable`(直接放置;`#empty` → `MEmpty`)
|
|
39
|
-
10. 分页由 `MTable paginator` 或同级 `MPagination`
|
|
40
|
-
11. 短新建/编辑:同页 `MDialog` + `MForm`
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
1
|
+
---
|
|
2
|
+
description: 生成 Morya UI 业务页面(列表/表单/仪表盘)时的布局规范
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 页面布局(Agent Requested)
|
|
7
|
+
|
|
8
|
+
生成完整页面时,先确定类型并 **复制黄金样例结构**:
|
|
9
|
+
|
|
10
|
+
| 类型 | MCP `get_golden_page` |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 列表页 | `list-page` |
|
|
13
|
+
| 表单页 | `form-page`(仅长表单 / 独立配置页) |
|
|
14
|
+
| 列表内弹窗表单 | `form-in-dialog` |
|
|
15
|
+
| 详情页 | `detail-page` |
|
|
16
|
+
| 结果 / 阻断页 | `result-page` |
|
|
17
|
+
| 设置页 | `settings-page` |
|
|
18
|
+
| 分步向导 | `wizard-form` |
|
|
19
|
+
| 仪表盘 | `dashboard-page` |
|
|
20
|
+
| 登录页 | `login-page` |
|
|
21
|
+
| 营销落地 | `landing-page` |
|
|
22
|
+
| 空状态 | `empty-state` |
|
|
23
|
+
|
|
24
|
+
## 列表内新建 / 编辑(默认)
|
|
25
|
+
|
|
26
|
+
后台 CRUD **优先**:列表页 + `MDialog`(或 `MDrawer`)内 `MForm`,不要把「新建用户 / 编辑角色」做成单独路由,除非字段很多或多步骤。
|
|
27
|
+
|
|
28
|
+
## 列表页区块顺序
|
|
29
|
+
|
|
30
|
+
1. `MLayout fillViewport` + 可选 `MLayoutSider bordered`
|
|
31
|
+
2. 侧栏 `MMenu`
|
|
32
|
+
3. `MLayoutHeader` → `MBreadcrumb`
|
|
33
|
+
4. `MLayoutContent` → `MPageContent`(**仅在下方高度规则适用时**再加 `fill`)
|
|
34
|
+
5. `MPageHeader`(页面标题 + `#actions` 主操作;视口内 **唯一** filled primary)
|
|
35
|
+
6. `MPageFilters`(可选 `variant="filled"`、`collapsible` + `#advanced`;查询/重置用 secondary)
|
|
36
|
+
7. 可选 `MPageFilterChips` + 可关闭 `MTag`(有已选条件时,放在筛选与表格之间)
|
|
37
|
+
8. 可选 `MPageToolbar`(仅批量操作,**不要**页面标题)
|
|
38
|
+
9. `MTable`(直接放置;`#empty` → `MEmpty`)
|
|
39
|
+
10. 分页由 `MTable paginator` 或同级 `MPagination`
|
|
40
|
+
11. 短新建/编辑:同页 `MDialog` + `MForm`
|
|
41
|
+
|
|
42
|
+
### 列表高度 — 先判断,再决定是否 fill
|
|
43
|
+
|
|
44
|
+
仅当 **多数** 条件成立时使用 `MPageContent fill` + `MTable fill paginator`:
|
|
45
|
+
|
|
46
|
+
- 全视口后台列表(`MLayout fillViewport`),页面主任务就是浏览一张表
|
|
47
|
+
- 表格按内容高度会留下大块空白、分页悬在中间不好看
|
|
48
|
+
- 希望表体内部滚动、分页贴在页面最下方
|
|
49
|
+
|
|
50
|
+
以下情况 **不要** 用 `fill`:
|
|
51
|
+
|
|
52
|
+
- 嵌入/次要表格(仪表盘「最近」、详情关联表、Card 内)
|
|
53
|
+
- 内容本身很短,内容高度表格即可
|
|
54
|
+
- 整页应作为文档滚动(长筛选 + 说明 + 表格)
|
|
55
|
+
- Dialog / Drawer 内表格
|
|
56
|
+
- 表格不是中间唯一主区域的混合布局
|
|
57
|
+
|
|
58
|
+
适合 `fill` 时不要手写 `min-height` / `calc`;不适合时不要硬套 `fill`。
|
|
59
|
+
|
|
60
|
+
## 表单页区块顺序
|
|
61
|
+
|
|
62
|
+
1. `MLayout fillViewport` → `MLayoutHeader` → `MBreadcrumb`
|
|
63
|
+
2. `MPageContent width="narrow"`
|
|
64
|
+
3. `MPageHeader`(标题 + 说明)
|
|
65
|
+
4. `MPageSection variant="form"` → `MForm`
|
|
66
|
+
5. `MPageSection variant="actions"`:保存(primary)+ 取消(secondary)
|
|
67
|
+
|
|
68
|
+
## 仪表盘区块顺序
|
|
69
|
+
|
|
70
|
+
1. `MLayout fillViewport` → `MLayoutHeader` → `MBreadcrumb`
|
|
71
|
+
2. `MPageContent density="spacious"` → `MPageHeader`
|
|
72
|
+
3. KPI:`MGrid` + `MPageStat`(4 列或响应式)
|
|
73
|
+
4. 主区两栏:`MCard shadow="always"` + `MEmpty`(图表未接入)/ 最近列表 `MTable`
|
|
74
|
+
|
|
75
|
+
## 页面标准
|
|
76
|
+
|
|
77
|
+
推荐实践(非强制),完整列表见 MCP `get_design_rules` → `standards`:
|
|
78
|
+
|
|
79
|
+
| 主题 | 推荐 | 通常不必 |
|
|
80
|
+
| --- | --- | --- |
|
|
81
|
+
| 骨架 | `MLayout fillViewport` + `MPageContent` | `MLayoutContent` 再写 padding |
|
|
82
|
+
| 区块 | `MPageFilters` / `MPageToolbar` / `MPageSection` | 手写 `.page-*`;`MCard` 再包一层 |
|
|
83
|
+
| 列表表格 | `MTable` 直接放 `MPageContent`;高度规则适用时再 `fill` | 用 `MCard` 再包 bordered 表格;不适合时硬套 `fill` |
|
|
84
|
+
| 控件间距 | 同行用 `MSpace` / `MFlex`;区块靠 `MPageContent` gap | 外包 padded `div` 叠间距 |
|
|
85
|
+
| 滚动 | 全视口主列表可表体滚动(`fill`);否则 Layout / 局部 `MScrollbar` | 在用户内容区强行内置滚动;无理由双滚动条 |
|
|
86
|
+
| 颜色 | `--m-*` Token | 页面级 hex / 裸 rgb() |
|
|
87
|
+
| 反馈 | 单行结果用 `message`;危险操作用 `MConfirmDialog` | 仅一行文案却用 toast |
|
|
88
|
+
| 无障碍 | 图标按钮 `aria-label`、表单可见 label | — |
|
|
89
|
+
|
|
90
|
+
仅允许控件宽度等局部 inline style(如筛选项 `width: 14rem`)。
|
|
91
|
+
|
|
92
|
+
## MCP
|
|
93
|
+
|
|
94
|
+
- 整页:`recommend_page`(可传 `style`)→ `get_golden_page` → `get_design_rules` / `list_style_presets`
|
|
95
|
+
- 风格:有参考则跟参考;否则按 `styleDirection` 或请用户从 quiet/soft/dense/rail/studio/ink 选
|
|
96
|
+
- 局部:`get_page_snippet`(如 `filters` / `toolbar` / `form-actions` / `scrollable-panel`)
|
|
97
|
+
- 可选:`validate_page`(参考建议,不阻断)
|
package/template/DESIGN.md
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
# Morya UI 设计系统(AI 第一信源)
|
|
2
|
-
|
|
3
|
-
> 生成或审查使用 `morya-ui` 的界面时,**必须先遵守本文**。
|
|
4
|
-
> 本文只写与页面类型无关的契约。某一类页面怎么拼、用哪个组件,见 `morya-ui-pages` skill 与 MCP,不要从本文推断出唯一布局。
|
|
5
|
-
|
|
6
|
-
## 1. 设计原则
|
|
7
|
-
|
|
8
|
-
1. **组件优先**:交互与布局使用库内 `M*`,不手写等价 DOM。
|
|
9
|
-
2. **令牌优先**:颜色、间距、圆角、阴影、动效使用 `--m-*`;禁止裸 `#hex` / `rgb()`(`scripts/check-raw-colors.mjs` 可扫描)。
|
|
10
|
-
3. **语义一致**:主操作 `severity="primary"`;破坏性操作用 `severity="danger"` 或确认。
|
|
11
|
-
4. **可访问性**:控件有可访问名称;仅图标的按钮带 `aria-label`;浮层可键盘关闭。
|
|
12
|
-
5. **单一事实源**:组件 API 以 MCP / 文档为准,禁止臆造 prop、event、slot。
|
|
13
|
-
|
|
14
|
-
## 2. 应用根
|
|
15
|
-
|
|
16
|
-
- 入口引入 `morya-ui/styles.css`(或按需子路径样式)。
|
|
17
|
-
- 应用根使用 `MConfigProvider`,统一 locale、主题、密度与浮层挂载。
|
|
18
|
-
- 外壳随场景选择,不要把侧栏后台当成所有页面的默认结构。
|
|
19
|
-
|
|
20
|
-
## 3. 设计令牌(摘要)
|
|
21
|
-
|
|
22
|
-
完整定义见 MCP `get_design_rules`。运行时以已安装的 `morya-ui/styles.css` 为准。
|
|
23
|
-
|
|
24
|
-
| 用途 | 变量 |
|
|
25
|
-
| --- | --- |
|
|
26
|
-
| 页面背景 | `--m-color-surface` |
|
|
27
|
-
| 正文 | `--m-color-text` |
|
|
28
|
-
| 次要文字 | `--m-color-text-muted` |
|
|
29
|
-
| 边框 | `--m-color-border` |
|
|
30
|
-
| 品牌 / 链接 | `--m-color-primary` |
|
|
31
|
-
| 错误 | `--m-color-danger` |
|
|
32
|
-
| 区块间距 | `--m-space-4` / `--m-space-6` |
|
|
33
|
-
| 圆角 / 阴影 | `--m-radius-md` / `--m-shadow-md` |
|
|
34
|
-
| 动效时长 | `--m-motion-fast/normal/enter/exit` |
|
|
35
|
-
| 进出场位移 / 缓动 | `--m-motion-distance` / `--m-motion-ease` |
|
|
36
|
-
|
|
37
|
-
动效强度用 `useMotion`(`data-m-motion`:`full` / `reduced` / `none`),不跟随系统 `prefers-reduced-motion`;进出场预设用 `motion.transitions` / 组件 `transition`(见文档站「动效」)。
|
|
38
|
-
|
|
39
|
-
## 4. 禁止项
|
|
40
|
-
|
|
41
|
-
- 禁止同一界面混用第二套 UI 库。
|
|
42
|
-
- 禁止业务 CSS 写死主题色;暗色须能随 `[data-theme="dark"]` 生效。
|
|
43
|
-
- 禁止用不可聚焦的容器冒充按钮。
|
|
44
|
-
- 禁止跳过样式入口。
|
|
45
|
-
- 禁止把某一类页面的配方写成所有页面的默认结构。
|
|
46
|
-
|
|
47
|
-
## 5. AI 工作流
|
|
48
|
-
|
|
49
|
-
1. 读本文,确认契约。
|
|
50
|
-
2. 加载 `morya-ui-pages`,由 skill 选定表面与布局;可选 companion 只补充视觉或无障碍,冲突时本文 + skill + MCP 优先。
|
|
51
|
-
3. 用 MCP 查真实 API 与样例后再写代码。
|
|
52
|
-
4. 完成后可运行 `pnpm check:colors`(若已配置)。
|
|
53
|
-
|
|
54
|
-
## 6. 相关资源
|
|
55
|
-
|
|
56
|
-
- 包:`morya-ui` · 样式:`morya-ui/styles.css`
|
|
57
|
-
- 页面配方:`.agents/skills/morya-ui-pages/`(及 setup 时勾选的 companion)
|
|
58
|
-
- 主题 API:`useTheme` / `useDensity` / `useMotion`
|
|
59
|
-
- 动效预设:`createMoryaUI({ motion })`、`componentDefaults.*.transition`、浮层 `transition` prop;详情见文档 `/docs/motion`
|
|
1
|
+
# Morya UI 设计系统(AI 第一信源)
|
|
2
|
+
|
|
3
|
+
> 生成或审查使用 `morya-ui` 的界面时,**必须先遵守本文**。
|
|
4
|
+
> 本文只写与页面类型无关的契约。某一类页面怎么拼、用哪个组件,见 `morya-ui-pages` skill 与 MCP,不要从本文推断出唯一布局。
|
|
5
|
+
|
|
6
|
+
## 1. 设计原则
|
|
7
|
+
|
|
8
|
+
1. **组件优先**:交互与布局使用库内 `M*`,不手写等价 DOM。
|
|
9
|
+
2. **令牌优先**:颜色、间距、圆角、阴影、动效使用 `--m-*`;禁止裸 `#hex` / `rgb()`(`scripts/check-raw-colors.mjs` 可扫描)。
|
|
10
|
+
3. **语义一致**:主操作 `severity="primary"`;破坏性操作用 `severity="danger"` 或确认。
|
|
11
|
+
4. **可访问性**:控件有可访问名称;仅图标的按钮带 `aria-label`;浮层可键盘关闭。
|
|
12
|
+
5. **单一事实源**:组件 API 以 MCP / 文档为准,禁止臆造 prop、event、slot。
|
|
13
|
+
|
|
14
|
+
## 2. 应用根
|
|
15
|
+
|
|
16
|
+
- 入口引入 `morya-ui/styles.css`(或按需子路径样式)。
|
|
17
|
+
- 应用根使用 `MConfigProvider`,统一 locale、主题、密度与浮层挂载。
|
|
18
|
+
- 外壳随场景选择,不要把侧栏后台当成所有页面的默认结构。
|
|
19
|
+
|
|
20
|
+
## 3. 设计令牌(摘要)
|
|
21
|
+
|
|
22
|
+
完整定义见 MCP `get_design_rules`。运行时以已安装的 `morya-ui/styles.css` 为准。
|
|
23
|
+
|
|
24
|
+
| 用途 | 变量 |
|
|
25
|
+
| --- | --- |
|
|
26
|
+
| 页面背景 | `--m-color-surface` |
|
|
27
|
+
| 正文 | `--m-color-text` |
|
|
28
|
+
| 次要文字 | `--m-color-text-muted` |
|
|
29
|
+
| 边框 | `--m-color-border` |
|
|
30
|
+
| 品牌 / 链接 | `--m-color-primary` |
|
|
31
|
+
| 错误 | `--m-color-danger` |
|
|
32
|
+
| 区块间距 | `--m-space-4` / `--m-space-6` |
|
|
33
|
+
| 圆角 / 阴影 | `--m-radius-md` / `--m-shadow-md` |
|
|
34
|
+
| 动效时长 | `--m-motion-fast/normal/enter/exit` |
|
|
35
|
+
| 进出场位移 / 缓动 | `--m-motion-distance` / `--m-motion-ease` |
|
|
36
|
+
|
|
37
|
+
动效强度用 `useMotion`(`data-m-motion`:`full` / `reduced` / `none`),不跟随系统 `prefers-reduced-motion`;进出场预设用 `motion.transitions` / 组件 `transition`(见文档站「动效」)。
|
|
38
|
+
|
|
39
|
+
## 4. 禁止项
|
|
40
|
+
|
|
41
|
+
- 禁止同一界面混用第二套 UI 库。
|
|
42
|
+
- 禁止业务 CSS 写死主题色;暗色须能随 `[data-theme="dark"]` 生效。
|
|
43
|
+
- 禁止用不可聚焦的容器冒充按钮。
|
|
44
|
+
- 禁止跳过样式入口。
|
|
45
|
+
- 禁止把某一类页面的配方写成所有页面的默认结构。
|
|
46
|
+
|
|
47
|
+
## 5. AI 工作流
|
|
48
|
+
|
|
49
|
+
1. 读本文,确认契约。
|
|
50
|
+
2. 加载 `morya-ui-pages`,由 skill 选定表面与布局;可选 companion 只补充视觉或无障碍,冲突时本文 + skill + MCP 优先。
|
|
51
|
+
3. 用 MCP 查真实 API 与样例后再写代码。
|
|
52
|
+
4. 完成后可运行 `pnpm check:colors`(若已配置)。
|
|
53
|
+
|
|
54
|
+
## 6. 相关资源
|
|
55
|
+
|
|
56
|
+
- 包:`morya-ui` · 样式:`morya-ui/styles.css`
|
|
57
|
+
- 页面配方:`.agents/skills/morya-ui-pages/`(及 setup 时勾选的 companion)
|
|
58
|
+
- 主题 API:`useTheme` / `useDensity` / `useMotion`
|
|
59
|
+
- 动效预设:`createMoryaUI({ motion })`、`componentDefaults.*.transition`、浮层 `transition` prop;详情见文档 `/docs/motion`
|
|
@@ -1,74 +1,74 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Scan source files for raw color literals outside design-tokens/ and theme/.
|
|
4
|
-
* Usage: node scripts/check-raw-colors.mjs [dir...]
|
|
5
|
-
* Exit 1 if violations found.
|
|
6
|
-
*/
|
|
7
|
-
import { readdirSync, readFileSync, statSync } from 'node:fs'
|
|
8
|
-
import path from 'node:path'
|
|
9
|
-
|
|
10
|
-
const roots = process.argv.slice(2).length ? process.argv.slice(2) : ['src']
|
|
11
|
-
const IGNORE_DIRS = new Set(['node_modules', 'dist', 'coverage', 'design-tokens', 'theme', '.git'])
|
|
12
|
-
const EXT = new Set(['.vue', '.css', '.scss', '.ts', '.tsx', '.js', '.jsx'])
|
|
13
|
-
|
|
14
|
-
const HEX = /#[0-9a-f]{3,8}\b/gi
|
|
15
|
-
const RGB = /\brgb\s*\(/g
|
|
16
|
-
const HSL = /\bhsl\s*\(/g
|
|
17
|
-
|
|
18
|
-
/** Allow transparent, currentColor, inherit in CSS values */
|
|
19
|
-
const ALLOW_LINE = /var\s*\(\s*--m-|color-mix\s*\(|transparent|currentColor|inherit|none/
|
|
20
|
-
|
|
21
|
-
/** Skip demo IDs like '#1024' or 'WO-1024' in script/template strings */
|
|
22
|
-
const DEMO_ID = /['"]#?[A-Z0-9-]{2,}['"]/
|
|
23
|
-
|
|
24
|
-
const violations = []
|
|
25
|
-
|
|
26
|
-
function walk(dir) {
|
|
27
|
-
for (const name of readdirSync(dir)) {
|
|
28
|
-
const full = path.join(dir, name)
|
|
29
|
-
const st = statSync(full)
|
|
30
|
-
if (st.isDirectory()) {
|
|
31
|
-
if (IGNORE_DIRS.has(name)) continue
|
|
32
|
-
walk(full)
|
|
33
|
-
continue
|
|
34
|
-
}
|
|
35
|
-
const ext = path.extname(name)
|
|
36
|
-
if (!EXT.has(ext)) continue
|
|
37
|
-
const normalized = full.replace(/\\/g, '/')
|
|
38
|
-
if (normalized.includes('design-tokens/') || normalized.includes('/theme/')) continue
|
|
39
|
-
if (normalized.includes('.test.') || normalized.includes('/__tests__/')) continue
|
|
40
|
-
|
|
41
|
-
const text = readFileSync(full, 'utf8')
|
|
42
|
-
const lines = text.split(/\r?\n/)
|
|
43
|
-
lines.forEach((line, index) => {
|
|
44
|
-
if (ALLOW_LINE.test(line)) return
|
|
45
|
-
if (DEMO_ID.test(line)) return
|
|
46
|
-
if (HEX.test(line) || RGB.test(line) || HSL.test(line)) {
|
|
47
|
-
HEX.lastIndex = 0
|
|
48
|
-
RGB.lastIndex = 0
|
|
49
|
-
HSL.lastIndex = 0
|
|
50
|
-
violations.push({ file: full, line: index + 1, text: line.trim() })
|
|
51
|
-
}
|
|
52
|
-
})
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
for (const root of roots) {
|
|
57
|
-
try {
|
|
58
|
-
walk(path.resolve(root))
|
|
59
|
-
} catch (error) {
|
|
60
|
-
if (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT') continue
|
|
61
|
-
throw error
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (violations.length) {
|
|
66
|
-
console.error(`Found ${violations.length} raw color literal(s). Use --m-* tokens instead:\n`)
|
|
67
|
-
for (const v of violations) {
|
|
68
|
-
console.error(` ${v.file}:${v.line}`)
|
|
69
|
-
console.error(` ${v.text}\n`)
|
|
70
|
-
}
|
|
71
|
-
process.exit(1)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
console.log('No raw color literals found.')
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Scan source files for raw color literals outside design-tokens/ and theme/.
|
|
4
|
+
* Usage: node scripts/check-raw-colors.mjs [dir...]
|
|
5
|
+
* Exit 1 if violations found.
|
|
6
|
+
*/
|
|
7
|
+
import { readdirSync, readFileSync, statSync } from 'node:fs'
|
|
8
|
+
import path from 'node:path'
|
|
9
|
+
|
|
10
|
+
const roots = process.argv.slice(2).length ? process.argv.slice(2) : ['src']
|
|
11
|
+
const IGNORE_DIRS = new Set(['node_modules', 'dist', 'coverage', 'design-tokens', 'theme', '.git'])
|
|
12
|
+
const EXT = new Set(['.vue', '.css', '.scss', '.ts', '.tsx', '.js', '.jsx'])
|
|
13
|
+
|
|
14
|
+
const HEX = /#[0-9a-f]{3,8}\b/gi
|
|
15
|
+
const RGB = /\brgb\s*\(/g
|
|
16
|
+
const HSL = /\bhsl\s*\(/g
|
|
17
|
+
|
|
18
|
+
/** Allow transparent, currentColor, inherit in CSS values */
|
|
19
|
+
const ALLOW_LINE = /var\s*\(\s*--m-|color-mix\s*\(|transparent|currentColor|inherit|none/
|
|
20
|
+
|
|
21
|
+
/** Skip demo IDs like '#1024' or 'WO-1024' in script/template strings */
|
|
22
|
+
const DEMO_ID = /['"]#?[A-Z0-9-]{2,}['"]/
|
|
23
|
+
|
|
24
|
+
const violations = []
|
|
25
|
+
|
|
26
|
+
function walk(dir) {
|
|
27
|
+
for (const name of readdirSync(dir)) {
|
|
28
|
+
const full = path.join(dir, name)
|
|
29
|
+
const st = statSync(full)
|
|
30
|
+
if (st.isDirectory()) {
|
|
31
|
+
if (IGNORE_DIRS.has(name)) continue
|
|
32
|
+
walk(full)
|
|
33
|
+
continue
|
|
34
|
+
}
|
|
35
|
+
const ext = path.extname(name)
|
|
36
|
+
if (!EXT.has(ext)) continue
|
|
37
|
+
const normalized = full.replace(/\\/g, '/')
|
|
38
|
+
if (normalized.includes('design-tokens/') || normalized.includes('/theme/')) continue
|
|
39
|
+
if (normalized.includes('.test.') || normalized.includes('/__tests__/')) continue
|
|
40
|
+
|
|
41
|
+
const text = readFileSync(full, 'utf8')
|
|
42
|
+
const lines = text.split(/\r?\n/)
|
|
43
|
+
lines.forEach((line, index) => {
|
|
44
|
+
if (ALLOW_LINE.test(line)) return
|
|
45
|
+
if (DEMO_ID.test(line)) return
|
|
46
|
+
if (HEX.test(line) || RGB.test(line) || HSL.test(line)) {
|
|
47
|
+
HEX.lastIndex = 0
|
|
48
|
+
RGB.lastIndex = 0
|
|
49
|
+
HSL.lastIndex = 0
|
|
50
|
+
violations.push({ file: full, line: index + 1, text: line.trim() })
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
for (const root of roots) {
|
|
57
|
+
try {
|
|
58
|
+
walk(path.resolve(root))
|
|
59
|
+
} catch (error) {
|
|
60
|
+
if (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT') continue
|
|
61
|
+
throw error
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (violations.length) {
|
|
66
|
+
console.error(`Found ${violations.length} raw color literal(s). Use --m-* tokens instead:\n`)
|
|
67
|
+
for (const v of violations) {
|
|
68
|
+
console.error(` ${v.file}:${v.line}`)
|
|
69
|
+
console.error(` ${v.text}\n`)
|
|
70
|
+
}
|
|
71
|
+
process.exit(1)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
console.log('No raw color literals found.')
|