create-middag-ui 0.1.4 → 0.2.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 +43 -24
- package/cli.js +149 -287
- package/lib/auth.js +210 -0
- package/lib/detect.js +29 -0
- package/lib/install.js +92 -0
- package/lib/prompts.js +120 -0
- package/lib/scaffold.js +386 -0
- package/lib/ui.js +85 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -8,17 +8,24 @@ Bootstrap a [MIDDAG React UI](https://github.com/middag-io/middag-react) layer i
|
|
|
8
8
|
npx create-middag-ui
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
Or specify a custom directory:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx create-middag-ui mydir
|
|
15
|
+
```
|
|
16
|
+
|
|
11
17
|
Run from your plugin project root. The wizard:
|
|
12
18
|
|
|
13
19
|
1. **Auto-detects your host** — finds `version.php` (Moodle) or `wp-config.php` (WordPress)
|
|
14
|
-
2. **
|
|
15
|
-
3. **
|
|
20
|
+
2. **Asks for target directory** — default `ui/`, or pass as CLI argument
|
|
21
|
+
3. **Configures registry** — GitHub Packages (with source maps) or npm public (no auth needed)
|
|
22
|
+
4. **Scaffolds everything** — config files, demo components, mock environment
|
|
23
|
+
5. **Installs dependencies** — runs `npm install` automatically with progress feedback
|
|
16
24
|
|
|
17
|
-
Then
|
|
25
|
+
Then start developing:
|
|
18
26
|
|
|
19
27
|
```bash
|
|
20
28
|
cd ui
|
|
21
|
-
npm install
|
|
22
29
|
npm run dev:mock
|
|
23
30
|
```
|
|
24
31
|
|
|
@@ -28,21 +35,43 @@ Your mock opens at `http://localhost:5174` (Moodle), `5175` (WordPress), or `517
|
|
|
28
35
|
|
|
29
36
|
```
|
|
30
37
|
ui/
|
|
31
|
-
.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
package.json # Dependencies and scripts
|
|
39
|
+
tsconfig.json # TypeScript config with path aliases
|
|
40
|
+
vite.mock.config.ts # Vite dev server config for mock build
|
|
41
|
+
src/
|
|
42
|
+
blocks/
|
|
43
|
+
hello-block.tsx # Custom block example (rename me!)
|
|
44
|
+
components/
|
|
45
|
+
greeting.tsx # Standalone component example (rename me!)
|
|
46
|
+
contracts.ts # PageContract type re-export
|
|
36
47
|
mock/
|
|
37
|
-
index.html
|
|
38
|
-
main.tsx
|
|
39
|
-
hello-contract.ts
|
|
40
|
-
tailwind.css
|
|
48
|
+
index.html # HTML entry point
|
|
49
|
+
main.tsx # React entry with registerDefaults() + ContractPage
|
|
50
|
+
hello-contract.ts # Example PageContract (metric card + data table)
|
|
51
|
+
tailwind.css # Tailwind CSS import
|
|
41
52
|
```
|
|
42
53
|
|
|
54
|
+
## Dual Registry
|
|
55
|
+
|
|
56
|
+
`@middag-io/react` is available from two registries:
|
|
57
|
+
|
|
58
|
+
### npm public (default, no auth)
|
|
59
|
+
|
|
60
|
+
Choose "No" when asked about GitHub access. Dependencies install from the public npm registry with zero configuration.
|
|
61
|
+
|
|
62
|
+
### GitHub Packages (with source maps)
|
|
63
|
+
|
|
64
|
+
Choose "Yes" when asked about GitHub access. The wizard will:
|
|
65
|
+
|
|
66
|
+
1. Ask for your GitHub Personal Access Token
|
|
67
|
+
2. Validate the token against GitHub Packages
|
|
68
|
+
3. Save the registry + token to `~/.npmrc` (global, not project-local)
|
|
69
|
+
|
|
70
|
+
Create a token at [github.com/settings/tokens](https://github.com/settings/tokens) with the `read:packages` scope.
|
|
71
|
+
|
|
43
72
|
## After setup
|
|
44
73
|
|
|
45
|
-
Once `@middag-io/react` is installed, more commands become available from inside
|
|
74
|
+
Once `@middag-io/react` is installed, more commands become available from inside your UI directory:
|
|
46
75
|
|
|
47
76
|
```bash
|
|
48
77
|
npx @middag-io/react doctor # Validate project setup
|
|
@@ -51,16 +80,6 @@ npx @middag-io/react add-block <t> # Scaffold a new block type
|
|
|
51
80
|
npx @middag-io/react upgrade # Check for updates
|
|
52
81
|
```
|
|
53
82
|
|
|
54
|
-
## Authentication
|
|
55
|
-
|
|
56
|
-
`@middag-io/react` is hosted on GitHub Packages. The wizard creates `.npmrc` with the registry, but you need to add your GitHub token:
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
echo '//npm.pkg.github.com/:_authToken=YOUR_GITHUB_TOKEN' >> ui/.npmrc
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
Create a token at [github.com/settings/tokens](https://github.com/settings/tokens) with the `read:packages` scope.
|
|
63
|
-
|
|
64
83
|
## Documentation
|
|
65
84
|
|
|
66
85
|
- **[Live Demo](https://middag-react-mock.pages.dev)** — 24 screens showing all block types
|
package/cli.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
/* global console, process */
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* create-middag-ui — Bootstrap a MIDDAG React UI layer.
|
|
@@ -6,322 +7,183 @@
|
|
|
6
7
|
* Published on public npm so `npx create-middag-ui` works without
|
|
7
8
|
* GitHub Packages authentication. This package handles:
|
|
8
9
|
* 1. Host detection (Moodle / WordPress / Custom)
|
|
9
|
-
* 2. ui
|
|
10
|
-
* 3.
|
|
11
|
-
* 4.
|
|
12
|
-
* 5.
|
|
10
|
+
* 2. Directory selection (default: ui/, or CLI arg)
|
|
11
|
+
* 3. GitHub access check (dual registry: GitHub Packages or npm public)
|
|
12
|
+
* 4. Directory + config scaffolding
|
|
13
|
+
* 5. Demo files (custom block, standalone component, type re-export)
|
|
14
|
+
* 6. Mock files (hello-contract, entry point, HTML, CSS)
|
|
15
|
+
* 7. npm install with spinner
|
|
16
|
+
* 8. Summary with next steps
|
|
13
17
|
*
|
|
14
|
-
* After init,
|
|
15
|
-
*
|
|
18
|
+
* After init, more CLI commands are available via:
|
|
19
|
+
* npx @middag-io/react <command>
|
|
16
20
|
*/
|
|
17
21
|
|
|
18
|
-
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
19
22
|
import { join } from "node:path";
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
);
|
|
38
|
-
}
|
|
23
|
+
import { detectHost, HOSTS } from "./lib/detect.js";
|
|
24
|
+
import { ask, select, confirm } from "./lib/prompts.js";
|
|
25
|
+
import { runTokenFlow } from "./lib/auth.js";
|
|
26
|
+
import {
|
|
27
|
+
createTargetDir,
|
|
28
|
+
scaffoldPackageJson,
|
|
29
|
+
scaffoldTsconfig,
|
|
30
|
+
scaffoldViteConfig,
|
|
31
|
+
scaffoldDemoFiles,
|
|
32
|
+
scaffoldMockFiles,
|
|
33
|
+
} from "./lib/scaffold.js";
|
|
34
|
+
import { runNpmInstall } from "./lib/install.js";
|
|
35
|
+
import { log, success, heading, blank, info } from "./lib/ui.js";
|
|
36
|
+
|
|
37
|
+
const TOTAL_STEPS = 10;
|
|
38
|
+
const cwd = process.cwd();
|
|
39
|
+
const startTime = Date.now();
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
function success(msg) {
|
|
44
|
-
console.log(` \x1b[32m✓\x1b[0m ${msg}`);
|
|
45
|
-
}
|
|
46
|
-
function warn(msg) {
|
|
47
|
-
console.log(` \x1b[33m⚠\x1b[0m ${msg}`);
|
|
48
|
-
}
|
|
41
|
+
blank();
|
|
42
|
+
log("Initializing MIDDAG React UI...\n");
|
|
49
43
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
44
|
+
// ── Step 1: Detect host ──────────────────────────────────────────────────
|
|
45
|
+
|
|
46
|
+
heading(1, TOTAL_STEPS, "Detecting host platform");
|
|
47
|
+
|
|
48
|
+
let hostKey = detectHost(cwd);
|
|
49
|
+
if (hostKey) {
|
|
50
|
+
success(`Detected: ${HOSTS[hostKey].name} (found ${HOSTS[hostKey].detect})`);
|
|
51
|
+
} else {
|
|
52
|
+
info("Could not auto-detect host platform.");
|
|
53
|
+
hostKey = await select("Select platform", [
|
|
54
|
+
{ label: "Moodle", value: "moodle" },
|
|
55
|
+
{ label: "WordPress", value: "wordpress" },
|
|
56
|
+
{ label: "Custom / Other", value: "custom" },
|
|
57
|
+
]);
|
|
58
|
+
success(`Selected: ${HOSTS[hostKey].name}`);
|
|
55
59
|
}
|
|
56
60
|
|
|
57
|
-
|
|
61
|
+
const host = HOSTS[hostKey];
|
|
58
62
|
|
|
59
|
-
|
|
60
|
-
const startTime = Date.now();
|
|
63
|
+
// ── Step 2: Ask directory ────────────────────────────────────────────────
|
|
61
64
|
|
|
62
|
-
|
|
65
|
+
heading(2, TOTAL_STEPS, "Target directory");
|
|
63
66
|
|
|
64
|
-
|
|
65
|
-
let
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
const cliArg = process.argv[2];
|
|
68
|
+
let dirName;
|
|
69
|
+
|
|
70
|
+
if (cliArg && !cliArg.startsWith("-")) {
|
|
71
|
+
dirName = cliArg;
|
|
72
|
+
success(`Using directory from argument: ${dirName}/`);
|
|
68
73
|
} else {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
console.log(" 3) Custom / Other");
|
|
73
|
-
const choice = await ask("\n Select platform [1-3]: ");
|
|
74
|
-
host =
|
|
75
|
-
["moodle", "wordpress", "custom"][parseInt(choice, 10) - 1] || "custom";
|
|
76
|
-
success(`Selected: ${HOSTS[host].name}`);
|
|
74
|
+
const answer = await ask(` Directory name (default: ui): `);
|
|
75
|
+
dirName = answer || "ui";
|
|
76
|
+
success(`Target: ${dirName}/`);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
const
|
|
79
|
+
const targetDir = join(cwd, dirName);
|
|
80
80
|
|
|
81
|
-
// Step
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
81
|
+
// ── Step 3: Ask GitHub access ────────────────────────────────────────────
|
|
82
|
+
|
|
83
|
+
heading(3, TOTAL_STEPS, "Registry configuration");
|
|
84
|
+
|
|
85
|
+
info("@middag-io/react can be installed from:");
|
|
86
|
+
info(" a) GitHub Packages (with source maps, requires token)");
|
|
87
|
+
info(" b) npm public registry (compiled only, no auth needed)");
|
|
88
|
+
blank();
|
|
88
89
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
"@middag-io:registry=https://npm.pkg.github.com\n",
|
|
95
|
-
);
|
|
96
|
-
success("Created .npmrc with GitHub Packages registry");
|
|
97
|
-
warn(
|
|
98
|
-
"Add your GitHub token: echo '//npm.pkg.github.com/:_authToken=YOUR_TOKEN' >> ui/.npmrc",
|
|
99
|
-
);
|
|
90
|
+
const hasGitHubAccess = await confirm("Do you have GitHub access to middag-io?", false);
|
|
91
|
+
|
|
92
|
+
let registryPath = "public";
|
|
93
|
+
if (hasGitHubAccess) {
|
|
94
|
+
registryPath = await runTokenFlow();
|
|
100
95
|
} else {
|
|
101
|
-
success("
|
|
96
|
+
success("Using npm public registry (no authentication needed)");
|
|
102
97
|
}
|
|
103
98
|
|
|
104
|
-
// Step 4: Create
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const projectName = cwd.split("/").pop() || "project";
|
|
108
|
-
const pkg = {
|
|
109
|
-
name: `${projectName}-ui`,
|
|
110
|
-
private: true,
|
|
111
|
-
type: "module",
|
|
112
|
-
scripts: {
|
|
113
|
-
dev: "vite --config vite.mock.config.ts",
|
|
114
|
-
"dev:mock": "vite --config vite.mock.config.ts",
|
|
115
|
-
build: "vite build",
|
|
116
|
-
"build:mock": "vite build --config vite.mock.config.ts",
|
|
117
|
-
typecheck: "tsc --noEmit",
|
|
118
|
-
lint: "eslint .",
|
|
119
|
-
"lint:fix": "eslint . --fix",
|
|
120
|
-
},
|
|
121
|
-
dependencies: {
|
|
122
|
-
"@middag-io/react": "^0.1.0",
|
|
123
|
-
},
|
|
124
|
-
devDependencies: {
|
|
125
|
-
"@types/react": "^19.0.0",
|
|
126
|
-
"@types/react-dom": "^19.0.0",
|
|
127
|
-
react: "^19.0.0",
|
|
128
|
-
"react-dom": "^19.0.0",
|
|
129
|
-
"@inertiajs/react": "^2.0.0",
|
|
130
|
-
"@inertiajs/core": "^2.0.0",
|
|
131
|
-
typescript: "^5.7.0",
|
|
132
|
-
vite: "^6.0.0",
|
|
133
|
-
"@vitejs/plugin-react": "^4.0.0",
|
|
134
|
-
tailwindcss: "^4.0.0",
|
|
135
|
-
"@tailwindcss/vite": "^4.0.0",
|
|
136
|
-
},
|
|
137
|
-
};
|
|
138
|
-
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
139
|
-
success("Created package.json");
|
|
140
|
-
}
|
|
99
|
+
// ── Step 4: Create directory ─────────────────────────────────────────────
|
|
100
|
+
|
|
101
|
+
heading(4, TOTAL_STEPS, "Creating directory");
|
|
141
102
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const tsconfig = {
|
|
146
|
-
compilerOptions: {
|
|
147
|
-
target: "ES2022",
|
|
148
|
-
module: "ESNext",
|
|
149
|
-
moduleResolution: "bundler",
|
|
150
|
-
jsx: "react-jsx",
|
|
151
|
-
strict: true,
|
|
152
|
-
noUnusedLocals: true,
|
|
153
|
-
noUnusedParameters: true,
|
|
154
|
-
skipLibCheck: true,
|
|
155
|
-
paths: { "@/*": ["./src/*"], "@mock/*": ["./mock/*"] },
|
|
156
|
-
baseUrl: ".",
|
|
157
|
-
},
|
|
158
|
-
include: ["src", "mock"],
|
|
159
|
-
};
|
|
160
|
-
writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2) + "\n");
|
|
161
|
-
success("Created tsconfig.json");
|
|
103
|
+
const dirCreated = createTargetDir(targetDir);
|
|
104
|
+
if (!dirCreated) {
|
|
105
|
+
process.exit(1);
|
|
162
106
|
}
|
|
163
107
|
|
|
164
|
-
// Step
|
|
165
|
-
const mockDir = join(uiDir, "mock");
|
|
166
|
-
mkdirSync(join(uiDir, "src"), { recursive: true });
|
|
167
|
-
mkdirSync(mockDir, { recursive: true });
|
|
108
|
+
// ── Step 5: Scaffold config files ────────────────────────────────────────
|
|
168
109
|
|
|
169
|
-
|
|
170
|
-
if (!existsSync(helloContractPath)) {
|
|
171
|
-
writeFileSync(
|
|
172
|
-
helloContractPath,
|
|
173
|
-
`import type { PageContract } from "@middag-io/react";
|
|
110
|
+
heading(5, TOTAL_STEPS, "Scaffolding config files");
|
|
174
111
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
* This is what your ${HOSTS[host].name} backend will send via Inertia.
|
|
179
|
-
* Replace this with real data from your server.
|
|
180
|
-
*/
|
|
181
|
-
export const helloContract: PageContract = {
|
|
182
|
-
shell: "admin",
|
|
183
|
-
meta: {
|
|
184
|
-
title: "Hello MIDDAG",
|
|
185
|
-
breadcrumbs: [
|
|
186
|
-
{ label: "Home", href: "/" },
|
|
187
|
-
{ label: "Hello", href: "/hello" },
|
|
188
|
-
],
|
|
189
|
-
},
|
|
190
|
-
layout: {
|
|
191
|
-
template: "stack",
|
|
192
|
-
regions: {
|
|
193
|
-
content: [
|
|
194
|
-
{
|
|
195
|
-
key: "welcome_metrics",
|
|
196
|
-
type: "metric_card",
|
|
197
|
-
data: {
|
|
198
|
-
title: "Setup Complete",
|
|
199
|
-
value: "1",
|
|
200
|
-
subtitle: "@middag-io/react is working",
|
|
201
|
-
trend: { direction: "up", value: "100%", label: "Ready" },
|
|
202
|
-
},
|
|
203
|
-
},
|
|
204
|
-
{
|
|
205
|
-
key: "hello_table",
|
|
206
|
-
type: "dense_table",
|
|
207
|
-
data: {
|
|
208
|
-
title: "Example Data",
|
|
209
|
-
columns: [
|
|
210
|
-
{ key: "id", label: "ID", sortable: true },
|
|
211
|
-
{ key: "name", label: "Name", sortable: true },
|
|
212
|
-
{ key: "status", label: "Status" },
|
|
213
|
-
],
|
|
214
|
-
rows: [
|
|
215
|
-
{ id: 1, name: "First item", status: "Active" },
|
|
216
|
-
{ id: 2, name: "Second item", status: "Draft" },
|
|
217
|
-
{ id: 3, name: "Third item", status: "Active" },
|
|
218
|
-
],
|
|
219
|
-
pagination: { current: 1, total: 1, perPage: 10, totalRows: 3 },
|
|
220
|
-
},
|
|
221
|
-
},
|
|
222
|
-
],
|
|
223
|
-
},
|
|
224
|
-
},
|
|
225
|
-
};
|
|
226
|
-
`,
|
|
227
|
-
);
|
|
228
|
-
success("Created mock/hello-contract.ts (hello-world PageContract)");
|
|
229
|
-
}
|
|
112
|
+
scaffoldPackageJson(targetDir, host, cwd);
|
|
113
|
+
scaffoldTsconfig(targetDir);
|
|
114
|
+
scaffoldViteConfig(targetDir, host);
|
|
230
115
|
|
|
231
|
-
// Step
|
|
232
|
-
const mockMainPath = join(mockDir, "main.tsx");
|
|
233
|
-
if (!existsSync(mockMainPath)) {
|
|
234
|
-
writeFileSync(
|
|
235
|
-
mockMainPath,
|
|
236
|
-
`import { StrictMode } from "react";
|
|
237
|
-
import { createRoot } from "react-dom/client";
|
|
238
|
-
import { ContractPage, registerDefaults } from "@middag-io/react";
|
|
239
|
-
import "@middag-io/react/style.css";
|
|
240
|
-
import "./tailwind.css";
|
|
241
|
-
import { helloContract } from "./hello-contract";
|
|
242
|
-
|
|
243
|
-
// Register all default shells, layouts, and blocks
|
|
244
|
-
registerDefaults();
|
|
245
|
-
|
|
246
|
-
createRoot(document.getElementById("root")!).render(
|
|
247
|
-
<StrictMode>
|
|
248
|
-
<ContractPage contract={helloContract} />
|
|
249
|
-
</StrictMode>,
|
|
250
|
-
);
|
|
251
|
-
`,
|
|
252
|
-
);
|
|
253
|
-
success("Created mock/main.tsx");
|
|
254
|
-
}
|
|
116
|
+
// ── Step 6: Scaffold ~/.npmrc (GitHub path only) ─────────────────────────
|
|
255
117
|
|
|
256
|
-
|
|
257
|
-
if (!existsSync(mockIndexPath)) {
|
|
258
|
-
writeFileSync(
|
|
259
|
-
mockIndexPath,
|
|
260
|
-
`<!doctype html>
|
|
261
|
-
<html lang="en">
|
|
262
|
-
<head>
|
|
263
|
-
<meta charset="UTF-8" />
|
|
264
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
265
|
-
<title>MIDDAG React UI — Mock</title>
|
|
266
|
-
</head>
|
|
267
|
-
<body>
|
|
268
|
-
<div id="root"></div>
|
|
269
|
-
<script type="module" src="./main.tsx"></script>
|
|
270
|
-
</body>
|
|
271
|
-
</html>
|
|
272
|
-
`,
|
|
273
|
-
);
|
|
274
|
-
success("Created mock/index.html");
|
|
275
|
-
}
|
|
118
|
+
heading(6, TOTAL_STEPS, "Registry setup");
|
|
276
119
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
`import { defineConfig } from "vite";
|
|
283
|
-
import react from "@vitejs/plugin-react";
|
|
284
|
-
import tailwindcss from "@tailwindcss/vite";
|
|
285
|
-
import { resolve } from "path";
|
|
286
|
-
|
|
287
|
-
export default defineConfig({
|
|
288
|
-
plugins: [react(), tailwindcss()],
|
|
289
|
-
root: "mock",
|
|
290
|
-
server: { port: ${HOSTS[host].port} },
|
|
291
|
-
resolve: {
|
|
292
|
-
alias: {
|
|
293
|
-
"@/": resolve(__dirname, "src") + "/",
|
|
294
|
-
"@mock/": resolve(__dirname, "mock") + "/",
|
|
295
|
-
},
|
|
296
|
-
},
|
|
297
|
-
});
|
|
298
|
-
`,
|
|
299
|
-
);
|
|
300
|
-
success("Created vite.mock.config.ts");
|
|
120
|
+
if (registryPath === "github") {
|
|
121
|
+
success("GitHub Packages registry configured in ~/.npmrc (global)");
|
|
122
|
+
info("Token was saved during authentication step");
|
|
123
|
+
} else {
|
|
124
|
+
success("No registry config needed (using npm public)");
|
|
301
125
|
}
|
|
302
126
|
|
|
303
|
-
// Step
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
127
|
+
// ── Step 7: Scaffold demo files in src/ ──────────────────────────────────
|
|
128
|
+
|
|
129
|
+
heading(7, TOTAL_STEPS, "Creating demo files");
|
|
130
|
+
|
|
131
|
+
scaffoldDemoFiles(targetDir);
|
|
132
|
+
|
|
133
|
+
// ── Step 8: Scaffold mock files ──────────────────────────────────────────
|
|
134
|
+
|
|
135
|
+
heading(8, TOTAL_STEPS, "Creating mock environment");
|
|
136
|
+
|
|
137
|
+
scaffoldMockFiles(targetDir);
|
|
138
|
+
|
|
139
|
+
// ── Step 9: npm install ──────────────────────────────────────────────────
|
|
140
|
+
|
|
141
|
+
heading(9, TOTAL_STEPS, "Installing dependencies");
|
|
142
|
+
|
|
143
|
+
info("This may take a minute...");
|
|
144
|
+
blank();
|
|
145
|
+
|
|
146
|
+
const installOk = await runNpmInstall(targetDir, registryPath);
|
|
147
|
+
|
|
148
|
+
// ── Step 10: Summary ─────────────────────────────────────────────────────
|
|
149
|
+
|
|
150
|
+
heading(10, TOTAL_STEPS, "Done!");
|
|
309
151
|
|
|
310
|
-
// Summary
|
|
311
152
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
console.log("
|
|
317
|
-
console.log(
|
|
318
|
-
console.log(`
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
console.log("
|
|
322
|
-
console.log(
|
|
323
|
-
console.log("
|
|
324
|
-
console.log(
|
|
325
|
-
|
|
153
|
+
blank();
|
|
154
|
+
|
|
155
|
+
if (installOk) {
|
|
156
|
+
log(`MIDDAG React UI ready in ${dirName}/ (${elapsed}s)\n`);
|
|
157
|
+
console.log(" Start developing:");
|
|
158
|
+
console.log(` cd ${dirName}`);
|
|
159
|
+
console.log(` npm run dev:mock \u2192 mock server at http://localhost:${host.port}`);
|
|
160
|
+
} else {
|
|
161
|
+
log(`Scaffold complete in ${dirName}/ (${elapsed}s) \u2014 install failed\n`);
|
|
162
|
+
console.log(" To retry install:");
|
|
163
|
+
console.log(` cd ${dirName}`);
|
|
164
|
+
console.log(" npm install");
|
|
165
|
+
console.log(` npm run dev:mock \u2192 mock server at http://localhost:${host.port}`);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
blank();
|
|
169
|
+
console.log(" Your scaffold includes:");
|
|
170
|
+
console.log(" src/blocks/hello-block.tsx \u2190 custom block example (rename me!)");
|
|
171
|
+
console.log(" src/components/greeting.tsx \u2190 standalone component (rename me!)");
|
|
172
|
+
console.log(" src/contracts.ts \u2190 PageContract type re-export");
|
|
173
|
+
console.log(" mock/hello-contract.ts \u2190 example PageContract with data");
|
|
174
|
+
|
|
175
|
+
blank();
|
|
176
|
+
console.log(` Integrate with your ${host.name} plugin:`);
|
|
177
|
+
console.log(" 1. Import { ContractPage } from '@middag-io/react'");
|
|
178
|
+
console.log(" 2. Pass your Inertia page props as the contract");
|
|
179
|
+
console.log(" 3. See: https://docs.middag.io/getting-started");
|
|
180
|
+
|
|
181
|
+
blank();
|
|
182
|
+
console.log(" More commands (after install):");
|
|
183
|
+
console.log(" npx @middag-io/react doctor \u2192 validate setup");
|
|
184
|
+
console.log(" npx @middag-io/react add-block \u2192 scaffold new block type");
|
|
185
|
+
console.log(" npx @middag-io/react upgrade \u2192 check for updates");
|
|
186
|
+
|
|
187
|
+
blank();
|
|
326
188
|
console.log(" Docs: https://docs.middag.io");
|
|
327
|
-
|
|
189
|
+
blank();
|