@morya-ui/setup 0.2.7 → 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.
- package/README.md +2 -8
- package/package.json +1 -1
- package/src/cli.mjs +9 -28
- package/src/styles.mjs +2 -87
- package/template/.agents/skills/morya-ui-pages/SKILL.md +1 -3
- package/template/.agents/skills/morya-ui-pages/references/component-index.md +7 -1
- package/template/.agents/skills/morya-ui-pages/references/design-system.md +1 -1
- package/template/.agents/skills/morya-ui-pages/references/feedback.md +1 -1
- package/template/.agents/skills/morya-ui-pages/references/page-layouts.md +10 -10
- package/template/.agents/skills/morya-ui-pages/references/surfaces.md +3 -3
- package/template/.cursor/rules/component-usage.mdc +2 -2
- package/template/.cursor/rules/design-system.mdc +5 -5
- package/template/.cursor/rules/page-layout.mdc +7 -9
- package/template/DESIGN.md +14 -14
- package/template/design-tokens/tokens.css +0 -55
- package/template/design-tokens/tokens.json +0 -77
- package/template/docs/components.md +0 -145
- package/template/docs/feedback-message-vs-toast.md +0 -103
- package/template/docs/golden-pages/dashboard-page.vue +0 -103
- package/template/docs/golden-pages/empty-state.vue +0 -66
- package/template/docs/golden-pages/form-page.vue +0 -107
- package/template/docs/golden-pages/landing-page.vue +0 -328
- package/template/docs/golden-pages/list-page.vue +0 -138
- package/template/docs/golden-pages/login-page.vue +0 -191
- package/template/src/examples/DashboardPageExample.vue +0 -103
- package/template/src/examples/EmptyStateExample.vue +0 -66
- package/template/src/examples/FormPageExample.vue +0 -107
- package/template/src/examples/LandingPageExample.vue +0 -328
- package/template/src/examples/ListPageExample.vue +0 -138
- package/template/src/examples/LoginPageExample.vue +0 -191
- package/template/src/styles/morya-app-shell.css +0 -6
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 skill / Cursor rules / design docs from `design-kit`, merges Cursor MCP for [`@morya-ui/mcp`](https://www.npmjs.com/package/@morya-ui/mcp), injects `import 'morya-ui/styles.css'
|
|
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'`.
|
|
13
13
|
|
|
14
14
|
## Usage
|
|
15
15
|
|
|
@@ -40,7 +40,7 @@ npx @morya-ui/setup app
|
|
|
40
40
|
| `--skip-install` | Do not install `morya-ui` |
|
|
41
41
|
| `--skip-template` | Do not copy AI skill / rules / docs / tokens |
|
|
42
42
|
| `--skip-mcp` | Do not write `.cursor/mcp.json` |
|
|
43
|
-
| `--skip-styles` | Do not inject `styles.css`
|
|
43
|
+
| `--skip-styles` | Do not inject `styles.css` |
|
|
44
44
|
| `--skip-scripts` | Do not add `check:colors` to `package.json` |
|
|
45
45
|
| `-h`, `--help` | Show help |
|
|
46
46
|
|
|
@@ -64,12 +64,7 @@ From the package `template/` (synced from repo `design-kit/`):
|
|
|
64
64
|
- `DESIGN.md`
|
|
65
65
|
- `.agents/skills/morya-ui-pages/`
|
|
66
66
|
- `.cursor/rules/`
|
|
67
|
-
- `docs/` (component index, golden pages, feedback guide)
|
|
68
|
-
- `design-tokens/`
|
|
69
67
|
- `scripts/check-raw-colors.mjs`
|
|
70
|
-
- `src/examples/`
|
|
71
|
-
|
|
72
|
-
`morya-app-shell.css` is written by the CLI (not copied from the template tree).
|
|
73
68
|
|
|
74
69
|
### MCP (Cursor)
|
|
75
70
|
|
|
@@ -96,7 +91,6 @@ Looks for `src/main.ts` / `.js` / `.tsx` / `.jsx`, root `main.*`, `src/app.ts` /
|
|
|
96
91
|
|
|
97
92
|
```ts
|
|
98
93
|
import 'morya-ui/styles.css'
|
|
99
|
-
import './styles/morya-app-shell.css'
|
|
100
94
|
```
|
|
101
95
|
|
|
102
96
|
The CLI does **not** call `app.use(MoryaUI)` or edit `App.vue`.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@morya-ui/setup",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.2.
|
|
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
|
@@ -6,7 +6,7 @@ import { readJson } from './fs-utils.mjs'
|
|
|
6
6
|
import { installMoryaUi } from './install.mjs'
|
|
7
7
|
import { mergeMcpConfig } from './mcp.mjs'
|
|
8
8
|
import { ensureCheckColorsScript } from './package-json.mjs'
|
|
9
|
-
import {
|
|
9
|
+
import { ensureStylesImport } from './styles.mjs'
|
|
10
10
|
|
|
11
11
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
12
12
|
const PKG_ROOT = resolve(__dirname, '..')
|
|
@@ -14,15 +14,12 @@ const TEMPLATE_ROOT = join(PKG_ROOT, 'template')
|
|
|
14
14
|
|
|
15
15
|
const MODES = new Set(['app', 'ai', 'full'])
|
|
16
16
|
|
|
17
|
-
/** AI pack paths under template
|
|
17
|
+
/** AI pack paths under template/. */
|
|
18
18
|
const AI_TEMPLATE_INCLUDE = [
|
|
19
19
|
'DESIGN.md',
|
|
20
20
|
'.agents/skills/morya-ui-pages',
|
|
21
21
|
'.cursor/rules',
|
|
22
|
-
'docs',
|
|
23
|
-
'design-tokens',
|
|
24
22
|
'scripts/check-raw-colors.mjs',
|
|
25
|
-
'src/examples',
|
|
26
23
|
]
|
|
27
24
|
|
|
28
25
|
/** Mode → default skips (user --skip-* can only add more skips). */
|
|
@@ -45,16 +42,15 @@ export function printHelp() {
|
|
|
45
42
|
|
|
46
43
|
Commands:
|
|
47
44
|
(default) / full Install morya-ui, AI template, MCP, styles, check:colors
|
|
48
|
-
app Install morya-ui and inject styles
|
|
49
|
-
ai Copy Agent skill / rules / DESIGN
|
|
45
|
+
app Install morya-ui and inject styles.css
|
|
46
|
+
ai Copy Agent skill / rules / DESIGN,
|
|
50
47
|
merge Cursor MCP, add check:colors
|
|
51
48
|
|
|
52
49
|
Default command:
|
|
53
50
|
- install morya-ui
|
|
54
|
-
- copy DESIGN.md, Agent skill, Cursor rules
|
|
51
|
+
- copy DESIGN.md, Agent skill, Cursor rules
|
|
55
52
|
- merge .cursor/mcp.json for @morya-ui/mcp
|
|
56
53
|
- inject import 'morya-ui/styles.css' into the app entry when found
|
|
57
|
-
- write src/styles/morya-app-shell.css and inject its import
|
|
58
54
|
- add check:colors script when missing
|
|
59
55
|
|
|
60
56
|
Options:
|
|
@@ -65,7 +61,7 @@ Options:
|
|
|
65
61
|
--skip-install Skip dependency install
|
|
66
62
|
--skip-template Skip copying AI template files
|
|
67
63
|
--skip-mcp Skip writing .cursor/mcp.json
|
|
68
|
-
--skip-styles Skip injecting styles.css
|
|
64
|
+
--skip-styles Skip injecting styles.css
|
|
69
65
|
--skip-scripts Skip adding check:colors to package.json
|
|
70
66
|
-h, --help Show this help
|
|
71
67
|
`)
|
|
@@ -210,10 +206,6 @@ export async function runSetup(options) {
|
|
|
210
206
|
? { action: 'skipped', reason: 'skip-styles' }
|
|
211
207
|
: ensureStylesImport(cwd, { dryRun })
|
|
212
208
|
|
|
213
|
-
const shell = skipStyles
|
|
214
|
-
? { fileAction: 'skipped', importAction: 'skipped', reason: 'skip-styles' }
|
|
215
|
-
: ensureShellStyles(cwd, { dryRun, force })
|
|
216
|
-
|
|
217
209
|
const scripts = skipScripts
|
|
218
210
|
? { action: 'skipped-flag' }
|
|
219
211
|
: ensureCheckColorsScript(cwd, { force, dryRun })
|
|
@@ -256,17 +248,6 @@ export async function runSetup(options) {
|
|
|
256
248
|
console.log(" import 'morya-ui/styles.css'")
|
|
257
249
|
}
|
|
258
250
|
|
|
259
|
-
if (shell.reason === 'skip-styles') {
|
|
260
|
-
console.log('Shell CSS: skipped (--skip-styles or ai mode)')
|
|
261
|
-
} else {
|
|
262
|
-
console.log(
|
|
263
|
-
`Shell CSS: file ${shell.fileAction}`
|
|
264
|
-
+ (shell.path ? ` (${rel(cwd, shell.path)})` : '')
|
|
265
|
-
+ `, import ${shell.importAction}`
|
|
266
|
-
+ (shell.entry ? ` (${rel(cwd, shell.entry)})` : ''),
|
|
267
|
-
)
|
|
268
|
-
}
|
|
269
|
-
|
|
270
251
|
if (scripts.action === 'skipped-flag') {
|
|
271
252
|
console.log('Scripts: skipped (--skip-scripts or app mode)')
|
|
272
253
|
} else {
|
|
@@ -276,18 +257,18 @@ export async function runSetup(options) {
|
|
|
276
257
|
console.log('')
|
|
277
258
|
console.log('Next:')
|
|
278
259
|
if (mode === 'app') {
|
|
279
|
-
console.log(' 1. Ensure styles.css
|
|
260
|
+
console.log(' 1. Ensure the styles.css import is in your app entry.')
|
|
280
261
|
console.log(' 2. Optional AI pack: npx @morya-ui/setup ai')
|
|
281
262
|
} else if (mode === 'ai') {
|
|
282
263
|
console.log(' 1. Restart Cursor (or reload MCP) so morya-ui MCP tools appear.')
|
|
283
264
|
console.log(' 2. Have the agent read DESIGN.md before generating pages.')
|
|
284
265
|
console.log(' 3. Optional: pnpm check:colors')
|
|
285
266
|
} else {
|
|
286
|
-
console.log(' 1. Ensure styles.css
|
|
267
|
+
console.log(' 1. Ensure the styles.css import is in your app entry.')
|
|
287
268
|
console.log(' 2. Restart Cursor (or reload MCP) so morya-ui MCP tools appear.')
|
|
288
269
|
console.log(' 3. Have the agent read DESIGN.md before generating pages.')
|
|
289
270
|
console.log(' 4. Optional: pnpm check:colors')
|
|
290
271
|
}
|
|
291
272
|
|
|
292
|
-
return { mode, install, template, mcp, styles,
|
|
273
|
+
return { mode, install, template, mcp, styles, scripts }
|
|
293
274
|
}
|
package/src/styles.mjs
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { existsSync,
|
|
2
|
-
import {
|
|
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.
|
|
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
|
-
| `
|
|
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
|
|
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 `
|
|
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**.
|
|
4
|
-
|
|
5
|
-
| Type |
|
|
6
|
-
| --- | --- |
|
|
7
|
-
| List | `
|
|
8
|
-
| Form | `
|
|
9
|
-
| Dashboard | `
|
|
10
|
-
| Login | `
|
|
11
|
-
| Landing | `
|
|
12
|
-
| Empty | `
|
|
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: `
|
|
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: `
|
|
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: `
|
|
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
|
-
- 详见 `
|
|
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
|
-
|
|
41
|
+
完整清单:MCP,或 skill `references/component-index.md`
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Morya UI 设计系统第一信源。生成或修改 UI 前必读 DESIGN.md
|
|
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
|
|
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. **页面结构**
|
|
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>`。见 `
|
|
15
|
+
8. **操作反馈默认 `message` API**;仅 `summary + detail` 或异步通知用 `toast`;表单常驻错误用 `<MMessage>`。见 skill `references/feedback.md`。
|
|
16
16
|
|
|
17
|
-
Token
|
|
17
|
+
Token 参考:MCP `get_design_rules`(运行时以 `morya-ui/styles.css` 为准)
|
|
@@ -7,14 +7,14 @@ alwaysApply: false
|
|
|
7
7
|
|
|
8
8
|
生成完整页面时,先确定类型并 **复制黄金样例结构**:
|
|
9
9
|
|
|
10
|
-
| 类型 |
|
|
10
|
+
| 类型 | MCP `get_golden_page` |
|
|
11
11
|
| --- | --- |
|
|
12
|
-
| 列表页 | `
|
|
13
|
-
| 表单页 | `
|
|
14
|
-
| 仪表盘 | `
|
|
15
|
-
| 登录页 | `
|
|
16
|
-
| 营销落地 | `
|
|
17
|
-
| 空状态 | `
|
|
12
|
+
| 列表页 | `list-page` |
|
|
13
|
+
| 表单页 | `form-page`(仅长表单 / 独立配置页) |
|
|
14
|
+
| 仪表盘 | `dashboard-page` |
|
|
15
|
+
| 登录页 | `login-page` |
|
|
16
|
+
| 营销落地 | `landing-page` |
|
|
17
|
+
| 空状态 | `empty-state` |
|
|
18
18
|
|
|
19
19
|
## 列表内新建 / 编辑(默认)
|
|
20
20
|
|
|
@@ -69,5 +69,3 @@ alwaysApply: false
|
|
|
69
69
|
- 整页:`recommend_page` → `get_golden_page` → `get_design_rules`
|
|
70
70
|
- 局部:`get_page_snippet`(如 `filters` / `toolbar` / `form-actions` / `scrollable-panel`)
|
|
71
71
|
- 可选:`validate_page`(参考建议,不阻断)
|
|
72
|
-
|
|
73
|
-
引用可运行示例:`src/examples/*PageExample.vue`
|
package/template/DESIGN.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Morya UI 设计系统(AI 第一信源)
|
|
2
2
|
|
|
3
|
-
> 基于 `morya-ui` v0.2.6
|
|
3
|
+
> 基于 `morya-ui` v0.2.6。生成或审查业务页面时,**必须先遵守本文**。样例用 MCP `get_golden_page`,组件 API 用 MCP,反馈选型见 `morya-ui-pages` skill 的 `references/feedback.md`。
|
|
4
4
|
|
|
5
5
|
## 1. 设计原则
|
|
6
6
|
|
|
@@ -49,14 +49,14 @@ import 'morya-ui/styles.css'
|
|
|
49
49
|
|
|
50
50
|
## 3. 页面类型与黄金样例
|
|
51
51
|
|
|
52
|
-
| 类型 |
|
|
52
|
+
| 类型 | MCP `get_golden_page` | 必备区块 |
|
|
53
53
|
| --- | --- | --- |
|
|
54
|
-
| 列表页 | `
|
|
55
|
-
| 表单页 | `
|
|
56
|
-
| 仪表盘 | `
|
|
57
|
-
| 登录页 | `
|
|
58
|
-
| 营销落地 | `
|
|
59
|
-
| 空状态 | `
|
|
54
|
+
| 列表页 | `list-page` | 面包屑、筛选区、工具栏、表格、分页 |
|
|
55
|
+
| 表单页 | `form-page` | 面包屑、分组表单、`MForm` / `MFormItem`、提交/取消 |
|
|
56
|
+
| 仪表盘 | `dashboard-page` | 统计卡片栅格、图表区占位、快捷入口 / 最近列表 |
|
|
57
|
+
| 登录页 | `login-page` | 品牌区 + `MForm` / `MInputPassword`;表单级错误用 token 告警条 |
|
|
58
|
+
| 营销落地 | `landing-page` | 单任务首屏、分节、`MButton` / `MTag` / `MAccordion` |
|
|
59
|
+
| 空状态 | `empty-state` | `MEmpty` + 说明 + 主 CTA;可嵌列表 `#empty` |
|
|
60
60
|
|
|
61
61
|
生成 **Ops** 页面时:结构对齐对应黄金样例,用 `MPage*` 拼装,尽量少写 scoped CSS。
|
|
62
62
|
生成 **Account / Express / Flow** 页面时:对齐上表样例;允许有节制的 scoped 布局,但颜色/间距仍用 `--m-*`。
|
|
@@ -65,7 +65,7 @@ import 'morya-ui/styles.css'
|
|
|
65
65
|
|
|
66
66
|
- 使用 `MForm` + `MFormItem`,`name` 与校验规则对应。
|
|
67
67
|
- **从列表新建/编辑(字段约 ≤8、单段表单)默认用 `MDialog` + `MForm`,不要为每个实体再开独立路由表单页。**
|
|
68
|
-
-
|
|
68
|
+
- 多分组、长流程、向导式录入再用独立表单页(MCP `get_golden_page` `form-page`)或 `MDrawer`。
|
|
69
69
|
- 字段组件自带 `label` / `invalid` / `helpText` 时优先用组件 prop(如 `MInput`、`MSelect`),复杂表单再用 `MFormItem` 包一层。
|
|
70
70
|
- 尺寸:默认 medium;密集后台可 `size="small"` 或 ConfigProvider `globalDensity`。
|
|
71
71
|
- 宽度:筛选项 `fluid` 慎用;独立表单页主栏 `max-width: 40rem` 左右。
|
|
@@ -88,11 +88,11 @@ import 'morya-ui/styles.css'
|
|
|
88
88
|
| 表单区常驻错误 | token 告警条 / 字段 `errorMessage` |
|
|
89
89
|
| 字段说明 | `MTooltip` |
|
|
90
90
|
|
|
91
|
-
**选型细则见
|
|
91
|
+
**选型细则见 `morya-ui-pages` skill 的 `references/feedback.md`。AI 生成代码时:无 `detail` 的操作回执一律用 `message`,不要默认 Toast。**
|
|
92
92
|
|
|
93
93
|
## 7. 设计令牌(摘要)
|
|
94
94
|
|
|
95
|
-
完整定义见 `
|
|
95
|
+
完整定义见 MCP `get_design_rules`。运行时以 `morya-ui/styles.css` 为准。
|
|
96
96
|
|
|
97
97
|
| 用途 | 变量 |
|
|
98
98
|
| --- | --- |
|
|
@@ -117,11 +117,11 @@ import 'morya-ui/styles.css'
|
|
|
117
117
|
## 9. AI 工作流
|
|
118
118
|
|
|
119
119
|
1. 读本文 → 确定页面类型(列表 / 表单 / 仪表盘)。
|
|
120
|
-
2.
|
|
121
|
-
3.
|
|
120
|
+
2. 用 MCP `get_golden_page` 读取对应样例。
|
|
121
|
+
3. 用 MCP `search` / `get_component` / `recommend_component` 选型。
|
|
122
122
|
4. 不确定 API 时查文档站或 MCP,**不要臆造 prop 名**。
|
|
123
123
|
5. 完成后运行 `pnpm check:colors`(若已配置)。
|
|
124
|
-
6. 操作反馈见 `
|
|
124
|
+
6. 操作反馈见 skill `references/feedback.md`:**默认 `message`,有 detail 才用 `toast`**。
|
|
125
125
|
|
|
126
126
|
## 10. 相关资源
|
|
127
127
|
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Morya UI design tokens (compiled view for AI / static tooling).
|
|
3
|
-
* Runtime source of truth: morya-ui/styles.css
|
|
4
|
-
* Do not hand-edit hex values in business code — use --m-* variables.
|
|
5
|
-
*/
|
|
6
|
-
:root {
|
|
7
|
-
--m-color-primary: #2563eb;
|
|
8
|
-
--m-color-primary-hover: #1d4ed8;
|
|
9
|
-
--m-color-surface: #ffffff;
|
|
10
|
-
--m-color-text: #0f172a;
|
|
11
|
-
--m-color-text-muted: #64748b;
|
|
12
|
-
--m-color-border: #e2e8f0;
|
|
13
|
-
--m-color-focus-ring: #2563eb;
|
|
14
|
-
--m-color-success: #159570;
|
|
15
|
-
--m-color-info: #2563eb;
|
|
16
|
-
--m-color-warning: #d97706;
|
|
17
|
-
--m-color-help: #9333ea;
|
|
18
|
-
--m-color-danger: #dc2626;
|
|
19
|
-
--m-color-contrast: #0f172a;
|
|
20
|
-
--m-color-contrast-fg: #ffffff;
|
|
21
|
-
--m-overlay-scrim: rgb(15 23 42 / 0.55);
|
|
22
|
-
|
|
23
|
-
--m-control-height-small: 28px;
|
|
24
|
-
--m-control-height-medium: 34px;
|
|
25
|
-
--m-control-height-large: 40px;
|
|
26
|
-
--m-radius-control: 3px;
|
|
27
|
-
--m-space-1: 0.25rem;
|
|
28
|
-
--m-space-2: 0.5rem;
|
|
29
|
-
--m-space-3: 0.75rem;
|
|
30
|
-
--m-space-4: 1rem;
|
|
31
|
-
--m-space-6: 1.5rem;
|
|
32
|
-
--m-space-8: 2rem;
|
|
33
|
-
--m-radius-sm: 0.25rem;
|
|
34
|
-
--m-radius-md: 0.5rem;
|
|
35
|
-
--m-radius-lg: 0.75rem;
|
|
36
|
-
--m-shadow-sm: 0 1px 2px rgb(15 23 42 / 0.25);
|
|
37
|
-
--m-shadow-md: 0 0.75rem 2rem rgb(15 23 42 / 0.16);
|
|
38
|
-
--m-shadow-lg: 0 1rem 3rem rgb(15 23 42 / 0.25);
|
|
39
|
-
--m-font-sans: Inter, ui-sans-serif, system-ui, sans-serif;
|
|
40
|
-
--m-motion-fast: 150ms;
|
|
41
|
-
--m-motion-normal: 250ms;
|
|
42
|
-
--m-motion-ease: cubic-bezier(0.2, 0, 0, 1);
|
|
43
|
-
--m-z-base: 1000;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
[data-theme="dark"] {
|
|
47
|
-
--m-color-primary: #60a5fa;
|
|
48
|
-
--m-color-primary-hover: #93c5fd;
|
|
49
|
-
--m-color-surface: #0f172a;
|
|
50
|
-
--m-color-text: #f8fafc;
|
|
51
|
-
--m-color-text-muted: #94a3b8;
|
|
52
|
-
--m-color-border: #334155;
|
|
53
|
-
--m-color-danger: #fca5a5;
|
|
54
|
-
--m-overlay-scrim: rgb(2 6 23 / 0.72);
|
|
55
|
-
}
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://design-tokens.github.io/community-group/format/",
|
|
3
|
-
"meta": {
|
|
4
|
-
"name": "morya-ui",
|
|
5
|
-
"version": "0.2.6",
|
|
6
|
-
"source": "morya-ui/src/theme/styles.css",
|
|
7
|
-
"prefix": "m"
|
|
8
|
-
},
|
|
9
|
-
"color": {
|
|
10
|
-
"primary": { "value": "#2563eb", "dark": "#60a5fa" },
|
|
11
|
-
"primary-hover": { "value": "#1d4ed8", "dark": "#93c5fd" },
|
|
12
|
-
"surface": { "value": "#ffffff", "dark": "#0f172a" },
|
|
13
|
-
"text": { "value": "#0f172a", "dark": "#f8fafc" },
|
|
14
|
-
"text-muted": { "value": "#64748b", "dark": "#94a3b8" },
|
|
15
|
-
"border": { "value": "#e2e8f0", "dark": "#334155" },
|
|
16
|
-
"focus-ring": { "value": "#2563eb", "dark": "#93c5fd" },
|
|
17
|
-
"success": { "value": "#159570", "dark": "#5eead4" },
|
|
18
|
-
"info": { "value": "#2563eb", "dark": "#93c5fd" },
|
|
19
|
-
"warning": { "value": "#d97706", "dark": "#fbbf24" },
|
|
20
|
-
"help": { "value": "#9333ea", "dark": "#c084fc" },
|
|
21
|
-
"danger": { "value": "#dc2626", "dark": "#fca5a5" },
|
|
22
|
-
"contrast": { "value": "#0f172a", "dark": "#f8fafc" },
|
|
23
|
-
"contrast-fg": { "value": "#ffffff", "dark": "#0f172a" },
|
|
24
|
-
"overlay-scrim": { "value": "rgb(15 23 42 / 0.55)", "dark": "rgb(2 6 23 / 0.72)" }
|
|
25
|
-
},
|
|
26
|
-
"control": {
|
|
27
|
-
"height": { "small": "28px", "medium": "34px", "large": "40px" },
|
|
28
|
-
"font": { "small": "14px", "medium": "14px", "large": "15px" },
|
|
29
|
-
"padding-x": { "small": "10px", "medium": "12px", "large": "14px" },
|
|
30
|
-
"affix-size": "2rem"
|
|
31
|
-
},
|
|
32
|
-
"space": {
|
|
33
|
-
"1": "0.25rem",
|
|
34
|
-
"2": "0.5rem",
|
|
35
|
-
"3": "0.75rem",
|
|
36
|
-
"4": "1rem",
|
|
37
|
-
"6": "1.5rem",
|
|
38
|
-
"8": "2rem"
|
|
39
|
-
},
|
|
40
|
-
"radius": {
|
|
41
|
-
"control": "3px",
|
|
42
|
-
"sm": "0.25rem",
|
|
43
|
-
"md": "0.5rem",
|
|
44
|
-
"lg": "0.75rem",
|
|
45
|
-
"full": "9999px"
|
|
46
|
-
},
|
|
47
|
-
"shadow": {
|
|
48
|
-
"sm": "0 1px 2px rgb(15 23 42 / 0.25)",
|
|
49
|
-
"md": "0 0.75rem 2rem rgb(15 23 42 / 0.16)",
|
|
50
|
-
"lg": "0 1rem 3rem rgb(15 23 42 / 0.25)"
|
|
51
|
-
},
|
|
52
|
-
"font": {
|
|
53
|
-
"sans": "Inter, ui-sans-serif, system-ui, sans-serif",
|
|
54
|
-
"size": { "xs": "0.75rem", "sm": "0.8125rem", "md": "0.875rem", "lg": "1.125rem" }
|
|
55
|
-
},
|
|
56
|
-
"motion": {
|
|
57
|
-
"fast": "150ms",
|
|
58
|
-
"normal": "250ms",
|
|
59
|
-
"ease": "cubic-bezier(0.2, 0, 0, 1)"
|
|
60
|
-
},
|
|
61
|
-
"zIndex": {
|
|
62
|
-
"base": 1000,
|
|
63
|
-
"dropdown": "calc(var(--m-z-base) + 50)",
|
|
64
|
-
"toast": "calc(var(--m-z-base) + 100)"
|
|
65
|
-
},
|
|
66
|
-
"cssVarMap": {
|
|
67
|
-
"color.primary": "--m-color-primary",
|
|
68
|
-
"color.surface": "--m-color-surface",
|
|
69
|
-
"color.text": "--m-color-text",
|
|
70
|
-
"color.textMuted": "--m-color-text-muted",
|
|
71
|
-
"color.border": "--m-color-border",
|
|
72
|
-
"color.danger": "--m-color-danger",
|
|
73
|
-
"space.4": "--m-space-4",
|
|
74
|
-
"radius.md": "--m-radius-md",
|
|
75
|
-
"shadow.md": "--m-shadow-md"
|
|
76
|
-
}
|
|
77
|
-
}
|