@morya-ui/setup 0.3.1 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +16 -10
- package/catalog/skills.json +18 -0
- package/package.json +1 -1
- package/src/cli.mjs +17 -2
- package/src/skills.mjs +73 -4
- package/template/.agents/skills/morya-ui-pages/SKILL.md +8 -6
- package/template/.agents/skills/morya-ui-pages/evals/evals.json +24 -6
- package/template/.agents/skills/morya-ui-pages/references/component-index.md +51 -50
- package/template/.agents/skills/morya-ui-pages/references/decision-recipes.md +1559 -0
- package/template/.agents/skills/morya-ui-pages/references/design-system.md +2 -2
- package/template/.agents/skills/morya-ui-pages/references/feedback.md +2 -0
- package/template/.agents/skills/morya-ui-pages/references/optional-companions.md +7 -7
- package/template/.agents/skills/morya-ui-pages/references/page-layouts.md +9 -7
- package/template/.agents/skills/morya-ui-pages/references/review-checklist.md +1 -1
- package/template/.agents/skills/morya-ui-pages/references/visual-craft.md +7 -9
- package/template/.cursor/rules/component-usage.mdc +1 -1
- package/template/.cursor/rules/design-system.mdc +1 -1
- package/template/.cursor/rules/page-layout.mdc +8 -6
- package/template/DESIGN.md +1 -1
- package/template/.agents/skills/fixing-accessibility/SKILL.md +0 -138
- package/template/.agents/skills/frontend-design/LICENSE.txt +0 -177
- package/template/.agents/skills/frontend-design/SKILL.md +0 -57
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Morya UI contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Docs (zh/en):
|
|
|
9
9
|
- [Agent Skill](https://morya-space.github.io/morya-ui/docs/agent-skill) — `morya-ui-pages` behavior
|
|
10
10
|
- [Quick start](https://morya-space.github.io/morya-ui/docs/quick-start) — install and first component
|
|
11
11
|
|
|
12
|
-
Installs the UI library, copies Agent skills / Cursor rules / design docs from `design-kit`, merges Cursor MCP for [`@morya-ui/mcp`](https://www.npmjs.com/package/@morya-ui/mcp), and injects `import 'morya-ui/styles.css'`.
|
|
12
|
+
Installs the UI library, copies first-party Agent skills / Cursor rules / design docs from `design-kit`, installs optional companion skills at **latest** via the [skills CLI](https://skills.sh/), merges Cursor MCP for [`@morya-ui/mcp`](https://www.npmjs.com/package/@morya-ui/mcp), and injects `import 'morya-ui/styles.css'`.
|
|
13
13
|
|
|
14
14
|
## Usage
|
|
15
15
|
|
|
@@ -32,7 +32,7 @@ npx @morya-ui/setup app
|
|
|
32
32
|
|
|
33
33
|
# Non-interactive skill selection
|
|
34
34
|
npx @morya-ui/setup ai --yes
|
|
35
|
-
npx @morya-ui/setup ai --skills=morya-ui-pages,frontend-design
|
|
35
|
+
npx @morya-ui/setup ai --skills=morya-ui-pages,frontend-design,impeccable
|
|
36
36
|
npx @morya-ui/setup ai --skills=all
|
|
37
37
|
```
|
|
38
38
|
|
|
@@ -47,7 +47,7 @@ npx @morya-ui/setup ai --skills=all
|
|
|
47
47
|
| `--force` | Overwrite existing template files and the `morya-ui` MCP entry |
|
|
48
48
|
| `--dry-run` | Print actions without writing or installing |
|
|
49
49
|
| `--skip-install` | Do not install `morya-ui` |
|
|
50
|
-
| `--skip-template` | Do not copy AI skill / rules / docs |
|
|
50
|
+
| `--skip-template` | Do not copy AI skill / rules / docs (also skips companion skill install) |
|
|
51
51
|
| `--skip-mcp` | Do not write `.cursor/mcp.json` |
|
|
52
52
|
| `--skip-styles` | Do not inject `styles.css` |
|
|
53
53
|
| `--skip-scripts` | Do not add `check:colors` to `package.json` |
|
|
@@ -55,30 +55,36 @@ npx @morya-ui/setup ai --skills=all
|
|
|
55
55
|
|
|
56
56
|
### Skills
|
|
57
57
|
|
|
58
|
-
| Id | Default | Role |
|
|
59
|
-
| --- | --- | --- |
|
|
60
|
-
| `morya-ui-pages` | required | Page generation with `M*` + golden layouts |
|
|
61
|
-
| `frontend-design` | optional | Express / brand visual taste |
|
|
62
|
-
| `fixing-accessibility` | optional | A11y audit and targeted fixes |
|
|
58
|
+
| Id | Default | Install | Role |
|
|
59
|
+
| --- | --- | --- | --- |
|
|
60
|
+
| `morya-ui-pages` | required | template (from this package) | Page generation with `M*` + golden layouts |
|
|
61
|
+
| `frontend-design` | optional | skills CLI → `anthropics/skills` (latest) | Express / brand visual taste |
|
|
62
|
+
| `fixing-accessibility` | optional | skills CLI → `ibelick/ui-skills` (latest) | A11y audit and targeted fixes |
|
|
63
|
+
| `impeccable` | optional | skills CLI → `pbakaus/impeccable` (latest) | Named polish / audit / redesign passes |
|
|
63
64
|
|
|
64
65
|
Catalog: [`catalog/skills.json`](./catalog/skills.json).
|
|
65
66
|
|
|
66
67
|
### Conflict policy
|
|
67
68
|
|
|
68
69
|
- Template files and `.cursor/rules/*`: **skip** if the destination exists (unless `--force`).
|
|
70
|
+
- Companion skills (`skills-cli`): always reinstall/update to **latest** when selected.
|
|
69
71
|
- `.cursor/mcp.json`: merge other servers; skip existing `morya-ui` entry unless `--force`.
|
|
70
72
|
- `package.json` `check:colors`: add only if missing (unless `--force`).
|
|
71
73
|
- Styles: inject only when an entry file is found and the import is not already present.
|
|
72
74
|
|
|
73
|
-
### What gets copied
|
|
75
|
+
### What gets copied / installed
|
|
74
76
|
|
|
75
77
|
From the package `template/` (synced from repo `design-kit/`):
|
|
76
78
|
|
|
77
79
|
- `DESIGN.md` — core design contract (principles, tokens, bans)
|
|
78
|
-
- `.agents/skills
|
|
80
|
+
- `.agents/skills/morya-ui-pages/` — first-party page skill
|
|
79
81
|
- `.cursor/rules/`
|
|
80
82
|
- `scripts/check-raw-colors.mjs`
|
|
81
83
|
|
|
84
|
+
Via `npx skills add …` when optional companions are selected:
|
|
85
|
+
|
|
86
|
+
- `.agents/skills/frontend-design/`, `fixing-accessibility/`, and/or `impeccable/` (latest upstream)
|
|
87
|
+
|
|
82
88
|
### MCP (Cursor)
|
|
83
89
|
|
|
84
90
|
Writes / merges:
|
package/catalog/skills.json
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"description": "Build admin and product pages with M* components, golden layouts, and tokens.",
|
|
7
7
|
"required": true,
|
|
8
8
|
"default": true,
|
|
9
|
+
"install": "template",
|
|
9
10
|
"path": ".agents/skills/morya-ui-pages"
|
|
10
11
|
},
|
|
11
12
|
{
|
|
@@ -14,6 +15,9 @@
|
|
|
14
15
|
"description": "Distinctive visual direction for Express / brand surfaces (taste only; still remediate with M*).",
|
|
15
16
|
"required": false,
|
|
16
17
|
"default": false,
|
|
18
|
+
"install": "skills-cli",
|
|
19
|
+
"source": "anthropics/skills",
|
|
20
|
+
"skill": "frontend-design",
|
|
17
21
|
"path": ".agents/skills/frontend-design"
|
|
18
22
|
},
|
|
19
23
|
{
|
|
@@ -22,7 +26,21 @@
|
|
|
22
26
|
"description": "Audit and fix names, keyboard, focus, forms, and WCAG basics.",
|
|
23
27
|
"required": false,
|
|
24
28
|
"default": false,
|
|
29
|
+
"install": "skills-cli",
|
|
30
|
+
"source": "ibelick/ui-skills",
|
|
31
|
+
"skill": "fixing-accessibility",
|
|
25
32
|
"path": ".agents/skills/fixing-accessibility"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"id": "impeccable",
|
|
36
|
+
"name": "Impeccable",
|
|
37
|
+
"description": "Named polish / audit / redesign passes for frontend UI (latest from pbakaus/impeccable).",
|
|
38
|
+
"required": false,
|
|
39
|
+
"default": false,
|
|
40
|
+
"install": "skills-cli",
|
|
41
|
+
"source": "pbakaus/impeccable",
|
|
42
|
+
"skill": "impeccable",
|
|
43
|
+
"path": ".agents/skills/impeccable"
|
|
26
44
|
}
|
|
27
45
|
]
|
|
28
46
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@morya-ui/setup",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.3",
|
|
5
5
|
"description": "One-shot setup for morya-ui: install the library, Cursor MCP, Agent skills, and design config.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://github.com/morya-space/morya-ui/tree/main/packages/setup#readme",
|
package/src/cli.mjs
CHANGED
|
@@ -8,6 +8,7 @@ import { mergeMcpConfig } from './mcp.mjs'
|
|
|
8
8
|
import { ensureCheckColorsScript } from './package-json.mjs'
|
|
9
9
|
import {
|
|
10
10
|
buildAiInclude,
|
|
11
|
+
installSkillsCli,
|
|
11
12
|
loadSkillsCatalog,
|
|
12
13
|
parseSkillsFlag,
|
|
13
14
|
resolveSkillSelection,
|
|
@@ -39,7 +40,8 @@ export function printHelp() {
|
|
|
39
40
|
const { skills } = loadSkillsCatalog()
|
|
40
41
|
const skillList = skills.map((s) => {
|
|
41
42
|
const tag = s.required ? 'required' : s.default ? 'default' : 'optional'
|
|
42
|
-
|
|
43
|
+
const via = s.install === 'skills-cli' ? ' [skills-cli latest]' : ''
|
|
44
|
+
return ` ${s.id.padEnd(24)} (${tag})${via} ${s.description}`
|
|
43
45
|
}).join('\n')
|
|
44
46
|
|
|
45
47
|
console.log(`Usage: morya-ui-setup [command] [options]
|
|
@@ -243,6 +245,10 @@ export async function runSetup(options) {
|
|
|
243
245
|
include: aiInclude,
|
|
244
246
|
})
|
|
245
247
|
|
|
248
|
+
const remoteSkills = skipTemplate || !selectedSkills.length
|
|
249
|
+
? { installed: [], commands: [], skipped: true }
|
|
250
|
+
: installSkillsCli(cwd, selectedSkills, catalog.skills, { dryRun })
|
|
251
|
+
|
|
246
252
|
const mcp = skipMcp
|
|
247
253
|
? { path: join(cwd, '.cursor', 'mcp.json'), action: 'skipped-flag' }
|
|
248
254
|
: mergeMcpConfig(cwd, { force, dryRun })
|
|
@@ -277,6 +283,15 @@ export async function runSetup(options) {
|
|
|
277
283
|
}
|
|
278
284
|
}
|
|
279
285
|
|
|
286
|
+
if (remoteSkills.skipped) {
|
|
287
|
+
// no companions selected or template step skipped
|
|
288
|
+
} else if (remoteSkills.dryRun) {
|
|
289
|
+
console.log(`Skills CLI: dry-run — would install ${remoteSkills.installed.join(', ')}`)
|
|
290
|
+
for (const command of remoteSkills.commands) console.log(` $ ${command}`)
|
|
291
|
+
} else {
|
|
292
|
+
console.log(`Skills CLI: installed ${remoteSkills.installed.join(', ')} (latest)`)
|
|
293
|
+
}
|
|
294
|
+
|
|
280
295
|
if (mcp.action === 'skipped-flag') {
|
|
281
296
|
console.log('MCP: skipped (--skip-mcp or app mode)')
|
|
282
297
|
} else {
|
|
@@ -316,5 +331,5 @@ export async function runSetup(options) {
|
|
|
316
331
|
console.log(' 4. Optional: pnpm check:colors')
|
|
317
332
|
}
|
|
318
333
|
|
|
319
|
-
return { mode, install, template, mcp, styles, scripts, skills: selectedSkills }
|
|
334
|
+
return { mode, install, template, remoteSkills, mcp, styles, scripts, skills: selectedSkills }
|
|
320
335
|
}
|
package/src/skills.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process'
|
|
1
2
|
import { createInterface } from 'node:readline'
|
|
2
3
|
import { dirname, join } from 'node:path'
|
|
3
4
|
import { fileURLToPath } from 'node:url'
|
|
@@ -13,6 +14,9 @@ const CATALOG_PATH = join(__dirname, '..', 'catalog', 'skills.json')
|
|
|
13
14
|
* description: string
|
|
14
15
|
* required?: boolean
|
|
15
16
|
* default?: boolean
|
|
17
|
+
* install?: 'template' | 'skills-cli'
|
|
18
|
+
* source?: string
|
|
19
|
+
* skill?: string
|
|
16
20
|
* path: string
|
|
17
21
|
* }} SkillEntry
|
|
18
22
|
*/
|
|
@@ -24,6 +28,20 @@ export function loadSkillsCatalog() {
|
|
|
24
28
|
return readJson(CATALOG_PATH)
|
|
25
29
|
}
|
|
26
30
|
|
|
31
|
+
/**
|
|
32
|
+
* @param {SkillEntry} skill
|
|
33
|
+
*/
|
|
34
|
+
export function isTemplateSkill(skill) {
|
|
35
|
+
return !skill.install || skill.install === 'template'
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {SkillEntry} skill
|
|
40
|
+
*/
|
|
41
|
+
export function isSkillsCliSkill(skill) {
|
|
42
|
+
return skill.install === 'skills-cli'
|
|
43
|
+
}
|
|
44
|
+
|
|
27
45
|
/**
|
|
28
46
|
* @param {SkillEntry[]} skills
|
|
29
47
|
*/
|
|
@@ -63,21 +81,23 @@ export function parseSkillsFlag(raw, skills) {
|
|
|
63
81
|
}
|
|
64
82
|
|
|
65
83
|
/**
|
|
84
|
+
* Template-relative paths for skills that ship inside the package template.
|
|
66
85
|
* @param {string[]} skillIds
|
|
67
86
|
* @param {SkillEntry[]} skills
|
|
68
87
|
* @returns {string[]}
|
|
69
88
|
*/
|
|
70
89
|
export function skillPathsForIds(skillIds, skills) {
|
|
71
90
|
const byId = new Map(skills.map((s) => [s.id, s]))
|
|
72
|
-
return skillIds.
|
|
91
|
+
return skillIds.flatMap((id) => {
|
|
73
92
|
const entry = byId.get(id)
|
|
74
93
|
if (!entry) throw new Error(`Unknown skill id: ${id}`)
|
|
75
|
-
return
|
|
94
|
+
if (!isTemplateSkill(entry)) return []
|
|
95
|
+
return [entry.path]
|
|
76
96
|
})
|
|
77
97
|
}
|
|
78
98
|
|
|
79
99
|
/**
|
|
80
|
-
* Build template include prefixes for the AI pack.
|
|
100
|
+
* Build template include prefixes for the AI pack (first-party files only).
|
|
81
101
|
* @param {string[]} skillIds
|
|
82
102
|
* @param {SkillEntry[]} skills
|
|
83
103
|
*/
|
|
@@ -90,6 +110,54 @@ export function buildAiInclude(skillIds, skills) {
|
|
|
90
110
|
]
|
|
91
111
|
}
|
|
92
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Install selected companion skills via the skills CLI (always latest from source).
|
|
115
|
+
* @param {string} cwd
|
|
116
|
+
* @param {string[]} skillIds
|
|
117
|
+
* @param {SkillEntry[]} skills
|
|
118
|
+
* @param {{ dryRun?: boolean }} [options]
|
|
119
|
+
* @returns {{ installed: string[], commands: string[], dryRun?: boolean, skipped?: boolean }}
|
|
120
|
+
*/
|
|
121
|
+
export function installSkillsCli(cwd, skillIds, skills, { dryRun = false } = {}) {
|
|
122
|
+
const selected = skills.filter((s) => skillIds.includes(s.id) && isSkillsCliSkill(s))
|
|
123
|
+
if (!selected.length) {
|
|
124
|
+
return { installed: [], commands: [], skipped: true }
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
for (const entry of selected) {
|
|
128
|
+
if (!entry.source) {
|
|
129
|
+
throw new Error(`Skill "${entry.id}" is marked skills-cli but has no source`)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** @type {Map<string, string[]>} */
|
|
134
|
+
const bySource = new Map()
|
|
135
|
+
for (const entry of selected) {
|
|
136
|
+
const name = entry.skill || entry.id
|
|
137
|
+
const list = bySource.get(entry.source) || []
|
|
138
|
+
list.push(name)
|
|
139
|
+
bySource.set(entry.source, list)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const commands = []
|
|
143
|
+
for (const [source, names] of bySource) {
|
|
144
|
+
const skillFlags = names.map((name) => `-s ${name}`).join(' ')
|
|
145
|
+
commands.push(`npx -y skills add ${source} ${skillFlags} -a cursor -y`)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (dryRun) {
|
|
149
|
+
return { installed: selected.map((s) => s.id), commands, dryRun: true }
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
console.log('Companion skills (latest via skills CLI):')
|
|
153
|
+
for (const command of commands) {
|
|
154
|
+
console.log(` $ ${command}`)
|
|
155
|
+
execSync(command, { cwd, stdio: 'inherit', shell: true })
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return { installed: selected.map((s) => s.id), commands }
|
|
159
|
+
}
|
|
160
|
+
|
|
93
161
|
/**
|
|
94
162
|
* Prompt for optional skills when stdin is a TTY.
|
|
95
163
|
* Required skills are always included.
|
|
@@ -108,7 +176,8 @@ export async function resolveSkillSelection(skills, { skipPrompt = false } = {})
|
|
|
108
176
|
console.log('Select optional Agent skills (in addition to required):')
|
|
109
177
|
optional.forEach((skill, index) => {
|
|
110
178
|
const mark = skill.default ? 'x' : ' '
|
|
111
|
-
|
|
179
|
+
const via = isSkillsCliSkill(skill) ? ' [latest via skills CLI]' : ''
|
|
180
|
+
console.log(` ${index + 1}. [${mark}] ${skill.id} — ${skill.description}${via}`)
|
|
112
181
|
})
|
|
113
182
|
console.log('')
|
|
114
183
|
console.log('Enter comma-separated numbers or ids (empty = defaults only).')
|
|
@@ -66,7 +66,7 @@ For Express / branded Account moments, also draft a tiny **design plan** (see [v
|
|
|
66
66
|
| Ops pattern | `recommend_page` → **`get_golden_page`** (mirror; do not invent a parallel scaffold aesthetic) | [page-layouts.md](references/page-layouts.md) |
|
|
67
67
|
| Account / Express / empty / result | `recommend_page` → `get_golden_page` (`login-page` / `landing-page` / `empty-state` / `result-page`) | [surfaces.md](references/surfaces.md) |
|
|
68
68
|
| Visual direction | — | [visual-craft.md](references/visual-craft.md) (Ops polish / atmosphere / anti-defaults) |
|
|
69
|
-
| Components / **API truth** | `search` / **`get_component`** / `get_example` /
|
|
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
70
|
| Tokens / rules | `get_design_rules` | [design-system.md](references/design-system.md) |
|
|
71
71
|
| Snippet | `get_page_snippet` | golden / surface excerpt |
|
|
72
72
|
| Feedback API | — | [feedback.md](references/feedback.md) |
|
|
@@ -85,11 +85,12 @@ For Express / branded Account moments, also draft a tiny **design plan** (see [v
|
|
|
85
85
|
### 4. Wire real API usage
|
|
86
86
|
|
|
87
87
|
- Import from `morya-ui` (or documented subpath + style).
|
|
88
|
-
-
|
|
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`).
|
|
89
90
|
- Tables: `columns` + `rows` + `row-key`; `#cell-{key}`. There is no `data` prop.
|
|
90
91
|
- Enums → `MSelect` / `MTreeSelect`; action menus → `MDropdown`.
|
|
91
|
-
- Destructive → `MConfirmDialog` / `MConfirmPopup
|
|
92
|
-
- Feedback → default **`message`**; `toast` only for summary+detail / async. See [feedback.md](references/feedback.md).
|
|
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).
|
|
93
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.
|
|
94
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.
|
|
95
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.
|
|
@@ -100,7 +101,7 @@ Run **before** delivery. Do not stop at a structurally correct shell.
|
|
|
100
101
|
|
|
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).
|
|
102
103
|
- **Account / Flow:** one calm brand or empty-state cue from § Atmosphere recipes; form errors via `errorMessage` / token `role="alert"`.
|
|
103
|
-
- **Express:** short design plan + one signature; avoid AI-default looks; optional 1–2 token-only motions;
|
|
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.
|
|
104
105
|
- **All lanes:** responsive, focus visible, domain-real copy (active voice).
|
|
105
106
|
|
|
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.
|
|
@@ -156,7 +157,8 @@ Details: [optional-companions.md](references/optional-companions.md). Distilled
|
|
|
156
157
|
| [page-layouts.md](references/page-layouts.md) | Ops golden layouts |
|
|
157
158
|
| [visual-craft.md](references/visual-craft.md) | Ops polish, atmosphere recipes, anti-defaults, polish modes |
|
|
158
159
|
| [design-system.md](references/design-system.md) | Principles, tokens, bans |
|
|
159
|
-
| [component-index.md](references/component-index.md) |
|
|
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) |
|
|
160
162
|
| [feedback.md](references/feedback.md) | message / toast / MMessage |
|
|
161
163
|
| [review-checklist.md](references/review-checklist.md) | Pre-delivery checks |
|
|
162
164
|
| [optional-companions.md](references/optional-companions.md) | Combining with external design skills |
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
{
|
|
5
5
|
"id": 1,
|
|
6
6
|
"prompt": "我们内部教务系统用 Vue3 + morya-ui。请做一个「课程列表」后台页:按课程名搜索、按开课状态(全部/开课中/已结课)筛选;表格列:名称、状态、学分、更新时间;行内「编辑」进抽屉表单,「删除」要二次确认;右上角「新建课程」。保存/删除成功只要一句话提示。输出单个 Vue SFC,结构对齐列表黄金样例,并做 Ops 精致化(侧栏图标、状态用 MStatus、空态用 MEmpty、行操作不要一排实心按钮)。",
|
|
7
|
-
"expected_output": "Ops list: MLayout/MPageFilters/
|
|
7
|
+
"expected_output": "Ops list: MLayout/MPageHeader/MPageFilters/MTable rows, optional batch MPageToolbar, MSelect status, MDrawer edit, MConfirmDialog delete, message not toast, MStatus for status, MEmpty in #empty, menu icons, text/small row actions, craft pass applied, no second UI kit.",
|
|
8
8
|
"files": []
|
|
9
9
|
},
|
|
10
10
|
{
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
{
|
|
17
17
|
"id": 3,
|
|
18
18
|
"prompt": "运营后台首页仪表盘:四个 KPI(今日订单、待处理、转化率、退款率)、中间一块图表占位、右侧或下方「最近告警」表格(级别、内容、时间)。Vue3 + morya-ui,可先用静态假数据;告警级别可用 Tag,状态用 MStatus。",
|
|
19
|
-
"expected_output": "Dashboard: MPageStat grid with domain labels,
|
|
19
|
+
"expected_output": "Dashboard: MPageStat grid with domain labels, MCard shadow=always + MEmpty chart pending, recent MTable with MStatus, MLayout shell, --m-* only, spacious density.",
|
|
20
20
|
"files": []
|
|
21
21
|
},
|
|
22
22
|
{
|
|
@@ -27,14 +27,14 @@
|
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
"id": 5,
|
|
30
|
-
"prompt": "
|
|
31
|
-
"expected_output": "Flow empty: MEmpty + next-action MButton, short copy,
|
|
30
|
+
"prompt": "课程列表在零数据时太空了。请设计一个空状态区块(可嵌在列表页内容区):说明还没有课程、引导「创建第一门课程」;视觉克制,用 morya-ui 默认空态即可,不要自定义 dashed 框或径向光晕。只要空状态相关模板片段或带空状态的列表 SFC 均可。",
|
|
31
|
+
"expected_output": "Flow empty: MPageHeader + MEmpty + next-action MButton, short copy, no custom dashed/radial shell, fits list content slot.",
|
|
32
32
|
"files": []
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
"id": 6,
|
|
36
|
-
"prompt": "为「流水线 CI」产品写一个营销落地首页(不是后台):首屏只有品牌名、一句主标题、一句副文、一组 CTA;下面再分「为何选择」「能力」「客户」三节。技术实现用 Vue3 + morya-ui 组件做按钮/标签/折叠 FAQ;颜色走 --m-*,避免紫渐变和奶油衬线陶土那套 AI 默认脸。可有 1–2
|
|
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,
|
|
36
|
+
"prompt": "为「流水线 CI」产品写一个营销落地首页(不是后台):首屏只有品牌名、一句主标题、一句副文、一组 CTA;下面再分「为何选择」「能力」「客户」三节。技术实现用 Vue3 + morya-ui 组件做按钮/标签/折叠 FAQ;颜色走 --m-*,避免紫渐变和奶油衬线陶土那套 AI 默认脸。可有 1–2 个微动效,强度跟 useMotion / data-m-motion。输出单个 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, motion gated by useMotion / data-m-motion.",
|
|
38
38
|
"files": []
|
|
39
39
|
},
|
|
40
40
|
{
|
|
@@ -66,6 +66,24 @@
|
|
|
66
66
|
"prompt": "用户列表页上「新建/编辑」不要另开路由:同页 MDialog(约 32rem)里放短表单(姓名、邮箱、角色),页脚取消/保存;保存成功用 message 一句话。输出单个 Vue SFC。",
|
|
67
67
|
"expected_output": "form-in-dialog: list stays, MDialog + MForm + #footer, message.success not toast string, MTable rows.",
|
|
68
68
|
"files": []
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"id": 12,
|
|
72
|
+
"prompt": "做一个用户列表表格页:列姓名、角色、状态。状态列必须用 MStatus;行数据绑定用 rows(不要写 data prop);空表用 #empty + MEmpty。Vue3 + morya-ui,输出单个 SFC。",
|
|
73
|
+
"expected_output": "Prop accuracy: MTable columns+rows (not :data), #cell or Status for status, #empty+MEmpty, validate_usage clean.",
|
|
74
|
+
"files": []
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"id": 13,
|
|
78
|
+
"prompt": "列表行删除:点删除后用 MConfirmDialog(危险确认),确认后 message.success('已删除')。不要用 toast,也不要手写 Dialog 当确认框。输出片段或 SFC 均可。",
|
|
79
|
+
"expected_output": "confirm-choice + feedback-choice: MConfirmDialog v-model header/message acceptSeverity=danger @accept, message.success not toast, no hand Dialog confirm.",
|
|
80
|
+
"files": []
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"id": 14,
|
|
84
|
+
"prompt": "短新建弹窗:MDialog v-model + header + #footer(取消 secondary、保存 primary);表单字段 fluid。保存成功 message 一句话。不要用 v-model:visible。",
|
|
85
|
+
"expected_output": "form-surface Dialog recipe: v-model not visible, #footer actions, fluid fields, message.success.",
|
|
86
|
+
"files": []
|
|
69
87
|
}
|
|
70
88
|
]
|
|
71
89
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# Component index (scenario map)
|
|
2
2
|
|
|
3
|
-
Full API: docs site `/components` or MCP (`get_component`, `search`, `validate_usage`).
|
|
3
|
+
Full API: docs site `/components` or MCP (`get_component`, `search`, `validate_usage`).
|
|
4
|
+
|
|
5
|
+
- **Selection + key props**: MCP `recommend_component`, or offline [decision-recipes.md](./decision-recipes.md) (generated from `packages/ui-mcp/src/decisions.ts`).
|
|
6
|
+
- This file is a **catalog + decision-id index**, not a prop manual.
|
|
4
7
|
|
|
5
8
|
## Shell
|
|
6
9
|
|
|
@@ -31,68 +34,66 @@ Full API: docs site `/components` or MCP (`get_component`, `search`, `validate_u
|
|
|
31
34
|
|
|
32
35
|
## Feedback
|
|
33
36
|
|
|
34
|
-
| API / component | When |
|
|
35
|
-
| --- | --- |
|
|
36
|
-
| `message` | **Default** one-line CRUD result |
|
|
37
|
-
| `toast` | `summary` + `detail`, or async / background feel |
|
|
38
|
-
| `<MMessage>` | Optional host for the `message` service
|
|
39
|
-
| field `errorMessage` or token `role="alert"` | Persistent form / auth error |
|
|
40
|
-
| `MEmpty` | No-data / first-use / filtered empty
|
|
41
|
-
| `MResult` | Terminal outcome: success, failure, 403 / 404 / 500 |
|
|
42
|
-
| `MLoading` / `v-loading` / `loading.service` | **Default** region or fullscreen loading mask |
|
|
43
|
-
| `MSkeleton` | Layout
|
|
44
|
-
| `MProgressBar` | Determinate progress |
|
|
45
|
-
| `MProgressSpinner` | Inline spinner only, not a region mask |
|
|
46
|
-
| `MBlockUI` | Block interaction without a loading message |
|
|
37
|
+
| API / component | When | Decision |
|
|
38
|
+
| --- | --- | --- |
|
|
39
|
+
| `message` | **Default** one-line CRUD result | `feedback-choice` |
|
|
40
|
+
| `toast` | `summary` + `detail`, or async / background feel | `feedback-choice` |
|
|
41
|
+
| `<MMessage>` | Optional host for the `message` service. **Not** an inline alert | `feedback-choice` |
|
|
42
|
+
| field `errorMessage` or token `role="alert"` | Persistent form / auth error | `feedback-choice` |
|
|
43
|
+
| `MEmpty` | No-data / first-use / filtered empty | `empty-result-choice` |
|
|
44
|
+
| `MResult` | Terminal outcome: success, failure, 403 / 404 / 500 | `empty-result-choice` |
|
|
45
|
+
| `MLoading` / `v-loading` / `loading.service` | **Default** region or fullscreen loading mask | `loading-choice` |
|
|
46
|
+
| `MSkeleton` | Layout known; placeholder while content arrives | `loading-choice` |
|
|
47
|
+
| `MProgressBar` | Determinate progress | `loading-choice` |
|
|
48
|
+
| `MProgressSpinner` | Inline spinner only, not a region mask | `loading-choice` |
|
|
49
|
+
| `MBlockUI` | Block interaction without a loading message | `loading-choice` |
|
|
47
50
|
|
|
48
51
|
## Overlays & menus
|
|
49
52
|
|
|
50
|
-
`MDialog`, `MDrawer`, `MConfirmDialog` / `MConfirmPopup`, `MPopover`, `MTooltip`, `MDropdown` (**actions only**), `MContextMenu
|
|
53
|
+
`MDialog`, `MDrawer`, `MConfirmDialog` / `MConfirmPopup`, `MPopover`, `MTooltip`, `MDropdown` (**actions only**), `MContextMenu`, `MCommandMenu`, `MMenu` / `MMenubar` / `MTieredMenu` / `MMegaMenu`, `MTabs`, `MStepper`
|
|
51
54
|
|
|
52
55
|
## Surfaces / media
|
|
53
56
|
|
|
54
57
|
`MCard`, `MPanel`, `MAccordion`, `MCarousel`, `MGallery`, `MIcon`, `MScrollbar`, `MInplace`, `MScrollTop`, `MTerminal`
|
|
55
58
|
|
|
56
|
-
## Scenario →
|
|
59
|
+
## Scenario → decision
|
|
60
|
+
|
|
61
|
+
Open MCP `recommend_component({ decision })` or the matching section in [decision-recipes.md](./decision-recipes.md) for **when / avoid / recipe props / anti-patterns**.
|
|
57
62
|
|
|
58
|
-
| Intent |
|
|
63
|
+
| Intent | Decision id |
|
|
59
64
|
| --- | --- |
|
|
60
|
-
|
|
|
61
|
-
|
|
|
62
|
-
|
|
|
63
|
-
|
|
|
64
|
-
|
|
|
65
|
-
|
|
|
66
|
-
|
|
|
67
|
-
|
|
|
68
|
-
|
|
|
69
|
-
|
|
|
70
|
-
|
|
|
71
|
-
|
|
|
72
|
-
|
|
|
73
|
-
|
|
|
74
|
-
|
|
|
75
|
-
|
|
|
76
|
-
|
|
|
77
|
-
|
|
|
78
|
-
|
|
|
79
|
-
|
|
|
80
|
-
|
|
|
81
|
-
|
|
|
82
|
-
| Right-click actions | `MContextMenu` |
|
|
83
|
-
| Global command search | `MCommandMenu` |
|
|
84
|
-
| Count or dot on a control | `MBadge` |
|
|
85
|
-
| Removable entity chip | `MChip` |
|
|
65
|
+
| Create / edit from a list (few–medium fields) vs long form page | `form-surface-choice` |
|
|
66
|
+
| Dialog vs Drawer vs Popover vs Tooltip | `overlay-choice` |
|
|
67
|
+
| Table vs DataView vs Tree / TreeTable | `data-display-choice` |
|
|
68
|
+
| Select vs TreeSelect vs AutoComplete vs Radio / … | `selection-choice` |
|
|
69
|
+
| Card vs Panel vs Fieldset | `surface-choice` |
|
|
70
|
+
| PageContent vs Flex vs Space vs Grid | `layout-spacing-choice` |
|
|
71
|
+
| PageFilters / Toolbar / Header / Section / Stat / Placeholder | `page-section-choice` |
|
|
72
|
+
| Layout scroll vs MScrollbar vs built-in | `page-scroll-choice` |
|
|
73
|
+
| Avoid double borders / extra Card wrappers | `surface-nesting-choice` |
|
|
74
|
+
| Loading vs Skeleton vs Progress* vs BlockUI | `loading-choice` |
|
|
75
|
+
| Status vs Tag vs Chip vs Badge | `status-label-choice` |
|
|
76
|
+
| Empty vs Result | `empty-result-choice` |
|
|
77
|
+
| Dropdown vs Menu vs ContextMenu vs CommandMenu | `action-menu-choice` |
|
|
78
|
+
| message vs toast vs field / form alert | `feedback-choice` |
|
|
79
|
+
| ConfirmDialog vs ConfirmPopup | `confirm-choice` |
|
|
80
|
+
| Searchable list + paging | `page-section-choice` + `data-display-choice` (+ list golden) |
|
|
81
|
+
| Delete / destructive | `confirm-choice` |
|
|
82
|
+
| Login / auth | `feedback-choice` + `login-page` golden |
|
|
83
|
+
| Marketing landing | `landing-page` golden (Express) |
|
|
84
|
+
| Multi-step create | `wizard-form` golden |
|
|
85
|
+
| Preferences / settings | `settings-page` golden |
|
|
86
|
+
| Resizable two-pane | use `MSplitter` (see docs / `get_component`) |
|
|
86
87
|
|
|
87
88
|
## Common mistakes
|
|
88
89
|
|
|
89
90
|
| Wrong | Right |
|
|
90
91
|
| --- | --- |
|
|
91
|
-
| `MDropdown` as form enum | `MSelect` |
|
|
92
|
-
| `MTable` `:data` | `:rows` (`
|
|
93
|
-
| `<MMessage severity>` as an inline alert | Field `errorMessage`, or
|
|
92
|
+
| `MDropdown` as form enum | `MSelect` (`selection-choice`) |
|
|
93
|
+
| `MTable` `:data` | `:rows` (`data-display-choice`) |
|
|
94
|
+
| `<MMessage severity>` as an inline alert | Field `errorMessage`, or token `role="alert"` (`feedback-choice`) |
|
|
94
95
|
| Hand `<table>` | `MTable` |
|
|
95
|
-
| Hand modal div | `MDialog` |
|
|
96
|
-
| Hand spinner or `MProgressSpinner` as a region / page mask | `MLoading` / `v-loading` |
|
|
97
|
-
| Extra `MCard` around every `MPage*` block |
|
|
98
|
-
| Assume undocumented props | MCP / docs lookup |
|
|
96
|
+
| Hand modal div | `MDialog` / `MConfirmDialog` |
|
|
97
|
+
| Hand spinner or `MProgressSpinner` as a region / page mask | `MLoading` / `v-loading` (`loading-choice`) |
|
|
98
|
+
| Extra `MCard` around every `MPage*` block | `surface-nesting-choice` |
|
|
99
|
+
| Assume undocumented props | MCP / docs lookup + `validate_usage` |
|