create-middag-ui 0.10.3 → 0.11.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/cli.js +18 -1
- package/lib/detect.js +73 -7
- package/lib/scaffold.js +323 -10
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -37,6 +37,9 @@ import {
|
|
|
37
37
|
scaffoldFreeApp,
|
|
38
38
|
scaffoldFreeAdapters,
|
|
39
39
|
scaffoldDevShell,
|
|
40
|
+
scaffoldHostEntry,
|
|
41
|
+
scaffoldHostViteConfig,
|
|
42
|
+
scaffoldHostThemeCSS,
|
|
40
43
|
} from "./lib/scaffold.js";
|
|
41
44
|
import { runNpmInstall } from "./lib/install.js";
|
|
42
45
|
import { log, success, heading, blank, info } from "./lib/ui.js";
|
|
@@ -116,7 +119,7 @@ if (!dirCreated) {
|
|
|
116
119
|
|
|
117
120
|
heading(5, TOTAL_STEPS, "Scaffolding config files");
|
|
118
121
|
|
|
119
|
-
scaffoldPackageJson(targetDir, host, cwd, registryPath);
|
|
122
|
+
scaffoldPackageJson(targetDir, host, cwd, registryPath, hostKey);
|
|
120
123
|
scaffoldTsconfig(targetDir);
|
|
121
124
|
scaffoldViteConfig(targetDir, host, registryPath);
|
|
122
125
|
scaffoldEslintConfig(targetDir);
|
|
@@ -157,6 +160,11 @@ if (isPro) {
|
|
|
157
160
|
success("FREE: generated DevShell + local Inertia adapters");
|
|
158
161
|
}
|
|
159
162
|
|
|
163
|
+
// Host-specific production files (entry, vite config, theme CSS)
|
|
164
|
+
scaffoldHostEntry(targetDir, hostKey);
|
|
165
|
+
scaffoldHostViteConfig(targetDir, hostKey, host);
|
|
166
|
+
scaffoldHostThemeCSS(targetDir, hostKey, host);
|
|
167
|
+
|
|
160
168
|
// ── Step 9: npm install ──────────────────────────────────────────────────
|
|
161
169
|
|
|
162
170
|
heading(9, TOTAL_STEPS, "Installing dependencies");
|
|
@@ -173,6 +181,10 @@ heading(10, TOTAL_STEPS, "Done!");
|
|
|
173
181
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
174
182
|
blank();
|
|
175
183
|
|
|
184
|
+
// Determine host-specific build script name for display
|
|
185
|
+
const hostBuildScript = hostKey === "wordpress" ? "build:wp" : hostKey === "moodle" ? "build:moodle" : "build:host";
|
|
186
|
+
const hostWatchScript = hostKey === "wordpress" ? "watch:wp" : hostKey === "moodle" ? "watch:moodle" : "watch:host";
|
|
187
|
+
|
|
176
188
|
if (installOk) {
|
|
177
189
|
log(`MIDDAG React UI ready in ${dirName}/ (${elapsed}s)\n`);
|
|
178
190
|
console.log(" Start developing:");
|
|
@@ -194,6 +206,11 @@ console.log(" src/pages/settings.ts \u2190 advanced: tabbed_panel + fo
|
|
|
194
206
|
console.log(" src/blocks/hello-block.tsx \u2190 custom block example (rename me!)");
|
|
195
207
|
console.log(" src/app.tsx \u2190 hash-based page router");
|
|
196
208
|
|
|
209
|
+
blank();
|
|
210
|
+
console.log(` Production build for ${host.name}:`);
|
|
211
|
+
console.log(` npm run ${hostBuildScript} \u2192 build for ${host.name}`);
|
|
212
|
+
console.log(` npm run ${hostWatchScript} \u2192 rebuild on change`);
|
|
213
|
+
|
|
197
214
|
blank();
|
|
198
215
|
console.log(` Integrate with your ${host.name} plugin:`);
|
|
199
216
|
console.log(" 1. Import { ContractPage } from '@middag-io/react'");
|
package/lib/detect.js
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* detect.js — Host detection (Moodle / WordPress / Custom).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Detection strategy:
|
|
5
|
+
* - Moodle plugin: cwd has version.php with $plugin->component
|
|
6
|
+
* - WordPress: wp-config.php found in ancestor dirs (plugin/theme is 3+ levels deep)
|
|
7
|
+
* - Moodle root: ancestor has version.php WITHOUT $plugin->component
|
|
8
|
+
*
|
|
9
|
+
* Walks up to MAX_DEPTH ancestor directories from cwd.
|
|
5
10
|
*/
|
|
6
11
|
|
|
7
|
-
import { existsSync } from "node:fs";
|
|
8
|
-
import { join } from "node:path";
|
|
12
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
13
|
+
import { join, dirname } from "node:path";
|
|
14
|
+
|
|
15
|
+
/** Max ancestor levels to walk when searching for platform markers. */
|
|
16
|
+
const MAX_DEPTH = 5;
|
|
9
17
|
|
|
10
18
|
export const HOSTS = {
|
|
11
19
|
moodle: { name: "Moodle", detect: "version.php", port: 5174, headerHeight: 50 },
|
|
@@ -14,16 +22,74 @@ export const HOSTS = {
|
|
|
14
22
|
};
|
|
15
23
|
|
|
16
24
|
/**
|
|
17
|
-
*
|
|
25
|
+
* Check if a version.php file contains $plugin->component (Moodle plugin marker).
|
|
26
|
+
*
|
|
27
|
+
* @param {string} filePath - Path to version.php
|
|
28
|
+
* @returns {boolean}
|
|
29
|
+
*/
|
|
30
|
+
function isMoodlePluginVersion(filePath) {
|
|
31
|
+
try {
|
|
32
|
+
const content = readFileSync(filePath, "utf-8");
|
|
33
|
+
return /\$plugin\s*->\s*component\s*=/.test(content);
|
|
34
|
+
} catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Check if a version.php file is a Moodle root version.php.
|
|
41
|
+
* Root has $version but NOT $plugin->component.
|
|
42
|
+
*
|
|
43
|
+
* @param {string} filePath - Path to version.php
|
|
44
|
+
* @returns {boolean}
|
|
45
|
+
*/
|
|
46
|
+
function isMoodleRootVersion(filePath) {
|
|
47
|
+
try {
|
|
48
|
+
const content = readFileSync(filePath, "utf-8");
|
|
49
|
+
if (/\$plugin\s*->\s*component\s*=/.test(content)) return false;
|
|
50
|
+
// Moodle root has both $version and $release — distinguishes from generic version.php
|
|
51
|
+
return /\$version\s*=/.test(content) && /\$release\s*=/.test(content);
|
|
52
|
+
} catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Detect host platform by checking cwd and ancestor directories.
|
|
59
|
+
*
|
|
60
|
+
* Priority:
|
|
61
|
+
* 1. Moodle plugin — cwd has version.php with $plugin->component
|
|
62
|
+
* 2. WordPress — wp-config.php in any ancestor (up to MAX_DEPTH)
|
|
63
|
+
* 3. Moodle root — version.php without $plugin->component in any ancestor
|
|
18
64
|
*
|
|
19
65
|
* @param {string} cwd - Directory to check
|
|
20
66
|
* @returns {string|null} Host key ('moodle', 'wordpress') or null
|
|
21
67
|
*/
|
|
22
68
|
export function detectHost(cwd) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
69
|
+
// 1. Moodle plugin — version.php in cwd with $plugin->component
|
|
70
|
+
const cwdVersion = join(cwd, "version.php");
|
|
71
|
+
if (existsSync(cwdVersion) && isMoodlePluginVersion(cwdVersion)) {
|
|
72
|
+
return "moodle";
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 2. Walk ancestors for WordPress (wp-config.php) or Moodle root (version.php)
|
|
76
|
+
let dir = cwd;
|
|
77
|
+
for (let i = 0; i < MAX_DEPTH; i++) {
|
|
78
|
+
const parent = dirname(dir);
|
|
79
|
+
if (parent === dir) break;
|
|
80
|
+
dir = parent;
|
|
81
|
+
|
|
82
|
+
// WordPress — wp-config.php
|
|
83
|
+
if (existsSync(join(dir, "wp-config.php"))) {
|
|
84
|
+
return "wordpress";
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Moodle root — version.php without $plugin->component
|
|
88
|
+
const versionFile = join(dir, "version.php");
|
|
89
|
+
if (existsSync(versionFile) && isMoodleRootVersion(versionFile)) {
|
|
90
|
+
return "moodle";
|
|
26
91
|
}
|
|
27
92
|
}
|
|
93
|
+
|
|
28
94
|
return null;
|
|
29
95
|
}
|
package/lib/scaffold.js
CHANGED
|
@@ -77,8 +77,9 @@ export function createTargetDir(targetDir) {
|
|
|
77
77
|
*/
|
|
78
78
|
/**
|
|
79
79
|
* @param {string} registryPath - "github" (PRO) or "public" (FREE)
|
|
80
|
+
* @param {string} [hostKey] - 'wordpress' | 'moodle' | 'custom' (adds host build scripts)
|
|
80
81
|
*/
|
|
81
|
-
export function scaffoldPackageJson(targetDir, host, cwd, registryPath) {
|
|
82
|
+
export function scaffoldPackageJson(targetDir, host, cwd, registryPath, hostKey) {
|
|
82
83
|
const filePath = join(targetDir, "package.json");
|
|
83
84
|
if (skipIfExists(filePath, "package.json")) return;
|
|
84
85
|
|
|
@@ -93,19 +94,33 @@ export function scaffoldPackageJson(targetDir, host, cwd, registryPath) {
|
|
|
93
94
|
deps["sonner"] = "^2.0.0";
|
|
94
95
|
}
|
|
95
96
|
|
|
97
|
+
const scripts = {
|
|
98
|
+
dev: "vite",
|
|
99
|
+
build: "vite build",
|
|
100
|
+
typecheck: "tsc --noEmit",
|
|
101
|
+
lint: "eslint .",
|
|
102
|
+
"lint:fix": "eslint . --fix",
|
|
103
|
+
format: 'prettier --write "src/**/*.{ts,tsx,css}"',
|
|
104
|
+
"format:check": 'prettier --check "src/**/*.{ts,tsx,css}"',
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// Add host-specific build/watch scripts
|
|
108
|
+
if (hostKey === "wordpress") {
|
|
109
|
+
scripts["build:wp"] = "vite build --config vite.config.wordpress.ts";
|
|
110
|
+
scripts["watch:wp"] = "vite build --config vite.config.wordpress.ts --watch";
|
|
111
|
+
} else if (hostKey === "moodle") {
|
|
112
|
+
scripts["build:moodle"] = "vite build --config vite.config.moodle.ts";
|
|
113
|
+
scripts["watch:moodle"] = "vite build --config vite.config.moodle.ts --watch";
|
|
114
|
+
} else if (hostKey === "custom") {
|
|
115
|
+
scripts["build:host"] = "vite build --config vite.config.custom.ts";
|
|
116
|
+
scripts["watch:host"] = "vite build --config vite.config.custom.ts --watch";
|
|
117
|
+
}
|
|
118
|
+
|
|
96
119
|
const pkg = {
|
|
97
120
|
name: `${projectName}-ui`,
|
|
98
121
|
private: true,
|
|
99
122
|
type: "module",
|
|
100
|
-
scripts
|
|
101
|
-
dev: "vite",
|
|
102
|
-
build: "vite build",
|
|
103
|
-
typecheck: "tsc --noEmit",
|
|
104
|
-
lint: "eslint .",
|
|
105
|
-
"lint:fix": "eslint . --fix",
|
|
106
|
-
format: 'prettier --write "src/**/*.{ts,tsx,css}"',
|
|
107
|
-
"format:check": 'prettier --check "src/**/*.{ts,tsx,css}"',
|
|
108
|
-
},
|
|
123
|
+
scripts,
|
|
109
124
|
dependencies: deps,
|
|
110
125
|
devDependencies: {
|
|
111
126
|
"@types/react": "^19.0.0",
|
|
@@ -185,6 +200,9 @@ import { resolve } from "path";
|
|
|
185
200
|
export default defineConfig({
|
|
186
201
|
plugins: [react()],
|
|
187
202
|
server: { port: ${host.port} },
|
|
203
|
+
optimizeDeps: {
|
|
204
|
+
include: ["@middag-io/react", "@middag-io/react/mock"],
|
|
205
|
+
},
|
|
188
206
|
resolve: {
|
|
189
207
|
alias: {
|
|
190
208
|
"@/": resolve(__dirname, "src") + "/",
|
|
@@ -1231,6 +1249,301 @@ export function App() {
|
|
|
1231
1249
|
}
|
|
1232
1250
|
}
|
|
1233
1251
|
|
|
1252
|
+
// ── Host-specific production files ─────────────────────────────────────
|
|
1253
|
+
|
|
1254
|
+
/**
|
|
1255
|
+
* Scaffold production entry point: src/entry-{hostKey}.tsx.
|
|
1256
|
+
* Uses real createInertiaApp — no mocks.
|
|
1257
|
+
*
|
|
1258
|
+
* @param {string} targetDir - Absolute path to UI dir
|
|
1259
|
+
* @param {string} hostKey - 'wordpress' | 'moodle' | 'custom'
|
|
1260
|
+
*/
|
|
1261
|
+
export function scaffoldHostEntry(targetDir, hostKey) {
|
|
1262
|
+
ensureDir(join(targetDir, "src"));
|
|
1263
|
+
|
|
1264
|
+
const filePath = join(targetDir, "src", `entry-${hostKey}.tsx`);
|
|
1265
|
+
const label = `src/entry-${hostKey}.tsx`;
|
|
1266
|
+
if (skipIfExists(filePath, label)) return;
|
|
1267
|
+
|
|
1268
|
+
// Host-specific setup and post-mount code
|
|
1269
|
+
let setupCode = "";
|
|
1270
|
+
let postMountCode = "";
|
|
1271
|
+
|
|
1272
|
+
if (hostKey === "wordpress") {
|
|
1273
|
+
setupCode = ` document.body.classList.add("middag-active");`;
|
|
1274
|
+
postMountCode = `
|
|
1275
|
+
// Relocate WP admin notices into the product shell content area
|
|
1276
|
+
const noticeContainer = document.createElement("div");
|
|
1277
|
+
noticeContainer.className = "middag-wp-notices";
|
|
1278
|
+
const observer = new MutationObserver(() => {
|
|
1279
|
+
const content = document.querySelector(".product-shell__content");
|
|
1280
|
+
if (!content) return;
|
|
1281
|
+
const notices = document.querySelectorAll(
|
|
1282
|
+
"#wpbody-content > .notice, #wpbody-content > .update-nag, #wpbody-content > .updated, #wpbody-content > .error",
|
|
1283
|
+
);
|
|
1284
|
+
if (notices.length > 0) {
|
|
1285
|
+
notices.forEach((n) => noticeContainer.appendChild(n));
|
|
1286
|
+
if (!noticeContainer.parentElement) {
|
|
1287
|
+
content.prepend(noticeContainer);
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
});
|
|
1291
|
+
observer.observe(document.body, { childList: true, subtree: true });`;
|
|
1292
|
+
} else if (hostKey === "moodle") {
|
|
1293
|
+
setupCode = ` document.body.classList.add("middag-active");`;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
const content = `/**
|
|
1297
|
+
* Production entry point for ${hostKey === "wordpress" ? "WordPress" : hostKey === "moodle" ? "Moodle" : "custom host"}.
|
|
1298
|
+
*
|
|
1299
|
+
* Uses real createInertiaApp — the host platform (${hostKey === "wordpress" ? "WP" : hostKey === "moodle" ? "Moodle" : "your backend"})
|
|
1300
|
+
* serves the HTML and Inertia page props. This file is the build target
|
|
1301
|
+
* for \`npm run build:${hostKey === "custom" ? "host" : hostKey}\`.
|
|
1302
|
+
*
|
|
1303
|
+
* NOT used by \`npm run dev\` — that uses src/main.tsx with mock adapters.
|
|
1304
|
+
*/
|
|
1305
|
+
import { createRoot } from "react-dom/client";
|
|
1306
|
+
import { createInertiaApp } from "@inertiajs/react";
|
|
1307
|
+
import {
|
|
1308
|
+
registerDefaults,
|
|
1309
|
+
registerShell,
|
|
1310
|
+
ContractPage,
|
|
1311
|
+
HostProductShell,
|
|
1312
|
+
I18nProvider,
|
|
1313
|
+
ProgressProvider,
|
|
1314
|
+
ptBR,
|
|
1315
|
+
} from "@middag-io/react";
|
|
1316
|
+
import type { PageContract } from "@middag-io/react";
|
|
1317
|
+
import "@middag-io/react/style.css";
|
|
1318
|
+
import "./theme.css";
|
|
1319
|
+
|
|
1320
|
+
registerDefaults();
|
|
1321
|
+
registerShell("product", HostProductShell);
|
|
1322
|
+
|
|
1323
|
+
createInertiaApp({
|
|
1324
|
+
id: "middag-app",
|
|
1325
|
+
resolve: () => {
|
|
1326
|
+
const Page = ({ contract }: { contract: PageContract }) => (
|
|
1327
|
+
<I18nProvider overrides={ptBR}>
|
|
1328
|
+
<ProgressProvider>
|
|
1329
|
+
<ContractPage contract={contract} />
|
|
1330
|
+
</ProgressProvider>
|
|
1331
|
+
</I18nProvider>
|
|
1332
|
+
);
|
|
1333
|
+
Page.displayName = "ContractPageWrapper";
|
|
1334
|
+
return Page;
|
|
1335
|
+
},
|
|
1336
|
+
setup({ el, App, props }) {
|
|
1337
|
+
el.classList.add("middag-root");
|
|
1338
|
+
${setupCode}
|
|
1339
|
+
createRoot(el).render(<App {...props} />);
|
|
1340
|
+
${postMountCode}
|
|
1341
|
+
},
|
|
1342
|
+
});
|
|
1343
|
+
`;
|
|
1344
|
+
|
|
1345
|
+
writeFile(filePath, content, label);
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
/**
|
|
1349
|
+
* Scaffold host-specific Vite build config: vite.config.{hostKey}.ts.
|
|
1350
|
+
*
|
|
1351
|
+
* @param {string} targetDir - Absolute path to UI dir
|
|
1352
|
+
* @param {string} hostKey - 'wordpress' | 'moodle' | 'custom'
|
|
1353
|
+
* @param {object} host - HOSTS[hostKey] object
|
|
1354
|
+
*/
|
|
1355
|
+
export function scaffoldHostViteConfig(targetDir, hostKey, host) {
|
|
1356
|
+
const filePath = join(targetDir, `vite.config.${hostKey}.ts`);
|
|
1357
|
+
const label = `vite.config.${hostKey}.ts`;
|
|
1358
|
+
if (skipIfExists(filePath, label)) return;
|
|
1359
|
+
|
|
1360
|
+
let outDir, formats, libName, fileName, extraRollup;
|
|
1361
|
+
|
|
1362
|
+
if (hostKey === "wordpress") {
|
|
1363
|
+
outDir = `resolve(__dirname, "../assets/dist")`;
|
|
1364
|
+
formats = `["iife"]`;
|
|
1365
|
+
libName = `"MiddagUI"`;
|
|
1366
|
+
fileName = `() => "app.js"`;
|
|
1367
|
+
extraRollup = `
|
|
1368
|
+
output: {
|
|
1369
|
+
assetFileNames: (assetInfo) => {
|
|
1370
|
+
if (assetInfo.name?.endsWith(".css")) return "style.css";
|
|
1371
|
+
return assetInfo.name || "[name]-[hash][extname]";
|
|
1372
|
+
},
|
|
1373
|
+
},`;
|
|
1374
|
+
} else if (hostKey === "moodle") {
|
|
1375
|
+
outDir = `resolve(__dirname, "../amd/build")`;
|
|
1376
|
+
formats = `["iife"]`;
|
|
1377
|
+
libName = `"MiddagUI"`;
|
|
1378
|
+
fileName = `() => "app.js"`;
|
|
1379
|
+
extraRollup = `
|
|
1380
|
+
output: {
|
|
1381
|
+
assetFileNames: (assetInfo) => {
|
|
1382
|
+
if (assetInfo.name?.endsWith(".css")) return "style.css";
|
|
1383
|
+
return assetInfo.name || "[name]-[hash][extname]";
|
|
1384
|
+
},
|
|
1385
|
+
},`;
|
|
1386
|
+
} else {
|
|
1387
|
+
outDir = `resolve(__dirname, "../dist")`;
|
|
1388
|
+
formats = `["es"]`;
|
|
1389
|
+
libName = `"MiddagUI"`;
|
|
1390
|
+
fileName = `() => "app.js"`;
|
|
1391
|
+
extraRollup = `
|
|
1392
|
+
output: {
|
|
1393
|
+
assetFileNames: (assetInfo) => {
|
|
1394
|
+
if (assetInfo.name?.endsWith(".css")) return "style.css";
|
|
1395
|
+
return assetInfo.name || "[name]-[hash][extname]";
|
|
1396
|
+
},
|
|
1397
|
+
},`;
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
const content = `/**
|
|
1401
|
+
* Vite build config for ${host.name} — production build target.
|
|
1402
|
+
*
|
|
1403
|
+
* Usage:
|
|
1404
|
+
* npm run build:${hostKey === "custom" ? "host" : hostKey} \u2192 single build
|
|
1405
|
+
* npm run watch:${hostKey === "custom" ? "host" : hostKey} \u2192 rebuild on change
|
|
1406
|
+
*
|
|
1407
|
+
* This config builds src/entry-${hostKey}.tsx into a${hostKey === "custom" ? "n ESM" : "n IIFE"} bundle.
|
|
1408
|
+
* The dev server (\`npm run dev\`) uses vite.config.ts instead.
|
|
1409
|
+
*/
|
|
1410
|
+
import { defineConfig } from "vite";
|
|
1411
|
+
import react from "@vitejs/plugin-react";
|
|
1412
|
+
import { resolve } from "path";
|
|
1413
|
+
|
|
1414
|
+
export default defineConfig({
|
|
1415
|
+
plugins: [react()],
|
|
1416
|
+
define: { "process.env.NODE_ENV": JSON.stringify("production") },
|
|
1417
|
+
resolve: { alias: { "@/": resolve(__dirname, "src") + "/" } },
|
|
1418
|
+
build: {
|
|
1419
|
+
outDir: ${outDir},
|
|
1420
|
+
emptyOutDir: true,
|
|
1421
|
+
lib: {
|
|
1422
|
+
entry: resolve(__dirname, "src/entry-${hostKey}.tsx"),
|
|
1423
|
+
formats: ${formats},
|
|
1424
|
+
name: ${libName},
|
|
1425
|
+
fileName: ${fileName},
|
|
1426
|
+
},
|
|
1427
|
+
cssCodeSplit: false,
|
|
1428
|
+
rollupOptions: {${extraRollup}
|
|
1429
|
+
},
|
|
1430
|
+
},
|
|
1431
|
+
});
|
|
1432
|
+
`;
|
|
1433
|
+
|
|
1434
|
+
writeFile(filePath, content, label);
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
/**
|
|
1438
|
+
* Append host-specific CSS to src/theme.css.
|
|
1439
|
+
* If theme.css doesn't exist yet, it will be created by scaffoldDemoFiles.
|
|
1440
|
+
*
|
|
1441
|
+
* @param {string} targetDir - Absolute path to UI dir
|
|
1442
|
+
* @param {string} hostKey - 'wordpress' | 'moodle' | 'custom'
|
|
1443
|
+
* @param {object} host - HOSTS[hostKey] object
|
|
1444
|
+
*/
|
|
1445
|
+
export function scaffoldHostThemeCSS(targetDir, hostKey, host) {
|
|
1446
|
+
const themePath = join(targetDir, "src", "theme.css");
|
|
1447
|
+
|
|
1448
|
+
let hostSection = "";
|
|
1449
|
+
|
|
1450
|
+
if (hostKey === "wordpress") {
|
|
1451
|
+
hostSection = `
|
|
1452
|
+
|
|
1453
|
+
/* \u2500\u2500 WordPress admin integration \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
1454
|
+
* Active when MIDDAG mounts inside wp-admin (body.middag-active).
|
|
1455
|
+
*/
|
|
1456
|
+
|
|
1457
|
+
body.middag-active #wpbody-content {
|
|
1458
|
+
padding-bottom: 0;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
body.middag-active [data-slot="sidebar-container"] {
|
|
1462
|
+
left: 160px !important;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
body.folded.middag-active [data-slot="sidebar-container"] {
|
|
1466
|
+
left: 36px !important;
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
@media screen and (max-width: 782px) {
|
|
1470
|
+
body.middag-active [data-slot="sidebar-container"] {
|
|
1471
|
+
left: 0 !important;
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
body.middag-active #wpbody-content > .notice,
|
|
1476
|
+
body.middag-active #wpbody-content > .update-nag,
|
|
1477
|
+
body.middag-active #wpbody-content > .updated,
|
|
1478
|
+
body.middag-active #wpbody-content > .error {
|
|
1479
|
+
display: none !important;
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
.middag-wp-notices {
|
|
1483
|
+
padding: 0.75rem 1.5rem 0;
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
.middag-wp-notices .notice {
|
|
1487
|
+
display: block !important;
|
|
1488
|
+
margin: 0 0 0.5rem;
|
|
1489
|
+
border-radius: var(--radius, 0.5rem);
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
body.middag-active #wpfooter {
|
|
1493
|
+
display: none !important;
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
body.middag-active {
|
|
1497
|
+
--host-header-height: 32px;
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
@media screen and (max-width: 782px) {
|
|
1501
|
+
body.middag-active {
|
|
1502
|
+
--host-header-height: 46px;
|
|
1503
|
+
}
|
|
1504
|
+
}`;
|
|
1505
|
+
} else if (hostKey === "moodle") {
|
|
1506
|
+
hostSection = `
|
|
1507
|
+
|
|
1508
|
+
/* \u2500\u2500 Moodle Boost integration \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
1509
|
+
* Active when MIDDAG mounts inside Moodle admin (body.middag-active).
|
|
1510
|
+
*/
|
|
1511
|
+
|
|
1512
|
+
body.middag-active {
|
|
1513
|
+
--host-header-height: 50px;
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
body.middag-active [data-slot="sidebar-container"] {
|
|
1517
|
+
left: 0 !important;
|
|
1518
|
+
}`;
|
|
1519
|
+
} else {
|
|
1520
|
+
hostSection = `
|
|
1521
|
+
|
|
1522
|
+
/* \u2500\u2500 Host integration \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
1523
|
+
* Set --host-header-height and --host-sidebar-width as needed.
|
|
1524
|
+
*/
|
|
1525
|
+
|
|
1526
|
+
:root {
|
|
1527
|
+
--host-header-height: 0px;
|
|
1528
|
+
--host-sidebar-width: 0px;
|
|
1529
|
+
}`;
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
// If theme.css exists, append; otherwise create with host section only
|
|
1533
|
+
if (existsSync(themePath)) {
|
|
1534
|
+
try {
|
|
1535
|
+
const existing = readFileSync(themePath, "utf-8");
|
|
1536
|
+
writeFileSync(themePath, existing + hostSection + "\n");
|
|
1537
|
+
success(`Appended ${host.name} integration CSS to src/theme.css`);
|
|
1538
|
+
} catch (err) {
|
|
1539
|
+
error(`Failed to append to src/theme.css: ${err.message}`);
|
|
1540
|
+
}
|
|
1541
|
+
} else {
|
|
1542
|
+
ensureDir(join(targetDir, "src"));
|
|
1543
|
+
writeFile(themePath, hostSection.trimStart() + "\n", "src/theme.css (host integration)");
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1234
1547
|
// ── LEGACY (kept for backward compat, delegates to FREE) ────────────────
|
|
1235
1548
|
|
|
1236
1549
|
/** @deprecated Use scaffoldFreeApp + scaffoldFreeAdapters instead */
|