@morya-ui/setup 0.2.6 → 0.2.8

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 (33) hide show
  1. package/README.md +23 -10
  2. package/package.json +1 -1
  3. package/src/cli.mjs +90 -32
  4. package/src/copy-template.mjs +18 -2
  5. package/src/fs-utils.mjs +2 -1
  6. package/src/styles.mjs +2 -87
  7. package/template/.agents/skills/morya-ui-pages/SKILL.md +1 -3
  8. package/template/.agents/skills/morya-ui-pages/references/component-index.md +7 -1
  9. package/template/.agents/skills/morya-ui-pages/references/design-system.md +1 -1
  10. package/template/.agents/skills/morya-ui-pages/references/feedback.md +1 -1
  11. package/template/.agents/skills/morya-ui-pages/references/page-layouts.md +10 -10
  12. package/template/.agents/skills/morya-ui-pages/references/surfaces.md +3 -3
  13. package/template/.cursor/rules/component-usage.mdc +2 -2
  14. package/template/.cursor/rules/design-system.mdc +5 -5
  15. package/template/.cursor/rules/page-layout.mdc +7 -9
  16. package/template/DESIGN.md +15 -15
  17. package/template/design-tokens/tokens.css +0 -55
  18. package/template/design-tokens/tokens.json +0 -77
  19. package/template/docs/components.md +0 -145
  20. package/template/docs/feedback-message-vs-toast.md +0 -103
  21. package/template/docs/golden-pages/dashboard-page.vue +0 -103
  22. package/template/docs/golden-pages/empty-state.vue +0 -66
  23. package/template/docs/golden-pages/form-page.vue +0 -107
  24. package/template/docs/golden-pages/landing-page.vue +0 -328
  25. package/template/docs/golden-pages/list-page.vue +0 -138
  26. package/template/docs/golden-pages/login-page.vue +0 -191
  27. package/template/src/examples/DashboardPageExample.vue +0 -103
  28. package/template/src/examples/EmptyStateExample.vue +0 -66
  29. package/template/src/examples/FormPageExample.vue +0 -107
  30. package/template/src/examples/LandingPageExample.vue +0 -328
  31. package/template/src/examples/ListPageExample.vue +0 -138
  32. package/template/src/examples/LoginPageExample.vue +0 -191
  33. package/template/src/styles/morya-app-shell.css +0 -6
package/README.md CHANGED
@@ -4,10 +4,12 @@ One-shot setup for consumer Vue projects using [`morya-ui`](https://www.npmjs.co
4
4
 
5
5
  Docs (zh/en):
6
6
 
7
- - [AI setup](https://morya-space.github.io/morya-ui/docs/ai-setup) — one-shot CLI
7
+ - [One-shot setup](https://morya-space.github.io/morya-ui/docs/setup) — CLI commands and options
8
+ - [AI setup](https://morya-space.github.io/morya-ui/docs/ai-setup) — Agent workflow
8
9
  - [Agent Skill](https://morya-space.github.io/morya-ui/docs/agent-skill) — `morya-ui-pages` behavior
10
+ - [Quick start](https://morya-space.github.io/morya-ui/docs/quick-start) — install and first component
9
11
 
10
- Installs the UI library, copies Agent skill / Cursor rules / design docs from `ai-design-config`, merges Cursor MCP for [`@morya-ui/mcp`](https://www.npmjs.com/package/@morya-ui/mcp), injects `import 'morya-ui/styles.css'`, and writes `src/styles/morya-app-shell.css` with its entry import.
12
+ Installs the UI library, copies Agent skill / 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'`.
11
13
 
12
14
  ## Usage
13
15
 
@@ -17,6 +19,16 @@ In your app project root:
17
19
  npx @morya-ui/setup
18
20
  ```
19
21
 
22
+ Other common commands:
23
+
24
+ ```bash
25
+ # AI config + MCP only (library already installed)
26
+ npx @morya-ui/setup ai
27
+
28
+ # Library + styles only
29
+ npx @morya-ui/setup app
30
+ ```
31
+
20
32
  ### Options
21
33
 
22
34
  | Flag | Meaning |
@@ -28,10 +40,16 @@ npx @morya-ui/setup
28
40
  | `--skip-install` | Do not install `morya-ui` |
29
41
  | `--skip-template` | Do not copy AI skill / rules / docs / tokens |
30
42
  | `--skip-mcp` | Do not write `.cursor/mcp.json` |
31
- | `--skip-styles` | Do not inject `styles.css` / write app-shell CSS |
43
+ | `--skip-styles` | Do not inject `styles.css` |
32
44
  | `--skip-scripts` | Do not add `check:colors` to `package.json` |
33
45
  | `-h`, `--help` | Show help |
34
46
 
47
+ Example: MCP only:
48
+
49
+ ```bash
50
+ npx @morya-ui/setup ai --skip-template --skip-scripts
51
+ ```
52
+
35
53
  ### Conflict policy
36
54
 
37
55
  - Template files and `.cursor/rules/*`: **skip** if the destination exists (unless `--force`).
@@ -41,16 +59,12 @@ npx @morya-ui/setup
41
59
 
42
60
  ### What gets copied
43
61
 
44
- From the package `template/` (synced from repo `ai-design-config/`):
62
+ From the package `template/` (synced from repo `design-kit/`):
45
63
 
46
64
  - `DESIGN.md`
47
65
  - `.agents/skills/morya-ui-pages/`
48
66
  - `.cursor/rules/`
49
- - `docs/` (component index, golden pages, feedback guide)
50
- - `design-tokens/`
51
67
  - `scripts/check-raw-colors.mjs`
52
- - `src/examples/`
53
- - `src/styles/morya-app-shell.css`
54
68
 
55
69
  ### MCP (Cursor)
56
70
 
@@ -77,7 +91,6 @@ Looks for `src/main.ts` / `.js` / `.tsx` / `.jsx`, root `main.*`, `src/app.ts` /
77
91
 
78
92
  ```ts
79
93
  import 'morya-ui/styles.css'
80
- import './styles/morya-app-shell.css'
81
94
  ```
82
95
 
83
96
  The CLI does **not** call `app.use(MoryaUI)` or edit `App.vue`.
@@ -85,7 +98,7 @@ The CLI does **not** call `app.use(MoryaUI)` or edit `App.vue`.
85
98
  ## Local development (this monorepo)
86
99
 
87
100
  ```bash
88
- pnpm setup:sync-template # refresh packages/setup/template from ai-design-config
101
+ pnpm setup:sync-template # refresh packages/setup/template from design-kit
89
102
  pnpm setup:build
90
103
  node packages/setup/bin/morya-ui-setup.js --cwd /path/to/app --dry-run
91
104
  ```
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@morya-ui/setup",
3
3
  "type": "module",
4
- "version": "0.2.6",
4
+ "version": "0.2.8",
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
@@ -1,15 +1,34 @@
1
+ import { existsSync } from 'node:fs'
1
2
  import { dirname, join, resolve } from 'node:path'
2
3
  import { fileURLToPath } from 'node:url'
3
4
  import { copyTemplate } from './copy-template.mjs'
5
+ import { readJson } from './fs-utils.mjs'
4
6
  import { installMoryaUi } from './install.mjs'
5
7
  import { mergeMcpConfig } from './mcp.mjs'
6
8
  import { ensureCheckColorsScript } from './package-json.mjs'
7
- import { ensureShellStyles, ensureStylesImport } from './styles.mjs'
9
+ import { ensureStylesImport } from './styles.mjs'
8
10
 
9
11
  const __dirname = dirname(fileURLToPath(import.meta.url))
10
12
  const PKG_ROOT = resolve(__dirname, '..')
11
13
  const TEMPLATE_ROOT = join(PKG_ROOT, 'template')
12
14
 
15
+ const MODES = new Set(['app', 'ai', 'full'])
16
+
17
+ /** AI pack paths under template/. */
18
+ const AI_TEMPLATE_INCLUDE = [
19
+ 'DESIGN.md',
20
+ '.agents/skills/morya-ui-pages',
21
+ '.cursor/rules',
22
+ 'scripts/check-raw-colors.mjs',
23
+ ]
24
+
25
+ /** Mode → default skips (user --skip-* can only add more skips). */
26
+ const MODE_DEFAULTS = {
27
+ full: {},
28
+ app: { skipTemplate: true, skipMcp: true, skipScripts: true },
29
+ ai: { skipInstall: true, skipStyles: true },
30
+ }
31
+
13
32
  const SKIP_FLAGS = {
14
33
  '--skip-install': 'skipInstall',
15
34
  '--skip-template': 'skipTemplate',
@@ -19,14 +38,19 @@ const SKIP_FLAGS = {
19
38
  }
20
39
 
21
40
  export function printHelp() {
22
- console.log(`Usage: morya-ui-setup [options]
41
+ console.log(`Usage: morya-ui-setup [command] [options]
23
42
 
24
- One-shot setup for morya-ui in a consumer Vue project:
43
+ Commands:
44
+ (default) / full Install morya-ui, AI template, MCP, styles, check:colors
45
+ app Install morya-ui and inject styles.css
46
+ ai Copy Agent skill / rules / DESIGN,
47
+ merge Cursor MCP, add check:colors
48
+
49
+ Default command:
25
50
  - install morya-ui
26
- - copy DESIGN.md, Agent skill, Cursor rules, docs, tokens, examples
51
+ - copy DESIGN.md, Agent skill, Cursor rules
27
52
  - merge .cursor/mcp.json for @morya-ui/mcp
28
53
  - inject import 'morya-ui/styles.css' into the app entry when found
29
- - write src/styles/morya-app-shell.css (html/body/#app height chain) and inject its import
30
54
  - add check:colors script when missing
31
55
 
32
56
  Options:
@@ -37,7 +61,7 @@ Options:
37
61
  --skip-install Skip dependency install
38
62
  --skip-template Skip copying AI template files
39
63
  --skip-mcp Skip writing .cursor/mcp.json
40
- --skip-styles Skip injecting styles.css / app-shell CSS
64
+ --skip-styles Skip injecting styles.css
41
65
  --skip-scripts Skip adding check:colors to package.json
42
66
  -h, --help Show this help
43
67
  `)
@@ -48,6 +72,7 @@ Options:
48
72
  */
49
73
  export function parseArgs(argv) {
50
74
  const options = {
75
+ mode: 'full',
51
76
  cwd: process.cwd(),
52
77
  pm: undefined,
53
78
  force: false,
@@ -66,6 +91,10 @@ export function parseArgs(argv) {
66
91
  options.help = true
67
92
  continue
68
93
  }
94
+ if (MODES.has(arg)) {
95
+ options.mode = arg
96
+ continue
97
+ }
69
98
  if (arg === '--force') {
70
99
  options.force = true
71
100
  continue
@@ -101,6 +130,11 @@ export function parseArgs(argv) {
101
130
  throw new Error(`Unknown argument: ${arg}`)
102
131
  }
103
132
 
133
+ const defaults = MODE_DEFAULTS[options.mode] || {}
134
+ for (const [key, value] of Object.entries(defaults)) {
135
+ if (value) options[key] = true
136
+ }
137
+
104
138
  return options
105
139
  }
106
140
 
@@ -109,11 +143,30 @@ function rel(cwd, path) {
109
143
  return path.startsWith(cwd) ? path.slice(cwd.length).replace(/^[\\/]/, '') || path : path
110
144
  }
111
145
 
146
+ /**
147
+ * @param {string} cwd
148
+ */
149
+ function hasMoryaUiDependency(cwd) {
150
+ const path = join(cwd, 'package.json')
151
+ if (!existsSync(path)) return false
152
+ try {
153
+ const pkg = readJson(path)
154
+ return Boolean(
155
+ pkg.dependencies?.['morya-ui']
156
+ || pkg.devDependencies?.['morya-ui']
157
+ || pkg.peerDependencies?.['morya-ui'],
158
+ )
159
+ } catch {
160
+ return false
161
+ }
162
+ }
163
+
112
164
  /**
113
165
  * @param {ReturnType<typeof parseArgs>} options
114
166
  */
115
167
  export async function runSetup(options) {
116
168
  const {
169
+ mode,
117
170
  cwd,
118
171
  force,
119
172
  dryRun,
@@ -125,14 +178,25 @@ export async function runSetup(options) {
125
178
  pm,
126
179
  } = options
127
180
 
128
- console.log(`@morya-ui/setup → ${cwd}${dryRun ? ' (dry-run)' : ''}`)
181
+ console.log(`@morya-ui/setup [${mode}] → ${cwd}${dryRun ? ' (dry-run)' : ''}`)
129
182
  console.log('')
130
183
 
184
+ if (mode === 'ai' && !hasMoryaUiDependency(cwd)) {
185
+ console.log(
186
+ 'Warning: morya-ui is not listed in package.json. Run `npx @morya-ui/setup app` first (or pnpm add morya-ui).',
187
+ )
188
+ console.log('')
189
+ }
190
+
131
191
  const install = installMoryaUi(cwd, { pm, dryRun, skipInstall })
132
192
 
133
193
  const template = skipTemplate
134
194
  ? { copied: [], skipped: [], forced: [], skippedStep: true }
135
- : copyTemplate(TEMPLATE_ROOT, cwd, { force, dryRun })
195
+ : copyTemplate(TEMPLATE_ROOT, cwd, {
196
+ force,
197
+ dryRun,
198
+ include: mode === 'ai' || mode === 'full' ? AI_TEMPLATE_INCLUDE : undefined,
199
+ })
136
200
 
137
201
  const mcp = skipMcp
138
202
  ? { path: join(cwd, '.cursor', 'mcp.json'), action: 'skipped-flag' }
@@ -142,10 +206,6 @@ export async function runSetup(options) {
142
206
  ? { action: 'skipped', reason: 'skip-styles' }
143
207
  : ensureStylesImport(cwd, { dryRun })
144
208
 
145
- const shell = skipStyles
146
- ? { fileAction: 'skipped', importAction: 'skipped', reason: 'skip-styles' }
147
- : ensureShellStyles(cwd, { dryRun, force })
148
-
149
209
  const scripts = skipScripts
150
210
  ? { action: 'skipped-flag' }
151
211
  : ensureCheckColorsScript(cwd, { force, dryRun })
@@ -158,7 +218,7 @@ export async function runSetup(options) {
158
218
  }
159
219
 
160
220
  if (template.skippedStep) {
161
- console.log('Template: skipped (--skip-template)')
221
+ console.log('Template: skipped (--skip-template or app mode)')
162
222
  } else {
163
223
  console.log(
164
224
  `Template: ${template.copied.length} copied, ${template.forced.length} overwritten, ${template.skipped.length} skipped`,
@@ -172,13 +232,13 @@ export async function runSetup(options) {
172
232
  }
173
233
 
174
234
  if (mcp.action === 'skipped-flag') {
175
- console.log('MCP: skipped (--skip-mcp)')
235
+ console.log('MCP: skipped (--skip-mcp or app mode)')
176
236
  } else {
177
237
  console.log(`MCP: ${mcp.action} (${rel(cwd, mcp.path) || '.cursor/mcp.json'})`)
178
238
  }
179
239
 
180
240
  if (styles.reason === 'skip-styles') {
181
- console.log('Styles: skipped (--skip-styles)')
241
+ console.log('Styles: skipped (--skip-styles or ai mode)')
182
242
  } else if (styles.action === 'injected') {
183
243
  console.log(`Styles: injected into ${rel(cwd, styles.path)}`)
184
244
  } else if (styles.action === 'skipped') {
@@ -188,29 +248,27 @@ export async function runSetup(options) {
188
248
  console.log(" import 'morya-ui/styles.css'")
189
249
  }
190
250
 
191
- if (shell.reason === 'skip-styles') {
192
- console.log('Shell CSS: skipped (--skip-styles)')
193
- } else {
194
- console.log(
195
- `Shell CSS: file ${shell.fileAction}`
196
- + (shell.path ? ` (${rel(cwd, shell.path)})` : '')
197
- + `, import ${shell.importAction}`
198
- + (shell.entry ? ` (${rel(cwd, shell.entry)})` : ''),
199
- )
200
- }
201
-
202
251
  if (scripts.action === 'skipped-flag') {
203
- console.log('Scripts: skipped (--skip-scripts)')
252
+ console.log('Scripts: skipped (--skip-scripts or app mode)')
204
253
  } else {
205
254
  console.log(`Scripts: check:colors ${scripts.action}`)
206
255
  }
207
256
 
208
257
  console.log('')
209
258
  console.log('Next:')
210
- console.log(' 1. Ensure styles.css + morya-app-shell.css imports are in your app entry.')
211
- console.log(' 2. Restart Cursor (or reload MCP) so morya-ui MCP tools appear.')
212
- console.log(' 3. Have the agent read DESIGN.md before generating pages.')
213
- console.log(' 4. Optional: pnpm check:colors')
259
+ if (mode === 'app') {
260
+ console.log(' 1. Ensure the styles.css import is in your app entry.')
261
+ console.log(' 2. Optional AI pack: npx @morya-ui/setup ai')
262
+ } else if (mode === 'ai') {
263
+ console.log(' 1. Restart Cursor (or reload MCP) so morya-ui MCP tools appear.')
264
+ console.log(' 2. Have the agent read DESIGN.md before generating pages.')
265
+ console.log(' 3. Optional: pnpm check:colors')
266
+ } else {
267
+ console.log(' 1. Ensure the styles.css import is in your app entry.')
268
+ console.log(' 2. Restart Cursor (or reload MCP) so morya-ui MCP tools appear.')
269
+ console.log(' 3. Have the agent read DESIGN.md before generating pages.')
270
+ console.log(' 4. Optional: pnpm check:colors')
271
+ }
214
272
 
215
- return { install, template, mcp, styles, shell, scripts }
273
+ return { mode, install, template, mcp, styles, scripts }
216
274
  }
@@ -20,11 +20,27 @@ function listFiles(dir) {
20
20
  return out
21
21
  }
22
22
 
23
+ /**
24
+ * @param {string} rel
25
+ * @param {string[] | undefined} include
26
+ */
27
+ function matchesInclude(rel, include) {
28
+ if (!include || include.length === 0) return true
29
+ const norm = rel.replace(/\\/g, '/')
30
+ return include.some((prefix) => {
31
+ const p = prefix.replace(/\\/g, '/')
32
+ return norm === p || norm.startsWith(`${p}/`)
33
+ })
34
+ }
35
+
23
36
  /**
24
37
  * Copy template tree into target cwd.
38
+ * @param {string} templateRoot
39
+ * @param {string} cwd
40
+ * @param {{ force?: boolean, dryRun?: boolean, include?: string[] }} [options]
25
41
  * @returns {{ copied: string[], skipped: string[], forced: string[] }}
26
42
  */
27
- export function copyTemplate(templateRoot, cwd, { force = false, dryRun = false } = {}) {
43
+ export function copyTemplate(templateRoot, cwd, { force = false, dryRun = false, include } = {}) {
28
44
  const copied = []
29
45
  const skipped = []
30
46
  const forced = []
@@ -35,7 +51,7 @@ export function copyTemplate(templateRoot, cwd, { force = false, dryRun = false
35
51
  )
36
52
  }
37
53
 
38
- const files = listFiles(templateRoot)
54
+ const files = listFiles(templateRoot).filter((rel) => matchesInclude(rel, include))
39
55
  for (const rel of files) {
40
56
  const from = join(templateRoot, rel)
41
57
  const to = join(cwd, rel)
package/src/fs-utils.mjs CHANGED
@@ -2,7 +2,8 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
2
2
  import { dirname } from 'node:path'
3
3
 
4
4
  export function readJson(path) {
5
- return JSON.parse(readFileSync(path, 'utf8'))
5
+ const text = readFileSync(path, 'utf8').replace(/^\uFEFF/, '')
6
+ return JSON.parse(text)
6
7
  }
7
8
 
8
9
  export function writeJson(path, value, { dryRun = false } = {}) {
package/src/styles.mjs CHANGED
@@ -1,10 +1,8 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
2
- import { dirname, join, relative, resolve } from 'node:path'
1
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs'
2
+ import { join, resolve } from 'node:path'
3
3
 
4
4
  const STYLE_IMPORT = "import 'morya-ui/styles.css'"
5
5
  const STYLE_MARKER = 'morya-ui/styles.css'
6
- const SHELL_MARKER = 'morya-app-shell.css'
7
- const SHELL_REL = 'src/styles/morya-app-shell.css'
8
6
 
9
7
  const CANDIDATES = [
10
8
  'src/main.ts',
@@ -17,14 +15,6 @@ const CANDIDATES = [
17
15
  'src/app.js',
18
16
  ]
19
17
 
20
- const SHELL_CSS = `html,
21
- body,
22
- #app {
23
- height: 100%;
24
- margin: 0;
25
- }
26
- `
27
-
28
18
  /**
29
19
  * @param {string} cwd
30
20
  * @returns {string | null} absolute path
@@ -100,16 +90,6 @@ export function injectStyleImport(source) {
100
90
  return injectImportLine(source, STYLE_IMPORT, STYLE_MARKER)
101
91
  }
102
92
 
103
- /**
104
- * @param {string} entryFile absolute
105
- * @param {string} shellFile absolute
106
- */
107
- export function shellImportLine(entryFile, shellFile) {
108
- let rel = relative(dirname(entryFile), shellFile).replace(/\\/g, '/')
109
- if (!rel.startsWith('.')) rel = `./${rel}`
110
- return `import '${rel}'`
111
- }
112
-
113
93
  /**
114
94
  * @returns {{
115
95
  * action: 'injected' | 'skipped' | 'missing-entry',
@@ -137,68 +117,3 @@ export function ensureStylesImport(cwd, { dryRun = false } = {}) {
137
117
 
138
118
  return { action: 'injected', path: entry, dryRun }
139
119
  }
140
-
141
- /**
142
- * Write morya-app-shell.css (height chain) and inject its import into the entry.
143
- * @returns {{
144
- * fileAction: 'written' | 'skipped' | 'dry-run',
145
- * importAction: 'injected' | 'skipped' | 'missing-entry',
146
- * path?: string,
147
- * entry?: string,
148
- * reason?: string,
149
- * dryRun?: boolean
150
- * }}
151
- */
152
- export function ensureShellStyles(cwd, { dryRun = false, force = false } = {}) {
153
- const shellFile = join(cwd, SHELL_REL)
154
- const entry = findEntryFile(cwd)
155
-
156
- let fileAction = 'skipped'
157
- if (!existsSync(shellFile) || force) {
158
- if (dryRun) {
159
- fileAction = 'dry-run'
160
- }
161
- else {
162
- mkdirSync(dirname(shellFile), { recursive: true })
163
- writeFileSync(shellFile, SHELL_CSS, 'utf8')
164
- fileAction = 'written'
165
- }
166
- }
167
-
168
- if (!entry) {
169
- return {
170
- fileAction,
171
- importAction: 'missing-entry',
172
- path: shellFile,
173
- reason: 'no-entry-found',
174
- dryRun,
175
- }
176
- }
177
-
178
- const importLine = shellImportLine(entry, shellFile)
179
- const original = readFileSync(entry, 'utf8')
180
- const { source, changed, reason } = injectImportLine(original, importLine, SHELL_MARKER)
181
-
182
- if (!changed) {
183
- return {
184
- fileAction,
185
- importAction: 'skipped',
186
- path: shellFile,
187
- entry,
188
- reason: reason || 'already-present',
189
- dryRun,
190
- }
191
- }
192
-
193
- if (!dryRun) {
194
- writeFileSync(entry, source, 'utf8')
195
- }
196
-
197
- return {
198
- fileAction,
199
- importAction: 'injected',
200
- path: shellFile,
201
- entry,
202
- dryRun,
203
- }
204
- }
@@ -44,9 +44,7 @@ Full taxonomy: [references/surfaces.md](references/surfaces.md).
44
44
 
45
45
  1. `morya-ui` installed; `morya-ui/styles.css` imported.
46
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`
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.
50
48
 
51
49
  ## Workflow
52
50
 
@@ -32,7 +32,11 @@ Full API: docs site `/components` or MCP (`get_component`, `search`, `validate_u
32
32
  | `<MMessage>` | Persistent in-page error / warning |
33
33
  | `MEmpty` | No-data / first-use / filtered empty (not an error) |
34
34
  | `MResult` | Terminal outcome: success, failure, 403 / 404 / 500 |
35
- | `MProgressBar` / `MProgressSpinner` / `MSkeleton` / `MBlockUI` | Loading / blocking |
35
+ | `MLoading` / `v-loading` / `loading.service` | **Default** region or fullscreen loading mask |
36
+ | `MSkeleton` | Layout is already known; placeholder while content arrives |
37
+ | `MProgressBar` | Determinate progress |
38
+ | `MProgressSpinner` | Inline spinner only, not a region mask |
39
+ | `MBlockUI` | Block interaction without a loading message |
36
40
 
37
41
  ## Overlays & menus
38
42
 
@@ -59,6 +63,7 @@ Full API: docs site `/components` or MCP (`get_component`, `search`, `validate_u
59
63
  | Marketing landing | `landing-page` golden + `MButton` / `MTag` / `MAccordion` |
60
64
  | Empty list / zero state | `MEmpty` (+ `empty-state` golden or `MTable` `#empty`) |
61
65
  | Submit success / HTTP error page | `MResult` |
66
+ | Region or page is waiting | `MLoading`, `v-loading`, or `loading.service`; known layout → `MSkeleton` |
62
67
  | Local capped scroll | Explicit `MScrollbar` |
63
68
  | Admin sider nav | `MMenu` |
64
69
 
@@ -69,5 +74,6 @@ Full API: docs site `/components` or MCP (`get_component`, `search`, `validate_u
69
74
  | `MDropdown` as form enum | `MSelect` |
70
75
  | Hand `<table>` | `MTable` |
71
76
  | Hand modal div | `MDialog` |
77
+ | Hand spinner or `MProgressSpinner` as a region / page mask | `MLoading` / `v-loading` |
72
78
  | Extra `MCard` around every `MPage*` block | Use page components' own surface/gap |
73
79
  | Assume undocumented props | MCP / docs lookup |
@@ -87,7 +87,7 @@ import 'morya-ui/styles.css'
87
87
  | Card radius | `--m-radius-md` |
88
88
  | Card shadow | `--m-shadow-md` |
89
89
 
90
- Full machine-readable set: project `design-tokens/tokens.json` (runtime truth remains `morya-ui/styles.css`).
90
+ Full set: MCP `get_design_rules`. Runtime truth remains `morya-ui/styles.css`.
91
91
 
92
92
  ## Bans
93
93
 
@@ -46,7 +46,7 @@ toast.success({
46
46
  ## Prefer `<MMessage>` / form-level errors
47
47
 
48
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`.
49
+ - Form-level persistent errors (login/auth): token-styled `role="alert"` bar as in MCP `get_golden_page` `login-page`.
50
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
51
 
52
52
  ```vue
@@ -1,15 +1,15 @@
1
1
  # Page layouts
2
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` |
3
+ When generating a full page, pick a type and **mirror the golden-page block order**. Source: MCP `get_golden_page`.
4
+
5
+ | Type | `get_golden_page` id |
6
+ | --- | --- |
7
+ | List | `list-page` |
8
+ | Form | `form-page` |
9
+ | Dashboard | `dashboard-page` |
10
+ | Login | `login-page` |
11
+ | Landing | `landing-page` |
12
+ | Empty | `empty-state` |
13
13
 
14
14
  Via MCP: `recommend_page` → `get_golden_page`; local edits: `get_page_snippet` (`filters`, `toolbar`, `form-actions`, `scrollable-panel`, …).
15
15
 
@@ -17,7 +17,7 @@ Pick a lane, then a surface. Prefer project golden pages for **Ops**; use the re
17
17
 
18
18
  | Surface | Job | Recipe |
19
19
  | --- | --- | --- |
20
- | Login / register | Authenticate with trust | Golden: `docs/golden-pages/login-page.vue` — split brand + `MForm` (`MInput`, `MInputPassword`); form-level errors via token `role="alert"` (not Toast) |
20
+ | Login / register | Authenticate with trust | Golden: MCP `get_golden_page` `login-page` — split brand + `MForm` (`MInput`, `MInputPassword`); form-level errors via token `role="alert"` (not Toast) |
21
21
  | Invite / accept | Join org | Same shell; show org name clearly |
22
22
  | Forgot / reset | Recover access | Short form + success state with next step |
23
23
  | Profile / account | Edit self | Settings-like sections; avatar via `MAvatar` |
@@ -28,7 +28,7 @@ Keep credential forms quiet: one primary CTA, clear labels, no decorative noise
28
28
 
29
29
  | Surface | Job | Recipe |
30
30
  | --- | --- | --- |
31
- | Empty state | Invite first action | Golden: `docs/golden-pages/empty-state.vue` — `MEmpty` + primary/secondary `MButton` in `#extra` |
31
+ | Empty state | Invite first action | Golden: MCP `get_golden_page` `empty-state` — `MEmpty` + primary/secondary `MButton` in `#extra` |
32
32
  | Onboarding | Teach the product path | `MStepper` or paced cards; one decision per step; finish → Ops home |
33
33
  | Wizard | Multi-step create | `MStepper` + `MForm` per step + sticky actions (`上一步` / `下一步` / `提交`) |
34
34
  | Success / result | Confirm completion | `MResult` (`status="success"` / `error` …) + next actions (`查看详情` / `返回列表`) |
@@ -51,7 +51,7 @@ Use when the brief is landing, pricing, launch, or docs marketing — **not** fo
51
51
 
52
52
  | Surface | Job | Recipe |
53
53
  | --- | --- | --- |
54
- | Landing | Convert / explain product | Golden: `docs/golden-pages/landing-page.vue` — one-job hero; CTAs → `MButton`; chips → `MTag`; FAQ → `MAccordion` |
54
+ | Landing | Convert / explain product | Golden: MCP `get_golden_page` `landing-page` — one-job hero; CTAs → `MButton`; chips → `MTag`; FAQ → `MAccordion` |
55
55
  | Pricing | Choose a plan | Clear plan cards (`MCard`) + primary CTA; highlight recommended plan without clutter |
56
56
  | Feature showcase | Prove capability | Alternating media/copy; live `M*` demo only if lightweight |
57
57
  | Docs marketing chrome | Frame documentation | Header + nav using `M*` where suitable; content area stays readable |
@@ -23,7 +23,7 @@ import { MButton, MInput } from 'morya-ui'
23
23
  - 单行操作结果 → `message.success/info/warn/error('…')`
24
24
  - 有标题 + 详情 / 异步通知 → `toast.*({ summary, detail })`
25
25
  - 表单区常驻错误 → `<MMessage>` 或字段 `errorMessage`
26
- - 详见 `docs/feedback-message-vs-toast.md`
26
+ - 详见 skill `references/feedback.md`
27
27
 
28
28
  ## Props 约定
29
29
 
@@ -38,4 +38,4 @@ import { MButton, MInput } from 'morya-ui'
38
38
  - 用 `MDropdown` 代替 Select 做枚举选择。
39
39
  - 手写 table/modal 替代 `MTable` / `MDialog`。
40
40
 
41
- 完整清单:`docs/components.md`
41
+ 完整清单:MCP,或 skill `references/component-index.md`
@@ -1,17 +1,17 @@
1
1
  ---
2
- description: Morya UI 设计系统第一信源。生成或修改 UI 前必读 DESIGN.md 与 design-tokens。
2
+ description: Morya UI 设计系统第一信源。生成或修改 UI 前必读 DESIGN.md。
3
3
  alwaysApply: true
4
4
  ---
5
5
 
6
6
  # Morya UI 设计系统
7
7
 
8
- 1. **先读** 项目根目录 `DESIGN.md`,再读 `docs/components.md`。
8
+ 1. **先读** 项目根目录 `DESIGN.md`。组件选型用 MCP,或 skill `references/component-index.md`。
9
9
  2. **只用** `morya-ui` 的 `M*` 组件;全局样式 `morya-ui/styles.css`。
10
10
  3. **颜色/间距/圆角** 使用 `--m-*` CSS 变量,禁止裸 hex/rgb(见 `scripts/check-raw-colors.mjs`)。
11
- 4. **页面结构** 对齐 `docs/golden-pages/`(列表 / 表单 / 仪表盘 / 登录 / 落地 / 空状态),不要发明新布局范式。
11
+ 4. **页面结构** 用 MCP `get_golden_page`(`list-page` / `form-page` / `dashboard-page` / `login-page` / `landing-page` / `empty-state`),不要发明新布局范式。
12
12
  5. **表单选项** 用 `MSelect` / `MTreeSelect`;**动作菜单** 用 `MDropdown`。
13
13
  6. 不确定 API 时查文档站或 MCP,**禁止臆造 prop**。
14
14
  7. 根节点用 `MConfigProvider`;后台布局用 `MLayout` 系列。
15
- 8. **操作反馈默认 `message` API**;仅 `summary + detail` 或异步通知用 `toast`;表单常驻错误用 `<MMessage>`。见 `docs/feedback-message-vs-toast.md`。
15
+ 8. **操作反馈默认 `message` API**;仅 `summary + detail` 或异步通知用 `toast`;表单常驻错误用 `<MMessage>`。见 skill `references/feedback.md`。
16
16
 
17
- Token 参考:`design-tokens/tokens.json`
17
+ Token 参考:MCP `get_design_rules`(运行时以 `morya-ui/styles.css` 为准)