@onexapis/cli 1.1.1 → 1.1.2
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/dist/cli.js +94 -2
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +94 -2
- package/dist/cli.mjs.map +1 -1
- package/dist/index.js +88 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +88 -1
- package/dist/index.mjs.map +1 -1
- package/dist/preview/preview-app.tsx +91 -24
- package/package.json +4 -3
|
@@ -147,9 +147,25 @@ function discoverPageConfigs(
|
|
|
147
147
|
|
|
148
148
|
// ===== 6. PREVIEW APP COMPONENT =====
|
|
149
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Match URL pathname to a page index.
|
|
152
|
+
* "/" or "/home" → home page, "/showcase" → showcase page, etc.
|
|
153
|
+
*/
|
|
154
|
+
function getInitialPageFromURL(pages: Array<{ key: string; label: string; config: any }>): number {
|
|
155
|
+
const pathname = window.location.pathname.replace(/^\/+|\/+$/g, "").toLowerCase();
|
|
156
|
+
if (!pathname || pathname === "home") return 0; // home is always first after sorting
|
|
157
|
+
|
|
158
|
+
const idx = pages.findIndex((p) => {
|
|
159
|
+
const pageSlug = p.label.toLowerCase().replace(/\s+/g, "-");
|
|
160
|
+
const pageKey = p.key.replace("PageConfig", "").toLowerCase();
|
|
161
|
+
return pageSlug === pathname || pageKey === pathname;
|
|
162
|
+
});
|
|
163
|
+
return idx >= 0 ? idx : -2; // -2 = page not found
|
|
164
|
+
}
|
|
165
|
+
|
|
150
166
|
function PreviewApp() {
|
|
151
167
|
const [themeExports, setThemeExports] = useState<ThemeExports | null>(null);
|
|
152
|
-
const [selectedPage, setSelectedPage] = useState(
|
|
168
|
+
const [selectedPage, setSelectedPage] = useState(-1); // -1 = not yet resolved from URL
|
|
153
169
|
const [wsStatus, setWsStatus] = useState<
|
|
154
170
|
"connected" | "disconnected" | "rebuilding"
|
|
155
171
|
>("disconnected");
|
|
@@ -173,6 +189,16 @@ function PreviewApp() {
|
|
|
173
189
|
loadTheme();
|
|
174
190
|
}, [loadTheme]);
|
|
175
191
|
|
|
192
|
+
// Handle browser back/forward navigation
|
|
193
|
+
useEffect(() => {
|
|
194
|
+
const handlePopState = () => {
|
|
195
|
+
// Reset to -1 to re-resolve from URL
|
|
196
|
+
setSelectedPage(-1);
|
|
197
|
+
};
|
|
198
|
+
window.addEventListener("popstate", handlePopState);
|
|
199
|
+
return () => window.removeEventListener("popstate", handlePopState);
|
|
200
|
+
}, []);
|
|
201
|
+
|
|
176
202
|
// WebSocket connection for hot reload
|
|
177
203
|
useEffect(() => {
|
|
178
204
|
function connect() {
|
|
@@ -242,7 +268,43 @@ function PreviewApp() {
|
|
|
242
268
|
const pages = discoverPageConfigs(themeExports);
|
|
243
269
|
const themeId = themeExports.themeConfig?.id || "";
|
|
244
270
|
const themePrefix = themeId ? `${themeId}-` : "";
|
|
245
|
-
|
|
271
|
+
|
|
272
|
+
// Resolve initial page from URL path (once pages are discovered)
|
|
273
|
+
const resolvedPage = selectedPage === -1 ? getInitialPageFromURL(pages) : selectedPage;
|
|
274
|
+
|
|
275
|
+
// Page not found (-2)
|
|
276
|
+
if (resolvedPage === -2) {
|
|
277
|
+
const pathname = window.location.pathname;
|
|
278
|
+
return (
|
|
279
|
+
<div style={{ padding: "80px 40px", textAlign: "center", fontFamily: "system-ui" }}>
|
|
280
|
+
<h1 style={{ fontSize: "4rem", margin: 0, color: "#E11D48" }}>404</h1>
|
|
281
|
+
<p style={{ fontSize: "1.25rem", color: "#333", marginTop: 12 }}>
|
|
282
|
+
Page not found: <code style={{ background: "#f1f5f9", padding: "2px 8px", borderRadius: 4 }}>{pathname}</code>
|
|
283
|
+
</p>
|
|
284
|
+
<p style={{ color: "#888", marginTop: 8 }}>Available pages:</p>
|
|
285
|
+
<div style={{ display: "flex", gap: 8, justifyContent: "center", marginTop: 12 }}>
|
|
286
|
+
{pages.map((page) => {
|
|
287
|
+
const pageSlug = page.key.replace("PageConfig", "").toLowerCase();
|
|
288
|
+
const pagePath = pageSlug === "home" ? "/" : `/${pageSlug}`;
|
|
289
|
+
return (
|
|
290
|
+
<a
|
|
291
|
+
key={page.key}
|
|
292
|
+
href={pagePath}
|
|
293
|
+
style={{
|
|
294
|
+
padding: "6px 16px", borderRadius: 6, background: "#E11D48",
|
|
295
|
+
color: "white", textDecoration: "none", fontSize: 14, fontWeight: 500,
|
|
296
|
+
}}
|
|
297
|
+
>
|
|
298
|
+
{page.label}
|
|
299
|
+
</a>
|
|
300
|
+
);
|
|
301
|
+
})}
|
|
302
|
+
</div>
|
|
303
|
+
</div>
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const currentPage = pages[resolvedPage] || pages[0];
|
|
246
308
|
|
|
247
309
|
if (!currentPage) {
|
|
248
310
|
return (
|
|
@@ -290,28 +352,33 @@ function PreviewApp() {
|
|
|
290
352
|
gap: 4,
|
|
291
353
|
}}
|
|
292
354
|
>
|
|
293
|
-
{pages.map((page, i) =>
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
355
|
+
{pages.map((page, i) => {
|
|
356
|
+
const pageSlug = page.key.replace("PageConfig", "").toLowerCase();
|
|
357
|
+
const pagePath = pageSlug === "home" ? "/" : `/${pageSlug}`;
|
|
358
|
+
return (
|
|
359
|
+
<button
|
|
360
|
+
key={page.key}
|
|
361
|
+
onClick={() => {
|
|
362
|
+
setSelectedPage(i);
|
|
363
|
+
window.history.pushState(null, "", pagePath);
|
|
364
|
+
const el = document.getElementById("page-indicator");
|
|
365
|
+
if (el) el.textContent = page.label;
|
|
366
|
+
}}
|
|
367
|
+
style={{
|
|
368
|
+
padding: "4px 12px",
|
|
369
|
+
border: "none",
|
|
370
|
+
borderRadius: 4,
|
|
371
|
+
cursor: "pointer",
|
|
372
|
+
background: i === resolvedPage ? "#E11D48" : "transparent",
|
|
373
|
+
color: i === resolvedPage ? "white" : "#333",
|
|
374
|
+
fontSize: 12,
|
|
375
|
+
fontWeight: 500,
|
|
376
|
+
}}
|
|
377
|
+
>
|
|
378
|
+
{page.label}
|
|
379
|
+
</button>
|
|
380
|
+
);
|
|
381
|
+
})}
|
|
315
382
|
</div>
|
|
316
383
|
)}
|
|
317
384
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onexapis/cli",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "CLI tool for OneX theme development - scaffolds themes using @onexapis/core",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -52,16 +52,17 @@
|
|
|
52
52
|
"adm-zip": "^0.5.16",
|
|
53
53
|
"archiver": "^7.0.1",
|
|
54
54
|
"chalk": "^5.3.0",
|
|
55
|
+
"chokidar": "^4.0.0",
|
|
55
56
|
"commander": "^12.1.0",
|
|
56
57
|
"dotenv": "^17.3.1",
|
|
57
58
|
"ejs": "^3.1.10",
|
|
59
|
+
"esbuild": "^0.25.0",
|
|
58
60
|
"form-data": "^4.0.5",
|
|
59
61
|
"fs-extra": "^11.2.0",
|
|
60
62
|
"glob": "^10.3.10",
|
|
61
63
|
"inquirer": "^9.2.12",
|
|
64
|
+
"jiti": "^2.6.1",
|
|
62
65
|
"node-fetch": "^3.3.2",
|
|
63
|
-
"chokidar": "^4.0.0",
|
|
64
|
-
"esbuild": "^0.25.0",
|
|
65
66
|
"open": "^10.1.0",
|
|
66
67
|
"ora": "^8.0.1",
|
|
67
68
|
"ws": "^8.18.0"
|