@onexapis/cli 1.1.16 → 1.1.17
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 +46 -46
- package/bin/onexthm.js +4 -0
- package/dist/cli.js +230 -44
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +230 -44
- package/dist/cli.mjs.map +1 -1
- package/dist/index.js +115 -29
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +115 -29
- package/dist/index.mjs.map +1 -1
- package/dist/preview/preview-app.tsx +175 -53
- package/package.json +14 -12
package/dist/cli.js
CHANGED
|
@@ -8,13 +8,13 @@ var path8 = require('path');
|
|
|
8
8
|
var fs7 = require('fs/promises');
|
|
9
9
|
var crypto = require('crypto');
|
|
10
10
|
var glob = require('glob');
|
|
11
|
+
var module$1 = require('module');
|
|
11
12
|
var os = require('os');
|
|
12
13
|
var dotenv = require('dotenv');
|
|
13
14
|
var fs = require('fs-extra');
|
|
14
15
|
var ejs = require('ejs');
|
|
15
16
|
var child_process = require('child_process');
|
|
16
17
|
var commander = require('commander');
|
|
17
|
-
var module$1 = require('module');
|
|
18
18
|
var fs2 = require('fs');
|
|
19
19
|
var inquirer = require('inquirer');
|
|
20
20
|
var archiver = require('archiver');
|
|
@@ -285,6 +285,12 @@ function createThemeDepsStubPlugin(themePath) {
|
|
|
285
285
|
if (!result.errors.length) return result;
|
|
286
286
|
} catch {
|
|
287
287
|
}
|
|
288
|
+
try {
|
|
289
|
+
const req = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)) || __filename);
|
|
290
|
+
const resolved = req.resolve(args.path);
|
|
291
|
+
if (resolved) return { path: resolved, namespace: "file" };
|
|
292
|
+
} catch {
|
|
293
|
+
}
|
|
288
294
|
return { path: args.path, namespace };
|
|
289
295
|
});
|
|
290
296
|
};
|
|
@@ -293,11 +299,19 @@ function createThemeDepsStubPlugin(themePath) {
|
|
|
293
299
|
const stubs = {
|
|
294
300
|
"next/image": `
|
|
295
301
|
import React from 'react';
|
|
296
|
-
const Image = (props) => {
|
|
297
|
-
const { src, alt, width, height, fill, priority, ...rest } = props;
|
|
302
|
+
const Image = React.forwardRef((props, ref) => {
|
|
303
|
+
const { src, alt, width, height, fill, priority, sizes, quality, placeholder, blurDataURL, onLoad, onError, style, className, ...rest } = props;
|
|
298
304
|
const imgSrc = typeof src === 'object' ? src.src : src;
|
|
299
|
-
|
|
300
|
-
};
|
|
305
|
+
const fillStyle = fill ? { position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: style?.objectFit || 'cover', display: 'block' } : {};
|
|
306
|
+
const mergedStyle = { ...fillStyle, ...style };
|
|
307
|
+
return React.createElement('img', {
|
|
308
|
+
ref, src: imgSrc, alt,
|
|
309
|
+
width: fill ? undefined : width, height: fill ? undefined : height,
|
|
310
|
+
loading: priority ? 'eager' : 'lazy',
|
|
311
|
+
style: Object.keys(mergedStyle).length > 0 ? mergedStyle : undefined,
|
|
312
|
+
className, onLoad, onError, ...rest,
|
|
313
|
+
});
|
|
314
|
+
});
|
|
301
315
|
export default Image;
|
|
302
316
|
`,
|
|
303
317
|
"next/link": `
|
|
@@ -331,7 +345,10 @@ export function headers() { return new Headers(); }
|
|
|
331
345
|
if (!lucideThemeScanned) {
|
|
332
346
|
lucideThemeScanned = true;
|
|
333
347
|
try {
|
|
334
|
-
const scanned = await scanImportsFromPackage(
|
|
348
|
+
const scanned = await scanImportsFromPackage(
|
|
349
|
+
themePath,
|
|
350
|
+
"lucide-react"
|
|
351
|
+
);
|
|
335
352
|
for (const names of Object.values(scanned)) {
|
|
336
353
|
for (const name of names) lucideImports.add(name);
|
|
337
354
|
}
|
|
@@ -394,10 +411,13 @@ export function useFormContext() { return useForm(); }
|
|
|
394
411
|
loader: "js"
|
|
395
412
|
}));
|
|
396
413
|
tryResolveOrStub(/^@hookform\/resolvers/, "hookform-resolvers-stub");
|
|
397
|
-
build2.onLoad(
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
414
|
+
build2.onLoad(
|
|
415
|
+
{ filter: /.*/, namespace: "hookform-resolvers-stub" },
|
|
416
|
+
() => ({
|
|
417
|
+
contents: `export function zodResolver() { return () => ({ values: {}, errors: {} }); }`,
|
|
418
|
+
loader: "js"
|
|
419
|
+
})
|
|
420
|
+
);
|
|
401
421
|
tryResolveOrStub(/^next-intl$/, "next-intl-stub");
|
|
402
422
|
build2.onLoad({ filter: /.*/, namespace: "next-intl-stub" }, () => ({
|
|
403
423
|
contents: `
|
|
@@ -655,7 +675,11 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
655
675
|
banner: {
|
|
656
676
|
js: '"use client";'
|
|
657
677
|
},
|
|
658
|
-
plugins: [
|
|
678
|
+
plugins: [
|
|
679
|
+
reactGlobalPlugin,
|
|
680
|
+
createCoreGlobalPlugin(themePath),
|
|
681
|
+
createThemeDepsStubPlugin(themePath)
|
|
682
|
+
],
|
|
659
683
|
external: [],
|
|
660
684
|
alias: {
|
|
661
685
|
events: "events/",
|
|
@@ -737,7 +761,11 @@ async function compileStandaloneThemeDev(themePath, themeName) {
|
|
|
737
761
|
banner: {
|
|
738
762
|
js: '"use client";'
|
|
739
763
|
},
|
|
740
|
-
plugins: [
|
|
764
|
+
plugins: [
|
|
765
|
+
reactGlobalPlugin,
|
|
766
|
+
createCoreGlobalPlugin(themePath),
|
|
767
|
+
createThemeDepsStubPlugin(themePath)
|
|
768
|
+
],
|
|
741
769
|
external: [],
|
|
742
770
|
alias: {
|
|
743
771
|
events: "events/",
|
|
@@ -872,7 +900,16 @@ ${locations.join("\n")}`
|
|
|
872
900
|
path8__default.default.join(themePath, "node_modules", "@onexapis", "core", "src"),
|
|
873
901
|
path8__default.default.join(themePath, "..", "..", "packages", "core", "src"),
|
|
874
902
|
// monorepo sibling
|
|
875
|
-
path8__default.default.join(
|
|
903
|
+
path8__default.default.join(
|
|
904
|
+
__dirname,
|
|
905
|
+
"..",
|
|
906
|
+
"..",
|
|
907
|
+
"..",
|
|
908
|
+
"..",
|
|
909
|
+
"packages",
|
|
910
|
+
"core",
|
|
911
|
+
"src"
|
|
912
|
+
)
|
|
876
913
|
// from CLI src
|
|
877
914
|
];
|
|
878
915
|
let coreSourceDir = null;
|
|
@@ -886,7 +923,10 @@ ${locations.join("\n")}`
|
|
|
886
923
|
}
|
|
887
924
|
if (coreSourceDir) {
|
|
888
925
|
try {
|
|
889
|
-
const scanned = await scanImportsFromPackage(
|
|
926
|
+
const scanned = await scanImportsFromPackage(
|
|
927
|
+
coreSourceDir,
|
|
928
|
+
"lucide-react"
|
|
929
|
+
);
|
|
890
930
|
for (const names of Object.values(scanned)) {
|
|
891
931
|
for (const name of names) lucideIconNames.add(name);
|
|
892
932
|
}
|
|
@@ -907,7 +947,10 @@ ${locations.join("\n")}`
|
|
|
907
947
|
const mjsFiles = await glob.glob("*.mjs", { cwd: candidate });
|
|
908
948
|
const importRegex = /import\s*\{([^}]+)\}\s*from\s*["']lucide-react["']/g;
|
|
909
949
|
for (const file of mjsFiles) {
|
|
910
|
-
const content = await fs7__default.default.readFile(
|
|
950
|
+
const content = await fs7__default.default.readFile(
|
|
951
|
+
path8__default.default.join(candidate, file),
|
|
952
|
+
"utf-8"
|
|
953
|
+
);
|
|
911
954
|
for (const match of content.matchAll(importRegex)) {
|
|
912
955
|
for (const name of match[1].split(",")) {
|
|
913
956
|
const original = name.trim().split(/\s+as\s+/)[0].trim();
|
|
@@ -923,7 +966,10 @@ ${locations.join("\n")}`
|
|
|
923
966
|
}
|
|
924
967
|
}
|
|
925
968
|
try {
|
|
926
|
-
const scanned = await scanImportsFromPackage(
|
|
969
|
+
const scanned = await scanImportsFromPackage(
|
|
970
|
+
themePath,
|
|
971
|
+
"lucide-react"
|
|
972
|
+
);
|
|
927
973
|
for (const names of Object.values(scanned)) {
|
|
928
974
|
for (const name of names) lucideIconNames.add(name);
|
|
929
975
|
}
|
|
@@ -953,14 +999,39 @@ export default new Proxy({}, { get: (_, name) => name === '__esModule' ? true :
|
|
|
953
999
|
if (!result.errors.length) return result;
|
|
954
1000
|
} catch {
|
|
955
1001
|
}
|
|
1002
|
+
try {
|
|
1003
|
+
const req = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)) || __filename);
|
|
1004
|
+
const cjsPath = req.resolve("framer-motion");
|
|
1005
|
+
const pkgDir = cjsPath.replace(/[/\\]dist[/\\].*$/, "");
|
|
1006
|
+
const esmEntry = path8__default.default.join(pkgDir, "dist", "es", "index.mjs");
|
|
1007
|
+
const { existsSync } = await import('fs');
|
|
1008
|
+
if (existsSync(esmEntry)) {
|
|
1009
|
+
return { path: esmEntry, namespace: "file" };
|
|
1010
|
+
}
|
|
1011
|
+
return { path: cjsPath, namespace: "file" };
|
|
1012
|
+
} catch {
|
|
1013
|
+
}
|
|
956
1014
|
return { path: args.path, namespace: "motion-stub" };
|
|
957
1015
|
});
|
|
958
1016
|
build2.onLoad({ filter: /.*/, namespace: "motion-stub" }, () => ({
|
|
959
1017
|
contents: `
|
|
960
|
-
|
|
961
|
-
const
|
|
1018
|
+
import React from 'react';
|
|
1019
|
+
const MotionComponent = React.forwardRef((props, ref) => {
|
|
1020
|
+
const { initial, animate, exit, variants, transition, whileInView, whileHover, whileTap, viewport, onAnimationComplete, layout, layoutId, style, className, ...rest } = props;
|
|
1021
|
+
return React.createElement(rest.as || 'div', { ref, style, className, ...rest }, rest.children);
|
|
1022
|
+
});
|
|
1023
|
+
const handler = { get: (_, name) => {
|
|
1024
|
+
if (name === '__esModule') return true;
|
|
1025
|
+
if (name === 'create') return () => new Proxy({}, handler);
|
|
1026
|
+
return MotionComponent;
|
|
1027
|
+
}};
|
|
962
1028
|
export const motion = new Proxy({}, handler);
|
|
963
|
-
export const AnimatePresence =
|
|
1029
|
+
export const AnimatePresence = (props) => props.children || null;
|
|
1030
|
+
export const useInView = () => true;
|
|
1031
|
+
export const useAnimation = () => ({ start: () => {}, stop: () => {}, set: () => {} });
|
|
1032
|
+
export const useMotionValue = (v) => ({ get: () => v, set: () => {}, onChange: () => () => {} });
|
|
1033
|
+
export const useTransform = (v) => v;
|
|
1034
|
+
export const useScroll = () => ({ scrollY: { get: () => 0, onChange: () => () => {} }, scrollYProgress: { get: () => 0, onChange: () => () => {} } });
|
|
964
1035
|
export default { motion, AnimatePresence };
|
|
965
1036
|
`.trim(),
|
|
966
1037
|
loader: "jsx"
|
|
@@ -983,12 +1054,26 @@ export default { motion, AnimatePresence };
|
|
|
983
1054
|
build2.onLoad({ filter: /.*/, namespace: "next-stub" }, (args) => {
|
|
984
1055
|
const stubs = {
|
|
985
1056
|
"next/image": `
|
|
986
|
-
const Image = (props) => {
|
|
987
|
-
const { src, alt, width, height, fill, priority, ...rest } = props;
|
|
988
|
-
const imgSrc = typeof src === 'object' ? src.src : src;
|
|
989
|
-
return React.createElement('img', { src: imgSrc, alt, width: fill ? undefined : width, height: fill ? undefined : height, loading: priority ? 'eager' : 'lazy', ...rest });
|
|
990
|
-
};
|
|
991
1057
|
import React from 'react';
|
|
1058
|
+
const Image = React.forwardRef((props, ref) => {
|
|
1059
|
+
const { src, alt, width, height, fill, priority, sizes, quality, placeholder, blurDataURL, onLoad, onError, style, className, ...rest } = props;
|
|
1060
|
+
const imgSrc = typeof src === 'object' ? src.src : src;
|
|
1061
|
+
const fillStyle = fill ? { position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: style?.objectFit || 'cover', display: 'block' } : {};
|
|
1062
|
+
const mergedStyle = { ...fillStyle, ...style };
|
|
1063
|
+
return React.createElement('img', {
|
|
1064
|
+
ref,
|
|
1065
|
+
src: imgSrc,
|
|
1066
|
+
alt,
|
|
1067
|
+
width: fill ? undefined : width,
|
|
1068
|
+
height: fill ? undefined : height,
|
|
1069
|
+
loading: priority ? 'eager' : 'lazy',
|
|
1070
|
+
style: Object.keys(mergedStyle).length > 0 ? mergedStyle : undefined,
|
|
1071
|
+
className,
|
|
1072
|
+
onLoad,
|
|
1073
|
+
onError,
|
|
1074
|
+
...rest,
|
|
1075
|
+
});
|
|
1076
|
+
});
|
|
992
1077
|
export default Image;
|
|
993
1078
|
`,
|
|
994
1079
|
"next/link": `
|
|
@@ -1487,7 +1572,7 @@ Add your theme-specific blocks here.
|
|
|
1487
1572
|
try {
|
|
1488
1573
|
child_process.execSync("git init", { cwd: projectPath, stdio: "ignore" });
|
|
1489
1574
|
child_process.execSync("git add .", { cwd: projectPath, stdio: "ignore" });
|
|
1490
|
-
child_process.execSync('git commit -m "Initial commit from
|
|
1575
|
+
child_process.execSync('git commit -m "Initial commit from onexthm init"', {
|
|
1491
1576
|
cwd: projectPath,
|
|
1492
1577
|
stdio: "ignore"
|
|
1493
1578
|
});
|
|
@@ -2837,7 +2922,7 @@ async function buildCommand(options) {
|
|
|
2837
2922
|
logger.stopSpinner(true, "Lint passed");
|
|
2838
2923
|
const pkgJson = fs__default.default.readJsonSync(packageJsonPath);
|
|
2839
2924
|
const buildScript = pkgJson.scripts?.build || "";
|
|
2840
|
-
const isRecursive = buildScript.includes("
|
|
2925
|
+
const isRecursive = buildScript.includes("onexthm build") || buildScript.includes("onex-cli build");
|
|
2841
2926
|
logger.startSpinner(
|
|
2842
2927
|
options.watch ? "Building (watch mode)..." : "Building..."
|
|
2843
2928
|
);
|
|
@@ -2983,7 +3068,7 @@ async function packageCommand(options) {
|
|
|
2983
3068
|
logger.newLine();
|
|
2984
3069
|
logger.section("Next steps:");
|
|
2985
3070
|
logger.log(
|
|
2986
|
-
`
|
|
3071
|
+
` onexthm deploy --package ${path8__default.default.relative(process.cwd(), outputPath)}`
|
|
2987
3072
|
);
|
|
2988
3073
|
} catch (error) {
|
|
2989
3074
|
logger.stopSpinner(false, "Failed to create package");
|
|
@@ -3045,7 +3130,7 @@ async function deployCommand(options) {
|
|
|
3045
3130
|
} else if (options.theme) {
|
|
3046
3131
|
const distDir = path8__default.default.join(process.cwd(), "dist");
|
|
3047
3132
|
if (!fs__default.default.existsSync(distDir)) {
|
|
3048
|
-
logger.error("No dist/ directory found. Run '
|
|
3133
|
+
logger.error("No dist/ directory found. Run 'onexthm package' first.");
|
|
3049
3134
|
process.exit(1);
|
|
3050
3135
|
}
|
|
3051
3136
|
const files = fs__default.default.readdirSync(distDir);
|
|
@@ -3054,7 +3139,7 @@ async function deployCommand(options) {
|
|
|
3054
3139
|
);
|
|
3055
3140
|
if (packageFiles.length === 0) {
|
|
3056
3141
|
logger.error(`No package found for theme "${options.theme}".`);
|
|
3057
|
-
logger.info("Run:
|
|
3142
|
+
logger.info("Run: onexthm package --theme " + options.theme);
|
|
3058
3143
|
process.exit(1);
|
|
3059
3144
|
}
|
|
3060
3145
|
packageFiles.sort().reverse();
|
|
@@ -3062,8 +3147,8 @@ async function deployCommand(options) {
|
|
|
3062
3147
|
} else {
|
|
3063
3148
|
logger.error("Either --package or --theme must be specified.");
|
|
3064
3149
|
logger.info("Examples:");
|
|
3065
|
-
logger.log("
|
|
3066
|
-
logger.log("
|
|
3150
|
+
logger.log(" onexthm deploy --package dist/tinan-1.0.0.zip");
|
|
3151
|
+
logger.log(" onexthm deploy --theme tinan");
|
|
3067
3152
|
process.exit(1);
|
|
3068
3153
|
}
|
|
3069
3154
|
if (!fs__default.default.existsSync(packagePath)) {
|
|
@@ -3079,7 +3164,7 @@ async function deployCommand(options) {
|
|
|
3079
3164
|
logger.log(`Path: ${path8__default.default.relative(process.cwd(), packagePath)}`);
|
|
3080
3165
|
logger.newLine();
|
|
3081
3166
|
const apiUrl = options.apiUrl || process.env.ONEX_API_URL || "http://localhost:3001";
|
|
3082
|
-
const uploadEndpoint = `${apiUrl}/api/themes/upload`;
|
|
3167
|
+
const uploadEndpoint = `${apiUrl}/website-api/themes/upload`;
|
|
3083
3168
|
logger.section("Uploading to API Server");
|
|
3084
3169
|
logger.info(`Endpoint: ${uploadEndpoint}`);
|
|
3085
3170
|
logger.newLine();
|
|
@@ -3284,7 +3369,7 @@ async function uploadCommand(options) {
|
|
|
3284
3369
|
if (!compiledDir) {
|
|
3285
3370
|
spinner.fail(
|
|
3286
3371
|
chalk4__default.default.red(
|
|
3287
|
-
`Compiled theme not found for ${themeId}@${version2}. Run '
|
|
3372
|
+
`Compiled theme not found for ${themeId}@${version2}. Run 'onexthm build' first.`
|
|
3288
3373
|
)
|
|
3289
3374
|
);
|
|
3290
3375
|
logger.info(chalk4__default.default.gray(`Expected location:
|
|
@@ -3516,7 +3601,7 @@ function showDownloadFailureHelp(themeId, bucket) {
|
|
|
3516
3601
|
console.log(chalk4__default.default.white("1. Compile and upload the theme:"));
|
|
3517
3602
|
console.log(chalk4__default.default.gray(` cd themes/${themeId}`));
|
|
3518
3603
|
console.log(chalk4__default.default.gray(" pnpm build"));
|
|
3519
|
-
console.log(chalk4__default.default.gray("
|
|
3604
|
+
console.log(chalk4__default.default.gray(" onexthm upload"));
|
|
3520
3605
|
console.log();
|
|
3521
3606
|
console.log(chalk4__default.default.white("2. Verify AWS credentials are set:"));
|
|
3522
3607
|
console.log(
|
|
@@ -3818,7 +3903,7 @@ async function cloneCommand(themeName, options) {
|
|
|
3818
3903
|
chalk4__default.default.yellow("The theme source may not have been uploaded yet.")
|
|
3819
3904
|
);
|
|
3820
3905
|
console.log(
|
|
3821
|
-
chalk4__default.default.gray(`Upload source with:
|
|
3906
|
+
chalk4__default.default.gray(`Upload source with: onexthm upload --theme ${themeName}`)
|
|
3822
3907
|
);
|
|
3823
3908
|
console.log();
|
|
3824
3909
|
process.exit(1);
|
|
@@ -3887,7 +3972,7 @@ async function cloneCommand(themeName, options) {
|
|
|
3887
3972
|
if (options.install === false) {
|
|
3888
3973
|
console.log(chalk4__default.default.gray(" pnpm install"));
|
|
3889
3974
|
}
|
|
3890
|
-
console.log(chalk4__default.default.gray("
|
|
3975
|
+
console.log(chalk4__default.default.gray(" onexthm build"));
|
|
3891
3976
|
console.log();
|
|
3892
3977
|
} catch (error) {
|
|
3893
3978
|
spinner.fail(chalk4__default.default.red(`Clone failed: ${error.message}`));
|
|
@@ -3915,6 +4000,7 @@ var MIME_TYPES = {
|
|
|
3915
4000
|
};
|
|
3916
4001
|
function createDevServer(options) {
|
|
3917
4002
|
const clients = /* @__PURE__ */ new Set();
|
|
4003
|
+
const themeDataPath = path8__default.default.join(options.distDir, "theme-data.json");
|
|
3918
4004
|
const server = http__default.default.createServer((req, res) => {
|
|
3919
4005
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
3920
4006
|
res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
@@ -3928,7 +4014,9 @@ function createDevServer(options) {
|
|
|
3928
4014
|
const pathname = url.pathname;
|
|
3929
4015
|
if (pathname === "/" || pathname === "/index.html") {
|
|
3930
4016
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
3931
|
-
res.end(
|
|
4017
|
+
res.end(
|
|
4018
|
+
generatePreviewHTML(options.themeName, options.port, themeDataPath)
|
|
4019
|
+
);
|
|
3932
4020
|
return;
|
|
3933
4021
|
}
|
|
3934
4022
|
if (pathname === "/preview-runtime.js") {
|
|
@@ -3947,6 +4035,37 @@ function createDevServer(options) {
|
|
|
3947
4035
|
serveFile(res, assetPath);
|
|
3948
4036
|
return;
|
|
3949
4037
|
}
|
|
4038
|
+
if (pathname.startsWith("/themes/")) {
|
|
4039
|
+
const match = pathname.match(/^\/themes\/[^/]+\/assets\/(.+)/);
|
|
4040
|
+
if (match) {
|
|
4041
|
+
const assetPath = path8__default.default.join(options.themePath, "assets", match[1]);
|
|
4042
|
+
if (!assetPath.startsWith(path8__default.default.join(options.themePath, "assets"))) {
|
|
4043
|
+
res.writeHead(403);
|
|
4044
|
+
res.end("Forbidden");
|
|
4045
|
+
return;
|
|
4046
|
+
}
|
|
4047
|
+
serveFile(res, assetPath);
|
|
4048
|
+
return;
|
|
4049
|
+
}
|
|
4050
|
+
}
|
|
4051
|
+
if (pathname.startsWith("/assets/")) {
|
|
4052
|
+
const subpath = pathname.replace(/^\/assets\//, "");
|
|
4053
|
+
const segments = subpath.split("/");
|
|
4054
|
+
let assetPath;
|
|
4055
|
+
if (segments[0] === options.themeName || segments[0] === options.themeName.replace(/^my-/, "")) {
|
|
4056
|
+
assetPath = path8__default.default.join(
|
|
4057
|
+
options.themePath,
|
|
4058
|
+
"assets",
|
|
4059
|
+
segments.slice(1).join("/")
|
|
4060
|
+
);
|
|
4061
|
+
} else {
|
|
4062
|
+
assetPath = path8__default.default.join(options.themePath, "assets", subpath);
|
|
4063
|
+
}
|
|
4064
|
+
if (assetPath.startsWith(path8__default.default.join(options.themePath, "assets")) && fs2__default.default.existsSync(assetPath)) {
|
|
4065
|
+
serveFile(res, assetPath);
|
|
4066
|
+
return;
|
|
4067
|
+
}
|
|
4068
|
+
}
|
|
3950
4069
|
const filePath = path8__default.default.join(options.distDir, pathname);
|
|
3951
4070
|
if (!filePath.startsWith(options.distDir)) {
|
|
3952
4071
|
res.writeHead(403);
|
|
@@ -3957,7 +4076,9 @@ function createDevServer(options) {
|
|
|
3957
4076
|
serveFile(res, filePath);
|
|
3958
4077
|
} else {
|
|
3959
4078
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
3960
|
-
res.end(
|
|
4079
|
+
res.end(
|
|
4080
|
+
generatePreviewHTML(options.themeName, options.port, themeDataPath)
|
|
4081
|
+
);
|
|
3961
4082
|
}
|
|
3962
4083
|
});
|
|
3963
4084
|
const wss = new ws.WebSocketServer({ server });
|
|
@@ -3998,17 +4119,82 @@ function serveFile(res, filePath) {
|
|
|
3998
4119
|
res.end("Internal Server Error");
|
|
3999
4120
|
}
|
|
4000
4121
|
}
|
|
4001
|
-
function generatePreviewHTML(themeName, port) {
|
|
4122
|
+
function generatePreviewHTML(themeName, port, themeDataPath) {
|
|
4123
|
+
let fontLinks = "";
|
|
4124
|
+
let fontVarsCSS = "";
|
|
4125
|
+
if (themeDataPath) {
|
|
4126
|
+
try {
|
|
4127
|
+
const themeData = JSON.parse(fs2__default.default.readFileSync(themeDataPath, "utf-8"));
|
|
4128
|
+
const typography = (themeData?.themeConfig || themeData?.theme?.config)?.typography?.fontFamily;
|
|
4129
|
+
if (typography) {
|
|
4130
|
+
const fontFamilies = /* @__PURE__ */ new Set();
|
|
4131
|
+
for (const value of Object.values(typography)) {
|
|
4132
|
+
const primary = value.split(",")[0].trim();
|
|
4133
|
+
if (primary && ![
|
|
4134
|
+
"serif",
|
|
4135
|
+
"sans-serif",
|
|
4136
|
+
"monospace",
|
|
4137
|
+
"system-ui",
|
|
4138
|
+
"Georgia",
|
|
4139
|
+
"Inter",
|
|
4140
|
+
"Consolas"
|
|
4141
|
+
].includes(primary)) {
|
|
4142
|
+
fontFamilies.add(primary);
|
|
4143
|
+
}
|
|
4144
|
+
}
|
|
4145
|
+
if (fontFamilies.size > 0) {
|
|
4146
|
+
const families = Array.from(fontFamilies).map(
|
|
4147
|
+
(f) => `family=${f.replace(/\s+/g, "+")}:wght@300;400;500;600;700;800;900`
|
|
4148
|
+
).join("&");
|
|
4149
|
+
fontLinks = `<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
4150
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
4151
|
+
<link href="https://fonts.googleapis.com/css2?${families}&display=swap" rel="stylesheet">`;
|
|
4152
|
+
}
|
|
4153
|
+
const heading = typography.heading || typography.body || "system-ui";
|
|
4154
|
+
const body = typography.body || "system-ui";
|
|
4155
|
+
fontVarsCSS = `
|
|
4156
|
+
:root {
|
|
4157
|
+
--font-heading: ${heading};
|
|
4158
|
+
--font-body: ${body};
|
|
4159
|
+
}
|
|
4160
|
+
body { font-family: var(--font-body); }
|
|
4161
|
+
h1, h2, h3, h4, h5, h6 { font-family: var(--font-heading); }`;
|
|
4162
|
+
}
|
|
4163
|
+
} catch {
|
|
4164
|
+
}
|
|
4165
|
+
}
|
|
4002
4166
|
return `<!DOCTYPE html>
|
|
4003
4167
|
<html lang="en">
|
|
4004
4168
|
<head>
|
|
4005
4169
|
<meta charset="UTF-8">
|
|
4006
4170
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
4007
4171
|
<title>OneX Dev \u2014 ${themeName}</title>
|
|
4172
|
+
${fontLinks}
|
|
4008
4173
|
<!-- Tailwind CSS Play CDN \u2014 JIT compilation in browser for dev preview -->
|
|
4009
4174
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
4175
|
+
<script>
|
|
4176
|
+
tailwind.config = {
|
|
4177
|
+
theme: {
|
|
4178
|
+
extend: {
|
|
4179
|
+
aspectRatio: {
|
|
4180
|
+
'2/1': '2 / 1',
|
|
4181
|
+
'3/2': '3 / 2',
|
|
4182
|
+
'4/3': '4 / 3',
|
|
4183
|
+
'3/4': '3 / 4',
|
|
4184
|
+
'5/4': '5 / 4',
|
|
4185
|
+
'16/9': '16 / 9',
|
|
4186
|
+
'21/9': '21 / 9',
|
|
4187
|
+
},
|
|
4188
|
+
fontFamily: {
|
|
4189
|
+
playfair: ['Playfair Display', 'Georgia', 'serif'],
|
|
4190
|
+
roboto: ['Roboto', 'system-ui', 'sans-serif'],
|
|
4191
|
+
},
|
|
4192
|
+
},
|
|
4193
|
+
},
|
|
4194
|
+
}
|
|
4195
|
+
</script>
|
|
4010
4196
|
<style>
|
|
4011
|
-
#onex-preview-root { margin-top: 0; }
|
|
4197
|
+
#onex-preview-root { margin-top: 0; }${fontVarsCSS}
|
|
4012
4198
|
</style>
|
|
4013
4199
|
</head>
|
|
4014
4200
|
<body>
|
|
@@ -4127,7 +4313,7 @@ async function devCommand(options) {
|
|
|
4127
4313
|
|
|
4128
4314
|
// src/commands/config.ts
|
|
4129
4315
|
init_logger();
|
|
4130
|
-
var CONFIG_DIR = path8__default.default.join(os__default.default.homedir(), ".
|
|
4316
|
+
var CONFIG_DIR = path8__default.default.join(os__default.default.homedir(), ".onexthm");
|
|
4131
4317
|
var CONFIG_FILE = path8__default.default.join(CONFIG_DIR, ".env");
|
|
4132
4318
|
var CONFIG_ENTRIES = [
|
|
4133
4319
|
{
|
|
@@ -4181,7 +4367,7 @@ function parseEnvFile(content) {
|
|
|
4181
4367
|
function serializeEnv(values) {
|
|
4182
4368
|
const lines = [
|
|
4183
4369
|
"# OneX CLI Configuration",
|
|
4184
|
-
"# Generated by:
|
|
4370
|
+
"# Generated by: onexthm config",
|
|
4185
4371
|
""
|
|
4186
4372
|
];
|
|
4187
4373
|
lines.push("# AWS / S3 Configuration");
|
|
@@ -4279,13 +4465,13 @@ try {
|
|
|
4279
4465
|
} catch {
|
|
4280
4466
|
}
|
|
4281
4467
|
dotenv__default.default.config({
|
|
4282
|
-
path: path8__default.default.join(os__default.default.homedir(), ".
|
|
4468
|
+
path: path8__default.default.join(os__default.default.homedir(), ".onexthm", ".env"),
|
|
4283
4469
|
quiet: true
|
|
4284
4470
|
});
|
|
4285
4471
|
var require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
|
|
4286
4472
|
var { version } = require2("../package.json");
|
|
4287
4473
|
var program = new commander.Command();
|
|
4288
|
-
program.name("
|
|
4474
|
+
program.name("onexthm").description("CLI tool for OneX theme development").version(version);
|
|
4289
4475
|
program.command("init").description("Create a new OneX theme project").argument("[project-name]", "Name of the project").option(
|
|
4290
4476
|
"-t, --template <template>",
|
|
4291
4477
|
"Template to use (default, minimal)",
|