@duro-app/cli 5.15.0 → 5.17.0
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 +32 -11
- package/dist/bin.js +13 -5
- package/dist/bin.js.map +1 -1
- package/dist/commands/doctor.d.ts +7 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +25 -12
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/hook.d.ts.map +1 -1
- package/dist/commands/hook.js +11 -2
- package/dist/commands/hook.js.map +1 -1
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +23 -2
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/lookup.d.ts.map +1 -1
- package/dist/commands/lookup.js +15 -1
- package/dist/commands/lookup.js.map +1 -1
- package/dist/commands/mcp.d.ts +57 -0
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +87 -37
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/mockup.d.ts +33 -5
- package/dist/commands/mockup.d.ts.map +1 -1
- package/dist/commands/mockup.js +167 -13
- package/dist/commands/mockup.js.map +1 -1
- package/dist/commands/skill.d.ts +6 -0
- package/dist/commands/skill.d.ts.map +1 -1
- package/dist/commands/skill.js +168 -24
- package/dist/commands/skill.js.map +1 -1
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +7 -0
- package/dist/format.js.map +1 -1
- package/dist/hook-script.d.ts +2 -2
- package/dist/hook-script.d.ts.map +1 -1
- package/dist/hook-script.js +1 -1
- package/dist/manifest.d.ts +2 -0
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +28 -10
- package/dist/manifest.js.map +1 -1
- package/dist/registry-types.d.ts +5 -0
- package/dist/registry-types.d.ts.map +1 -1
- package/dist/registry.d.ts +20 -0
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +38 -0
- package/dist/registry.js.map +1 -1
- package/dist/skill-template.d.ts +1 -1
- package/dist/skill-template.d.ts.map +1 -1
- package/dist/skill-template.js +20 -9
- package/dist/skill-template.js.map +1 -1
- package/package.json +6 -5
- package/registry.json +35 -0
- package/{LICENSE → skills/colors/LICENSE} +1 -1
- package/skills/colors/NOTICE.md +36 -0
- package/skills/colors/SKILL.md +99 -0
- package/skills/colors/color-formats.md +90 -0
- package/skills/colors/color-usage.md +109 -0
- package/skills/colors/contrast.md +70 -0
- package/skills/colors/palette-generation.md +108 -0
- package/skills/colors/palette-structure.md +72 -0
- package/skills/colors/token-naming.md +99 -0
- package/skills/typography/LICENSE +21 -0
- package/skills/typography/NOTICE.md +36 -0
- package/skills/typography/SKILL.md +169 -0
- package/skills/typography/choosing-fonts.md +53 -0
- package/skills/typography/css-cheat-sheet.md +67 -0
- package/skills/typography/details-and-accessibility.md +84 -0
- package/skills/typography/spacing-and-sizing.md +87 -0
- package/skills/typography/variable-fonts-and-opentype.md +100 -0
- package/skills/typography/wrapping-and-punctuation.md +23 -0
- package/skills/ui/LICENSE +21 -0
- package/skills/ui/NOTICE.md +36 -0
- package/skills/ui/SKILL.md +139 -0
- package/skills/ui/animations.md +170 -0
- package/skills/ui/enter-exit.md +157 -0
- package/skills/ui/icon-transitions.md +72 -0
- package/skills/ui/icons.md +105 -0
- package/skills/ui/performance.md +63 -0
- package/skills/ui/surfaces.md +166 -0
package/dist/commands/mcp.d.ts
CHANGED
|
@@ -21,6 +21,8 @@ export declare function toolDefinitions(registry: Registry): ({
|
|
|
21
21
|
kind?: undefined;
|
|
22
22
|
html?: undefined;
|
|
23
23
|
file?: undefined;
|
|
24
|
+
artboards?: undefined;
|
|
25
|
+
title?: undefined;
|
|
24
26
|
};
|
|
25
27
|
required: string[];
|
|
26
28
|
};
|
|
@@ -39,6 +41,8 @@ export declare function toolDefinitions(registry: Registry): ({
|
|
|
39
41
|
sourceOnly?: undefined;
|
|
40
42
|
html?: undefined;
|
|
41
43
|
file?: undefined;
|
|
44
|
+
artboards?: undefined;
|
|
45
|
+
title?: undefined;
|
|
42
46
|
};
|
|
43
47
|
required?: undefined;
|
|
44
48
|
};
|
|
@@ -54,6 +58,8 @@ export declare function toolDefinitions(registry: Registry): ({
|
|
|
54
58
|
kind?: undefined;
|
|
55
59
|
html?: undefined;
|
|
56
60
|
file?: undefined;
|
|
61
|
+
artboards?: undefined;
|
|
62
|
+
title?: undefined;
|
|
57
63
|
};
|
|
58
64
|
required?: undefined;
|
|
59
65
|
};
|
|
@@ -75,6 +81,45 @@ export declare function toolDefinitions(registry: Registry): ({
|
|
|
75
81
|
part?: undefined;
|
|
76
82
|
sourceOnly?: undefined;
|
|
77
83
|
kind?: undefined;
|
|
84
|
+
artboards?: undefined;
|
|
85
|
+
title?: undefined;
|
|
86
|
+
};
|
|
87
|
+
required: string[];
|
|
88
|
+
};
|
|
89
|
+
} | {
|
|
90
|
+
name: string;
|
|
91
|
+
description: string;
|
|
92
|
+
inputSchema: {
|
|
93
|
+
type: string;
|
|
94
|
+
properties: {
|
|
95
|
+
artboards: {
|
|
96
|
+
type: string;
|
|
97
|
+
description: string;
|
|
98
|
+
items: {
|
|
99
|
+
type: string;
|
|
100
|
+
properties: {
|
|
101
|
+
file: {
|
|
102
|
+
type: string;
|
|
103
|
+
description: string;
|
|
104
|
+
};
|
|
105
|
+
html: {
|
|
106
|
+
type: string;
|
|
107
|
+
description: string;
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
required: string[];
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
title: {
|
|
114
|
+
type: string;
|
|
115
|
+
description: string;
|
|
116
|
+
};
|
|
117
|
+
name?: undefined;
|
|
118
|
+
part?: undefined;
|
|
119
|
+
sourceOnly?: undefined;
|
|
120
|
+
kind?: undefined;
|
|
121
|
+
html?: undefined;
|
|
122
|
+
file?: undefined;
|
|
78
123
|
};
|
|
79
124
|
required: string[];
|
|
80
125
|
};
|
|
@@ -98,5 +143,17 @@ export declare function callTool(registry: Registry, name: string, args: Record<
|
|
|
98
143
|
data: unknown;
|
|
99
144
|
isError: boolean;
|
|
100
145
|
};
|
|
146
|
+
export declare function listResources(registry: Registry): {
|
|
147
|
+
uri: string;
|
|
148
|
+
name: string;
|
|
149
|
+
mimeType: string;
|
|
150
|
+
}[];
|
|
151
|
+
export declare function readResource(registry: Registry, uri: string): {
|
|
152
|
+
contents: {
|
|
153
|
+
uri: string;
|
|
154
|
+
mimeType: string;
|
|
155
|
+
text: string;
|
|
156
|
+
}[];
|
|
157
|
+
};
|
|
101
158
|
export declare function runMcp(registry: Registry): Promise<void>;
|
|
102
159
|
//# sourceMappingURL=mcp.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAA;AAclD,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA4EjD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;uBAInB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;EAG/F;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;EAwCvF;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAC,EAAE,CAkBjG;AAED,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,MAAM,GACV;IAAC,QAAQ,EAAE;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC,EAAE,CAAA;CAAC,CAkB7D;AAED,wBAAsB,MAAM,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAmE9D"}
|
package/dist/commands/mcp.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { buildManifest } from '../manifest.js';
|
|
2
|
+
import { guideNames, lookupGuide } from '../registry.js';
|
|
2
3
|
import { runLookup } from './lookup.js';
|
|
3
4
|
import { runList } from './list.js';
|
|
4
5
|
import { cliVersion } from './manifest.js';
|
|
5
6
|
import { renderComponent, renderRecipe } from '../format.js';
|
|
6
|
-
import { checkArtboard } from './mockup.js';
|
|
7
|
+
import { buildCanvas, checkArtboard } from './mockup.js';
|
|
7
8
|
const INSTALL_HINT = `duro mcp needs @modelcontextprotocol/sdk (an optional peer).
|
|
8
9
|
npm i -D @modelcontextprotocol/sdk
|
|
9
10
|
or run it without installing:
|
|
@@ -13,13 +14,13 @@ export function toolDefinitions(registry) {
|
|
|
13
14
|
return [
|
|
14
15
|
{
|
|
15
16
|
name: 'duro_ds_lookup',
|
|
16
|
-
description: 'Docs for anything in the Duro design system by name: a component (props, usage, example), a recipe (runnable source), a token group, "icons", or "
|
|
17
|
+
description: 'Docs for anything in the Duro design system by name: a component (props, usage, example), a recipe (runnable source), a token group, "icons", "rules", or an interface guide ("guide:colors", "guide:typography", "guide:ui"; "guide:<skill>/<file>" for one of its reference files). Free text falls back to a ranked search over usage metadata — pass what you need, e.g. "tags that wrap".',
|
|
17
18
|
inputSchema: {
|
|
18
19
|
type: 'object',
|
|
19
20
|
properties: {
|
|
20
21
|
name: {
|
|
21
22
|
type: 'string',
|
|
22
|
-
description: 'Component/recipe/token-group name, "icons", "rules", or free text to search',
|
|
23
|
+
description: 'Component/recipe/token-group name, "icons", "rules", "guide:<skill>[/<file>]", or free text to search',
|
|
23
24
|
},
|
|
24
25
|
part: {
|
|
25
26
|
type: 'string',
|
|
@@ -32,11 +33,11 @@ export function toolDefinitions(registry) {
|
|
|
32
33
|
},
|
|
33
34
|
{
|
|
34
35
|
name: 'duro_ds_list',
|
|
35
|
-
description: `One-line index of everything documented (${Object.keys(registry.components).length} components, ${Object.keys(registry.recipes).length} recipes, token groups).`,
|
|
36
|
+
description: `One-line index of everything documented (${Object.keys(registry.components).length} components, ${Object.keys(registry.recipes).length} recipes, token groups; kind "guides" lists the interface guides).`,
|
|
36
37
|
inputSchema: {
|
|
37
38
|
type: 'object',
|
|
38
39
|
properties: {
|
|
39
|
-
kind: { type: 'string', enum: ['components', 'recipes', 'tokens'] },
|
|
40
|
+
kind: { type: 'string', enum: ['components', 'recipes', 'tokens', 'guides'] },
|
|
40
41
|
},
|
|
41
42
|
},
|
|
42
43
|
},
|
|
@@ -57,6 +58,29 @@ export function toolDefinitions(registry) {
|
|
|
57
58
|
required: ['html'],
|
|
58
59
|
},
|
|
59
60
|
},
|
|
61
|
+
{
|
|
62
|
+
name: 'duro_ds_mockup_canvas',
|
|
63
|
+
description: 'One self-contained HTML review page for a set of mockup artboards: each direction (Tree.dc.html and Tree-Phone.dc.html are direction Tree) under a letter, every artboard inlined and scaled to its frame. Publish the page for the person to pick a direction. Nothing is built while an artboard fails duro_ds_mockup_check: the findings come back instead.',
|
|
64
|
+
inputSchema: {
|
|
65
|
+
type: 'object',
|
|
66
|
+
properties: {
|
|
67
|
+
artboards: {
|
|
68
|
+
type: 'array',
|
|
69
|
+
description: 'The artboards, each with its file name and full HTML',
|
|
70
|
+
items: {
|
|
71
|
+
type: 'object',
|
|
72
|
+
properties: {
|
|
73
|
+
file: { type: 'string', description: 'e.g. Tree-Phone.dc.html' },
|
|
74
|
+
html: { type: 'string', description: 'The full artboard HTML' },
|
|
75
|
+
},
|
|
76
|
+
required: ['file', 'html'],
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
title: { type: 'string', description: 'The page title' },
|
|
80
|
+
},
|
|
81
|
+
required: ['artboards'],
|
|
82
|
+
},
|
|
83
|
+
},
|
|
60
84
|
];
|
|
61
85
|
}
|
|
62
86
|
/**
|
|
@@ -96,10 +120,66 @@ export function callTool(registry, name, args) {
|
|
|
96
120
|
: findings.map((f) => `${f.file}:${f.line} ${f.rule}: ${f.message}`).join('\n');
|
|
97
121
|
return { text, data: { ok: findings.length === 0, findings }, isError: false };
|
|
98
122
|
}
|
|
123
|
+
case 'duro_ds_mockup_canvas': {
|
|
124
|
+
const artboards = (Array.isArray(args.artboards) ? args.artboards : [])
|
|
125
|
+
.filter((a) => typeof a === 'object' && a !== null)
|
|
126
|
+
.map((a) => ({ file: String(a.file ?? 'artboard.dc.html'), html: String(a.html ?? '') }));
|
|
127
|
+
if (artboards.length === 0) {
|
|
128
|
+
return { text: 'give at least one artboard', data: { ok: false }, isError: true };
|
|
129
|
+
}
|
|
130
|
+
const title = typeof args.title === 'string' ? args.title : undefined;
|
|
131
|
+
const { html, findings } = buildCanvas(registry, artboards, { title });
|
|
132
|
+
const text = html ?? findings.map((f) => `${f.file}:${f.line} ${f.rule}: ${f.message}`).join('\n');
|
|
133
|
+
return { text, data: { ok: html !== null, html, findings }, isError: false };
|
|
134
|
+
}
|
|
99
135
|
default:
|
|
100
136
|
throw new Error(`unknown tool ${name}`);
|
|
101
137
|
}
|
|
102
138
|
}
|
|
139
|
+
export function listResources(registry) {
|
|
140
|
+
return [
|
|
141
|
+
...Object.keys(registry.components).map((name) => ({
|
|
142
|
+
uri: `duro://component/${encodeURIComponent(name)}`,
|
|
143
|
+
name: `${name} docs`,
|
|
144
|
+
mimeType: 'text/plain',
|
|
145
|
+
})),
|
|
146
|
+
...Object.keys(registry.recipes).map((name) => ({
|
|
147
|
+
uri: `duro://recipe/${name}`,
|
|
148
|
+
name: `${name} recipe`,
|
|
149
|
+
mimeType: 'text/plain',
|
|
150
|
+
})),
|
|
151
|
+
...guideNames(registry).map((name) => ({
|
|
152
|
+
uri: `duro://guide/${name.slice('guide:'.length)}`,
|
|
153
|
+
name: `${name} guide`,
|
|
154
|
+
mimeType: 'text/markdown',
|
|
155
|
+
})),
|
|
156
|
+
];
|
|
157
|
+
}
|
|
158
|
+
export function readResource(registry, uri) {
|
|
159
|
+
const componentMatch = /^duro:\/\/component\/(.+)$/.exec(uri);
|
|
160
|
+
const recipeMatch = /^duro:\/\/recipe\/(.+)$/.exec(uri);
|
|
161
|
+
const guideMatch = /^duro:\/\/guide\/(.+)$/.exec(uri);
|
|
162
|
+
let text = null;
|
|
163
|
+
if (guideMatch) {
|
|
164
|
+
const guide = lookupGuide(registry, `guide:${guideMatch[1]}`);
|
|
165
|
+
if (guide.ok)
|
|
166
|
+
text = guide.content;
|
|
167
|
+
}
|
|
168
|
+
else if (componentMatch) {
|
|
169
|
+
const key = decodeURIComponent(componentMatch[1]);
|
|
170
|
+
const entry = registry.components[key];
|
|
171
|
+
if (entry)
|
|
172
|
+
text = renderComponent(registry, key, entry);
|
|
173
|
+
}
|
|
174
|
+
else if (recipeMatch) {
|
|
175
|
+
const entry = registry.recipes[recipeMatch[1]];
|
|
176
|
+
if (entry)
|
|
177
|
+
text = renderRecipe(entry);
|
|
178
|
+
}
|
|
179
|
+
if (text === null)
|
|
180
|
+
throw new Error(`unknown resource ${uri}`);
|
|
181
|
+
return { contents: [{ uri, mimeType: 'text/plain', text }] };
|
|
182
|
+
}
|
|
103
183
|
export async function runMcp(registry) {
|
|
104
184
|
let sdkServer, sdkStdio, sdkTypes;
|
|
105
185
|
try {
|
|
@@ -117,39 +197,9 @@ export async function runMcp(registry) {
|
|
|
117
197
|
}));
|
|
118
198
|
server.setRequestHandler(sdkTypes.CallToolRequestSchema, (request) => toolResponse(registry, request.params.name, (request.params.arguments ?? {})));
|
|
119
199
|
server.setRequestHandler(sdkTypes.ListResourcesRequestSchema, () => ({
|
|
120
|
-
resources:
|
|
121
|
-
...Object.keys(registry.components).map((name) => ({
|
|
122
|
-
uri: `duro://component/${encodeURIComponent(name)}`,
|
|
123
|
-
name: `${name} docs`,
|
|
124
|
-
mimeType: 'text/plain',
|
|
125
|
-
})),
|
|
126
|
-
...Object.keys(registry.recipes).map((name) => ({
|
|
127
|
-
uri: `duro://recipe/${name}`,
|
|
128
|
-
name: `${name} recipe`,
|
|
129
|
-
mimeType: 'text/plain',
|
|
130
|
-
})),
|
|
131
|
-
],
|
|
200
|
+
resources: listResources(registry),
|
|
132
201
|
}));
|
|
133
|
-
server.setRequestHandler(sdkTypes.ReadResourceRequestSchema, (request) =>
|
|
134
|
-
const uri = request.params.uri;
|
|
135
|
-
const componentMatch = /^duro:\/\/component\/(.+)$/.exec(uri);
|
|
136
|
-
const recipeMatch = /^duro:\/\/recipe\/(.+)$/.exec(uri);
|
|
137
|
-
let text = null;
|
|
138
|
-
if (componentMatch) {
|
|
139
|
-
const key = decodeURIComponent(componentMatch[1]);
|
|
140
|
-
const entry = registry.components[key];
|
|
141
|
-
if (entry)
|
|
142
|
-
text = renderComponent(registry, key, entry);
|
|
143
|
-
}
|
|
144
|
-
else if (recipeMatch) {
|
|
145
|
-
const entry = registry.recipes[recipeMatch[1]];
|
|
146
|
-
if (entry)
|
|
147
|
-
text = renderRecipe(entry);
|
|
148
|
-
}
|
|
149
|
-
if (text === null)
|
|
150
|
-
throw new Error(`unknown resource ${uri}`);
|
|
151
|
-
return { contents: [{ uri, mimeType: 'text/plain', text }] };
|
|
152
|
-
});
|
|
202
|
+
server.setRequestHandler(sdkTypes.ReadResourceRequestSchema, (request) => readResource(registry, request.params.uri));
|
|
153
203
|
server.setRequestHandler(sdkTypes.ListPromptsRequestSchema, () => ({
|
|
154
204
|
prompts: [
|
|
155
205
|
{
|
package/dist/commands/mcp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,aAAa,EAAC,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAA;AACrC,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AACjC,OAAO,EAAC,UAAU,EAAC,MAAM,eAAe,CAAA;AACxC,OAAO,EAAC,eAAe,EAAE,YAAY,EAAC,MAAM,cAAc,CAAA;AAC1D,OAAO,EAAC,aAAa,EAAC,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { Registry } from '../registry-types.js';
|
|
2
2
|
import type { CommandResult } from './lookup.js';
|
|
3
|
+
import { MOCKUP_SUBCOMMANDS } from '../manifest.js';
|
|
3
4
|
export declare const TOKENS_START = "/* duro:tokens start */";
|
|
4
5
|
export declare const TOKENS_END = "/* duro:tokens end */";
|
|
5
|
-
/** The artboard size the
|
|
6
|
+
/** The artboard size, on the root element and in the review canvas's frames. */
|
|
6
7
|
export declare const ARTBOARD_WIDTH = 1120;
|
|
7
8
|
export declare const ARTBOARD_HEIGHT = 840;
|
|
8
9
|
export declare const MOCKUP_THEMES: readonly ["dark", "light", "high-contrast"];
|
|
@@ -10,7 +11,7 @@ export type MockupTheme = (typeof MOCKUP_THEMES)[number];
|
|
|
10
11
|
export interface SeedOptions {
|
|
11
12
|
/** Directory to write into. Defaults to docs/mockups/<name>. */
|
|
12
13
|
out?: string;
|
|
13
|
-
/** Artboard file stem
|
|
14
|
+
/** Artboard file stem (default Main). */
|
|
14
15
|
name?: string;
|
|
15
16
|
theme?: string;
|
|
16
17
|
cwd?: string;
|
|
@@ -18,6 +19,18 @@ export interface SeedOptions {
|
|
|
18
19
|
export interface CheckOptions {
|
|
19
20
|
cwd?: string;
|
|
20
21
|
}
|
|
22
|
+
export interface CanvasOptions {
|
|
23
|
+
/** Where to write the page. Defaults to <dir>/canvas.html. */
|
|
24
|
+
out?: string;
|
|
25
|
+
/** The page title. Defaults to "<dir name> directions". */
|
|
26
|
+
title?: string;
|
|
27
|
+
cwd?: string;
|
|
28
|
+
}
|
|
29
|
+
/** One artboard handed to the canvas: its file name and its HTML. */
|
|
30
|
+
export interface CanvasArtboard {
|
|
31
|
+
file: string;
|
|
32
|
+
html: string;
|
|
33
|
+
}
|
|
21
34
|
export interface Finding {
|
|
22
35
|
file: string;
|
|
23
36
|
line: number;
|
|
@@ -25,8 +38,8 @@ export interface Finding {
|
|
|
25
38
|
message: string;
|
|
26
39
|
}
|
|
27
40
|
/**
|
|
28
|
-
* The artboard skeleton
|
|
29
|
-
*
|
|
41
|
+
* The artboard skeleton: support.js verbatim, one <x-dc>, one
|
|
42
|
+
* <helmet><style>. Everything a
|
|
30
43
|
* finished artboard adds goes inside the same style block and the root div.
|
|
31
44
|
*/
|
|
32
45
|
export declare function seedArtboard(registry: Registry, name: string, theme: MockupTheme): string;
|
|
@@ -34,5 +47,20 @@ export declare function runMockupSeed(registry: Registry, options?: SeedOptions)
|
|
|
34
47
|
/** Every finding for one artboard's HTML. Exported for the MCP tool and tests. */
|
|
35
48
|
export declare function checkArtboard(registry: Registry, file: string, source: string): Finding[];
|
|
36
49
|
export declare function runMockupCheck(registry: Registry, files: string[], options?: CheckOptions): CommandResult;
|
|
37
|
-
|
|
50
|
+
/**
|
|
51
|
+
* The review page: every direction side by side, each artboard inlined by
|
|
52
|
+
* srcdoc so the page is one file (an Artifact needs no supporting files, and
|
|
53
|
+
* a local copy opens from disk). The frames are sandboxed: an artboard is
|
|
54
|
+
* untrusted HTML (the MCP tool takes it from the caller) and needs no script. Nothing is built while an artboard fails the
|
|
55
|
+
* check: the person picks from contracts, not from sketches that drift.
|
|
56
|
+
*/
|
|
57
|
+
export declare function buildCanvas(registry: Registry, artboards: CanvasArtboard[], options: {
|
|
58
|
+
title?: string;
|
|
59
|
+
}): {
|
|
60
|
+
html: string | null;
|
|
61
|
+
findings: Finding[];
|
|
62
|
+
};
|
|
63
|
+
export declare function runMockupCanvas(registry: Registry, dir: string | undefined, options?: CanvasOptions): CommandResult;
|
|
64
|
+
export { MOCKUP_SUBCOMMANDS };
|
|
65
|
+
export declare function runMockup(registry: Registry, sub: string | undefined, rest: string[], options: SeedOptions & CheckOptions & CanvasOptions): CommandResult;
|
|
38
66
|
//# sourceMappingURL=mockup.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mockup.d.ts","sourceRoot":"","sources":["../../src/commands/mockup.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAA;AAClD,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"mockup.d.ts","sourceRoot":"","sources":["../../src/commands/mockup.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAA;AAClD,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,aAAa,CAAA;AAI9C,OAAO,EAAC,kBAAkB,EAAC,MAAM,gBAAgB,CAAA;AAuBjD,eAAO,MAAM,YAAY,4BAA4B,CAAA;AACrD,eAAO,MAAM,UAAU,0BAA0B,CAAA;AAEjD,gFAAgF;AAChF,eAAO,MAAM,cAAc,OAAO,CAAA;AAClC,eAAO,MAAM,eAAe,MAAM,CAAA;AAElC,eAAO,MAAM,aAAa,6CAA8C,CAAA;AACxE,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAA;AAExD,MAAM,WAAW,WAAW;IAC1B,gEAAgE;IAChE,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,8DAA8D;IAC9D,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,qEAAqE;AACrE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EACA,WAAW,GACX,YAAY,GACZ,gBAAgB,GAChB,mBAAmB,GACnB,kBAAkB,GAClB,qBAAqB,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;CAChB;AAKD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,MAAM,CA6DzF;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,GAAE,WAAgB,GAAG,aAAa,CAgC1F;AA+UD,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,EAAE,CAUzF;AAED,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,MAAM,EAAE,EACf,OAAO,GAAE,YAAiB,GACzB,aAAa,CA+Bf;AAoDD;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,cAAc,EAAE,EAC3B,OAAO,EAAE;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAC,GACxB;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,OAAO,EAAE,CAAA;CAAC,CAqD5C;AAED,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,OAAO,GAAE,aAAkB,GAC1B,aAAa,CAsCf;AAED,OAAO,EAAC,kBAAkB,EAAC,CAAA;AAE3B,wBAAgB,SAAS,CACvB,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,WAAW,GAAG,YAAY,GAAG,aAAa,GAClD,aAAa,CAaf"}
|
package/dist/commands/mockup.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { join, resolve } from 'node:path';
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, join, relative, resolve } from 'node:path';
|
|
3
3
|
import { lookup } from '../registry.js';
|
|
4
4
|
import { suggestions } from '../search.js';
|
|
5
5
|
import { lineOf } from '../scan.js';
|
|
6
|
+
import { MOCKUP_SUBCOMMANDS } from '../manifest.js';
|
|
7
|
+
import { uiVersionSkew } from './doctor.js';
|
|
6
8
|
/*
|
|
7
9
|
* duro mockup — token-seeded artboards, and the check that makes one a
|
|
8
10
|
* handoff contract.
|
|
@@ -13,7 +15,9 @@ import { lineOf } from '../scan.js';
|
|
|
13
15
|
* palette). `seed` writes an artboard whose only design vocabulary is the
|
|
14
16
|
* resolved token block, so the artboard is written in token names from the
|
|
15
17
|
* first line; `check` refuses an artboard that reaches past them, and refuses
|
|
16
|
-
* one that does not say which design-system component each control is
|
|
18
|
+
* one that does not say which design-system component each control is;
|
|
19
|
+
* `canvas` puts the directions side by side on one page for the person to
|
|
20
|
+
* pick from, and builds it only from artboards that pass `check`.
|
|
17
21
|
*
|
|
18
22
|
* What binds when a direction is chosen: layout, hierarchy, states, the
|
|
19
23
|
* data-duro component map and the token names — sizes and border widths
|
|
@@ -22,15 +26,15 @@ import { lineOf } from '../scan.js';
|
|
|
22
26
|
*/
|
|
23
27
|
export const TOKENS_START = '/* duro:tokens start */';
|
|
24
28
|
export const TOKENS_END = '/* duro:tokens end */';
|
|
25
|
-
/** The artboard size the
|
|
29
|
+
/** The artboard size, on the root element and in the review canvas's frames. */
|
|
26
30
|
export const ARTBOARD_WIDTH = 1120;
|
|
27
31
|
export const ARTBOARD_HEIGHT = 840;
|
|
28
32
|
export const MOCKUP_THEMES = ['dark', 'light', 'high-contrast'];
|
|
29
33
|
// ---------------------------------------------------------------------------
|
|
30
34
|
// seed
|
|
31
35
|
/**
|
|
32
|
-
* The artboard skeleton
|
|
33
|
-
*
|
|
36
|
+
* The artboard skeleton: support.js verbatim, one <x-dc>, one
|
|
37
|
+
* <helmet><style>. Everything a
|
|
34
38
|
* finished artboard adds goes inside the same style block and the root div.
|
|
35
39
|
*/
|
|
36
40
|
export function seedArtboard(registry, name, theme) {
|
|
@@ -450,20 +454,165 @@ export function runMockupCheck(registry, files, options = {}) {
|
|
|
450
454
|
}
|
|
451
455
|
all.push(...checkArtboard(registry, file, source));
|
|
452
456
|
}
|
|
453
|
-
const lines = all.map(
|
|
457
|
+
const lines = all.map(findingLine);
|
|
458
|
+
const skew = uiVersionSkew(cwd);
|
|
459
|
+
const note = skew ? `\n${skewNote(skew, `mockup check ${files.join(' ')}`)}` : '';
|
|
454
460
|
if (all.length === 0) {
|
|
455
461
|
return {
|
|
456
|
-
text: `duro mockup check: ${files.length} artboard(s) speak tokens and name their components`,
|
|
457
|
-
data: { ok: true, files, findings: [] },
|
|
462
|
+
text: `duro mockup check: ${files.length} artboard(s) speak tokens and name their components${note}`,
|
|
463
|
+
data: { ok: true, files, findings: [], ...(skew && { skew }) },
|
|
458
464
|
};
|
|
459
465
|
}
|
|
460
466
|
return {
|
|
461
|
-
text: `duro mockup check: ${all.length} finding(s)\n${lines.join('\n')}`,
|
|
462
|
-
data: { ok: false, files, findings: all },
|
|
467
|
+
text: `duro mockup check: ${all.length} finding(s)\n${lines.join('\n')}${note}`,
|
|
468
|
+
data: { ok: false, files, findings: all, ...(skew && { skew }) },
|
|
463
469
|
exitCode: 1,
|
|
464
470
|
};
|
|
465
471
|
}
|
|
466
|
-
const
|
|
472
|
+
const findingLine = (f) => `${f.file}:${f.line} ${f.rule}: ${f.message}`;
|
|
473
|
+
/**
|
|
474
|
+
* doctor's version-skew finding, said where it explains a finding: a checker
|
|
475
|
+
* older than the app reports a component it has not heard of as unknown. npx
|
|
476
|
+
* keeps a cached CLI that satisfies a range, so this is not hypothetical.
|
|
477
|
+
*/
|
|
478
|
+
function skewNote(skew, command) {
|
|
479
|
+
return `note: @duro-app/ui is ${skew.installed}, but this checker knows ${skew.own} — a component newer than the checker reads as unknown. Run: npx -y @duro-app/cli@${skew.installed} ${command}`;
|
|
480
|
+
}
|
|
481
|
+
// ---------------------------------------------------------------------------
|
|
482
|
+
// canvas
|
|
483
|
+
const ARTBOARD_SUFFIX = '.dc.html';
|
|
484
|
+
/** The artboard's own canvas size, from the seeded custom properties. */
|
|
485
|
+
function artboardSize(html) {
|
|
486
|
+
const width = /--duro-mockup-canvas-width:\s*(\d+)px/.exec(html);
|
|
487
|
+
const height = /--duro-mockup-canvas-height:\s*(\d+)px/.exec(html);
|
|
488
|
+
return {
|
|
489
|
+
width: width ? Number(width[1]) : ARTBOARD_WIDTH,
|
|
490
|
+
height: height ? Number(height[1]) : ARTBOARD_HEIGHT,
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
const escapeHtml = (text) => text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
494
|
+
/**
|
|
495
|
+
* An artboard as the page inlines it: without the seed's relative support.js,
|
|
496
|
+
* which a srcdoc frame cannot load and the page does not need.
|
|
497
|
+
*/
|
|
498
|
+
const inlineable = (html) => html.replace(/<script src="\.\/support\.js"><\/script>\n?/g, '');
|
|
499
|
+
/** `Tree-Phone.dc.html` is direction `Tree`; `Main` sorts first, then by name. */
|
|
500
|
+
function directions(artboards) {
|
|
501
|
+
const stem = (a) => a.file.split('/').pop().replace(ARTBOARD_SUFFIX, '');
|
|
502
|
+
const groups = new Map();
|
|
503
|
+
for (const artboard of artboards) {
|
|
504
|
+
const key = stem(artboard).split('-')[0];
|
|
505
|
+
groups.set(key, [...(groups.get(key) ?? []), artboard]);
|
|
506
|
+
}
|
|
507
|
+
const rank = (key) => (key === 'Main' ? '' : key);
|
|
508
|
+
return [...groups.entries()]
|
|
509
|
+
.sort(([a], [b]) => rank(a).localeCompare(rank(b)))
|
|
510
|
+
.map(([key, group]) => [key, group.sort((a, b) => stem(a).localeCompare(stem(b)))]);
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* The review page: every direction side by side, each artboard inlined by
|
|
514
|
+
* srcdoc so the page is one file (an Artifact needs no supporting files, and
|
|
515
|
+
* a local copy opens from disk). The frames are sandboxed: an artboard is
|
|
516
|
+
* untrusted HTML (the MCP tool takes it from the caller) and needs no script. Nothing is built while an artboard fails the
|
|
517
|
+
* check: the person picks from contracts, not from sketches that drift.
|
|
518
|
+
*/
|
|
519
|
+
export function buildCanvas(registry, artboards, options) {
|
|
520
|
+
const findings = artboards.flatMap((a) => checkArtboard(registry, a.file, a.html));
|
|
521
|
+
if (findings.length > 0)
|
|
522
|
+
return { html: null, findings };
|
|
523
|
+
const title = escapeHtml(options.title ?? 'Mockup directions');
|
|
524
|
+
const sections = directions(artboards).map(([key, group], index) => {
|
|
525
|
+
const letter = String.fromCharCode(65 + (index % 26));
|
|
526
|
+
const figures = group.map((artboard) => {
|
|
527
|
+
const { width, height } = artboardSize(artboard.html);
|
|
528
|
+
const name = escapeHtml(artboard.file.split('/').pop());
|
|
529
|
+
return `<figure>
|
|
530
|
+
<div class="frame" style="aspect-ratio: ${width} / ${height}"><iframe title="${name}" width="${width}" height="${height}" data-width="${width}" style="transform: scale(0.5)" sandbox="" srcdoc="${escapeHtml(inlineable(artboard.html))}"></iframe></div>
|
|
531
|
+
<figcaption>${name} · ${width}×${height}</figcaption>
|
|
532
|
+
</figure>`;
|
|
533
|
+
});
|
|
534
|
+
return `<section>\n<h2>${letter} · ${escapeHtml(key)}</h2>\n<div class="grid">\n${figures.join('\n')}\n</div>\n</section>`;
|
|
535
|
+
});
|
|
536
|
+
const html = `<!doctype html>
|
|
537
|
+
<html lang="en">
|
|
538
|
+
<head>
|
|
539
|
+
<meta charset="utf-8">
|
|
540
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
541
|
+
<title>${title}</title>
|
|
542
|
+
<!-- GENERATED by duro mockup canvas: regenerate it, never edit it. -->
|
|
543
|
+
<style>
|
|
544
|
+
/* The page's own chrome, not a Duro surface: self-contained, themed by system colours. */
|
|
545
|
+
:root { color-scheme: light dark; --gap: 16px; }
|
|
546
|
+
body { margin: 0; padding: var(--gap); background: Canvas; color: CanvasText; font: 14px/1.5 system-ui, sans-serif; }
|
|
547
|
+
h1 { font-size: 20px; margin: 0 0 4px; }
|
|
548
|
+
h2 { font-size: 14px; margin: 32px 0 8px; text-transform: uppercase; letter-spacing: 0.04em; }
|
|
549
|
+
p { margin: 0; opacity: 0.75; }
|
|
550
|
+
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 420px), 1fr)); gap: var(--gap); }
|
|
551
|
+
figure { margin: 0; min-width: 0; }
|
|
552
|
+
.frame { position: relative; width: 100%; overflow: hidden; border: 1px solid GrayText; border-radius: 8px; }
|
|
553
|
+
.frame iframe { position: absolute; inset: 0 auto auto 0; border: 0; transform-origin: 0 0; }
|
|
554
|
+
figcaption { margin-top: 4px; font-size: 12px; opacity: 0.75; }
|
|
555
|
+
</style>
|
|
556
|
+
</head>
|
|
557
|
+
<body>
|
|
558
|
+
<h1>${title}</h1>
|
|
559
|
+
<p>Pick one direction by its letter. Sizes, colours and the component map are the contract; positions are a sketch.</p>
|
|
560
|
+
${sections.join('\n')}
|
|
561
|
+
<script>
|
|
562
|
+
// Scale each artboard to its frame's width; 0.5 stands until this runs.
|
|
563
|
+
const fit = () => document.querySelectorAll('.frame iframe').forEach((f) => {
|
|
564
|
+
f.style.transform = 'scale(' + f.parentElement.clientWidth / Number(f.dataset.width) + ')'
|
|
565
|
+
})
|
|
566
|
+
new ResizeObserver(fit).observe(document.body)
|
|
567
|
+
fit()
|
|
568
|
+
</script>
|
|
569
|
+
</body>
|
|
570
|
+
</html>
|
|
571
|
+
`;
|
|
572
|
+
return { html, findings: [] };
|
|
573
|
+
}
|
|
574
|
+
export function runMockupCanvas(registry, dir, options = {}) {
|
|
575
|
+
if (!dir)
|
|
576
|
+
return usage('duro mockup canvas: give the directory holding the *.dc.html artboards');
|
|
577
|
+
const cwd = options.cwd ?? process.cwd();
|
|
578
|
+
const abs = resolve(cwd, dir);
|
|
579
|
+
if (!existsSync(abs) || !statSync(abs).isDirectory()) {
|
|
580
|
+
return usage(`duro mockup canvas: ${dir} is not a directory`);
|
|
581
|
+
}
|
|
582
|
+
const files = readdirSync(abs)
|
|
583
|
+
.filter((name) => name.endsWith(ARTBOARD_SUFFIX))
|
|
584
|
+
.sort();
|
|
585
|
+
if (files.length === 0)
|
|
586
|
+
return usage(`duro mockup canvas: no *${ARTBOARD_SUFFIX} in ${dir}`);
|
|
587
|
+
const artboards = files.map((name) => ({
|
|
588
|
+
file: join(dir, name),
|
|
589
|
+
html: readFileSync(join(abs, name), 'utf8'),
|
|
590
|
+
}));
|
|
591
|
+
const title = options.title ?? `${abs.split('/').pop()} directions`;
|
|
592
|
+
const { html, findings } = buildCanvas(registry, artboards, { title });
|
|
593
|
+
const skew = uiVersionSkew(cwd);
|
|
594
|
+
const note = skew ? `\n${skewNote(skew, `mockup canvas ${dir}`)}` : '';
|
|
595
|
+
if (html === null) {
|
|
596
|
+
return {
|
|
597
|
+
text: `duro mockup canvas: ${findings.length} finding(s) — fix them, then build the page\n${findings.map(findingLine).join('\n')}${note}`,
|
|
598
|
+
data: { ok: false, findings, ...(skew && { skew }) },
|
|
599
|
+
exitCode: 1,
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
const out = options.out ?? join(dir, 'canvas.html');
|
|
603
|
+
mkdirSync(dirname(resolve(cwd, out)), { recursive: true });
|
|
604
|
+
writeFileSync(resolve(cwd, out), html, 'utf8');
|
|
605
|
+
return {
|
|
606
|
+
text: `duro mockup canvas: ${relative(cwd, resolve(cwd, out))} — ${files.length} artboard(s). Publish it as the Artifact, or open it locally.${note}`,
|
|
607
|
+
data: {
|
|
608
|
+
ok: true,
|
|
609
|
+
path: relative(cwd, resolve(cwd, out)),
|
|
610
|
+
artboards: files.length,
|
|
611
|
+
...(skew && { skew }),
|
|
612
|
+
},
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
export { MOCKUP_SUBCOMMANDS };
|
|
467
616
|
export function runMockup(registry, sub, rest, options) {
|
|
468
617
|
if (sub === 'seed') {
|
|
469
618
|
if (rest.length > 0)
|
|
@@ -472,6 +621,11 @@ export function runMockup(registry, sub, rest, options) {
|
|
|
472
621
|
}
|
|
473
622
|
if (sub === 'check')
|
|
474
623
|
return runMockupCheck(registry, rest, options);
|
|
475
|
-
|
|
624
|
+
if (sub === 'canvas') {
|
|
625
|
+
if (rest.length > 1)
|
|
626
|
+
return usage('duro mockup canvas takes one directory');
|
|
627
|
+
return runMockupCanvas(registry, rest[0], options);
|
|
628
|
+
}
|
|
629
|
+
return usage(`duro mockup: unknown subcommand "${sub ?? ''}" — expected ${MOCKUP_SUBCOMMANDS.join(' | ')}`);
|
|
476
630
|
}
|
|
477
631
|
//# sourceMappingURL=mockup.js.map
|