@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.
Files changed (31) hide show
  1. package/README.md +103 -103
  2. package/bin/morya-ui-setup.js +14 -14
  3. package/catalog/skills.json +46 -46
  4. package/package.json +5 -3
  5. package/src/cli.mjs +335 -335
  6. package/src/copy-template.mjs +78 -78
  7. package/src/fs-utils.mjs +24 -24
  8. package/src/install.mjs +63 -63
  9. package/src/mcp.mjs +50 -50
  10. package/src/package-json.mjs +30 -30
  11. package/src/skills.mjs +223 -223
  12. package/src/styles.mjs +119 -119
  13. package/template/.agents/skills/morya-ui-pages/SKILL.md +184 -164
  14. package/template/.agents/skills/morya-ui-pages/evals/evals.json +89 -89
  15. package/template/.agents/skills/morya-ui-pages/references/component-index.md +99 -99
  16. package/template/.agents/skills/morya-ui-pages/references/decision-recipes.md +32 -0
  17. package/template/.agents/skills/morya-ui-pages/references/design-system.md +101 -100
  18. package/template/.agents/skills/morya-ui-pages/references/feedback.md +68 -68
  19. package/template/.agents/skills/morya-ui-pages/references/optional-companions.md +107 -34
  20. package/template/.agents/skills/morya-ui-pages/references/page-layouts.md +141 -119
  21. package/template/.agents/skills/morya-ui-pages/references/review-checklist.md +64 -61
  22. package/template/.agents/skills/morya-ui-pages/references/style-presets.md +73 -0
  23. package/template/.agents/skills/morya-ui-pages/references/surfaces.md +91 -89
  24. package/template/.agents/skills/morya-ui-pages/references/visual-craft.md +221 -196
  25. package/template/.cursor/rules/coding-style.mdc +41 -41
  26. package/template/.cursor/rules/component-usage.mdc +41 -41
  27. package/template/.cursor/rules/design-system.mdc +17 -17
  28. package/template/.cursor/rules/page-layout.mdc +97 -78
  29. package/template/DESIGN.md +59 -59
  30. package/template/scripts/check-raw-colors.mjs +74 -74
  31. package/LICENSE +0 -21
package/src/styles.mjs CHANGED
@@ -1,119 +1,119 @@
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 an import after the last leading import, or at top.
45
- * @param {string} source
46
- * @param {string} importLine
47
- * @param {string} marker substring that means "already present"
48
- */
49
- export function injectImportLine(source, importLine, marker) {
50
- if (source.includes(marker)) {
51
- return { source, changed: false, reason: 'already-present' }
52
- }
53
-
54
- const lines = source.split(/\r?\n/)
55
- let lastImportIndex = -1
56
- for (let i = 0; i < lines.length; i++) {
57
- const line = lines[i].trim()
58
- if (!line) {
59
- if (lastImportIndex >= 0) continue
60
- continue
61
- }
62
- if (line.startsWith('//') || line.startsWith('/*') || line.startsWith('*')) {
63
- if (lastImportIndex < 0) continue
64
- break
65
- }
66
- if (/^import\s/.test(line) || /^import["']/.test(line)) {
67
- lastImportIndex = i
68
- continue
69
- }
70
- break
71
- }
72
-
73
- if (lastImportIndex >= 0) {
74
- lines.splice(lastImportIndex + 1, 0, importLine)
75
- }
76
- else {
77
- let insertAt = 0
78
- if (lines[0]?.startsWith('#!')) insertAt = 1
79
- lines.splice(insertAt, 0, importLine, '')
80
- }
81
-
82
- return { source: lines.join('\n'), changed: true }
83
- }
84
-
85
- /**
86
- * @param {string} source
87
- * @deprecated use injectImportLine
88
- */
89
- export function injectStyleImport(source) {
90
- return injectImportLine(source, STYLE_IMPORT, STYLE_MARKER)
91
- }
92
-
93
- /**
94
- * @returns {{
95
- * action: 'injected' | 'skipped' | 'missing-entry',
96
- * path?: string,
97
- * reason?: string,
98
- * dryRun?: boolean
99
- * }}
100
- */
101
- export function ensureStylesImport(cwd, { dryRun = false } = {}) {
102
- const entry = findEntryFile(cwd)
103
- if (!entry) {
104
- return { action: 'missing-entry', reason: 'no-entry-found' }
105
- }
106
-
107
- const original = readFileSync(entry, 'utf8')
108
- const { source, changed, reason } = injectImportLine(original, STYLE_IMPORT, STYLE_MARKER)
109
-
110
- if (!changed) {
111
- return { action: 'skipped', path: entry, reason: reason || 'already-present' }
112
- }
113
-
114
- if (!dryRun) {
115
- writeFileSync(entry, source, 'utf8')
116
- }
117
-
118
- return { action: 'injected', path: entry, dryRun }
119
- }
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 an import after the last leading import, or at top.
45
+ * @param {string} source
46
+ * @param {string} importLine
47
+ * @param {string} marker substring that means "already present"
48
+ */
49
+ export function injectImportLine(source, importLine, marker) {
50
+ if (source.includes(marker)) {
51
+ return { source, changed: false, reason: 'already-present' }
52
+ }
53
+
54
+ const lines = source.split(/\r?\n/)
55
+ let lastImportIndex = -1
56
+ for (let i = 0; i < lines.length; i++) {
57
+ const line = lines[i].trim()
58
+ if (!line) {
59
+ if (lastImportIndex >= 0) continue
60
+ continue
61
+ }
62
+ if (line.startsWith('//') || line.startsWith('/*') || line.startsWith('*')) {
63
+ if (lastImportIndex < 0) continue
64
+ break
65
+ }
66
+ if (/^import\s/.test(line) || /^import["']/.test(line)) {
67
+ lastImportIndex = i
68
+ continue
69
+ }
70
+ break
71
+ }
72
+
73
+ if (lastImportIndex >= 0) {
74
+ lines.splice(lastImportIndex + 1, 0, importLine)
75
+ }
76
+ else {
77
+ let insertAt = 0
78
+ if (lines[0]?.startsWith('#!')) insertAt = 1
79
+ lines.splice(insertAt, 0, importLine, '')
80
+ }
81
+
82
+ return { source: lines.join('\n'), changed: true }
83
+ }
84
+
85
+ /**
86
+ * @param {string} source
87
+ * @deprecated use injectImportLine
88
+ */
89
+ export function injectStyleImport(source) {
90
+ return injectImportLine(source, STYLE_IMPORT, STYLE_MARKER)
91
+ }
92
+
93
+ /**
94
+ * @returns {{
95
+ * action: 'injected' | 'skipped' | 'missing-entry',
96
+ * path?: string,
97
+ * reason?: string,
98
+ * dryRun?: boolean
99
+ * }}
100
+ */
101
+ export function ensureStylesImport(cwd, { dryRun = false } = {}) {
102
+ const entry = findEntryFile(cwd)
103
+ if (!entry) {
104
+ return { action: 'missing-entry', reason: 'no-entry-found' }
105
+ }
106
+
107
+ const original = readFileSync(entry, 'utf8')
108
+ const { source, changed, reason } = injectImportLine(original, STYLE_IMPORT, STYLE_MARKER)
109
+
110
+ if (!changed) {
111
+ return { action: 'skipped', path: entry, reason: reason || 'already-present' }
112
+ }
113
+
114
+ if (!dryRun) {
115
+ writeFileSync(entry, source, 'utf8')
116
+ }
117
+
118
+ return { action: 'injected', path: entry, dryRun }
119
+ }
@@ -1,164 +1,184 @@
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. Golden pages, component APIs, and feedback rules come from `@morya-ui/mcp`. Without MCP, use this skill's `references/`. Project `DESIGN.md` overrides generic taste when the AI pack is merged.
48
-
49
- ## Workflow
50
-
51
- ### 1. Pin subject, audience, surface, job
52
-
53
- State explicitly (even briefly in thinking):
54
-
55
- - **Subject** — product / domain vernacular (not generic “SaaS”)
56
- - **Audience** — who uses this screen
57
- - **Surface** — from the map above
58
- - **Single job** — what the first viewport must accomplish
59
-
60
- 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.
61
-
62
- ### 2. Load the smallest useful references
63
-
64
- | Need | Prefer (MCP) | Else read |
65
- | --- | --- | --- |
66
- | Ops pattern | `recommend_page` → **`get_golden_page`** (mirror; do not invent a parallel scaffold aesthetic) | [page-layouts.md](references/page-layouts.md) |
67
- | Account / Express / empty / result | `recommend_page` → `get_golden_page` (`login-page` / `landing-page` / `empty-state` / `result-page`) | [surfaces.md](references/surfaces.md) |
68
- | Visual direction | — | [visual-craft.md](references/visual-craft.md) (Ops polish / atmosphere / anti-defaults) |
69
- | Components / **API truth** | `search` / **`get_component`** / `get_example` / **`recommend_component`** (includes L2 recipes) | [decision-recipes.md](references/decision-recipes.md) + [component-index.md](references/component-index.md) |
70
- | Tokens / rules | `get_design_rules` | [design-system.md](references/design-system.md) |
71
- | Snippet | `get_page_snippet` | golden / surface excerpt |
72
- | Feedback API | — | [feedback.md](references/feedback.md) |
73
- | **Required checks** | **`validate_usage`** (every `M*` you used) + `validate_page` | [review-checklist.md](references/review-checklist.md) |
74
-
75
- ### 3. Compose
76
-
77
- **Ops:** mirror golden-page block order; prefer `MPage*` over custom chrome.
78
-
79
- **Account / Flow / System:** centered or split shells with `MCard` / `MForm` / `MEmpty` / `MResult` (see surfaces); keep controls as `M*`. Persistent form errors use field `errorMessage` or a token-styled `role="alert"` — `<MMessage>` is the `message` host, not an inline alert.
80
-
81
- **Express:** hero + sections with intentional hierarchy; interactive bits still `MButton` / `MTag` / etc.; atmosphere via layout, motion, and tokens — not a second component library.
82
-
83
- **Overlay:** build the host page lightly; put the real job inside `MDialog` / `MDrawer` / `MCommandMenu`.
84
-
85
- ### 4. Wire real API usage
86
-
87
- - Import from `morya-ui` (or documented subpath + style).
88
- - **Selection + key props:** call MCP **`recommend_component`** (by query or `decision` id) and apply the returned **recipe** (`props` / `slots` / `events`) and **antiPatterns**. Without MCP, read [decision-recipes.md](references/decision-recipes.md). Then confirm full API with `get_component` / `get_example`.
89
- - Forms: `MForm` + fields; `@submit` + `type="submit"` (or documented footer button pattern on `form-in-dialog`).
90
- - Tables: `columns` + `rows` + `row-key`; `#cell-{key}`. There is no `data` prop.
91
- - Enums → `MSelect` / `MTreeSelect`; action menus → `MDropdown`.
92
- - Destructive → `MConfirmDialog` / `MConfirmPopup` (`confirm-choice`).
93
- - Feedback → default **`message`**; `toast` only for summary+detail / async; persistent form errors → `errorMessage` / `role="alert"` (`feedback-choice`). See [feedback.md](references/feedback.md).
94
- - Motion → intensity with `useMotion` (`full` / `reduced` / `none`); overlay enter/exit with `transition` prop or `createMoryaUI({ motion: { transitions } })` — do not invent a second animation stack. Prefer MCP / docs `motion` guide.
95
- - **Before craft:** for each unfamiliar or newly written `M*` usage, call MCP **`get_component` / `get_example`**, then **`validate_usage`**. Fix every `unknown-prop` / `unknown-event` before delivery.
96
- - `recommend_page(includeScaffold: true)` returns the **golden page source** when one exists — remap copy/data only; never treat generated fallback as the visual target.
97
-
98
- ### 5. Craft pass (always — lane-aware)
99
-
100
- Run **before** delivery. Do not stop at a structurally correct shell.
101
-
102
- - **Ops:** apply [visual-craft.md](references/visual-craft.md) § Ops polish (one primary, menu icons, `MStatus` in tables, designed empty, no decorative cards).
103
- - **Account / Flow:** one calm brand or empty-state cue from § Atmosphere recipes; form errors via `errorMessage` / token `role="alert"`.
104
- - **Express:** short design plan + one signature; avoid AI-default looks; optional 1–2 token-only motions; intensity via `useMotion` (`full` / `reduced` / `none`), not the OS `prefers-reduced-motion` setting.
105
- - **All lanes:** responsive, focus visible, domain-real copy (active voice).
106
-
107
- Named polish modes (`quieter` | `bolder` | `clarify` | `audit` | …): use as an **extra** pass when the user asks to improve an existing screen. See [visual-craft.md](references/visual-craft.md) § Polish modes.
108
-
109
- ### 6. Review
110
-
111
- Use [review-checklist.md](references/review-checklist.md) (contract + craft sections).
112
-
113
- **Required when MCP is available:**
114
-
115
- 1. `validate_usage` on the page (or per component) — API accuracy gate
116
- 2. `validate_page` — layout / token / contract advisories
117
-
118
- Do not deliver with unresolved `unknown-prop` / `unknown-event`.
119
-
120
- ## Hard boundaries
121
-
122
- - No second UI kit on the same surface.
123
- - No hand-rolled table/modal when `MTable` / `MDialog` / `MDrawer` fit.
124
- - No invented props / events / slots.
125
- - No defaulting every success to `toast`.
126
- - No substituting a generated scaffold for `get_golden_page` when a golden sample exists.
127
- - Ops surfaces follow golden layouts first — do not replace them with marketing heroes.
128
- - Express surfaces still use `M*` for controls and `--m-*` for color/space; do not introduce shadcn/Element/etc. stacks suggested by generic design skills.
129
- - Soft-load companions only; never require Impeccable / UI-UX-Pro-Max / Frontend Design to be installed.
130
-
131
- ## Soft companions
132
-
133
- If already installed in the consumer project:
134
-
135
- | Companion | After contract is fixed, may help with |
136
- | --- | --- |
137
- | `frontend-design` | Distinctive Express / brand moments |
138
- | `impeccable` | Named polish / audit passes |
139
- | `ui-ux-pro-max` | Mood / industry keywords for Express only |
140
-
141
- Details: [optional-companions.md](references/optional-companions.md). Distilled craft lives in [visual-craft.md](references/visual-craft.md) so this skill works **standalone**.
142
-
143
- ## Output expectations
144
-
145
- - Vue 3 `<script setup lang="ts">`.
146
- - PascalCase `M*` in templates.
147
- - Domain-real copy and data shapes (not placeholder “示例 / Name / No data” when the brief names a product).
148
- - Scoped CSS minimal; tokens only (`color-mix` / gradients from `--m-*` OK; control widths may be inline).
149
- - Craft pass completed for the lane (see step 5).
150
- - For multi-file asks: sensible `views/` / `components/` split; otherwise one SFC is fine.
151
-
152
- ## Bundled references
153
-
154
- | File | Read when |
155
- | --- | --- |
156
- | [surfaces.md](references/surfaces.md) | Choosing / composing non-Ops (and hybrid) surfaces |
157
- | [page-layouts.md](references/page-layouts.md) | Ops golden layouts |
158
- | [visual-craft.md](references/visual-craft.md) | Ops polish, atmosphere recipes, anti-defaults, polish modes |
159
- | [design-system.md](references/design-system.md) | Principles, tokens, bans |
160
- | [component-index.md](references/component-index.md) | Catalog + decision-id index |
161
- | [decision-recipes.md](references/decision-recipes.md) | Scenario → component → key props (generated; offline MCP mirror) |
162
- | [feedback.md](references/feedback.md) | message / toast / MMessage |
163
- | [review-checklist.md](references/review-checklist.md) | Pre-delivery checks |
164
- | [optional-companions.md](references/optional-companions.md) | Combining with external design skills |
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 deepen taste and polish
13
+ after structure/contract are fixed (see references/optional-companions.md).
14
+ Do not use for backend-only work or for authoring new components inside the
15
+ morya-ui library source itself.
16
+ ---
17
+
18
+ # Morya UI Pages
19
+
20
+ Guide agents that **consume morya-ui** across the full product surface — not only admin CRUD.
21
+
22
+ Two layers always apply:
23
+
24
+ 1. **Contract** — only `M*` controls, `--m-*` tokens, real APIs (MCP/docs). Never invent props or mix UI kits.
25
+ 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.
26
+
27
+ When companions conflict with this skill or project `DESIGN.md`, **this skill wins**.
28
+
29
+ ## Surface map (pick one first)
30
+
31
+ | Lane | Surfaces | Primary references |
32
+ | --- | --- | --- |
33
+ | **Ops** | list, form, dashboard, detail, settings, filter drawer, CRUD dialog | [page-layouts.md](references/page-layouts.md), golden pages |
34
+ | **Account** | login, register, invite, forgot/reset password, profile | [surfaces.md](references/surfaces.md) § Account |
35
+ | **Flow** | onboarding, empty state, wizard/stepper, success/result | [surfaces.md](references/surfaces.md) § Flow |
36
+ | **System** | 404 / error, permission denied, maintenance | [surfaces.md](references/surfaces.md) § System |
37
+ | **Express** | marketing landing, pricing, feature showcase, docs marketing chrome | [surfaces.md](references/surfaces.md) § Express + [visual-craft.md](references/visual-craft.md) |
38
+ | **Overlay** | dialog, drawer, popover, command menu as the main UI | [surfaces.md](references/surfaces.md) § Overlay |
39
+
40
+ Unclear brief → ask **one** short question, or default: Ops → closest golden page; public marketing → Express.
41
+
42
+ Full taxonomy: [references/surfaces.md](references/surfaces.md).
43
+
44
+ ## Prerequisites
45
+
46
+ 1. `morya-ui` installed; `morya-ui/styles.css` imported.
47
+ 2. Prefer `@morya-ui/mcp` — never invent prop / event / slot names.
48
+ 3. Golden pages, component APIs, and feedback rules come from `@morya-ui/mcp`. Without MCP, use this skill's `references/`. Project `DESIGN.md` overrides generic taste when the AI pack is merged.
49
+
50
+ ## Workflow
51
+
52
+ ### 1. Pin subject, audience, surface, job, **style**
53
+
54
+ State explicitly (even briefly in thinking):
55
+
56
+ - **Subject** — product / domain vernacular (not generic “SaaS”)
57
+ - **Audience** — who uses this screen
58
+ - **Surface** — from the map above
59
+ - **Single job** — what the first viewport must accomplish
60
+ - **Style direction** — resolve in this order (see [style-presets.md](references/style-presets.md)):
61
+ 1. User **reference** (screenshot / mock / existing page / “像 XX”) → extract cues, map to `--m-*` + `M*`
62
+ 2. User **named preset** (`soft` / 柔和留白 / …) → apply it
63
+ 3. **Prompt cues** (行业/气质) → infer a preset and name it
64
+ 4. Still unclear → ask **one** question with 3–4 presets; if “直接写” → domain heuristic (**not** always `quiet`)
65
+
66
+ Golden pages lock **structure/API**, not the only aesthetic. Blindly cloning golden visuals makes pages feel stiff.
67
+
68
+ 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. For Ops, a named preset + Ops polish is enough unless the user asks for a redesign.
69
+
70
+ ### 2. Load the smallest useful references
71
+
72
+ | Need | Prefer (MCP) | Else read |
73
+ | --- | --- | --- |
74
+ | Ops pattern | `recommend_page` → **`get_golden_page`** (mirror structure; craft from style direction) | [page-layouts.md](references/page-layouts.md) |
75
+ | Style direction | `recommend_page({ style })` / **`list_style_presets`** / **`get_style_preset`** | [style-presets.md](references/style-presets.md) |
76
+ | Account / Express / empty / result | `recommend_page` → `get_golden_page` (`login-page` / `landing-page` / `empty-state` / `result-page`) | [surfaces.md](references/surfaces.md) |
77
+ | Visual direction | — | [visual-craft.md](references/visual-craft.md) + [style-presets.md](references/style-presets.md) |
78
+ | Components / **API truth** | `search` / **`get_component`** / `get_example` / **`recommend_component`** (includes L2 recipes) | [decision-recipes.md](references/decision-recipes.md) + [component-index.md](references/component-index.md) |
79
+ | Tokens / rules | `get_design_rules` | [design-system.md](references/design-system.md) |
80
+ | Snippet | `get_page_snippet` | golden / surface excerpt |
81
+ | Feedback API | — | [feedback.md](references/feedback.md) |
82
+ | **Required checks** | **`validate_usage`** (every `M*` you used) + `validate_page` | [review-checklist.md](references/review-checklist.md) |
83
+
84
+ ### 3. Compose
85
+
86
+ **Ops:** mirror golden-page **block order**; apply the resolved **style preset** (or reference cues) for density/chrome/copy; prefer `MPage*` over custom chrome. Do not freeze every Ops page into identical quiet chrome. List craft variants: `list-page` (soft structure), `list-page-dense`, `list-page-rail` — `recommend_page({ style })` routes them.
87
+
88
+ **Account / Flow / System:** centered or split shells with `MCard` / `MForm` / `MEmpty` / `MResult` (see surfaces); keep controls as `M*`. Persistent form errors use field `errorMessage` or a token-styled `role="alert"` — `<MMessage>` is the `message` host, not an inline alert.
89
+
90
+ **Express:** hero + sections with intentional hierarchy; interactive bits still `MButton` / `MTag` / etc.; atmosphere via layout, motion, and tokens — not a second component library.
91
+
92
+ **Overlay:** build the host page lightly; put the real job inside `MDialog` / `MDrawer` / `MCommandMenu`.
93
+
94
+ ### 4. Wire real API usage
95
+
96
+ - Import from `morya-ui` (or documented subpath + style).
97
+ - **Selection + key props:** call MCP **`recommend_component`** (by query or `decision` id) and apply the returned **recipe** (`props` / `slots` / `events`) and **antiPatterns**. Without MCP, read [decision-recipes.md](references/decision-recipes.md). Then confirm full API with `get_component` / `get_example`.
98
+ - Forms: `MForm` + fields; `@submit` + `type="submit"` (or documented footer button pattern on `form-in-dialog`).
99
+ - Tables: `columns` + `rows` + `row-key`; `#cell-{key}`. There is no `data` prop. For full-viewport admin lists whose main job is one table, consider `MPageContent fill` + `MTable fill paginator`; skip `fill` for embedded/short/whole-page-scroll cases (see [page-layouts.md](references/page-layouts.md)).
100
+ - Enums → `MSelect` / `MTreeSelect`; action menus → `MDropdown`.
101
+ - Destructive → `MConfirmDialog` / `MConfirmPopup` (`confirm-choice`).
102
+ - Feedback → default **`message`**; `toast` only for summary+detail / async; persistent form errors → `errorMessage` / `role="alert"` (`feedback-choice`). See [feedback.md](references/feedback.md).
103
+ - Motion → intensity with `useMotion` (`full` / `reduced` / `none`); overlay enter/exit with `transition` prop or `createMoryaUI({ motion: { transitions } })` — do not invent a second animation stack. Prefer MCP / docs `motion` guide.
104
+ - **Before craft:** for each unfamiliar or newly written `M*` usage, call MCP **`get_component` / `get_example`**, then **`validate_usage`**. Fix every `unknown-prop` / `unknown-event` before delivery.
105
+ - `recommend_page(includeScaffold: true)` returns the **golden page source** when one exists — remap copy/data only; never treat generated fallback as the visual target.
106
+
107
+ ### 5. Craft pass (always — lane-aware + companions)
108
+
109
+ Run **before** delivery. Do not stop at a structurally correct shell.
110
+
111
+ 1. Resolve **style direction** ([style-presets.md](references/style-presets.md)) — reference → preset → cues → ask.
112
+ 2. Apply lane craft from [visual-craft.md](references/visual-craft.md):
113
+ - **Ops / Operate:** style preset + § Ops polish (one primary, menu icons, `MStatus`, designed empty, no decorative cards).
114
+ - **Account / Flow:** one calm brand or empty-state cue from § Atmosphere; form errors via `errorMessage` / token `role="alert"`.
115
+ - **Express / Persuade:** short design plan + one signature; avoid AI-default looks; optional 1–2 token-only motions via `useMotion`.
116
+ 3. **If companions are already installed** (see [optional-companions.md](references/optional-companions.md)):
117
+ - Express / brand → may load **`frontend-design`** for POV after contract is fixed
118
+ - User asks 更大胆/更克制/polish/audit → may load **`impeccable`** command (`bolder` / `quieter` / `polish` / …)
119
+ - Mood/industry keywords only → optional **`ui-ux-pro-max`** search, then map to tokens/preset
120
+ - a11y pass → optional **`fixing-accessibility`** after visual
121
+ - Max **one** visual companion per task; always remediate with `M*` + `--m-*`
122
+ 4. If companions are **absent**, use distilled visual-craft / style-presets — do **not** block or ask to install mid-task.
123
+ 5. **All lanes:** responsive, focus visible, domain-real copy. User **reference** overrides companion taste within the morya contract.
124
+
125
+ Named polish modes (`quieter` | `bolder` | `clarify` | `audit` | …): extra pass when the user asks to improve an existing screen.
126
+
127
+ ### 6. Review
128
+
129
+ Use [review-checklist.md](references/review-checklist.md) (contract + craft sections).
130
+
131
+ **Required when MCP is available:**
132
+
133
+ 1. `validate_usage` on the page (or per component) — API accuracy gate
134
+ 2. `validate_page` — layout / token / contract advisories
135
+
136
+ Do not deliver with unresolved `unknown-prop` / `unknown-event`.
137
+
138
+ ## Hard boundaries
139
+
140
+ - No second UI kit on the same surface.
141
+ - No hand-rolled table/modal when `MTable` / `MDialog` / `MDrawer` fit.
142
+ - No invented props / events / slots.
143
+ - No defaulting every success to `toast`.
144
+ - No substituting a generated scaffold for `get_golden_page` when a golden sample exists.
145
+ - Ops surfaces follow golden layouts first — do not replace them with marketing heroes.
146
+ - Express surfaces still use `M*` for controls and `--m-*` for color/space; do not introduce shadcn/Element/etc. stacks suggested by generic design skills.
147
+ - Soft-load companions only; never require Impeccable / UI-UX-Pro-Max / Frontend Design to be installed.
148
+
149
+ ## Soft companions
150
+
151
+ If already installed in the consumer project, **combine** them after structure + contract (do not replace this skill):
152
+
153
+ | Companion | Load when | Role |
154
+ | --- | --- | --- |
155
+ | `frontend-design` | Express / branded Account moments | Distinctive design plan + signature (taste) |
156
+ | `impeccable` | Polish / bolder / quieter / audit / delight asks | Named Operate/Persuade craft passes |
157
+ | `ui-ux-pro-max` | Mood / industry keyword search for Express | Keywords → map to `--m-*` + style preset |
158
+ | `fixing-accessibility` | a11y audit after visual | Names, keyboard, focus on top of `M*` |
159
+
160
+ Routing, conflict rules, and load budget: [optional-companions.md](references/optional-companions.md). Distilled craft in [visual-craft.md](references/visual-craft.md) + [style-presets.md](references/style-presets.md) keeps this skill **standalone**.
161
+
162
+ ## Output expectations
163
+
164
+ - Vue 3 `<script setup lang="ts">`.
165
+ - PascalCase `M*` in templates.
166
+ - Domain-real copy and data shapes (not placeholder “示例 / Name / No data” when the brief names a product).
167
+ - Scoped CSS minimal; tokens only (`color-mix` / gradients from `--m-*` OK; control widths may be inline).
168
+ - Craft pass completed for the lane (see step 5).
169
+ - For multi-file asks: sensible `views/` / `components/` split; otherwise one SFC is fine.
170
+
171
+ ## Bundled references
172
+
173
+ | File | Read when |
174
+ | --- | --- |
175
+ | [surfaces.md](references/surfaces.md) | Choosing / composing non-Ops (and hybrid) surfaces |
176
+ | [page-layouts.md](references/page-layouts.md) | Ops golden layouts |
177
+ | [style-presets.md](references/style-presets.md) | Style resolution + named presets users can pick |
178
+ | [visual-craft.md](references/visual-craft.md) | Ops polish, atmosphere recipes, anti-defaults, polish modes |
179
+ | [design-system.md](references/design-system.md) | Principles, tokens, bans |
180
+ | [component-index.md](references/component-index.md) | Catalog + decision-id index |
181
+ | [decision-recipes.md](references/decision-recipes.md) | Scenario → component → key props (generated; offline MCP mirror) |
182
+ | [feedback.md](references/feedback.md) | message / toast / MMessage |
183
+ | [review-checklist.md](references/review-checklist.md) | Pre-delivery checks |
184
+ | [optional-companions.md](references/optional-companions.md) | Combining with external design skills |