@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.mjs
CHANGED
|
@@ -6,13 +6,13 @@ import path8 from 'path';
|
|
|
6
6
|
import fs7 from 'fs/promises';
|
|
7
7
|
import crypto from 'crypto';
|
|
8
8
|
import { glob } from 'glob';
|
|
9
|
+
import { createRequire } from 'module';
|
|
9
10
|
import os from 'os';
|
|
10
11
|
import dotenv from 'dotenv';
|
|
11
12
|
import fs from 'fs-extra';
|
|
12
13
|
import ejs from 'ejs';
|
|
13
14
|
import { execSync, spawn } from 'child_process';
|
|
14
15
|
import { Command } from 'commander';
|
|
15
|
-
import { createRequire } from 'module';
|
|
16
16
|
import fs2 from 'fs';
|
|
17
17
|
import inquirer from 'inquirer';
|
|
18
18
|
import archiver from 'archiver';
|
|
@@ -243,6 +243,12 @@ function createThemeDepsStubPlugin(themePath) {
|
|
|
243
243
|
if (!result.errors.length) return result;
|
|
244
244
|
} catch {
|
|
245
245
|
}
|
|
246
|
+
try {
|
|
247
|
+
const req = createRequire(import.meta.url || __filename);
|
|
248
|
+
const resolved = req.resolve(args.path);
|
|
249
|
+
if (resolved) return { path: resolved, namespace: "file" };
|
|
250
|
+
} catch {
|
|
251
|
+
}
|
|
246
252
|
return { path: args.path, namespace };
|
|
247
253
|
});
|
|
248
254
|
};
|
|
@@ -251,11 +257,19 @@ function createThemeDepsStubPlugin(themePath) {
|
|
|
251
257
|
const stubs = {
|
|
252
258
|
"next/image": `
|
|
253
259
|
import React from 'react';
|
|
254
|
-
const Image = (props) => {
|
|
255
|
-
const { src, alt, width, height, fill, priority, ...rest } = props;
|
|
260
|
+
const Image = React.forwardRef((props, ref) => {
|
|
261
|
+
const { src, alt, width, height, fill, priority, sizes, quality, placeholder, blurDataURL, onLoad, onError, style, className, ...rest } = props;
|
|
256
262
|
const imgSrc = typeof src === 'object' ? src.src : src;
|
|
257
|
-
|
|
258
|
-
};
|
|
263
|
+
const fillStyle = fill ? { position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: style?.objectFit || 'cover', display: 'block' } : {};
|
|
264
|
+
const mergedStyle = { ...fillStyle, ...style };
|
|
265
|
+
return React.createElement('img', {
|
|
266
|
+
ref, src: imgSrc, alt,
|
|
267
|
+
width: fill ? undefined : width, height: fill ? undefined : height,
|
|
268
|
+
loading: priority ? 'eager' : 'lazy',
|
|
269
|
+
style: Object.keys(mergedStyle).length > 0 ? mergedStyle : undefined,
|
|
270
|
+
className, onLoad, onError, ...rest,
|
|
271
|
+
});
|
|
272
|
+
});
|
|
259
273
|
export default Image;
|
|
260
274
|
`,
|
|
261
275
|
"next/link": `
|
|
@@ -289,7 +303,10 @@ export function headers() { return new Headers(); }
|
|
|
289
303
|
if (!lucideThemeScanned) {
|
|
290
304
|
lucideThemeScanned = true;
|
|
291
305
|
try {
|
|
292
|
-
const scanned = await scanImportsFromPackage(
|
|
306
|
+
const scanned = await scanImportsFromPackage(
|
|
307
|
+
themePath,
|
|
308
|
+
"lucide-react"
|
|
309
|
+
);
|
|
293
310
|
for (const names of Object.values(scanned)) {
|
|
294
311
|
for (const name of names) lucideImports.add(name);
|
|
295
312
|
}
|
|
@@ -352,10 +369,13 @@ export function useFormContext() { return useForm(); }
|
|
|
352
369
|
loader: "js"
|
|
353
370
|
}));
|
|
354
371
|
tryResolveOrStub(/^@hookform\/resolvers/, "hookform-resolvers-stub");
|
|
355
|
-
build2.onLoad(
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
372
|
+
build2.onLoad(
|
|
373
|
+
{ filter: /.*/, namespace: "hookform-resolvers-stub" },
|
|
374
|
+
() => ({
|
|
375
|
+
contents: `export function zodResolver() { return () => ({ values: {}, errors: {} }); }`,
|
|
376
|
+
loader: "js"
|
|
377
|
+
})
|
|
378
|
+
);
|
|
359
379
|
tryResolveOrStub(/^next-intl$/, "next-intl-stub");
|
|
360
380
|
build2.onLoad({ filter: /.*/, namespace: "next-intl-stub" }, () => ({
|
|
361
381
|
contents: `
|
|
@@ -613,7 +633,11 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
613
633
|
banner: {
|
|
614
634
|
js: '"use client";'
|
|
615
635
|
},
|
|
616
|
-
plugins: [
|
|
636
|
+
plugins: [
|
|
637
|
+
reactGlobalPlugin,
|
|
638
|
+
createCoreGlobalPlugin(themePath),
|
|
639
|
+
createThemeDepsStubPlugin(themePath)
|
|
640
|
+
],
|
|
617
641
|
external: [],
|
|
618
642
|
alias: {
|
|
619
643
|
events: "events/",
|
|
@@ -695,7 +719,11 @@ async function compileStandaloneThemeDev(themePath, themeName) {
|
|
|
695
719
|
banner: {
|
|
696
720
|
js: '"use client";'
|
|
697
721
|
},
|
|
698
|
-
plugins: [
|
|
722
|
+
plugins: [
|
|
723
|
+
reactGlobalPlugin,
|
|
724
|
+
createCoreGlobalPlugin(themePath),
|
|
725
|
+
createThemeDepsStubPlugin(themePath)
|
|
726
|
+
],
|
|
699
727
|
external: [],
|
|
700
728
|
alias: {
|
|
701
729
|
events: "events/",
|
|
@@ -830,7 +858,16 @@ ${locations.join("\n")}`
|
|
|
830
858
|
path8.join(themePath, "node_modules", "@onexapis", "core", "src"),
|
|
831
859
|
path8.join(themePath, "..", "..", "packages", "core", "src"),
|
|
832
860
|
// monorepo sibling
|
|
833
|
-
path8.join(
|
|
861
|
+
path8.join(
|
|
862
|
+
__dirname,
|
|
863
|
+
"..",
|
|
864
|
+
"..",
|
|
865
|
+
"..",
|
|
866
|
+
"..",
|
|
867
|
+
"packages",
|
|
868
|
+
"core",
|
|
869
|
+
"src"
|
|
870
|
+
)
|
|
834
871
|
// from CLI src
|
|
835
872
|
];
|
|
836
873
|
let coreSourceDir = null;
|
|
@@ -844,7 +881,10 @@ ${locations.join("\n")}`
|
|
|
844
881
|
}
|
|
845
882
|
if (coreSourceDir) {
|
|
846
883
|
try {
|
|
847
|
-
const scanned = await scanImportsFromPackage(
|
|
884
|
+
const scanned = await scanImportsFromPackage(
|
|
885
|
+
coreSourceDir,
|
|
886
|
+
"lucide-react"
|
|
887
|
+
);
|
|
848
888
|
for (const names of Object.values(scanned)) {
|
|
849
889
|
for (const name of names) lucideIconNames.add(name);
|
|
850
890
|
}
|
|
@@ -865,7 +905,10 @@ ${locations.join("\n")}`
|
|
|
865
905
|
const mjsFiles = await glob("*.mjs", { cwd: candidate });
|
|
866
906
|
const importRegex = /import\s*\{([^}]+)\}\s*from\s*["']lucide-react["']/g;
|
|
867
907
|
for (const file of mjsFiles) {
|
|
868
|
-
const content = await fs7.readFile(
|
|
908
|
+
const content = await fs7.readFile(
|
|
909
|
+
path8.join(candidate, file),
|
|
910
|
+
"utf-8"
|
|
911
|
+
);
|
|
869
912
|
for (const match of content.matchAll(importRegex)) {
|
|
870
913
|
for (const name of match[1].split(",")) {
|
|
871
914
|
const original = name.trim().split(/\s+as\s+/)[0].trim();
|
|
@@ -881,7 +924,10 @@ ${locations.join("\n")}`
|
|
|
881
924
|
}
|
|
882
925
|
}
|
|
883
926
|
try {
|
|
884
|
-
const scanned = await scanImportsFromPackage(
|
|
927
|
+
const scanned = await scanImportsFromPackage(
|
|
928
|
+
themePath,
|
|
929
|
+
"lucide-react"
|
|
930
|
+
);
|
|
885
931
|
for (const names of Object.values(scanned)) {
|
|
886
932
|
for (const name of names) lucideIconNames.add(name);
|
|
887
933
|
}
|
|
@@ -911,14 +957,39 @@ export default new Proxy({}, { get: (_, name) => name === '__esModule' ? true :
|
|
|
911
957
|
if (!result.errors.length) return result;
|
|
912
958
|
} catch {
|
|
913
959
|
}
|
|
960
|
+
try {
|
|
961
|
+
const req = createRequire(import.meta.url || __filename);
|
|
962
|
+
const cjsPath = req.resolve("framer-motion");
|
|
963
|
+
const pkgDir = cjsPath.replace(/[/\\]dist[/\\].*$/, "");
|
|
964
|
+
const esmEntry = path8.join(pkgDir, "dist", "es", "index.mjs");
|
|
965
|
+
const { existsSync } = await import('fs');
|
|
966
|
+
if (existsSync(esmEntry)) {
|
|
967
|
+
return { path: esmEntry, namespace: "file" };
|
|
968
|
+
}
|
|
969
|
+
return { path: cjsPath, namespace: "file" };
|
|
970
|
+
} catch {
|
|
971
|
+
}
|
|
914
972
|
return { path: args.path, namespace: "motion-stub" };
|
|
915
973
|
});
|
|
916
974
|
build2.onLoad({ filter: /.*/, namespace: "motion-stub" }, () => ({
|
|
917
975
|
contents: `
|
|
918
|
-
|
|
919
|
-
const
|
|
976
|
+
import React from 'react';
|
|
977
|
+
const MotionComponent = React.forwardRef((props, ref) => {
|
|
978
|
+
const { initial, animate, exit, variants, transition, whileInView, whileHover, whileTap, viewport, onAnimationComplete, layout, layoutId, style, className, ...rest } = props;
|
|
979
|
+
return React.createElement(rest.as || 'div', { ref, style, className, ...rest }, rest.children);
|
|
980
|
+
});
|
|
981
|
+
const handler = { get: (_, name) => {
|
|
982
|
+
if (name === '__esModule') return true;
|
|
983
|
+
if (name === 'create') return () => new Proxy({}, handler);
|
|
984
|
+
return MotionComponent;
|
|
985
|
+
}};
|
|
920
986
|
export const motion = new Proxy({}, handler);
|
|
921
|
-
export const AnimatePresence =
|
|
987
|
+
export const AnimatePresence = (props) => props.children || null;
|
|
988
|
+
export const useInView = () => true;
|
|
989
|
+
export const useAnimation = () => ({ start: () => {}, stop: () => {}, set: () => {} });
|
|
990
|
+
export const useMotionValue = (v) => ({ get: () => v, set: () => {}, onChange: () => () => {} });
|
|
991
|
+
export const useTransform = (v) => v;
|
|
992
|
+
export const useScroll = () => ({ scrollY: { get: () => 0, onChange: () => () => {} }, scrollYProgress: { get: () => 0, onChange: () => () => {} } });
|
|
922
993
|
export default { motion, AnimatePresence };
|
|
923
994
|
`.trim(),
|
|
924
995
|
loader: "jsx"
|
|
@@ -941,12 +1012,26 @@ export default { motion, AnimatePresence };
|
|
|
941
1012
|
build2.onLoad({ filter: /.*/, namespace: "next-stub" }, (args) => {
|
|
942
1013
|
const stubs = {
|
|
943
1014
|
"next/image": `
|
|
944
|
-
const Image = (props) => {
|
|
945
|
-
const { src, alt, width, height, fill, priority, ...rest } = props;
|
|
946
|
-
const imgSrc = typeof src === 'object' ? src.src : src;
|
|
947
|
-
return React.createElement('img', { src: imgSrc, alt, width: fill ? undefined : width, height: fill ? undefined : height, loading: priority ? 'eager' : 'lazy', ...rest });
|
|
948
|
-
};
|
|
949
1015
|
import React from 'react';
|
|
1016
|
+
const Image = React.forwardRef((props, ref) => {
|
|
1017
|
+
const { src, alt, width, height, fill, priority, sizes, quality, placeholder, blurDataURL, onLoad, onError, style, className, ...rest } = props;
|
|
1018
|
+
const imgSrc = typeof src === 'object' ? src.src : src;
|
|
1019
|
+
const fillStyle = fill ? { position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: style?.objectFit || 'cover', display: 'block' } : {};
|
|
1020
|
+
const mergedStyle = { ...fillStyle, ...style };
|
|
1021
|
+
return React.createElement('img', {
|
|
1022
|
+
ref,
|
|
1023
|
+
src: imgSrc,
|
|
1024
|
+
alt,
|
|
1025
|
+
width: fill ? undefined : width,
|
|
1026
|
+
height: fill ? undefined : height,
|
|
1027
|
+
loading: priority ? 'eager' : 'lazy',
|
|
1028
|
+
style: Object.keys(mergedStyle).length > 0 ? mergedStyle : undefined,
|
|
1029
|
+
className,
|
|
1030
|
+
onLoad,
|
|
1031
|
+
onError,
|
|
1032
|
+
...rest,
|
|
1033
|
+
});
|
|
1034
|
+
});
|
|
950
1035
|
export default Image;
|
|
951
1036
|
`,
|
|
952
1037
|
"next/link": `
|
|
@@ -1445,7 +1530,7 @@ Add your theme-specific blocks here.
|
|
|
1445
1530
|
try {
|
|
1446
1531
|
execSync("git init", { cwd: projectPath, stdio: "ignore" });
|
|
1447
1532
|
execSync("git add .", { cwd: projectPath, stdio: "ignore" });
|
|
1448
|
-
execSync('git commit -m "Initial commit from
|
|
1533
|
+
execSync('git commit -m "Initial commit from onexthm init"', {
|
|
1449
1534
|
cwd: projectPath,
|
|
1450
1535
|
stdio: "ignore"
|
|
1451
1536
|
});
|
|
@@ -2795,7 +2880,7 @@ async function buildCommand(options) {
|
|
|
2795
2880
|
logger.stopSpinner(true, "Lint passed");
|
|
2796
2881
|
const pkgJson = fs.readJsonSync(packageJsonPath);
|
|
2797
2882
|
const buildScript = pkgJson.scripts?.build || "";
|
|
2798
|
-
const isRecursive = buildScript.includes("
|
|
2883
|
+
const isRecursive = buildScript.includes("onexthm build") || buildScript.includes("onex-cli build");
|
|
2799
2884
|
logger.startSpinner(
|
|
2800
2885
|
options.watch ? "Building (watch mode)..." : "Building..."
|
|
2801
2886
|
);
|
|
@@ -2941,7 +3026,7 @@ async function packageCommand(options) {
|
|
|
2941
3026
|
logger.newLine();
|
|
2942
3027
|
logger.section("Next steps:");
|
|
2943
3028
|
logger.log(
|
|
2944
|
-
`
|
|
3029
|
+
` onexthm deploy --package ${path8.relative(process.cwd(), outputPath)}`
|
|
2945
3030
|
);
|
|
2946
3031
|
} catch (error) {
|
|
2947
3032
|
logger.stopSpinner(false, "Failed to create package");
|
|
@@ -3003,7 +3088,7 @@ async function deployCommand(options) {
|
|
|
3003
3088
|
} else if (options.theme) {
|
|
3004
3089
|
const distDir = path8.join(process.cwd(), "dist");
|
|
3005
3090
|
if (!fs.existsSync(distDir)) {
|
|
3006
|
-
logger.error("No dist/ directory found. Run '
|
|
3091
|
+
logger.error("No dist/ directory found. Run 'onexthm package' first.");
|
|
3007
3092
|
process.exit(1);
|
|
3008
3093
|
}
|
|
3009
3094
|
const files = fs.readdirSync(distDir);
|
|
@@ -3012,7 +3097,7 @@ async function deployCommand(options) {
|
|
|
3012
3097
|
);
|
|
3013
3098
|
if (packageFiles.length === 0) {
|
|
3014
3099
|
logger.error(`No package found for theme "${options.theme}".`);
|
|
3015
|
-
logger.info("Run:
|
|
3100
|
+
logger.info("Run: onexthm package --theme " + options.theme);
|
|
3016
3101
|
process.exit(1);
|
|
3017
3102
|
}
|
|
3018
3103
|
packageFiles.sort().reverse();
|
|
@@ -3020,8 +3105,8 @@ async function deployCommand(options) {
|
|
|
3020
3105
|
} else {
|
|
3021
3106
|
logger.error("Either --package or --theme must be specified.");
|
|
3022
3107
|
logger.info("Examples:");
|
|
3023
|
-
logger.log("
|
|
3024
|
-
logger.log("
|
|
3108
|
+
logger.log(" onexthm deploy --package dist/tinan-1.0.0.zip");
|
|
3109
|
+
logger.log(" onexthm deploy --theme tinan");
|
|
3025
3110
|
process.exit(1);
|
|
3026
3111
|
}
|
|
3027
3112
|
if (!fs.existsSync(packagePath)) {
|
|
@@ -3037,7 +3122,7 @@ async function deployCommand(options) {
|
|
|
3037
3122
|
logger.log(`Path: ${path8.relative(process.cwd(), packagePath)}`);
|
|
3038
3123
|
logger.newLine();
|
|
3039
3124
|
const apiUrl = options.apiUrl || process.env.ONEX_API_URL || "http://localhost:3001";
|
|
3040
|
-
const uploadEndpoint = `${apiUrl}/api/themes/upload`;
|
|
3125
|
+
const uploadEndpoint = `${apiUrl}/website-api/themes/upload`;
|
|
3041
3126
|
logger.section("Uploading to API Server");
|
|
3042
3127
|
logger.info(`Endpoint: ${uploadEndpoint}`);
|
|
3043
3128
|
logger.newLine();
|
|
@@ -3242,7 +3327,7 @@ async function uploadCommand(options) {
|
|
|
3242
3327
|
if (!compiledDir) {
|
|
3243
3328
|
spinner.fail(
|
|
3244
3329
|
chalk4.red(
|
|
3245
|
-
`Compiled theme not found for ${themeId}@${version2}. Run '
|
|
3330
|
+
`Compiled theme not found for ${themeId}@${version2}. Run 'onexthm build' first.`
|
|
3246
3331
|
)
|
|
3247
3332
|
);
|
|
3248
3333
|
logger.info(chalk4.gray(`Expected location:
|
|
@@ -3474,7 +3559,7 @@ function showDownloadFailureHelp(themeId, bucket) {
|
|
|
3474
3559
|
console.log(chalk4.white("1. Compile and upload the theme:"));
|
|
3475
3560
|
console.log(chalk4.gray(` cd themes/${themeId}`));
|
|
3476
3561
|
console.log(chalk4.gray(" pnpm build"));
|
|
3477
|
-
console.log(chalk4.gray("
|
|
3562
|
+
console.log(chalk4.gray(" onexthm upload"));
|
|
3478
3563
|
console.log();
|
|
3479
3564
|
console.log(chalk4.white("2. Verify AWS credentials are set:"));
|
|
3480
3565
|
console.log(
|
|
@@ -3776,7 +3861,7 @@ async function cloneCommand(themeName, options) {
|
|
|
3776
3861
|
chalk4.yellow("The theme source may not have been uploaded yet.")
|
|
3777
3862
|
);
|
|
3778
3863
|
console.log(
|
|
3779
|
-
chalk4.gray(`Upload source with:
|
|
3864
|
+
chalk4.gray(`Upload source with: onexthm upload --theme ${themeName}`)
|
|
3780
3865
|
);
|
|
3781
3866
|
console.log();
|
|
3782
3867
|
process.exit(1);
|
|
@@ -3845,7 +3930,7 @@ async function cloneCommand(themeName, options) {
|
|
|
3845
3930
|
if (options.install === false) {
|
|
3846
3931
|
console.log(chalk4.gray(" pnpm install"));
|
|
3847
3932
|
}
|
|
3848
|
-
console.log(chalk4.gray("
|
|
3933
|
+
console.log(chalk4.gray(" onexthm build"));
|
|
3849
3934
|
console.log();
|
|
3850
3935
|
} catch (error) {
|
|
3851
3936
|
spinner.fail(chalk4.red(`Clone failed: ${error.message}`));
|
|
@@ -3873,6 +3958,7 @@ var MIME_TYPES = {
|
|
|
3873
3958
|
};
|
|
3874
3959
|
function createDevServer(options) {
|
|
3875
3960
|
const clients = /* @__PURE__ */ new Set();
|
|
3961
|
+
const themeDataPath = path8.join(options.distDir, "theme-data.json");
|
|
3876
3962
|
const server = http.createServer((req, res) => {
|
|
3877
3963
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
3878
3964
|
res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
@@ -3886,7 +3972,9 @@ function createDevServer(options) {
|
|
|
3886
3972
|
const pathname = url.pathname;
|
|
3887
3973
|
if (pathname === "/" || pathname === "/index.html") {
|
|
3888
3974
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
3889
|
-
res.end(
|
|
3975
|
+
res.end(
|
|
3976
|
+
generatePreviewHTML(options.themeName, options.port, themeDataPath)
|
|
3977
|
+
);
|
|
3890
3978
|
return;
|
|
3891
3979
|
}
|
|
3892
3980
|
if (pathname === "/preview-runtime.js") {
|
|
@@ -3905,6 +3993,37 @@ function createDevServer(options) {
|
|
|
3905
3993
|
serveFile(res, assetPath);
|
|
3906
3994
|
return;
|
|
3907
3995
|
}
|
|
3996
|
+
if (pathname.startsWith("/themes/")) {
|
|
3997
|
+
const match = pathname.match(/^\/themes\/[^/]+\/assets\/(.+)/);
|
|
3998
|
+
if (match) {
|
|
3999
|
+
const assetPath = path8.join(options.themePath, "assets", match[1]);
|
|
4000
|
+
if (!assetPath.startsWith(path8.join(options.themePath, "assets"))) {
|
|
4001
|
+
res.writeHead(403);
|
|
4002
|
+
res.end("Forbidden");
|
|
4003
|
+
return;
|
|
4004
|
+
}
|
|
4005
|
+
serveFile(res, assetPath);
|
|
4006
|
+
return;
|
|
4007
|
+
}
|
|
4008
|
+
}
|
|
4009
|
+
if (pathname.startsWith("/assets/")) {
|
|
4010
|
+
const subpath = pathname.replace(/^\/assets\//, "");
|
|
4011
|
+
const segments = subpath.split("/");
|
|
4012
|
+
let assetPath;
|
|
4013
|
+
if (segments[0] === options.themeName || segments[0] === options.themeName.replace(/^my-/, "")) {
|
|
4014
|
+
assetPath = path8.join(
|
|
4015
|
+
options.themePath,
|
|
4016
|
+
"assets",
|
|
4017
|
+
segments.slice(1).join("/")
|
|
4018
|
+
);
|
|
4019
|
+
} else {
|
|
4020
|
+
assetPath = path8.join(options.themePath, "assets", subpath);
|
|
4021
|
+
}
|
|
4022
|
+
if (assetPath.startsWith(path8.join(options.themePath, "assets")) && fs2.existsSync(assetPath)) {
|
|
4023
|
+
serveFile(res, assetPath);
|
|
4024
|
+
return;
|
|
4025
|
+
}
|
|
4026
|
+
}
|
|
3908
4027
|
const filePath = path8.join(options.distDir, pathname);
|
|
3909
4028
|
if (!filePath.startsWith(options.distDir)) {
|
|
3910
4029
|
res.writeHead(403);
|
|
@@ -3915,7 +4034,9 @@ function createDevServer(options) {
|
|
|
3915
4034
|
serveFile(res, filePath);
|
|
3916
4035
|
} else {
|
|
3917
4036
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
3918
|
-
res.end(
|
|
4037
|
+
res.end(
|
|
4038
|
+
generatePreviewHTML(options.themeName, options.port, themeDataPath)
|
|
4039
|
+
);
|
|
3919
4040
|
}
|
|
3920
4041
|
});
|
|
3921
4042
|
const wss = new WebSocketServer({ server });
|
|
@@ -3956,17 +4077,82 @@ function serveFile(res, filePath) {
|
|
|
3956
4077
|
res.end("Internal Server Error");
|
|
3957
4078
|
}
|
|
3958
4079
|
}
|
|
3959
|
-
function generatePreviewHTML(themeName, port) {
|
|
4080
|
+
function generatePreviewHTML(themeName, port, themeDataPath) {
|
|
4081
|
+
let fontLinks = "";
|
|
4082
|
+
let fontVarsCSS = "";
|
|
4083
|
+
if (themeDataPath) {
|
|
4084
|
+
try {
|
|
4085
|
+
const themeData = JSON.parse(fs2.readFileSync(themeDataPath, "utf-8"));
|
|
4086
|
+
const typography = (themeData?.themeConfig || themeData?.theme?.config)?.typography?.fontFamily;
|
|
4087
|
+
if (typography) {
|
|
4088
|
+
const fontFamilies = /* @__PURE__ */ new Set();
|
|
4089
|
+
for (const value of Object.values(typography)) {
|
|
4090
|
+
const primary = value.split(",")[0].trim();
|
|
4091
|
+
if (primary && ![
|
|
4092
|
+
"serif",
|
|
4093
|
+
"sans-serif",
|
|
4094
|
+
"monospace",
|
|
4095
|
+
"system-ui",
|
|
4096
|
+
"Georgia",
|
|
4097
|
+
"Inter",
|
|
4098
|
+
"Consolas"
|
|
4099
|
+
].includes(primary)) {
|
|
4100
|
+
fontFamilies.add(primary);
|
|
4101
|
+
}
|
|
4102
|
+
}
|
|
4103
|
+
if (fontFamilies.size > 0) {
|
|
4104
|
+
const families = Array.from(fontFamilies).map(
|
|
4105
|
+
(f) => `family=${f.replace(/\s+/g, "+")}:wght@300;400;500;600;700;800;900`
|
|
4106
|
+
).join("&");
|
|
4107
|
+
fontLinks = `<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
4108
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
4109
|
+
<link href="https://fonts.googleapis.com/css2?${families}&display=swap" rel="stylesheet">`;
|
|
4110
|
+
}
|
|
4111
|
+
const heading = typography.heading || typography.body || "system-ui";
|
|
4112
|
+
const body = typography.body || "system-ui";
|
|
4113
|
+
fontVarsCSS = `
|
|
4114
|
+
:root {
|
|
4115
|
+
--font-heading: ${heading};
|
|
4116
|
+
--font-body: ${body};
|
|
4117
|
+
}
|
|
4118
|
+
body { font-family: var(--font-body); }
|
|
4119
|
+
h1, h2, h3, h4, h5, h6 { font-family: var(--font-heading); }`;
|
|
4120
|
+
}
|
|
4121
|
+
} catch {
|
|
4122
|
+
}
|
|
4123
|
+
}
|
|
3960
4124
|
return `<!DOCTYPE html>
|
|
3961
4125
|
<html lang="en">
|
|
3962
4126
|
<head>
|
|
3963
4127
|
<meta charset="UTF-8">
|
|
3964
4128
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
3965
4129
|
<title>OneX Dev \u2014 ${themeName}</title>
|
|
4130
|
+
${fontLinks}
|
|
3966
4131
|
<!-- Tailwind CSS Play CDN \u2014 JIT compilation in browser for dev preview -->
|
|
3967
4132
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
4133
|
+
<script>
|
|
4134
|
+
tailwind.config = {
|
|
4135
|
+
theme: {
|
|
4136
|
+
extend: {
|
|
4137
|
+
aspectRatio: {
|
|
4138
|
+
'2/1': '2 / 1',
|
|
4139
|
+
'3/2': '3 / 2',
|
|
4140
|
+
'4/3': '4 / 3',
|
|
4141
|
+
'3/4': '3 / 4',
|
|
4142
|
+
'5/4': '5 / 4',
|
|
4143
|
+
'16/9': '16 / 9',
|
|
4144
|
+
'21/9': '21 / 9',
|
|
4145
|
+
},
|
|
4146
|
+
fontFamily: {
|
|
4147
|
+
playfair: ['Playfair Display', 'Georgia', 'serif'],
|
|
4148
|
+
roboto: ['Roboto', 'system-ui', 'sans-serif'],
|
|
4149
|
+
},
|
|
4150
|
+
},
|
|
4151
|
+
},
|
|
4152
|
+
}
|
|
4153
|
+
</script>
|
|
3968
4154
|
<style>
|
|
3969
|
-
#onex-preview-root { margin-top: 0; }
|
|
4155
|
+
#onex-preview-root { margin-top: 0; }${fontVarsCSS}
|
|
3970
4156
|
</style>
|
|
3971
4157
|
</head>
|
|
3972
4158
|
<body>
|
|
@@ -4085,7 +4271,7 @@ async function devCommand(options) {
|
|
|
4085
4271
|
|
|
4086
4272
|
// src/commands/config.ts
|
|
4087
4273
|
init_logger();
|
|
4088
|
-
var CONFIG_DIR = path8.join(os.homedir(), ".
|
|
4274
|
+
var CONFIG_DIR = path8.join(os.homedir(), ".onexthm");
|
|
4089
4275
|
var CONFIG_FILE = path8.join(CONFIG_DIR, ".env");
|
|
4090
4276
|
var CONFIG_ENTRIES = [
|
|
4091
4277
|
{
|
|
@@ -4139,7 +4325,7 @@ function parseEnvFile(content) {
|
|
|
4139
4325
|
function serializeEnv(values) {
|
|
4140
4326
|
const lines = [
|
|
4141
4327
|
"# OneX CLI Configuration",
|
|
4142
|
-
"# Generated by:
|
|
4328
|
+
"# Generated by: onexthm config",
|
|
4143
4329
|
""
|
|
4144
4330
|
];
|
|
4145
4331
|
lines.push("# AWS / S3 Configuration");
|
|
@@ -4237,13 +4423,13 @@ try {
|
|
|
4237
4423
|
} catch {
|
|
4238
4424
|
}
|
|
4239
4425
|
dotenv.config({
|
|
4240
|
-
path: path8.join(os.homedir(), ".
|
|
4426
|
+
path: path8.join(os.homedir(), ".onexthm", ".env"),
|
|
4241
4427
|
quiet: true
|
|
4242
4428
|
});
|
|
4243
4429
|
var require2 = createRequire(import.meta.url);
|
|
4244
4430
|
var { version } = require2("../package.json");
|
|
4245
4431
|
var program = new Command();
|
|
4246
|
-
program.name("
|
|
4432
|
+
program.name("onexthm").description("CLI tool for OneX theme development").version(version);
|
|
4247
4433
|
program.command("init").description("Create a new OneX theme project").argument("[project-name]", "Name of the project").option(
|
|
4248
4434
|
"-t, --template <template>",
|
|
4249
4435
|
"Template to use (default, minimal)",
|