@morya-ui/setup 0.2.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.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +93 -0
  3. package/bin/morya-ui-setup.js +14 -0
  4. package/package.json +35 -0
  5. package/src/cli.mjs +200 -0
  6. package/src/copy-template.mjs +62 -0
  7. package/src/fs-utils.mjs +23 -0
  8. package/src/install.mjs +63 -0
  9. package/src/mcp.mjs +50 -0
  10. package/src/package-json.mjs +30 -0
  11. package/src/styles.mjs +109 -0
  12. package/template/.agents/skills/morya-ui-pages/SKILL.md +150 -0
  13. package/template/.agents/skills/morya-ui-pages/evals/evals.json +53 -0
  14. package/template/.agents/skills/morya-ui-pages/references/component-index.md +72 -0
  15. package/template/.agents/skills/morya-ui-pages/references/design-system.md +90 -0
  16. package/template/.agents/skills/morya-ui-pages/references/feedback.md +66 -0
  17. package/template/.agents/skills/morya-ui-pages/references/optional-companions.md +29 -0
  18. package/template/.agents/skills/morya-ui-pages/references/page-layouts.md +76 -0
  19. package/template/.agents/skills/morya-ui-pages/references/review-checklist.md +49 -0
  20. package/template/.agents/skills/morya-ui-pages/references/surfaces.md +89 -0
  21. package/template/.agents/skills/morya-ui-pages/references/visual-craft.md +83 -0
  22. package/template/.cursor/rules/coding-style.mdc +41 -0
  23. package/template/.cursor/rules/component-usage.mdc +41 -0
  24. package/template/.cursor/rules/design-system.mdc +17 -0
  25. package/template/.cursor/rules/page-layout.mdc +67 -0
  26. package/template/DESIGN.md +121 -0
  27. package/template/design-tokens/tokens.css +55 -0
  28. package/template/design-tokens/tokens.json +77 -0
  29. package/template/docs/components.md +144 -0
  30. package/template/docs/feedback-message-vs-toast.md +103 -0
  31. package/template/docs/golden-pages/dashboard-page.vue +103 -0
  32. package/template/docs/golden-pages/empty-state.vue +66 -0
  33. package/template/docs/golden-pages/form-page.vue +107 -0
  34. package/template/docs/golden-pages/landing-page.vue +328 -0
  35. package/template/docs/golden-pages/list-page.vue +127 -0
  36. package/template/docs/golden-pages/login-page.vue +191 -0
  37. package/template/scripts/check-raw-colors.mjs +74 -0
  38. package/template/src/examples/DashboardPageExample.vue +103 -0
  39. package/template/src/examples/EmptyStateExample.vue +66 -0
  40. package/template/src/examples/FormPageExample.vue +107 -0
  41. package/template/src/examples/LandingPageExample.vue +328 -0
  42. package/template/src/examples/ListPageExample.vue +127 -0
  43. package/template/src/examples/LoginPageExample.vue +191 -0
package/src/styles.mjs ADDED
@@ -0,0 +1,109 @@
1
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs'
2
+ import { join, resolve } from 'node:path'
3
+
4
+ const STYLE_IMPORT = "import 'morya-ui/styles.css'"
5
+ const STYLE_MARKER = 'morya-ui/styles.css'
6
+
7
+ const CANDIDATES = [
8
+ 'src/main.ts',
9
+ 'src/main.js',
10
+ 'src/main.tsx',
11
+ 'src/main.jsx',
12
+ 'main.ts',
13
+ 'main.js',
14
+ 'src/app.ts',
15
+ 'src/app.js',
16
+ ]
17
+
18
+ /**
19
+ * @param {string} cwd
20
+ * @returns {string | null} absolute path
21
+ */
22
+ export function findEntryFile(cwd) {
23
+ for (const rel of CANDIDATES) {
24
+ const full = join(cwd, rel)
25
+ if (existsSync(full)) return full
26
+ }
27
+
28
+ const indexHtml = join(cwd, 'index.html')
29
+ if (existsSync(indexHtml)) {
30
+ const html = readFileSync(indexHtml, 'utf8')
31
+ const match = html.match(/<script[^>]*type=["']module["'][^>]*src=["']([^"']+)["']/i)
32
+ || html.match(/<script[^>]*src=["']([^"']+)["'][^>]*type=["']module["']/i)
33
+ if (match?.[1]) {
34
+ const src = match[1].replace(/^\//, '')
35
+ const full = resolve(cwd, src)
36
+ if (existsSync(full)) return full
37
+ }
38
+ }
39
+
40
+ return null
41
+ }
42
+
43
+ /**
44
+ * Insert style import after the last leading import, or at top.
45
+ * @param {string} source
46
+ */
47
+ export function injectStyleImport(source) {
48
+ if (source.includes(STYLE_MARKER)) {
49
+ return { source, changed: false, reason: 'already-present' }
50
+ }
51
+
52
+ const lines = source.split(/\r?\n/)
53
+ let lastImportIndex = -1
54
+ for (let i = 0; i < lines.length; i++) {
55
+ const line = lines[i].trim()
56
+ if (!line) {
57
+ if (lastImportIndex >= 0) continue
58
+ continue
59
+ }
60
+ if (line.startsWith('//') || line.startsWith('/*') || line.startsWith('*')) {
61
+ if (lastImportIndex < 0) continue
62
+ break
63
+ }
64
+ if (/^import\s/.test(line) || /^import["']/.test(line)) {
65
+ lastImportIndex = i
66
+ continue
67
+ }
68
+ break
69
+ }
70
+
71
+ if (lastImportIndex >= 0) {
72
+ lines.splice(lastImportIndex + 1, 0, STYLE_IMPORT)
73
+ } else {
74
+ // After shebang / 'use strict' if present
75
+ let insertAt = 0
76
+ if (lines[0]?.startsWith('#!')) insertAt = 1
77
+ lines.splice(insertAt, 0, STYLE_IMPORT, '')
78
+ }
79
+
80
+ return { source: lines.join('\n'), changed: true }
81
+ }
82
+
83
+ /**
84
+ * @returns {{
85
+ * action: 'injected' | 'skipped' | 'missing-entry',
86
+ * path?: string,
87
+ * reason?: string,
88
+ * dryRun?: boolean
89
+ * }}
90
+ */
91
+ export function ensureStylesImport(cwd, { dryRun = false } = {}) {
92
+ const entry = findEntryFile(cwd)
93
+ if (!entry) {
94
+ return { action: 'missing-entry', reason: 'no-entry-found' }
95
+ }
96
+
97
+ const original = readFileSync(entry, 'utf8')
98
+ const { source, changed, reason } = injectStyleImport(original)
99
+
100
+ if (!changed) {
101
+ return { action: 'skipped', path: entry, reason: reason || 'already-present' }
102
+ }
103
+
104
+ if (!dryRun) {
105
+ writeFileSync(entry, source, 'utf8')
106
+ }
107
+
108
+ return { action: 'injected', path: entry, dryRun }
109
+ }
@@ -0,0 +1,150 @@
1
+ ---
2
+ name: morya-ui-pages
3
+ description: >
4
+ Build, redesign, critique, or polish any Vue 3 UI surface that should use the
5
+ morya-ui component library — admin CRUD (list, form, dashboard, detail,
6
+ settings), auth and onboarding, empty and error states, wizards, overlays,
7
+ marketing/landing and pricing pages, docs chrome, and hybrid product UI.
8
+ Trigger on: morya-ui, M* components, --m-* tokens, golden pages, 后台页,
9
+ 列表页, 表单页, 仪表盘, 登录页, 注册, 空状态, 向导, 落地页, 官网, landing,
10
+ login, dashboard, settings, onboarding, or “用组件库做页面”. Prefer this
11
+ skill over generic frontend-design, impeccable, or ui-ux-pro-max when the
12
+ implementation stack is morya-ui; those companions may inform taste only.
13
+ Do not use for backend-only work or for authoring new components inside the
14
+ morya-ui library source itself.
15
+ ---
16
+
17
+ # Morya UI Pages
18
+
19
+ Guide agents that **consume morya-ui** across the full product surface — not only admin CRUD.
20
+
21
+ Two layers always apply:
22
+
23
+ 1. **Contract** — only `M*` controls, `--m-*` tokens, real APIs (MCP/docs). Never invent props or mix UI kits.
24
+ 2. **Craft** — pick the right surface pattern, then apply intentional visual direction (distilled from Frontend Design / Impeccable / UI-UX-Pro-Max ideas). Admin golden pages stay disciplined; expressive surfaces (landing, auth brand moments, empty states) may take a justified aesthetic risk — still on-token and on-component.
25
+
26
+ When companions conflict with this skill or project `DESIGN.md`, **this skill wins**.
27
+
28
+ ## Surface map (pick one first)
29
+
30
+ | Lane | Surfaces | Primary references |
31
+ | --- | --- | --- |
32
+ | **Ops** | list, form, dashboard, detail, settings, filter drawer, CRUD dialog | [page-layouts.md](references/page-layouts.md), golden pages |
33
+ | **Account** | login, register, invite, forgot/reset password, profile | [surfaces.md](references/surfaces.md) § Account |
34
+ | **Flow** | onboarding, empty state, wizard/stepper, success/result | [surfaces.md](references/surfaces.md) § Flow |
35
+ | **System** | 404 / error, permission denied, maintenance | [surfaces.md](references/surfaces.md) § System |
36
+ | **Express** | marketing landing, pricing, feature showcase, docs marketing chrome | [surfaces.md](references/surfaces.md) § Express + [visual-craft.md](references/visual-craft.md) |
37
+ | **Overlay** | dialog, drawer, popover, command menu as the main UI | [surfaces.md](references/surfaces.md) § Overlay |
38
+
39
+ Unclear brief → ask **one** short question, or default: Ops → closest golden page; public marketing → Express.
40
+
41
+ Full taxonomy: [references/surfaces.md](references/surfaces.md).
42
+
43
+ ## Prerequisites
44
+
45
+ 1. `morya-ui` installed; `morya-ui/styles.css` imported.
46
+ 2. Prefer `@morya-ui/mcp` — never invent prop / event / slot names.
47
+ 3. If the AI config pack is merged, prefer project files over bundled copies:
48
+ - `DESIGN.md`
49
+ - `docs/golden-pages/*.vue`, `docs/components.md`, `docs/feedback-message-vs-toast.md`
50
+
51
+ ## Workflow
52
+
53
+ ### 1. Pin subject, audience, surface, job
54
+
55
+ State explicitly (even briefly in thinking):
56
+
57
+ - **Subject** — product / domain vernacular (not generic “SaaS”)
58
+ - **Audience** — who uses this screen
59
+ - **Surface** — from the map above
60
+ - **Single job** — what the first viewport must accomplish
61
+
62
+ For Express / branded Account moments, also draft a tiny **design plan** (see [visual-craft.md](references/visual-craft.md)): palette roles mapped to `--m-*` (extend only if the project already customizes theme), type roles, layout concept, one signature element. Skip the full plan for routine Ops CRUD unless the user asks for a redesign.
63
+
64
+ ### 2. Load the smallest useful references
65
+
66
+ | Need | Prefer (MCP) | Else read |
67
+ | --- | --- | --- |
68
+ | Ops pattern | `recommend_page` → `get_golden_page` | [page-layouts.md](references/page-layouts.md) |
69
+ | Account / Express / empty | `recommend_page` → `get_golden_page` (`login-page` / `landing-page` / `empty-state`) | [surfaces.md](references/surfaces.md) |
70
+ | Visual direction | — | [visual-craft.md](references/visual-craft.md) (Express / polish / anti-defaults) |
71
+ | Components | `search` / `get_component` / `recommend_component` | [component-index.md](references/component-index.md) |
72
+ | Tokens / rules | `get_design_rules` | [design-system.md](references/design-system.md) |
73
+ | Snippet | `get_page_snippet` | golden / surface excerpt |
74
+ | Feedback API | — | [feedback.md](references/feedback.md) |
75
+ | Soft check | `validate_page` | [review-checklist.md](references/review-checklist.md) |
76
+
77
+ ### 3. Compose
78
+
79
+ **Ops:** mirror golden-page block order; prefer `MPage*` over custom chrome.
80
+
81
+ **Account / Flow / System:** centered or split shells with `MCard` / `MForm` / `MMessage` / `MEmpty` / `MResult` (see surfaces); keep controls as `M*`.
82
+
83
+ **Express:** hero + sections with intentional hierarchy; interactive bits still `MButton` / `MTag` / etc.; atmosphere via layout, motion, and tokens — not a second component library.
84
+
85
+ **Overlay:** build the host page lightly; put the real job inside `MDialog` / `MDrawer` / `MCommandMenu`.
86
+
87
+ ### 4. Wire real API usage
88
+
89
+ - Import from `morya-ui` (or documented subpath + style).
90
+ - Forms: `MForm` + fields; `@submit` + `type="submit"`.
91
+ - Tables: `columns` + `data` + `row-key`; `#cell-{key}`.
92
+ - Enums → `MSelect` / `MTreeSelect`; action menus → `MDropdown`.
93
+ - Destructive → `MConfirmDialog` / `MConfirmPopup`.
94
+ - Feedback → default **`message`**; `toast` only for summary+detail / async. See [feedback.md](references/feedback.md).
95
+
96
+ ### 5. Craft pass (lane-aware)
97
+
98
+ - **Ops:** restraint — clarity over spectacle; cut decoration.
99
+ - **Express / branded auth:** one signature moment; avoid AI-default looks listed in [visual-craft.md](references/visual-craft.md).
100
+ - **All lanes:** responsive, focus visible, respect `prefers-reduced-motion` when adding motion.
101
+ - Copy: user language, active voice, specific — not filler marketing on Ops screens.
102
+
103
+ Optional polish modes (Impeccable-inspired): `quieter` | `bolder` | `clarify` | `audit` — apply as a second pass when the user asks. See [visual-craft.md](references/visual-craft.md) § Polish modes.
104
+
105
+ ### 6. Review
106
+
107
+ Use [review-checklist.md](references/review-checklist.md) (Ops + Express sections). Run MCP `validate_page` when available (advisory).
108
+
109
+ ## Hard boundaries
110
+
111
+ - No second UI kit on the same surface.
112
+ - No hand-rolled table/modal when `MTable` / `MDialog` / `MDrawer` fit.
113
+ - No invented props / events / slots.
114
+ - No defaulting every success to `toast`.
115
+ - Ops surfaces follow golden layouts first — do not replace them with marketing heroes.
116
+ - Express surfaces still use `M*` for controls and `--m-*` for color/space; do not introduce shadcn/Element/etc. stacks suggested by generic design skills.
117
+ - Soft-load companions only; never require Impeccable / UI-UX-Pro-Max / Frontend Design to be installed.
118
+
119
+ ## Soft companions
120
+
121
+ If already installed in the consumer project:
122
+
123
+ | Companion | After contract is fixed, may help with |
124
+ | --- | --- |
125
+ | `frontend-design` | Distinctive Express / brand moments |
126
+ | `impeccable` | Named polish / audit passes |
127
+ | `ui-ux-pro-max` | Mood / industry keywords for Express only |
128
+
129
+ Details: [optional-companions.md](references/optional-companions.md). Distilled craft lives in [visual-craft.md](references/visual-craft.md) so this skill works **standalone**.
130
+
131
+ ## Output expectations
132
+
133
+ - Vue 3 `<script setup lang="ts">`.
134
+ - PascalCase `M*` in templates.
135
+ - Domain-real copy and data shapes.
136
+ - Scoped CSS minimal; tokens only (control widths may be inline).
137
+ - For multi-file asks: sensible `views/` / `components/` split; otherwise one SFC is fine.
138
+
139
+ ## Bundled references
140
+
141
+ | File | Read when |
142
+ | --- | --- |
143
+ | [surfaces.md](references/surfaces.md) | Choosing / composing non-Ops (and hybrid) surfaces |
144
+ | [page-layouts.md](references/page-layouts.md) | Ops golden layouts |
145
+ | [visual-craft.md](references/visual-craft.md) | Design plan, anti-defaults, polish modes, Express craft |
146
+ | [design-system.md](references/design-system.md) | Principles, tokens, bans |
147
+ | [component-index.md](references/component-index.md) | Scenario → component |
148
+ | [feedback.md](references/feedback.md) | message / toast / MMessage |
149
+ | [review-checklist.md](references/review-checklist.md) | Pre-delivery checks |
150
+ | [optional-companions.md](references/optional-companions.md) | Combining with external design skills |
@@ -0,0 +1,53 @@
1
+ {
2
+ "skill_name": "morya-ui-pages",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "prompt": "我们内部教务系统用 Vue3 + morya-ui。请做一个「课程列表」后台页:按课程名搜索、按开课状态(全部/开课中/已结课)筛选;表格列:名称、状态 Tag、学分、更新时间;行内「编辑」进抽屉表单,「删除」要二次确认;右上角「新建课程」。保存/删除成功只要一句话提示。输出单个 Vue SFC,结构对齐列表黄金样例。",
7
+ "expected_output": "Ops list: MLayout/MPageFilters/MPageToolbar/MTable, MSelect status, MDrawer or route edit, MConfirmDialog delete, message not toast, MTag for status, no second UI kit.",
8
+ "files": []
9
+ },
10
+ {
11
+ "id": 2,
12
+ "prompt": "同一个 morya-ui 项目里,生成「新建员工」独立表单页:姓名、工作邮箱、部门(下拉)、入职日期;窄栏;页头有标题和一句说明;底栏保存(primary)/取消(secondary)。不要做成营销落地页,不要用 Toast 提示「已保存」。输出单个 Vue SFC。",
13
+ "expected_output": "Ops form golden: narrow MPageContent, MPageHeader, MPageSection form/actions, MForm + MSelect/MDatePicker, message for success if shown, no landing hero.",
14
+ "files": []
15
+ },
16
+ {
17
+ "id": 3,
18
+ "prompt": "运营后台首页仪表盘:四个 KPI(今日订单、待处理、转化率、退款率)、中间一块图表占位、右侧或下方「最近告警」表格(级别、内容、时间)。Vue3 + morya-ui,可先用静态假数据。",
19
+ "expected_output": "Dashboard: MPageStat grid, MPagePlaceholder/chart card, recent MTable, MLayout shell, --m-* only.",
20
+ "files": []
21
+ },
22
+ {
23
+ "id": 4,
24
+ "prompt": "给「青禾书房」这个独立书店品牌做登录页:左品牌、右表单(邮箱+密码+登录)。要有一点品牌感,但控件必须用 morya-ui;登录失败用表单区常驻错误,不要一闪而过的 Toast。输出单个 Vue SFC。",
25
+ "expected_output": "Account+craft: split shell, MForm/MInputPassword/MButton, MMessage or field error for failure, brand panel without second UI kit, tokens for colors.",
26
+ "files": []
27
+ },
28
+ {
29
+ "id": 5,
30
+ "prompt": "课程列表在零数据时太空了。请设计一个空状态区块(可嵌在列表页内容区):说明还没有课程、引导「创建第一门课程」,视觉克制但有一个记忆点。只要空状态相关模板片段或带空状态的列表 SFC 均可,须 morya-ui。",
31
+ "expected_output": "Flow empty: clear next action CTA with MButton, short copy, one signature visual, no emoji clutter, fits list content slot.",
32
+ "files": []
33
+ },
34
+ {
35
+ "id": 6,
36
+ "prompt": "为「流水线 CI」产品写一个营销落地首页(不是后台):首屏只有品牌名、一句主标题、一句副文、一组 CTA;下面再分「为何选择」「能力」「客户」三节。技术实现用 Vue3 + morya-ui 组件做按钮/标签/折叠 FAQ;颜色走 --m-*,避免紫渐变和奶油衬线陶土那套 AI 默认脸。输出单个 Vue SFC。",
37
+ "expected_output": "Express landing: single-job hero, MButton CTAs, sections with one job each, MAccordion FAQ optional, no purple/cream-terracotta defaults, no admin MPageFilters shell.",
38
+ "files": []
39
+ },
40
+ {
41
+ "id": 7,
42
+ "prompt": "做一个三步「创建工作空间」向导:1 名称与地区 2 邀请成员(邮箱标签)3 确认。用 morya-ui 的 Stepper + Form;每步一个主任务;最后提交成功进入结果页(查看工作空间 / 返回)。输出一个或两个 SFC。",
43
+ "expected_output": "Flow wizard: MStepper, per-step MForm, MInputTags or similar for invites, clear next/back/submit, success with next actions, message/toast per feedback rules.",
44
+ "files": []
45
+ },
46
+ {
47
+ "id": 8,
48
+ "prompt": "用户点了删除项目但权限不足:做一张「无权限」系统页(或全页占位),说明原因,并提供返回上一页、联系管理员。用 morya-ui,文案直接别玩梗。",
49
+ "expected_output": "System surface: plain explanation, escape actions with MButton, no jokey 404 essay, on-token.",
50
+ "files": []
51
+ }
52
+ ]
53
+ }
@@ -0,0 +1,72 @@
1
+ # Component index (scenario map)
2
+
3
+ Full API: docs site `/components` or MCP (`get_component`, `search`, `validate_usage`). This file is for **selection**, not prop manuals.
4
+
5
+ ## Shell
6
+
7
+ | Component | Use |
8
+ | --- | --- |
9
+ | `MConfigProvider` | Root locale / theme / density / defaults |
10
+ | `MLayout` family | Admin chrome |
11
+ | `MBreadcrumb` | Path |
12
+ | `MPageContent` / `MPageFilters` / `MPageToolbar` / `MPageHeader` / `MPageSection` / `MPageStat` / `MPagePlaceholder` | Page composition |
13
+
14
+ ## Forms · inputs
15
+
16
+ `MForm`, `MFormItem`, `MInput`, `MInputPassword`, `MInputNumber`, `MTextarea`, `MSelect`, `MTreeSelect`, `MCascadeSelect`, `MDatePicker`, `MAutoComplete`, `MCheckbox` / `MCheckboxGroup`, `MRadio` / `MRadioGroup`, `MSwitch`, `MSlider`, `MRating`, `MInputTags`, `MFileUpload`, `MFloatLabel`, `MIconField`
17
+
18
+ ## Layout helpers
19
+
20
+ `MGrid` / `MGridItem`, `MFlex`, `MSpace`, `MFluid`, `MDivider`, `MFieldset`
21
+
22
+ ## Data
23
+
24
+ `MTable`, `MTreeTable`, `MDataView`, `MTree`, `MPagination`, `MStatus` / `MTag` / `MChip` / `MBadge`, `MAvatar` / `MAvatarGroup`, `MTimeline`, `MMeterGroup`, `MVirtualScroller`
25
+
26
+ ## Feedback
27
+
28
+ | API / component | When |
29
+ | --- | --- |
30
+ | `message` | **Default** one-line CRUD result |
31
+ | `toast` | `summary` + `detail`, or async / background feel |
32
+ | `<MMessage>` | Persistent in-page error / warning |
33
+ | `MEmpty` | No-data / first-use / filtered empty (not an error) |
34
+ | `MResult` | Terminal outcome: success, failure, 403 / 404 / 500 |
35
+ | `MProgressBar` / `MProgressSpinner` / `MSkeleton` / `MBlockUI` | Loading / blocking |
36
+
37
+ ## Overlays & menus
38
+
39
+ `MDialog`, `MDrawer`, `MConfirmDialog` / `MConfirmPopup`, `MPopover`, `MTooltip`, `MDropdown` (**actions only**), `MMenu` / `MMenubar` / `MTieredMenu` / `MMegaMenu`, `MTabs`, `MStepper`, `MCommandMenu`
40
+
41
+ ## Surfaces / media
42
+
43
+ `MCard`, `MPanel`, `MAccordion`, `MCarousel`, `MGallery`, `MIcon`, `MScrollbar`
44
+
45
+ ## Scenario → pick
46
+
47
+ | Intent | Prefer |
48
+ | --- | --- |
49
+ | Searchable list + paging | `MPageFilters` + `MTable` (+ paginator) |
50
+ | Create / edit entity page | Form golden layout + `MForm` |
51
+ | Create / edit in place | `MDialog` or `MDrawer` + form |
52
+ | Delete | `MConfirmDialog` |
53
+ | Lightweight inline status | `MStatus` (dot + label) |
54
+ | Status chip / closable label | `MTag` severities |
55
+ | Primary / secondary actions | `MSpace` + `MButton` |
56
+ | Dashboard KPIs | `MGrid` + `MPageStat` |
57
+ | Org tree | `MTree` / `MTreeSelect` |
58
+ | Login / auth | `login-page` golden + `MInputPassword` |
59
+ | Marketing landing | `landing-page` golden + `MButton` / `MTag` / `MAccordion` |
60
+ | Empty list / zero state | `MEmpty` (+ `empty-state` golden or `MTable` `#empty`) |
61
+ | Submit success / HTTP error page | `MResult` |
62
+ | Local capped scroll | Explicit `MScrollbar` |
63
+
64
+ ## Common mistakes
65
+
66
+ | Wrong | Right |
67
+ | --- | --- |
68
+ | `MDropdown` as form enum | `MSelect` |
69
+ | Hand `<table>` | `MTable` |
70
+ | Hand modal div | `MDialog` |
71
+ | Extra `MCard` around every `MPage*` block | Use page components' own surface/gap |
72
+ | Assume undocumented props | MCP / docs lookup |
@@ -0,0 +1,90 @@
1
+ # Design system (consumer summary)
2
+
3
+ Canonical long form lives in project-root `DESIGN.md` when the AI config pack is merged. This file is the portable subset for agents.
4
+
5
+ ## Principles
6
+
7
+ 1. **Components first** — layout, forms, tables, overlays use `M*` from `morya-ui`, not equivalent hand-rolled DOM.
8
+ 2. **Tokens first** — color, space, radius, shadow, motion via `--m-*`. No raw `#hex` / `rgb()` in page styles.
9
+ 3. **Semantic actions** — primary work uses `MButton severity="primary"`; destructive uses `severity="danger"` or confirm dialogs.
10
+ 4. **Accessibility** — fields have visible labels; icon buttons have `aria-label`; overlays dismiss with Esc (library default).
11
+ 5. **ConfigProvider** — wrap the app (or isolated demo) in `MConfigProvider` for locale, theme, density, overlay mount.
12
+
13
+ ## App shell
14
+
15
+ ```vue
16
+ <script setup lang="ts">
17
+ import { MConfigProvider, zhCN } from 'morya-ui'
18
+ import 'morya-ui/styles.css'
19
+ </script>
20
+
21
+ <template>
22
+ <MConfigProvider :locale="zhCN">
23
+ <MLayout fill-viewport has-sider>
24
+ <MLayoutSider bordered>...</MLayoutSider>
25
+ <MLayout>
26
+ <MLayoutHeader>...</MLayoutHeader>
27
+ <MLayoutContent>...</MLayoutContent>
28
+ </MLayout>
29
+ </MLayout>
30
+ </MConfigProvider>
31
+ </template>
32
+ ```
33
+
34
+ | Role | Prefer |
35
+ | --- | --- |
36
+ | Admin chrome | `MLayout fillViewport` + sider / header / content |
37
+ | Page stack | `MPageContent` inside `MLayoutContent` |
38
+ | Filters / toolbar | `MPageFilters` + `MPageToolbar` |
39
+ | Form surfaces | `MPageHeader` + `MPageSection variant="form|actions"` |
40
+ | Dashboard KPI | `MPageStat` + `MPagePlaceholder` |
41
+ | Module cards | `MCard` / `MPanel` / `MFieldset` |
42
+ | Grid / spacing | `MGrid` + `MGridItem`, or `MFlex` / `MSpace` |
43
+
44
+ ## Forms
45
+
46
+ - `MForm` + `MFormItem` with `name` aligned to rules.
47
+ - Prefer field props (`label`, `invalid`, `helpText`) when the control supports them; wrap with `MFormItem` for denser / complex forms.
48
+ - Default size medium; dense apps may use `size="small"` or ConfigProvider density.
49
+ - Form pages: keep the main column narrow (`MPageContent width="narrow"` or ~`40rem`).
50
+
51
+ ## Data display
52
+
53
+ - `MTable` with columns + data + `row-key`.
54
+ - Row actions: text/link `MButton` or `MDropdown`.
55
+ - Pagination: table `paginator` or sibling `MPagination`.
56
+ - Empty states: `MEmpty` in `#empty` / Flow golden — never a silent blank table.
57
+ - Terminal outcomes (success / 403 / 404 / 500): `MResult` — do not reuse `MEmpty` for errors.
58
+
59
+ ## Overlays
60
+
61
+ | Need | Component |
62
+ | --- | --- |
63
+ | Delete confirm | `MConfirmDialog` / `MConfirmPopup` |
64
+ | Detail / edit modal | `MDialog` |
65
+ | Side filter / detail | `MDrawer` |
66
+ | Field hint | `MTooltip` |
67
+
68
+ ## Token cheat sheet
69
+
70
+ | Use | Variable |
71
+ | --- | --- |
72
+ | Page background | `--m-color-surface` |
73
+ | Body text | `--m-color-text` |
74
+ | Muted text | `--m-color-text-muted` |
75
+ | Border | `--m-color-border` |
76
+ | Brand / link | `--m-color-primary` |
77
+ | Danger | `--m-color-danger` |
78
+ | Section gap | `--m-space-4` / `--m-space-6` |
79
+ | Card radius | `--m-radius-md` |
80
+ | Card shadow | `--m-shadow-md` |
81
+
82
+ Full machine-readable set: project `design-tokens/tokens.json` (runtime truth remains `morya-ui/styles.css`).
83
+
84
+ ## Bans
85
+
86
+ - Second UI library on the same page.
87
+ - Hard-coded theme colors that break `[data-theme="dark"]`.
88
+ - `<div @click>` instead of `MButton` / `<button>`.
89
+ - Using `MDropdown` for form enum selection (use `MSelect` / `MTreeSelect`).
90
+ - Skipping `import 'morya-ui/styles.css'`.
@@ -0,0 +1,66 @@
1
+ # Message / Toast / MMessage
2
+
3
+ **Default rule:** operation feedback uses the `message` API. Use `toast` only when you need a title plus detail, or an async / background notification feel.
4
+
5
+ ## Three different things
6
+
7
+ | Name | Shape | API | Typical use |
8
+ | --- | --- | --- | --- |
9
+ | Message service | Top-centered one-liner | `message.success('已保存')` | Most CRUD results |
10
+ | Toast service | Corner notice with `summary` + optional `detail` | `toast.success({ summary, detail })` | Extra explanation, job results |
11
+ | `MMessage` | In-page bar, stays | `<MMessage severity="error">…</MMessage>` | Persistent form / auth errors |
12
+
13
+ ## Decision tree
14
+
15
+ ```
16
+ Need immediate feedback after a user action?
17
+ ├─ No → maybe confirm dialog or field errorMessage only
18
+ └─ Yes → must the error stay in the form until fixed?
19
+ ├─ Yes → field invalid / errorMessage; form-level token alert (see login-page)
20
+ └─ No → only one short line (no separate detail)?
21
+ ├─ Yes → message.* ← default
22
+ └─ No → summary + detail / async feel → toast.*
23
+ ```
24
+
25
+ ## Prefer `message`
26
+
27
+ ```ts
28
+ import { message } from 'morya-ui'
29
+
30
+ message.success('已创建')
31
+ message.info('已移入回收站')
32
+ message.error('操作失败')
33
+ ```
34
+
35
+ ## Prefer `toast`
36
+
37
+ ```ts
38
+ import { toast } from 'morya-ui'
39
+
40
+ toast.success({
41
+ summary: '导入完成',
42
+ detail: '成功 128 条,失败 2 条',
43
+ })
44
+ ```
45
+
46
+ ## Prefer `<MMessage>` / form-level errors
47
+
48
+ - Field validation: component `invalid` / `errorMessage` (preferred).
49
+ - Form-level persistent errors (login/auth): token-styled `role="alert"` bar as in `docs/golden-pages/login-page.vue`.
50
+ - Note: `<MMessage>` today is primarily the **message service host** (`messages` / teleport). Do not invent a `severity` + default-slot Alert API unless docs add it.
51
+
52
+ ```vue
53
+ <p v-if="formError" class="form-alert" role="alert">{{ formError }}</p>
54
+ ```
55
+
56
+ ```css
57
+ .form-alert {
58
+ margin: 0 0 var(--m-space-4);
59
+ padding: var(--m-space-3) var(--m-space-4);
60
+ border: 1px solid color-mix(in srgb, var(--m-color-danger) 40%, var(--m-color-border));
61
+ border-radius: var(--m-radius-md);
62
+ background: color-mix(in srgb, var(--m-color-danger) 10%, var(--m-color-surface));
63
+ color: var(--m-color-danger);
64
+ }
65
+ ```
66
+
@@ -0,0 +1,29 @@
1
+ # Optional companions
2
+
3
+ This skill is **standalone**. Distilled craft lives in [visual-craft.md](visual-craft.md). Companions are optional soft upgrades when already present in the consumer repo.
4
+
5
+ ## Conflict rule
6
+
7
+ `morya-ui-pages` + project `DESIGN.md` + MCP APIs **override** companion advice whenever they disagree (component choice, tokens, Ops layout, feedback API).
8
+
9
+ ## How to combine
10
+
11
+ | Installed companion | Safe use | Unsafe use |
12
+ | --- | --- | --- |
13
+ | `frontend-design` | Express / brand panel taste after surface + contract are fixed | Replacing Ops golden shell with a custom landing |
14
+ | `impeccable` | Named passes (`audit`, `quieter`, …) aligned with [visual-craft.md](visual-craft.md) polish modes | Swapping `M*` for raw HTML controls or new token schema |
15
+ | `ui-ux-pro-max` | Mood / industry keywords for Express | Adopting its React/shadcn/Flutter stack suggestions |
16
+
17
+ Suggested prompt glue:
18
+
19
+ > Follow morya-ui-pages for surface, components, and tokens. Optionally apply \<companion\> only for visual taste on Express sections; remediate with M* and --m-*.
20
+
21
+ ## Load budget
22
+
23
+ - Default: **this skill only**
24
+ - Max: this skill + **one** companion
25
+ - Broad redesign review: this skill + impeccable-style `audit` (or the real skill if installed) — still one companion
26
+
27
+ ## If companions are absent
28
+
29
+ Do **not** tell the user to install them mid-task. Use [visual-craft.md](visual-craft.md) and continue.
@@ -0,0 +1,76 @@
1
+ # Page layouts
2
+
3
+ When generating a full page, pick a type and **mirror the golden-page block order**. Prefer project files when present:
4
+
5
+ | Type | Golden page | Runnable example |
6
+ | --- | --- | --- |
7
+ | List | `docs/golden-pages/list-page.vue` | `src/examples/ListPageExample.vue` |
8
+ | Form | `docs/golden-pages/form-page.vue` | `src/examples/FormPageExample.vue` |
9
+ | Dashboard | `docs/golden-pages/dashboard-page.vue` | `src/examples/DashboardPageExample.vue` |
10
+ | Login | `docs/golden-pages/login-page.vue` | `src/examples/LoginPageExample.vue` |
11
+ | Landing | `docs/golden-pages/landing-page.vue` | `src/examples/LandingPageExample.vue` |
12
+ | Empty | `docs/golden-pages/empty-state.vue` | `src/examples/EmptyStateExample.vue` |
13
+
14
+ Via MCP: `recommend_page` → `get_golden_page`; local edits: `get_page_snippet` (`filters`, `toolbar`, `form-actions`, `scrollable-panel`, …).
15
+
16
+ ## List page — block order
17
+
18
+ 1. `MLayout fillViewport` + optional `MLayoutSider bordered`
19
+ 2. `MLayoutHeader` → `MBreadcrumb`
20
+ 3. `MLayoutContent` → `MPageContent`
21
+ 4. `MPageFilters` — inner `MSpace` + Input/Select + query/reset
22
+ 5. `MPageToolbar` — title + `#actions` primary action
23
+ 6. `MTable` directly in content (usually **no** wrapping `MCard`)
24
+ 7. Pagination via `MTable` paginator or sibling `MPagination`
25
+
26
+ ## Form page — block order
27
+
28
+ 1. `MLayout fillViewport` → `MLayoutHeader` → `MBreadcrumb`
29
+ 2. `MPageContent width="narrow"`
30
+ 3. `MPageHeader` (title + description)
31
+ 4. `MPageSection variant="form"` → `MForm`
32
+ 5. `MPageSection variant="actions"` — save (`primary`) + cancel (`secondary`)
33
+
34
+ ## Dashboard — block order
35
+
36
+ 1. `MLayout fillViewport` → `MLayoutHeader` → `MBreadcrumb`
37
+ 2. `MPageContent density="spacious"` → `MPageHeader`
38
+ 3. KPI row: `MGrid` + `MPageStat` (4 columns or responsive)
39
+ 4. Main split: `MCard` + `MPagePlaceholder` and/or recent `MTable`
40
+
41
+ ## Composition standards
42
+
43
+ | Topic | Prefer | Usually avoid |
44
+ | --- | --- | --- |
45
+ | Shell | `MLayout fillViewport` + `MPageContent` | Hand `min-height: 100vh`; padding on `MLayoutContent` |
46
+ | Sections | `MPageFilters` / `MPageToolbar` / `MPageSection` | Custom `.page-*`; extra `MCard` wrappers |
47
+ | List table | `MTable` in `MPageContent` | Border card solely to wrap the table |
48
+ | Spacing | `MSpace` / `MFlex` for peers; page gap from `MPageContent` | Nested padded divs stacking gaps |
49
+ | Scroll | Rely on layout scroll; explicit `MScrollbar` for local panes | Forcing overflow on every content slot |
50
+ | Color | `--m-*` | Page-level hex / rgb |
51
+ | Feedback | One-line → `message`; danger → confirm dialog | Toast for a single short string |
52
+ | A11y | Labels + icon `aria-label` | Unlabeled icon controls |
53
+
54
+ Inline style is acceptable for control widths (e.g. filter `width: 14rem`).
55
+
56
+ ## Detail page — suggested order
57
+
58
+ 1. Same admin chrome as list (breadcrumb → `MPageContent`)
59
+ 2. `MPageHeader` — title, status via `MStatus` (light) or `MTag` (chip), primary/secondary actions
60
+ 3. Summary `MCard` or definition sections via `MPageSection`
61
+ 4. Related data: nested `MTabs` + `MTable` / timeline
62
+ 5. Edit via route, or `MDrawer` / `MDialog` — do not turn detail into a marketing page
63
+
64
+ ## Settings page — suggested order
65
+
66
+ 1. Admin chrome + `MPageContent width="narrow"` (or split: side `MMenu`/`MTabs` + content)
67
+ 2. Grouped `MPageSection` or `MTabs` by concern (资料 / 通知 / 安全)
68
+ 3. Each group: `MForm` + save actions (section-level or page-level — be consistent)
69
+ 4. Dangerous zone last: `severity="danger"` + confirm
70
+
71
+ ## Hybrids
72
+
73
+ - List + row edit dialog → list golden page + `MDialog` form body.
74
+ - List + side detail → list + `MDrawer`.
75
+ - Settings without admin chrome → still use `MPageContent` + `MPageSection`; omit sider only if the host app already provides chrome.
76
+ - Non-Ops surfaces (auth, landing, empty, wizard) → [surfaces.md](surfaces.md), not these golden orders.