framer-export 4.2.1 → 4.3.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/index.js CHANGED
@@ -15,7 +15,7 @@ var init_package = __esm({
15
15
  "package.json"() {
16
16
  package_default = {
17
17
  name: "framer-export",
18
- version: "4.2.1",
18
+ version: "4.3.2",
19
19
  description: "Export any Framer, Webflow, or Wix site into a fully working local mirror. Downloads all assets, strips badges, rewrites URLs, and pretty-prints JS.",
20
20
  type: "module",
21
21
  main: "dist/cli/index.js",
@@ -92,16 +92,16 @@ function showBanner() {
92
92
  const isSmall = width < 65;
93
93
  if (isSmall) {
94
94
  console.log(`
95
- ${chalk.cyan.bold("F-EXPORT")} ${chalk.gray(`v${package_default.version}`)}`);
95
+ ${chalk.hex("#D4A017").bold("F-EXPORT")} ${chalk.gray(`v${package_default.version}`)}`);
96
96
  console.log(` ${chalk.white.bold("Framer \xB7 Webflow \xB7 Wix Exporter")}
97
97
  `);
98
98
  return;
99
99
  }
100
- const cyan = chalk.cyan.bold;
100
+ const gold = chalk.hex("#D4A017").bold;
101
101
  const gray = chalk.gray;
102
102
  console.log("");
103
- ASCII_ART.forEach((line2) => {
104
- console.log(" " + cyan(line2));
103
+ ASCII_ART.forEach((line) => {
104
+ console.log(" " + gold(line));
105
105
  });
106
106
  console.log("");
107
107
  console.log(` ${gray(`v${package_default.version}`)} ${chalk.white.bold("Framer \xB7 Webflow \xB7 Wix Exporter")}
@@ -263,27 +263,304 @@ import chalk3 from "chalk";
263
263
  function setCooking(spinner) {
264
264
  _cooking = spinner;
265
265
  }
266
- function output(line2) {
266
+ function trunc(text, max) {
267
+ if (text.length <= max) return text;
268
+ return text.slice(0, max - 2) + "..";
269
+ }
270
+ function nextColor() {
271
+ return MSG_COLORS[_msgIdx++ % MSG_COLORS.length];
272
+ }
273
+ function output(line) {
267
274
  if (_cooking) {
268
- _cooking.log(line2);
275
+ _cooking.log(line);
269
276
  } else {
270
- console.log(line2);
277
+ console.log(line);
271
278
  }
272
279
  }
273
- var _cooking, T, log, info, warn, success;
280
+ var _cooking, T, MSG_COLORS, _msgIdx, log, info, warn, success;
274
281
  var init_logger = __esm({
275
282
  "src/logger/index.ts"() {
276
283
  "use strict";
277
284
  _cooking = null;
278
285
  T = () => (/* @__PURE__ */ new Date()).toISOString().slice(11, 19);
279
- log = (m) => output(`${chalk3.gray(`[${T()}]`)} ${chalk3.cyan("[LOG]")} ${m}`);
280
- info = (m) => output(`${chalk3.gray(`[${T()}]`)} ${chalk3.blue("[INFO]")} ${chalk3.bold(m)}`);
286
+ MSG_COLORS = [
287
+ (s) => chalk3.hex("#e8c33a")(s),
288
+ (s) => chalk3.hex("#d4a76a")(s),
289
+ (s) => chalk3.hex("#c8a040")(s),
290
+ (s) => chalk3.hex("#e0b040")(s),
291
+ (s) => chalk3.hex("#dab660")(s),
292
+ (s) => chalk3.hex("#c4953a")(s),
293
+ (s) => chalk3.hex("#daa520")(s),
294
+ (s) => chalk3.hex("#b8960a")(s)
295
+ ];
296
+ _msgIdx = 0;
297
+ log = (m) => output(`${chalk3.hex("#6d6d6d")(`[${T()}]`)} ${chalk3.hex("#D4A017")("[LOG]")} ${nextColor()(trunc(m, 120))}`);
298
+ info = (m) => output(`${chalk3.hex("#757575")(`[${T()}]`)} ${chalk3.hex("#E8A317").bold("[INFO]")} ${chalk3.bold(trunc(m, 120))}`);
281
299
  warn = (m) => {
282
- const line2 = `${chalk3.gray(`[${T()}]`)} ${chalk3.yellow("[WARN]")} ${chalk3.yellow(m)}`;
283
- if (_cooking) _cooking.log(line2);
284
- else console.warn(line2);
300
+ const line = `${chalk3.hex("#8a8a8a")(`[${T()}]`)} ${chalk3.hex("#CC7722").bold("[WARN]")} ${chalk3.hex("#CC7722")(trunc(m, 120))}`;
301
+ if (_cooking) _cooking.log(line);
302
+ else console.warn(line);
303
+ };
304
+ success = (m) => output(`${chalk3.hex("#7a7a7a")(`[${T()}]`)} ${chalk3.greenBright("[OK]")} ${chalk3.green(trunc(m, 120))}`);
305
+ }
306
+ });
307
+
308
+ // src/platforms/framer.ts
309
+ var FONT_EXTS, framer;
310
+ var init_framer = __esm({
311
+ "src/platforms/framer.ts"() {
312
+ "use strict";
313
+ FONT_EXTS = [".woff2", ".woff", ".ttf", ".otf"];
314
+ framer = {
315
+ name: "framer",
316
+ displayName: "Framer",
317
+ detectByUrl(url) {
318
+ return /\.framer\.(app|website)|framercanvas\.com/.test(url);
319
+ },
320
+ detectByHtml(html) {
321
+ return html.includes('id="main"') && (html.includes("framerstatic.com") || html.includes("framerusercontent.com"));
322
+ },
323
+ stripDomains: ["events.framer.com", "api.framer.com", "collect.frameranalytics.com"],
324
+ stripSelectors: [
325
+ 'script[src*="events.framer.com"]',
326
+ "#__framer-badge-container",
327
+ "#__framer-badge",
328
+ 'link[href*="canvas-sandbox"]',
329
+ 'script[src*="framer.com/bootstrap"]'
330
+ ],
331
+ stripPatterns: [
332
+ /<div id="__framer-badge-container"[^>]*><\/div>/g,
333
+ /<script>try\{if\(localStorage\.get\("__framer_force_showing_editorbar_since"\)\)[^<]*<\/script>/g
334
+ ],
335
+ hydrationTimeout: 1e4,
336
+ needsHydrationCheck: true,
337
+ mapAssetDir(host, pathname, ext) {
338
+ if (host.includes("framerusercontent.com")) {
339
+ if (pathname.startsWith("/images/")) return "assets/images";
340
+ if (pathname.startsWith("/assets/")) {
341
+ return FONT_EXTS.includes(ext) ? "assets/fonts" : "assets/misc";
342
+ }
343
+ if (pathname.startsWith("/sites/")) {
344
+ if (ext === ".mjs" || ext === ".js") return "scripts/vendor";
345
+ if (ext === ".json") return "data";
346
+ if (ext === ".css") return "styles";
347
+ if (ext === ".framercms") return "data";
348
+ return "assets/misc";
349
+ }
350
+ if (pathname.startsWith("/modules/")) {
351
+ return ext === ".framercms" ? "data" : "scripts/modules";
352
+ }
353
+ return "assets/misc";
354
+ }
355
+ if (host.includes("app.framerstatic.com")) {
356
+ if (ext === ".css") return "styles";
357
+ if (ext === ".mjs" || ext === ".js") return "scripts/vendor";
358
+ if (ext === ".woff2" || ext === ".woff") return "assets/fonts";
359
+ if (ext === ".png" || ext === ".svg") return "assets/images";
360
+ return "assets/misc";
361
+ }
362
+ if (host.includes("framercanvas.com") || host.includes("framer.com")) {
363
+ if (ext === ".mjs" || ext === ".js") return "scripts/vendor";
364
+ if (ext === ".css") return "styles";
365
+ return "assets/misc";
366
+ }
367
+ return null;
368
+ }
369
+ };
370
+ }
371
+ });
372
+
373
+ // src/platforms/webflow.ts
374
+ var IMG_EXTS, FONT_EXTS2, VIDEO_EXTS, webflow;
375
+ var init_webflow = __esm({
376
+ "src/platforms/webflow.ts"() {
377
+ "use strict";
378
+ IMG_EXTS = [".jpg", ".jpeg", ".png", ".gif", ".svg", ".webp", ".avif"];
379
+ FONT_EXTS2 = [".woff2", ".woff", ".ttf", ".otf", ".eot"];
380
+ VIDEO_EXTS = [".mp4", ".webm", ".ogg"];
381
+ webflow = {
382
+ name: "webflow",
383
+ displayName: "Webflow",
384
+ detectByUrl(url) {
385
+ return /\.webflow\.(io|com)/.test(url);
386
+ },
387
+ detectByHtml(html) {
388
+ return html.includes("data-wf-site") || html.includes("w-webflow-badge") || html.includes("Webflow") || html.includes("webflow.js");
389
+ },
390
+ stripDomains: ["js-agent.newrelic.com", "cdn.heapanalytics.com", "tr.snapchat.com"],
391
+ stripSelectors: [".w-webflow-badge", 'link[href*="editorbar"]'],
392
+ stripPatterns: [
393
+ /<a[^>]*class="[^"]*w-webflow-badge[^"]*"[^>]*>[\s\S]*?<\/a>/g,
394
+ /<a[^>]*href="[^"]*webflow\.com\?utm_campaign=brandjs[^"]*"[^>]*>[\s\S]*?<\/a>/g,
395
+ /<style>[^<]*\.w-webflow-badge[^<]*<\/style>/g,
396
+ /Powered by <a[^>]*href="[^"]*webflow\.com"[^>]*>[^<]*<\/a>/g,
397
+ /<!-- This site was created in Webflow\.[^>]*-->/g,
398
+ /<html([^>]*) data-wf-domain="[^"]*"/g,
399
+ /<html([^>]*) data-wf-page="[^"]*"/g,
400
+ /<html([^>]*) data-wf-site="[^"]*"/g,
401
+ /<html([^>]*) data-wf-status="[^"]*"/g,
402
+ /<meta[^>]*content="Webflow"[^>]*>/g
403
+ ],
404
+ hydrationTimeout: 2e3,
405
+ needsHydrationCheck: false,
406
+ mapAssetDir(host, pathname, ext) {
407
+ if (host.includes("website-files.com") || host.includes("webflow.com") || host.includes("uploads-ssl.webflow.com")) {
408
+ if (VIDEO_EXTS.includes(ext)) return "assets/videos";
409
+ if (pathname.includes("/images/") || IMG_EXTS.includes(ext)) return "assets/images";
410
+ if (pathname.includes("/css/") || ext === ".css") return "styles";
411
+ if (pathname.includes("/js/") || ext === ".js") return "scripts/vendor";
412
+ if (pathname.includes("/gsap/") || pathname.includes("/plugins/")) return "scripts/vendor";
413
+ if (FONT_EXTS2.includes(ext)) return "assets/fonts";
414
+ return "assets/misc";
415
+ }
416
+ if (host.includes("d3e54v103j8qbb.cloudfront.net")) {
417
+ if (ext === ".js") return "scripts/vendor";
418
+ if (ext === ".css") return "styles";
419
+ if (IMG_EXTS.includes(ext)) return "assets/images";
420
+ return "assets/misc";
421
+ }
422
+ return null;
423
+ }
424
+ };
425
+ }
426
+ });
427
+
428
+ // src/platforms/wix.ts
429
+ var IMG_EXTS2, FONT_EXTS3, VIDEO_EXTS2, wix;
430
+ var init_wix = __esm({
431
+ "src/platforms/wix.ts"() {
432
+ "use strict";
433
+ IMG_EXTS2 = [".jpg", ".jpeg", ".png", ".gif", ".svg", ".webp", ".avif", ".ico"];
434
+ FONT_EXTS3 = [".woff2", ".woff", ".ttf", ".otf", ".eot"];
435
+ VIDEO_EXTS2 = [".mp4", ".webm", ".ogg"];
436
+ wix = {
437
+ name: "wix",
438
+ displayName: "Wix",
439
+ detectByUrl(url) {
440
+ return /\.wixsite\.com|\.wix\.com/.test(url);
441
+ },
442
+ detectByHtml(html) {
443
+ return html.includes("wix-viewer-model") || html.includes('id="WIX_ADS"') || html.includes("X-Wix-") || html.includes("Wix.com") || html.includes("wixcode-sdk") || html.includes("data-wix") || html.includes("wix-code") || html.includes("WixCode") || /\bwix\.com\b/.test(html) || /meta\s+name=["']generator["']\s+content=["'][^"']*Wix[^"']*["']/i.test(html) || /_wix_/i.test(html) || /wix-ecom/i.test(html);
444
+ },
445
+ stripDomains: [
446
+ "frog.wix.com",
447
+ "bi.wixapi.com",
448
+ "fed.wixcodescheduler.com",
449
+ "editor.wix.com",
450
+ "panorama.wixapps.net"
451
+ ],
452
+ stripSelectors: ["#WIX_ADS", ".wix-ads", "#wix-badge", "#SCROLL_TO_TOP"],
453
+ stripPatterns: [
454
+ /<div[^>]*class="[^"]*wix-ads[^"]*"[^>]*>[\s\S]*?<\/div>/g
455
+ ],
456
+ hydrationTimeout: 3e3,
457
+ needsHydrationCheck: false,
458
+ mapAssetDir(host, pathname, ext) {
459
+ if (host === "video.wixstatic.com") {
460
+ return "assets/videos";
461
+ }
462
+ if (host.includes("wixstatic.com")) {
463
+ if (VIDEO_EXTS2.includes(ext)) return "assets/videos";
464
+ if (pathname.includes("/images/") || IMG_EXTS2.includes(ext)) return "assets/images";
465
+ if (ext === ".css") return "styles";
466
+ if (ext === ".js") return "scripts/vendor";
467
+ if (FONT_EXTS3.includes(ext)) return "assets/fonts";
468
+ return "assets/misc";
469
+ }
470
+ if (host.includes("parastorage.com")) {
471
+ if (ext === ".js") return "scripts/vendor";
472
+ if (ext === ".css") return "styles";
473
+ if (FONT_EXTS3.includes(ext)) return "assets/fonts";
474
+ if (IMG_EXTS2.includes(ext)) return "assets/images";
475
+ return "assets/misc";
476
+ }
477
+ return null;
478
+ }
285
479
  };
286
- success = (m) => output(`${chalk3.gray(`[${T()}]`)} ${chalk3.green("[OK]")} ${chalk3.green(m)}`);
480
+ }
481
+ });
482
+
483
+ // src/platforms/detect.ts
484
+ function detectByUrl(url) {
485
+ for (const platform of ALL_PLATFORMS) {
486
+ if (platform.detectByUrl(url)) return platform;
487
+ }
488
+ return null;
489
+ }
490
+ function detectByHtml(html) {
491
+ for (const platform of ALL_PLATFORMS) {
492
+ if (platform.detectByHtml(html)) return platform;
493
+ }
494
+ return null;
495
+ }
496
+ function detectPlatform(url, html) {
497
+ const byUrl = detectByUrl(url);
498
+ if (byUrl) return byUrl;
499
+ if (html) {
500
+ const byHtml = detectByHtml(html);
501
+ if (byHtml) return byHtml;
502
+ }
503
+ return framer;
504
+ }
505
+ async function detectByDom(page) {
506
+ try {
507
+ const signal = await page.evaluate(() => {
508
+ const html = document.documentElement.outerHTML || "";
509
+ if (/wix-viewer-model|_wix_|wix-ecom/i.test(html)) return "wix";
510
+ if (/data-wf-|w-webflow-badge|webflow\.js/i.test(html)) return "webflow";
511
+ if (/framerusercontent|framercanvas|framerstatic/i.test(html)) return "framer";
512
+ const srcs = [];
513
+ const scripts = document.querySelectorAll("script[src]");
514
+ scripts.forEach((s) => {
515
+ if (s.src) srcs.push(s.src);
516
+ });
517
+ const allSrcs = srcs.join(" ");
518
+ if (/wixstatic\.com|parastorage\.com/.test(allSrcs)) return "wix";
519
+ if (/website-files\.com|webflow\.com/.test(allSrcs)) return "webflow";
520
+ if (/framerusercontent\.com|framerstatic\.com|framer\.app/.test(allSrcs)) return "framer";
521
+ return "";
522
+ });
523
+ if (signal === "wix") return wix;
524
+ if (signal === "webflow") return webflow;
525
+ if (signal === "framer") return framer;
526
+ } catch {
527
+ }
528
+ return null;
529
+ }
530
+ function getPlatformByName(name) {
531
+ const map = { framer, webflow, wix };
532
+ return map[name] || framer;
533
+ }
534
+ var ALL_PLATFORMS;
535
+ var init_detect = __esm({
536
+ "src/platforms/detect.ts"() {
537
+ "use strict";
538
+ init_framer();
539
+ init_webflow();
540
+ init_wix();
541
+ ALL_PLATFORMS = [framer, webflow, wix];
542
+ }
543
+ });
544
+
545
+ // src/platforms/index.ts
546
+ var platforms_exports = {};
547
+ __export(platforms_exports, {
548
+ detectByDom: () => detectByDom,
549
+ detectByHtml: () => detectByHtml,
550
+ detectByUrl: () => detectByUrl,
551
+ detectPlatform: () => detectPlatform,
552
+ framer: () => framer,
553
+ getPlatformByName: () => getPlatformByName,
554
+ webflow: () => webflow,
555
+ wix: () => wix
556
+ });
557
+ var init_platforms = __esm({
558
+ "src/platforms/index.ts"() {
559
+ "use strict";
560
+ init_framer();
561
+ init_webflow();
562
+ init_wix();
563
+ init_detect();
287
564
  }
288
565
  });
289
566
 
@@ -342,6 +619,12 @@ async function launchAndCapture(exporter) {
342
619
  });
343
620
  success("Page loaded (networkidle2)");
344
621
  log("Intercepted " + intercepted + " resources, blocked " + blocked + " tracking requests");
622
+ log("Checking DOM-based platform detection...");
623
+ const domDetected = await detectByDom(exporter.page);
624
+ if (domDetected && domDetected.name !== exporter.platform.name) {
625
+ log("Platform refined from DOM: " + domDetected.displayName + " (override: " + exporter.platform.name + ")");
626
+ exporter.platform = domDetected;
627
+ }
345
628
  exporter.cooking?.update("Waiting for " + exporter.platform.displayName + " hydration...");
346
629
  if (exporter.platform.needsHydrationCheck) {
347
630
  log("Checking for #main element hydration...");
@@ -403,15 +686,42 @@ async function launchAndCapture(exporter) {
403
686
  const imgCount = [...exporter.assets.entries.values()].filter((e) => e.localPath.startsWith("assets/images")).length;
404
687
  const fontCount = [...exporter.assets.entries.values()].filter((e) => e.localPath.startsWith("assets/fonts")).length;
405
688
  log(" CSS: " + cssCount + " | JS: " + jsCount + " | Images: " + imgCount + " | Fonts: " + fontCount);
406
- await exporter.browser.close();
407
- exporter.browser = null;
408
- log("Browser closed");
689
+ }
690
+ async function closeBrowser(exporter) {
691
+ if (exporter.browser) {
692
+ await exporter.browser.close();
693
+ exporter.browser = null;
694
+ log("Browser closed");
695
+ }
696
+ }
697
+ async function captureSubpage(page, url, platform) {
698
+ log(" Navigating to sub-page: " + url);
699
+ await page.goto(url, { waitUntil: "networkidle2", timeout: CFG.timeout });
700
+ if (platform.needsHydrationCheck) {
701
+ await page.evaluate(
702
+ `new Promise(function(r) {
703
+ var t = Date.now();
704
+ (function tick() {
705
+ var m = document.getElementById('main') || document.body;
706
+ if (m && m.children.length > 0) setTimeout(r, 500);
707
+ else if (Date.now() - t > ${platform.hydrationTimeout}) r();
708
+ else setTimeout(tick, 200);
709
+ })();
710
+ })`
711
+ );
712
+ } else {
713
+ await new Promise((r) => setTimeout(r, 1e3));
714
+ }
715
+ const html = await page.evaluate(() => document.documentElement.outerHTML || document.body.innerHTML);
716
+ log(" Sub-page fetched: " + (html.length / 1024).toFixed(1) + " KB");
717
+ return html;
409
718
  }
410
719
  var init_capture = __esm({
411
720
  "src/exporter/capture.ts"() {
412
721
  "use strict";
413
722
  init_config();
414
723
  init_logger();
724
+ init_platforms();
415
725
  }
416
726
  });
417
727
 
@@ -843,16 +1153,64 @@ var init_output = __esm({
843
1153
  }
844
1154
  });
845
1155
 
846
- // src/exporter/summary.ts
847
- import fs3 from "fs/promises";
848
- import path4 from "path";
1156
+ // src/cli/box.ts
849
1157
  import chalk4 from "chalk";
850
- function getWidth2() {
851
- return process.stdout.columns || 80;
1158
+ function maxWidth() {
1159
+ return Math.min(process.stdout.columns || 80, 62);
1160
+ }
1161
+ function padRight(text, w) {
1162
+ const visible = stripAnsi(text).length;
1163
+ if (visible >= w) return text;
1164
+ return text + " ".repeat(w - visible);
1165
+ }
1166
+ function stripAnsi(s) {
1167
+ return s.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "");
1168
+ }
1169
+ function boxTop(w) {
1170
+ const inner = w - 4;
1171
+ return " " + B("\u2554\u2550") + B("\u2550".repeat(inner)) + B("\u2550\u2557");
1172
+ }
1173
+ function boxBot(w) {
1174
+ const inner = w - 4;
1175
+ return " " + B("\u255A\u2550") + B("\u2550".repeat(inner)) + B("\u2550\u255D");
852
1176
  }
1177
+ function boxLine(w, text) {
1178
+ const inner = w - 4;
1179
+ const padded = padRight(text, inner);
1180
+ return " " + B("\u2551 ") + padded + B(" \u2551");
1181
+ }
1182
+ function boxSep(w) {
1183
+ const inner = w - 4;
1184
+ return " " + B("\u2560\u2550") + B("\u2550".repeat(inner)) + B("\u2550\u2563");
1185
+ }
1186
+ function boxRow(w, label, value) {
1187
+ const inner = w - 4;
1188
+ const labelPlain = stripAnsi(chalk4.bold(label));
1189
+ const visible = labelPlain.length + 1 + value.length;
1190
+ if (visible > inner) {
1191
+ const avail = inner - labelPlain.length - 2;
1192
+ const truncated = value.length > avail ? value.slice(0, avail - 1) + ".." : value;
1193
+ return " " + G("\u2551 ") + chalk4.bold(label) + ": " + chalk4.yellow(truncated) + " ".repeat(Math.max(0, inner - labelPlain.length - 1 - truncated.length)) + G(" \u2551");
1194
+ }
1195
+ const right = inner - labelPlain.length - 1 - value.length;
1196
+ return " " + G("\u2551 ") + chalk4.bold(label) + ": " + chalk4.yellow(value) + " ".repeat(right) + G(" \u2551");
1197
+ }
1198
+ var B, G;
1199
+ var init_box = __esm({
1200
+ "src/cli/box.ts"() {
1201
+ "use strict";
1202
+ B = chalk4.hex("#8B6914");
1203
+ G = chalk4.hex("#C4953A");
1204
+ }
1205
+ });
1206
+
1207
+ // src/exporter/summary.ts
1208
+ import fs3 from "fs/promises";
1209
+ import path4 from "path";
1210
+ import chalk5 from "chalk";
853
1211
  async function printSummary(exporter) {
854
- const width = getWidth2();
855
- const isSmall = width < 50;
1212
+ const w = maxWidth();
1213
+ const isSmall = w < 50;
856
1214
  const count = async (d) => {
857
1215
  try {
858
1216
  return (await fs3.readdir(path4.join(exporter.outDir, d))).length;
@@ -860,7 +1218,7 @@ async function printSummary(exporter) {
860
1218
  return 0;
861
1219
  }
862
1220
  };
863
- const [imgs, fonts, videos, misc, scripts, vendor, styles, data] = await Promise.all([
1221
+ const [imgs, fonts, videos, misc, scripts, vendor, styles, data, subpages] = await Promise.all([
864
1222
  count("assets/images"),
865
1223
  count("assets/fonts"),
866
1224
  count("assets/videos"),
@@ -868,316 +1226,125 @@ async function printSummary(exporter) {
868
1226
  count("scripts/modules"),
869
1227
  count("scripts/vendor"),
870
1228
  count("styles"),
871
- count("data")
1229
+ count("data"),
1230
+ count("subpages")
872
1231
  ]);
1232
+ const G2 = chalk5.hex("#D4A017");
1233
+ const G22 = chalk5.hex("#DAA520");
1234
+ const C2 = chalk5.hex("#E0B040");
1235
+ const Y = chalk5.yellow;
1236
+ const O = chalk5.hex("#CC7722");
1237
+ const Br = chalk5.hex("#B8860B");
1238
+ const Gr = chalk5.gray;
1239
+ const Gn = chalk5.green;
1240
+ const entries = [
1241
+ ["styles/", styles, "CSS", G2],
1242
+ ["scripts/vendor/", vendor, "JS vendor", G22],
1243
+ ["scripts/modules/", scripts, "JS modules", C2],
1244
+ ["assets/images/", imgs, "images", Y],
1245
+ ["assets/videos/", videos, "videos", O],
1246
+ ["assets/fonts/", fonts, "fonts", Br],
1247
+ ["assets/misc/", misc, "misc", Gr],
1248
+ ["data/", data, "data", Gr],
1249
+ ["subpages/", subpages, "pages", Gn]
1250
+ ];
873
1251
  console.log("");
874
1252
  if (!isSmall) {
875
- console.log(chalk4.magenta(" \u250C\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\u2510"));
876
- console.log(chalk4.magenta(" \u2502") + chalk4.bold.white(" Export Summary ") + chalk4.magenta("\u2502"));
877
- console.log(chalk4.magenta(" \u251C\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\u2524"));
1253
+ console.log(boxTop(w));
1254
+ console.log(boxLine(w, chalk5.bold.white(" Export Summary")));
1255
+ console.log(boxSep(w));
878
1256
  } else {
879
- console.log(chalk4.bold.white(" Export Summary:"));
880
- }
881
- const row = (label, count2, type) => {
882
- if (count2 === 0) return;
883
- const l = label.padEnd(18);
884
- const c = String(count2).padStart(3);
1257
+ console.log(chalk5.bold.white(" Export Summary:"));
1258
+ }
1259
+ for (const [label, cnt, type, color] of entries) {
1260
+ if (cnt === 0) continue;
1261
+ const inner = w - 4;
1262
+ const l = label.padEnd(16);
1263
+ const c = String(cnt).padStart(3);
1264
+ const rowText = `${color(l)}${chalk5.white(c)} ${chalk5.gray(type)}`;
1265
+ const visible = 16 + 3 + 2 + type.length;
1266
+ const pad = Math.max(0, inner - visible);
885
1267
  if (isSmall) {
886
- console.log(` ${chalk4.yellow(label)} ${chalk4.white(String(count2))} ${chalk4.gray(type)}`);
1268
+ console.log(` ${color(label)} ${chalk5.white(String(cnt))} ${chalk5.gray(type)}`);
887
1269
  } else {
888
- console.log(` ${chalk4.magenta("\u2502")} ${chalk4.yellow(l)} ${chalk4.white(c)} ${chalk4.gray(type.padEnd(20))} ${chalk4.magenta("\u2502")}`);
1270
+ console.log(" " + chalk5.hex("#C4953A")("\u2551 ") + rowText + " ".repeat(pad) + chalk5.hex("#C4953A")(" \u2551"));
889
1271
  }
890
- };
891
- row("styles/", styles, "CSS files");
892
- row("scripts/vendor/", vendor, "JS modules");
893
- row("scripts/modules/", scripts, "components");
894
- row("assets/images/", imgs, "images");
895
- row("assets/videos/", videos, "videos");
896
- row("assets/fonts/", fonts, "fonts");
897
- row("assets/misc/", misc, "misc files");
898
- row("data/", data, "data files");
1272
+ }
899
1273
  if (!isSmall) {
900
- console.log(chalk4.magenta(" \u2514\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\u2518"));
1274
+ console.log(boxBot(w));
901
1275
  }
902
1276
  console.log("");
903
- const quotedDir = `"${exporter.outDir}"`;
1277
+ const cdCmd = "cd " + path4.basename(exporter.outDir) + " && node serve.cjs";
904
1278
  if (!isSmall) {
905
- console.log(chalk4.magenta(" \u250C\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\u2510"));
906
- console.log(chalk4.magenta(" \u2502") + chalk4.bold.white(" To serve locally ") + chalk4.magenta("\u2502"));
907
- console.log(chalk4.magenta(" \u251C\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\u2524"));
908
- console.log(` ${chalk4.magenta("\u2502")} ${chalk4.cyan("cd " + path4.basename(exporter.outDir) + " && node serve.cjs").padEnd(44)} ${chalk4.magenta("\u2502")}`);
909
- console.log(chalk4.magenta(" \u2514\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\u2518"));
1279
+ console.log(boxTop(w));
1280
+ console.log(boxLine(w, chalk5.bold.white(" To serve locally")));
1281
+ console.log(boxSep(w));
1282
+ const inner = w - 6;
1283
+ const cmdLen = cdCmd.length;
1284
+ const pad = Math.max(0, inner - cmdLen);
1285
+ console.log(" " + chalk5.hex("#C4953A")("\u2551 ") + G2(cdCmd) + " ".repeat(pad) + chalk5.hex("#9e9e9e")(" \u{1F5D0}") + chalk5.hex("#C4953A")(" \u2551"));
1286
+ console.log(boxBot(w));
910
1287
  } else {
911
- console.log(chalk4.bold.white(" To serve locally:"));
912
- console.log(` ${chalk4.cyan("cd " + path4.basename(exporter.outDir) + " && node serve.cjs")}`);
1288
+ console.log(chalk5.bold.white(" To serve locally:"));
1289
+ console.log(` ${G2(cdCmd)}`);
913
1290
  }
914
1291
  console.log("");
915
- console.log(chalk4.gray(" NOTE: Must be served via HTTP for JS modules to work."));
1292
+ console.log(chalk5.gray(" NOTE: Must be served via HTTP for JS modules to work."));
916
1293
  console.log("");
917
1294
  }
918
1295
  var init_summary = __esm({
919
1296
  "src/exporter/summary.ts"() {
920
1297
  "use strict";
921
- }
922
- });
923
-
924
- // src/platforms/framer.ts
925
- var FONT_EXTS, framer;
926
- var init_framer = __esm({
927
- "src/platforms/framer.ts"() {
928
- "use strict";
929
- FONT_EXTS = [".woff2", ".woff", ".ttf", ".otf"];
930
- framer = {
931
- name: "framer",
932
- displayName: "Framer",
933
- detectByUrl(url) {
934
- return /\.framer\.(app|website)|framercanvas\.com/.test(url);
935
- },
936
- detectByHtml(html) {
937
- return html.includes('id="main"') && (html.includes("framerstatic.com") || html.includes("framerusercontent.com"));
938
- },
939
- stripDomains: ["events.framer.com", "api.framer.com", "collect.frameranalytics.com"],
940
- stripSelectors: [
941
- 'script[src*="events.framer.com"]',
942
- "#__framer-badge-container",
943
- "#__framer-badge",
944
- 'link[href*="canvas-sandbox"]',
945
- 'script[src*="framer.com/bootstrap"]'
946
- ],
947
- stripPatterns: [
948
- /<div id="__framer-badge-container"[^>]*><\/div>/g,
949
- /<script>try\{if\(localStorage\.get\("__framer_force_showing_editorbar_since"\)\)[^<]*<\/script>/g
950
- ],
951
- hydrationTimeout: 1e4,
952
- needsHydrationCheck: true,
953
- mapAssetDir(host, pathname, ext) {
954
- if (host.includes("framerusercontent.com")) {
955
- if (pathname.startsWith("/images/")) return "assets/images";
956
- if (pathname.startsWith("/assets/")) {
957
- return FONT_EXTS.includes(ext) ? "assets/fonts" : "assets/misc";
958
- }
959
- if (pathname.startsWith("/sites/")) {
960
- if (ext === ".mjs" || ext === ".js") return "scripts/vendor";
961
- if (ext === ".json") return "data";
962
- if (ext === ".css") return "styles";
963
- if (ext === ".framercms") return "data";
964
- return "assets/misc";
965
- }
966
- if (pathname.startsWith("/modules/")) {
967
- return ext === ".framercms" ? "data" : "scripts/modules";
968
- }
969
- return "assets/misc";
970
- }
971
- if (host.includes("app.framerstatic.com")) {
972
- if (ext === ".css") return "styles";
973
- if (ext === ".mjs" || ext === ".js") return "scripts/vendor";
974
- if (ext === ".woff2" || ext === ".woff") return "assets/fonts";
975
- if (ext === ".png" || ext === ".svg") return "assets/images";
976
- return "assets/misc";
977
- }
978
- if (host.includes("framercanvas.com") || host.includes("framer.com")) {
979
- if (ext === ".mjs" || ext === ".js") return "scripts/vendor";
980
- if (ext === ".css") return "styles";
981
- return "assets/misc";
982
- }
983
- return null;
984
- }
985
- };
986
- }
987
- });
988
-
989
- // src/platforms/webflow.ts
990
- var IMG_EXTS, FONT_EXTS2, VIDEO_EXTS, webflow;
991
- var init_webflow = __esm({
992
- "src/platforms/webflow.ts"() {
993
- "use strict";
994
- IMG_EXTS = [".jpg", ".jpeg", ".png", ".gif", ".svg", ".webp", ".avif"];
995
- FONT_EXTS2 = [".woff2", ".woff", ".ttf", ".otf", ".eot"];
996
- VIDEO_EXTS = [".mp4", ".webm", ".ogg"];
997
- webflow = {
998
- name: "webflow",
999
- displayName: "Webflow",
1000
- detectByUrl(url) {
1001
- return /\.webflow\.(io|com)/.test(url);
1002
- },
1003
- detectByHtml(html) {
1004
- return html.includes("data-wf-site") || html.includes("w-webflow-badge") || html.includes("Webflow") || html.includes("webflow.js");
1005
- },
1006
- stripDomains: ["js-agent.newrelic.com", "cdn.heapanalytics.com", "tr.snapchat.com"],
1007
- stripSelectors: [".w-webflow-badge", 'link[href*="editorbar"]'],
1008
- stripPatterns: [
1009
- /<a[^>]*class="[^"]*w-webflow-badge[^"]*"[^>]*>[\s\S]*?<\/a>/g,
1010
- /<a[^>]*href="[^"]*webflow\.com\?utm_campaign=brandjs[^"]*"[^>]*>[\s\S]*?<\/a>/g,
1011
- /<style>[^<]*\.w-webflow-badge[^<]*<\/style>/g,
1012
- /Powered by <a[^>]*href="[^"]*webflow\.com"[^>]*>[^<]*<\/a>/g,
1013
- /<!-- This site was created in Webflow\.[^>]*-->/g,
1014
- /<html([^>]*) data-wf-domain="[^"]*"/g,
1015
- /<html([^>]*) data-wf-page="[^"]*"/g,
1016
- /<html([^>]*) data-wf-site="[^"]*"/g,
1017
- /<html([^>]*) data-wf-status="[^"]*"/g,
1018
- /<meta[^>]*content="Webflow"[^>]*>/g
1019
- ],
1020
- hydrationTimeout: 2e3,
1021
- needsHydrationCheck: false,
1022
- mapAssetDir(host, pathname, ext) {
1023
- if (host.includes("website-files.com") || host.includes("webflow.com") || host.includes("uploads-ssl.webflow.com")) {
1024
- if (VIDEO_EXTS.includes(ext)) return "assets/videos";
1025
- if (pathname.includes("/images/") || IMG_EXTS.includes(ext)) return "assets/images";
1026
- if (pathname.includes("/css/") || ext === ".css") return "styles";
1027
- if (pathname.includes("/js/") || ext === ".js") return "scripts/vendor";
1028
- if (pathname.includes("/gsap/") || pathname.includes("/plugins/")) return "scripts/vendor";
1029
- if (FONT_EXTS2.includes(ext)) return "assets/fonts";
1030
- return "assets/misc";
1031
- }
1032
- if (host.includes("d3e54v103j8qbb.cloudfront.net")) {
1033
- if (ext === ".js") return "scripts/vendor";
1034
- if (ext === ".css") return "styles";
1035
- if (IMG_EXTS.includes(ext)) return "assets/images";
1036
- return "assets/misc";
1037
- }
1038
- return null;
1039
- }
1040
- };
1041
- }
1042
- });
1043
-
1044
- // src/platforms/wix.ts
1045
- var IMG_EXTS2, FONT_EXTS3, VIDEO_EXTS2, wix;
1046
- var init_wix = __esm({
1047
- "src/platforms/wix.ts"() {
1048
- "use strict";
1049
- IMG_EXTS2 = [".jpg", ".jpeg", ".png", ".gif", ".svg", ".webp", ".avif", ".ico"];
1050
- FONT_EXTS3 = [".woff2", ".woff", ".ttf", ".otf", ".eot"];
1051
- VIDEO_EXTS2 = [".mp4", ".webm", ".ogg"];
1052
- wix = {
1053
- name: "wix",
1054
- displayName: "Wix",
1055
- detectByUrl(url) {
1056
- return /\.wixsite\.com|\.wix\.com/.test(url);
1057
- },
1058
- detectByHtml(html) {
1059
- return html.includes("wix-viewer-model") || html.includes('id="WIX_ADS"') || html.includes("X-Wix-") || html.includes("Wix.com") || html.includes("wixcode-sdk");
1060
- },
1061
- stripDomains: [
1062
- "frog.wix.com",
1063
- "bi.wixapi.com",
1064
- "fed.wixcodescheduler.com",
1065
- "editor.wix.com",
1066
- "panorama.wixapps.net"
1067
- ],
1068
- stripSelectors: ["#WIX_ADS", ".wix-ads", "#wix-badge", "#SCROLL_TO_TOP"],
1069
- stripPatterns: [
1070
- /<div[^>]*class="[^"]*wix-ads[^"]*"[^>]*>[\s\S]*?<\/div>/g
1071
- ],
1072
- hydrationTimeout: 3e3,
1073
- needsHydrationCheck: false,
1074
- mapAssetDir(host, pathname, ext) {
1075
- if (host === "video.wixstatic.com") {
1076
- return "assets/videos";
1077
- }
1078
- if (host.includes("wixstatic.com")) {
1079
- if (VIDEO_EXTS2.includes(ext)) return "assets/videos";
1080
- if (pathname.includes("/images/") || IMG_EXTS2.includes(ext)) return "assets/images";
1081
- if (ext === ".css") return "styles";
1082
- if (ext === ".js") return "scripts/vendor";
1083
- if (FONT_EXTS3.includes(ext)) return "assets/fonts";
1084
- return "assets/misc";
1085
- }
1086
- if (host.includes("parastorage.com")) {
1087
- if (ext === ".js") return "scripts/vendor";
1088
- if (ext === ".css") return "styles";
1089
- if (FONT_EXTS3.includes(ext)) return "assets/fonts";
1090
- if (IMG_EXTS2.includes(ext)) return "assets/images";
1091
- return "assets/misc";
1092
- }
1093
- return null;
1094
- }
1095
- };
1096
- }
1097
- });
1098
-
1099
- // src/platforms/detect.ts
1100
- function detectByUrl(url) {
1101
- for (const platform of ALL_PLATFORMS) {
1102
- if (platform.detectByUrl(url)) return platform;
1103
- }
1104
- return null;
1105
- }
1106
- function detectByHtml(html) {
1107
- for (const platform of ALL_PLATFORMS) {
1108
- if (platform.detectByHtml(html)) return platform;
1109
- }
1110
- return null;
1111
- }
1112
- function detectPlatform(url, html) {
1113
- const byUrl = detectByUrl(url);
1114
- if (byUrl) return byUrl;
1115
- if (html) {
1116
- const byHtml = detectByHtml(html);
1117
- if (byHtml) return byHtml;
1118
- }
1119
- return framer;
1120
- }
1121
- function getPlatformByName(name) {
1122
- const map = { framer, webflow, wix };
1123
- return map[name] || framer;
1124
- }
1125
- var ALL_PLATFORMS;
1126
- var init_detect = __esm({
1127
- "src/platforms/detect.ts"() {
1128
- "use strict";
1129
- init_framer();
1130
- init_webflow();
1131
- init_wix();
1132
- ALL_PLATFORMS = [framer, webflow, wix];
1133
- }
1134
- });
1135
-
1136
- // src/platforms/index.ts
1137
- var platforms_exports = {};
1138
- __export(platforms_exports, {
1139
- detectByHtml: () => detectByHtml,
1140
- detectByUrl: () => detectByUrl,
1141
- detectPlatform: () => detectPlatform,
1142
- framer: () => framer,
1143
- getPlatformByName: () => getPlatformByName,
1144
- webflow: () => webflow,
1145
- wix: () => wix
1146
- });
1147
- var init_platforms = __esm({
1148
- "src/platforms/index.ts"() {
1149
- "use strict";
1150
- init_framer();
1151
- init_webflow();
1152
- init_wix();
1153
- init_detect();
1298
+ init_box();
1154
1299
  }
1155
1300
  });
1156
1301
 
1157
1302
  // src/cli/cooking.ts
1158
- import chalk5 from "chalk";
1159
- var SHINE_WIDTH, CookingSpinner;
1303
+ import chalk6 from "chalk";
1304
+ var SHINE_WIDTH, FRAME_INTERVAL, SPINNER_FRAMES, PALETTE, CookingSpinner;
1160
1305
  var init_cooking = __esm({
1161
1306
  "src/cli/cooking.ts"() {
1162
1307
  "use strict";
1163
- SHINE_WIDTH = 8;
1308
+ SHINE_WIDTH = 10;
1309
+ FRAME_INTERVAL = 140;
1310
+ SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
1311
+ PALETTE = [
1312
+ (s) => chalk6.hex("#D4A017")(s),
1313
+ (s) => chalk6.hex("#E8A317")(s),
1314
+ (s) => chalk6.hex("#DAA520")(s),
1315
+ (s) => chalk6.hex("#F0C040")(s),
1316
+ (s) => chalk6.hex("#C4953A")(s),
1317
+ (s) => chalk6.hex("#E6B83C")(s),
1318
+ (s) => chalk6.hex("#C8A951")(s),
1319
+ (s) => chalk6.hex("#D9B44D")(s)
1320
+ ];
1164
1321
  CookingSpinner = class {
1165
1322
  interval = null;
1323
+ bgInterval = null;
1166
1324
  frame = 0;
1167
1325
  phase = "";
1168
1326
  active = false;
1327
+ bar = 0;
1328
+ barDir = 1;
1169
1329
  start(phase = "") {
1170
1330
  this.phase = phase;
1171
1331
  this.frame = 0;
1332
+ this.bar = 0;
1333
+ this.barDir = 1;
1172
1334
  this.active = true;
1173
1335
  this.draw();
1174
1336
  this.interval = setInterval(() => {
1175
1337
  this.frame++;
1176
1338
  this.draw();
1177
- }, 70);
1339
+ }, FRAME_INTERVAL);
1340
+ this.bgInterval = setInterval(() => {
1341
+ this.bar++;
1342
+ this.draw();
1343
+ }, 800);
1178
1344
  }
1179
1345
  update(phase) {
1180
1346
  this.phase = phase;
1347
+ if (!this.active) this.draw();
1181
1348
  }
1182
1349
  log(message) {
1183
1350
  if (this.active) {
@@ -1194,18 +1361,27 @@ var init_cooking = __esm({
1194
1361
  clearInterval(this.interval);
1195
1362
  this.interval = null;
1196
1363
  }
1364
+ if (this.bgInterval) {
1365
+ clearInterval(this.bgInterval);
1366
+ this.bgInterval = null;
1367
+ }
1197
1368
  process.stdout.write("\r\x1B[2K");
1198
1369
  }
1199
1370
  draw() {
1200
1371
  if (!this.active) return;
1201
- const text = "Cooking";
1202
- const dotCount = 1 + this.frame % 3;
1203
- const dots = ".".repeat(dotCount);
1204
- const pad = " ".repeat(3 - dotCount);
1205
- const shimmer = this.renderShimmer(text);
1206
- const dotStr = chalk5.rgb(180, 180, 180)(dots);
1207
- const phaseText = this.phase ? ` ${chalk5.gray(this.phase)}` : "";
1208
- process.stdout.write(`\r\x1B[2K ${shimmer}${dotStr}${pad}${phaseText}`);
1372
+ const spinner = SPINNER_FRAMES[this.frame % SPINNER_FRAMES.length];
1373
+ const paletteFn = PALETTE[this.frame % PALETTE.length];
1374
+ const dotPhase = Math.floor(this.frame / 3) % 4;
1375
+ const dotStr = dotPhase === 0 ? " " : dotPhase === 1 ? ". " : dotPhase === 2 ? ".. " : "...";
1376
+ const shimmer = this.renderShimmer("Cooking");
1377
+ const spinnerChar = chalk6.hex("#F0C040")(spinner);
1378
+ const barLen = 12;
1379
+ const barPos = this.bar % (barLen * 2);
1380
+ const barStr = this.renderBar(barLen, barPos);
1381
+ const phaseStr = this.phase ? ` ${chalk6.gray(this.limitLen(this.phase, 38))}` : "";
1382
+ process.stdout.write(
1383
+ `\r\x1B[2K ${spinnerChar} ${shimmer} ${paletteFn(dotStr)} ${barStr}${phaseStr}`
1384
+ );
1209
1385
  }
1210
1386
  renderShimmer(text) {
1211
1387
  let result = "";
@@ -1214,14 +1390,36 @@ var init_cooking = __esm({
1214
1390
  const dist = Math.abs(i - pos);
1215
1391
  if (dist < SHINE_WIDTH) {
1216
1392
  const t = 1 - dist / SHINE_WIDTH;
1217
- const gray = Math.floor(180 + t * 75);
1218
- result += chalk5.rgb(gray, gray, gray)(text[i]);
1393
+ const g = Math.floor(160 + t * 95);
1394
+ result += chalk6.rgb(g, g, g)(text[i]);
1219
1395
  } else {
1220
- result += chalk5.rgb(180, 180, 180)(text[i]);
1396
+ result += chalk6.rgb(160, 160, 160)(text[i]);
1221
1397
  }
1222
1398
  }
1223
1399
  return result;
1224
1400
  }
1401
+ renderBar(len, pos) {
1402
+ let s = "";
1403
+ for (let i = 0; i < len; i++) {
1404
+ const dist = Math.abs(i - pos);
1405
+ if (dist < 3) {
1406
+ const t = 1 - dist / 3;
1407
+ const r = Math.floor(200 + t * 55);
1408
+ const g = Math.floor(160 + t * 50);
1409
+ const b = Math.floor(20 + t * 30);
1410
+ s += chalk6.rgb(r, g, b)("\u258C");
1411
+ } else if (dist < 6) {
1412
+ s += chalk6.rgb(140, 100, 20)("\u258C");
1413
+ } else {
1414
+ s += chalk6.rgb(50, 35, 10)(" ");
1415
+ }
1416
+ }
1417
+ return `[${s}]`;
1418
+ }
1419
+ limitLen(s, max) {
1420
+ if (s.length <= max) return s;
1421
+ return s.slice(0, max - 3) + "\u2026";
1422
+ }
1225
1423
  };
1226
1424
  }
1227
1425
  });
@@ -1234,7 +1432,7 @@ __export(exporter_exports, {
1234
1432
  });
1235
1433
  import fs4 from "fs/promises";
1236
1434
  import path5 from "path";
1237
- import chalk6 from "chalk";
1435
+ import chalk7 from "chalk";
1238
1436
  function deriveOutputName(url, platformName) {
1239
1437
  try {
1240
1438
  const parsed = new URL(url);
@@ -1292,11 +1490,14 @@ var init_exporter = __esm({
1292
1490
  this.platform = detectPlatform(siteUrl);
1293
1491
  }
1294
1492
  }
1295
- async run() {
1296
- console.log(chalk6.bold.magenta("\n Cooksite v4 - Full Mirror & Clean Export\n"));
1297
- info("Source : " + chalk6.underline(this.siteUrl));
1298
- info("Output : " + chalk6.yellow(this.outDir));
1299
- info("Platform : " + chalk6.magenta(this.platform.displayName));
1493
+ async run(includeSubpages = false) {
1494
+ console.log(chalk7.bold.hex("#D4A017")("\n Cooksite v4 - Full Mirror & Clean Export\n"));
1495
+ info("Source : " + chalk7.underline(this.siteUrl));
1496
+ info("Output : " + chalk7.yellow(this.outDir));
1497
+ info("Platform : " + chalk7.hex("#D4A017")(this.platform.displayName));
1498
+ if (includeSubpages) {
1499
+ info("Subpages : " + chalk7.green("enabled"));
1500
+ }
1300
1501
  console.log("");
1301
1502
  this.cooking = new CookingSpinner();
1302
1503
  setCooking(this.cooking);
@@ -1310,7 +1511,8 @@ var init_exporter = __esm({
1310
1511
  "styles",
1311
1512
  "scripts/vendor",
1312
1513
  "scripts/modules",
1313
- "data"
1514
+ "data",
1515
+ "subpages"
1314
1516
  ]) {
1315
1517
  await fs4.mkdir(path5.join(this.outDir, d), { recursive: true });
1316
1518
  }
@@ -1322,14 +1524,18 @@ var init_exporter = __esm({
1322
1524
  this.ssrHTML = buf.toString("utf-8");
1323
1525
  success("SSR HTML fetched (" + (this.ssrHTML.length / 1024).toFixed(1) + " KB)");
1324
1526
  } catch (e) {
1325
- log(chalk6.red("Could not fetch SSR HTML: " + e.message));
1527
+ log(chalk7.red("Could not fetch SSR HTML: " + e.message));
1326
1528
  }
1327
1529
  const htmlDetected = detectPlatform(this.siteUrl, this.ssrHTML);
1328
1530
  if (htmlDetected.name !== this.platform.name) {
1329
1531
  this.platform = htmlDetected;
1330
- log("Platform refined: " + chalk6.magenta(this.platform.displayName) + " (from HTML analysis)");
1532
+ log("Platform refined: " + chalk7.hex("#D4A017")(this.platform.displayName) + " (from HTML analysis)");
1331
1533
  }
1332
1534
  await launchAndCapture(this);
1535
+ if (includeSubpages && this.page) {
1536
+ await this.crawlSubpages();
1537
+ }
1538
+ await closeBrowser(this);
1333
1539
  this.cooking.update("Downloading assets...");
1334
1540
  await downloadAll(this);
1335
1541
  this.cooking.update("Building output...");
@@ -1340,6 +1546,64 @@ var init_exporter = __esm({
1340
1546
  success("Export complete!");
1341
1547
  await printSummary(this);
1342
1548
  }
1549
+ async crawlSubpages() {
1550
+ this.cooking?.update("Discovering sub-pages...");
1551
+ log("Scanning page for internal links...");
1552
+ const page = this.page;
1553
+ const baseUrl = new URL(this.siteUrl);
1554
+ const baseHost = baseUrl.hostname.replace(/^www\./, "");
1555
+ const links = await page.evaluate((host) => {
1556
+ const anchors = Array.from(document.querySelectorAll("a[href]"));
1557
+ const hrefs = /* @__PURE__ */ new Set();
1558
+ for (const a of anchors) {
1559
+ const href = a.href;
1560
+ if (!href || href.startsWith("javascript:") || href.startsWith("mailto:") || href.startsWith("tel:") || href.startsWith("#")) continue;
1561
+ try {
1562
+ const u = new URL(href);
1563
+ const h = u.hostname.replace(/^www\./, "");
1564
+ if (h === host && u.pathname !== "/" && u.pathname !== "" && !u.pathname.startsWith("/#")) {
1565
+ hrefs.add(href.split("#")[0]);
1566
+ }
1567
+ } catch {
1568
+ }
1569
+ }
1570
+ return Array.from(hrefs);
1571
+ }, baseHost);
1572
+ log("Found " + links.length + " sub-page links");
1573
+ const uniqueLinks = [...new Set(links)].slice(0, 50);
1574
+ if (uniqueLinks.length === 0) {
1575
+ log("No sub-pages to crawl");
1576
+ return;
1577
+ }
1578
+ for (let i = 0; i < uniqueLinks.length; i++) {
1579
+ const link = uniqueLinks[i];
1580
+ this.cooking?.update("Crawling sub-page " + (i + 1) + "/" + uniqueLinks.length);
1581
+ try {
1582
+ const html = await captureSubpage(page, link, {
1583
+ needsHydrationCheck: this.platform.needsHydrationCheck,
1584
+ hydrationTimeout: this.platform.hydrationTimeout
1585
+ });
1586
+ const slug = this.deriveSlug(link, baseUrl);
1587
+ const filename = slug + ".html";
1588
+ const filepath = path5.join(this.outDir, "subpages", filename);
1589
+ await fs4.writeFile(filepath, html, "utf-8");
1590
+ log(" Saved: subpages/" + filename);
1591
+ } catch (e) {
1592
+ log(" Skipped " + link + ": " + e.message);
1593
+ }
1594
+ }
1595
+ success("Sub-pages crawled: " + uniqueLinks.length);
1596
+ }
1597
+ deriveSlug(link, baseUrl) {
1598
+ try {
1599
+ const u = new URL(link);
1600
+ let pathname = u.pathname.replace(/\/+$/, "").replace(/^\//, "");
1601
+ if (!pathname) return "index";
1602
+ return pathname.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_") || "page";
1603
+ } catch {
1604
+ return "page";
1605
+ }
1606
+ }
1343
1607
  };
1344
1608
  }
1345
1609
  });
@@ -1347,7 +1611,7 @@ var init_exporter = __esm({
1347
1611
  // src/cli/select.ts
1348
1612
  import readline from "readline";
1349
1613
  import { stdin, stdout } from "process";
1350
- import chalk7 from "chalk";
1614
+ import chalk8 from "chalk";
1351
1615
  async function select(question, options, defaultIndex = 0) {
1352
1616
  return new Promise((resolve) => {
1353
1617
  let selected = defaultIndex;
@@ -1356,12 +1620,12 @@ async function select(question, options, defaultIndex = 0) {
1356
1620
  stdout.write(`\x1B[${options.length + 1}A`);
1357
1621
  stdout.write("\x1B[J");
1358
1622
  }
1359
- console.log(` ${chalk7.cyan("?")} ${chalk7.white.bold(question)}`);
1623
+ console.log(` ${chalk8.hex("#D4A017")("?")} ${chalk8.white.bold(question)}`);
1360
1624
  for (let i = 0; i < options.length; i++) {
1361
1625
  if (i === selected) {
1362
- console.log(` ${chalk7.cyan(">")} ${chalk7.white.bold(options[i].label)}`);
1626
+ console.log(` ${chalk8.hex("#D4A017")(">")} ${chalk8.white.bold(options[i].label)}`);
1363
1627
  } else {
1364
- console.log(` ${chalk7.gray(options[i].label)}`);
1628
+ console.log(` ${chalk8.gray(options[i].label)}`);
1365
1629
  }
1366
1630
  }
1367
1631
  };
@@ -1383,7 +1647,7 @@ async function select(question, options, defaultIndex = 0) {
1383
1647
  stdin.pause();
1384
1648
  stdout.write(`\x1B[${options.length + 1}A`);
1385
1649
  stdout.write("\x1B[J");
1386
- console.log(` ${chalk7.green("\u2713")} ${chalk7.white.bold(question)} ${chalk7.cyan(options[selected].label)}
1650
+ console.log(` ${chalk8.green("\u2713")} ${chalk8.white.bold(question)} ${chalk8.hex("#D4A017")(options[selected].label)}
1387
1651
  `);
1388
1652
  resolve(options[selected].value);
1389
1653
  } else if (key.ctrl && key.name === "c" || key.name === "escape") {
@@ -1411,46 +1675,27 @@ import readline2 from "readline/promises";
1411
1675
  import { stdin as stdin2, stdout as stdout2 } from "process";
1412
1676
  import path6 from "path";
1413
1677
  import { URL as URL4 } from "url";
1414
- import chalk8 from "chalk";
1415
- function getWidth3() {
1416
- return process.stdout.columns || 80;
1417
- }
1678
+ import chalk9 from "chalk";
1418
1679
  function drawHeader(title) {
1419
- const width = getWidth3();
1420
- const isSmall = width < 50;
1421
- const magenta = chalk8.magenta;
1422
- const boldWhite = chalk8.bold.white;
1423
- if (isSmall) {
1680
+ const w = maxWidth();
1681
+ if (w < 50) {
1424
1682
  console.log(`
1425
- ${magenta("\u25CF")} ${boldWhite(title)}`);
1683
+ ${chalk9.hex("#D4A017")("\u25CF")} ${chalk9.bold.white(title)}`);
1426
1684
  return;
1427
1685
  }
1428
- const boxWidth = 45;
1429
- const padding = Math.max(0, boxWidth - title.length - 2);
1430
- const rightPad = " ".repeat(padding);
1431
- console.log(magenta(" \u250C\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\u2510"));
1432
- console.log(magenta(" \u2502") + boldWhite(" " + title) + rightPad + magenta("\u2502"));
1433
- console.log(magenta(" \u2514\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\u2518"));
1686
+ console.log(boxTop(w));
1687
+ console.log(boxLine(w, chalk9.bold.white(" " + title)));
1688
+ console.log(boxBot(w));
1434
1689
  console.log("");
1435
1690
  }
1436
- function line(label, value) {
1437
- const width = getWidth3();
1438
- const isSmall = width < 50;
1439
- const magenta = chalk8.magenta;
1440
- if (isSmall) {
1441
- console.log(` ${chalk8.bold(label)}: ${chalk8.yellow(value)}`);
1442
- return;
1443
- }
1444
- console.log(` ${magenta("\u2502")} ${chalk8.bold(label.padEnd(14))} ${chalk8.yellow(value)}`);
1445
- }
1446
1691
  async function runSetup(legacyMode = false) {
1447
1692
  showBanner();
1448
- console.log(chalk8.bold.white(" Welcome to Framer Export setup.\n"));
1449
- console.log(chalk8.gray(" Supports Framer, Webflow, and Wix sites.\n"));
1693
+ console.log(chalk9.bold.white(" Welcome to Framer Export setup.\n"));
1694
+ console.log(chalk9.gray(" Supports Framer, Webflow, and Wix sites.\n"));
1450
1695
  const rl = readline2.createInterface({ input: stdin2, output: stdout2 });
1451
1696
  const ask = async (question, defaultVal) => {
1452
- const suffix = defaultVal ? chalk8.gray(` (${defaultVal})`) : "";
1453
- const prompt = ` ${chalk8.cyan("?")} ${chalk8.white.bold(question)}${suffix} ${chalk8.gray(">")} `;
1697
+ const suffix = defaultVal ? chalk9.gray(` (${defaultVal})`) : "";
1698
+ const prompt = ` ${chalk9.hex("#D4A017")("?")} ${chalk9.white.bold(question)}${suffix} ${chalk9.gray(">")} `;
1454
1699
  const answer = await rl.question(prompt);
1455
1700
  return answer.trim() || defaultVal || "";
1456
1701
  };
@@ -1462,54 +1707,59 @@ async function runSetup(legacyMode = false) {
1462
1707
  new URL4(input);
1463
1708
  siteUrl = input;
1464
1709
  } catch {
1465
- console.log(` ${chalk8.red("\u2717")} ${chalk8.red("Invalid URL. Enter a valid URL (https://...)")}
1710
+ console.log(` ${chalk9.red("\u2717")} ${chalk9.red("Invalid URL. Enter a valid URL (https://...)")}
1466
1711
  `);
1467
1712
  }
1468
1713
  }
1469
- console.log(` ${chalk8.green("\u2713")} ${chalk8.green("URL:")} ${chalk8.underline(siteUrl)}
1714
+ console.log(` ${chalk9.green("\u2713")} ${chalk9.green("URL:")} ${chalk9.underline(siteUrl)}
1470
1715
  `);
1471
1716
  drawHeader("Step 2 : Platform");
1472
1717
  const detected = detectPlatform(siteUrl);
1473
1718
  let platformName;
1474
1719
  if (legacyMode) {
1475
- console.log(` ${chalk8.blue("i")} Auto-detected: ${chalk8.magenta(detected.displayName)}`);
1720
+ console.log(` ${chalk9.blue("i")} Auto-detected: ${chalk9.hex("#D4A017")(detected.displayName)}`);
1476
1721
  const platformInput = await ask("Platform (framer/webflow/wix)", detected.name);
1477
1722
  platformName = ["framer", "webflow", "wix"].includes(platformInput) ? platformInput : detected.name;
1478
- console.log(` ${chalk8.green("\u2713")} ${chalk8.green("Platform:")} ${chalk8.magenta(platformName)}
1723
+ console.log(` ${chalk9.green("\u2713")} ${chalk9.green("Platform:")} ${chalk9.hex("#D4A017")(platformName)}
1479
1724
  `);
1480
1725
  } else {
1481
1726
  rl.close();
1482
1727
  const platforms = [
1483
- { label: `Framer${detected.name === "framer" ? chalk8.gray(" (detected)") : ""}`, value: "framer" },
1484
- { label: `Webflow${detected.name === "webflow" ? chalk8.gray(" (detected)") : ""}`, value: "webflow" },
1485
- { label: `Wix${detected.name === "wix" ? chalk8.gray(" (detected)") : ""}`, value: "wix" }
1728
+ { label: `Framer${detected.name === "framer" ? chalk9.gray(" (detected)") : ""}`, value: "framer" },
1729
+ { label: `Webflow${detected.name === "webflow" ? chalk9.gray(" (detected)") : ""}`, value: "webflow" },
1730
+ { label: `Wix${detected.name === "wix" ? chalk9.gray(" (detected)") : ""}`, value: "wix" }
1486
1731
  ];
1487
1732
  const defaultIdx = ["framer", "webflow", "wix"].indexOf(detected.name);
1488
1733
  platformName = await select("Select platform", platforms, Math.max(0, defaultIdx));
1489
1734
  }
1490
1735
  const rl2 = legacyMode ? rl : readline2.createInterface({ input: stdin2, output: stdout2 });
1491
1736
  const ask2 = async (question, defaultVal) => {
1492
- const suffix = defaultVal ? chalk8.gray(` (${defaultVal})`) : "";
1493
- const prompt = ` ${chalk8.cyan("?")} ${chalk8.white.bold(question)}${suffix} ${chalk8.gray(">")} `;
1737
+ const suffix = defaultVal ? chalk9.gray(` (${defaultVal})`) : "";
1738
+ const prompt = ` ${chalk9.hex("#D4A017")("?")} ${chalk9.white.bold(question)}${suffix} ${chalk9.gray(">")} `;
1494
1739
  const answer = await rl2.question(prompt);
1495
1740
  return answer.trim() || defaultVal || "";
1496
1741
  };
1497
1742
  const derivedName = deriveOutputName(siteUrl, platformName);
1498
1743
  drawHeader("Step 3 : Output Directory");
1499
1744
  const outDir = await ask2("Output directory", "./" + derivedName);
1500
- console.log(` ${chalk8.green("\u2713")} ${chalk8.green("Output:")} ${chalk8.yellow(outDir)}
1745
+ console.log(` ${chalk9.green("\u2713")} ${chalk9.green("Output:")} ${chalk9.yellow(outDir)}
1501
1746
  `);
1502
1747
  drawHeader("Step 4 : Options");
1503
1748
  let prettyPrint;
1504
1749
  let concurrency;
1750
+ let includeSubpages;
1505
1751
  if (legacyMode) {
1506
1752
  const prettyAnswer = await ask2("Pretty-print JS files? (y/n)", "y");
1507
1753
  prettyPrint = prettyAnswer.toLowerCase().startsWith("y");
1508
- console.log(` ${chalk8.green("\u2713")} Pretty-print: ${prettyPrint ? chalk8.green("yes") : chalk8.red("no")}
1754
+ console.log(` ${chalk9.green("\u2713")} Pretty-print: ${prettyPrint ? chalk9.green("yes") : chalk9.red("no")}
1755
+ `);
1756
+ const subpagesAnswer = await ask2("Export sub-pages? (y/n)", "n");
1757
+ includeSubpages = subpagesAnswer.toLowerCase().startsWith("y");
1758
+ console.log(` ${chalk9.green("\u2713")} Sub-pages: ${includeSubpages ? chalk9.green("yes") : chalk9.red("no")}
1509
1759
  `);
1510
1760
  const concurrencyAnswer = await ask2("Download concurrency", "12");
1511
1761
  concurrency = parseInt(concurrencyAnswer, 10) || 12;
1512
- console.log(` ${chalk8.green("\u2713")} Concurrency: ${chalk8.yellow(String(concurrency))}
1762
+ console.log(` ${chalk9.green("\u2713")} Concurrency: ${chalk9.yellow(String(concurrency))}
1513
1763
  `);
1514
1764
  } else {
1515
1765
  rl2.close();
@@ -1518,6 +1768,11 @@ async function runSetup(legacyMode = false) {
1518
1768
  { label: "No", value: "no" }
1519
1769
  ]);
1520
1770
  prettyPrint = prettyVal === "yes";
1771
+ const subpagesVal = await select("Export sub-pages?", [
1772
+ { label: "No", value: "no" },
1773
+ { label: "Yes, crawl and export", value: "yes" }
1774
+ ], 0);
1775
+ includeSubpages = subpagesVal === "yes";
1521
1776
  const concurrencyVal = await select("Download concurrency", [
1522
1777
  { label: "6 (slow connection)", value: "6" },
1523
1778
  { label: "12 (default)", value: "12" },
@@ -1525,23 +1780,29 @@ async function runSetup(legacyMode = false) {
1525
1780
  ], 1);
1526
1781
  concurrency = parseInt(concurrencyVal, 10);
1527
1782
  }
1783
+ const w = maxWidth();
1784
+ const isSmall = w < 50;
1785
+ const G2 = chalk9.hex("#C4953A");
1786
+ const B2 = chalk9.hex("#8B6914");
1528
1787
  console.log("");
1529
- const width = getWidth3();
1530
- const isSmall = width < 50;
1531
1788
  if (!isSmall) {
1532
- console.log(chalk8.magenta(" \u250C\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\u2510"));
1533
- console.log(chalk8.magenta(" \u2502") + chalk8.bold.white(" Summary ") + chalk8.magenta("\u2502"));
1534
- console.log(chalk8.magenta(" \u251C\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\u2524"));
1789
+ console.log(boxTop(w));
1790
+ console.log(boxLine(w, chalk9.bold.white(" Summary")));
1535
1791
  } else {
1536
- console.log(chalk8.bold.white(" Summary:"));
1792
+ console.log(chalk9.bold.white(" Summary:"));
1793
+ }
1794
+ for (const [label, value] of [
1795
+ ["URL", siteUrl],
1796
+ ["Platform", platformName],
1797
+ ["Output", path6.resolve(outDir)],
1798
+ ["Pretty-print", prettyPrint ? "yes" : "no"],
1799
+ ["Sub-pages", includeSubpages ? "yes" : "no"],
1800
+ ["Concurrency", String(concurrency)]
1801
+ ]) {
1802
+ console.log(boxRow(w, label, value));
1537
1803
  }
1538
- line("URL", siteUrl);
1539
- line("Platform", platformName);
1540
- line("Output", path6.resolve(outDir));
1541
- line("Pretty-print", prettyPrint ? "yes" : "no");
1542
- line("Concurrency", String(concurrency));
1543
1804
  if (!isSmall) {
1544
- console.log(chalk8.magenta(" \u2514\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\u2518"));
1805
+ console.log(boxBot(w));
1545
1806
  }
1546
1807
  console.log("");
1547
1808
  let startExport;
@@ -1558,7 +1819,7 @@ async function runSetup(legacyMode = false) {
1558
1819
  }
1559
1820
  if (!startExport) {
1560
1821
  console.log(`
1561
- ${chalk8.yellow("Export cancelled.")}
1822
+ ${chalk9.yellow("Export cancelled.")}
1562
1823
  `);
1563
1824
  return;
1564
1825
  }
@@ -1567,7 +1828,7 @@ async function runSetup(legacyMode = false) {
1567
1828
  CFG2.concurrency = concurrency;
1568
1829
  const exporter = new FramerExporter(siteUrl, path6.resolve(outDir), platformName);
1569
1830
  exporter.prettyPrint = prettyPrint;
1570
- await exporter.run();
1831
+ await exporter.run(includeSubpages);
1571
1832
  }
1572
1833
  var init_setup = __esm({
1573
1834
  "src/cli/setup.ts"() {
@@ -1576,6 +1837,7 @@ var init_setup = __esm({
1576
1837
  init_exporter();
1577
1838
  init_platforms();
1578
1839
  init_select();
1840
+ init_box();
1579
1841
  }
1580
1842
  });
1581
1843
 
@@ -1590,14 +1852,14 @@ import chalk2 from "chalk";
1590
1852
  function showHelp() {
1591
1853
  showBanner();
1592
1854
  console.log(chalk2.white.bold(" USAGE\n"));
1593
- console.log(` ${chalk2.cyan("npm run dev")} ${chalk2.gray("--")} ${chalk2.yellow("<url>")} ${chalk2.gray("[output-dir]")}`);
1594
- console.log(` ${chalk2.cyan("npm start")} ${chalk2.gray("--")} ${chalk2.yellow("<url>")} ${chalk2.gray("[output-dir]")}`);
1595
- console.log(` ${chalk2.cyan("framer-export")} ${chalk2.yellow("<url>")} ${chalk2.gray("[output-dir]")}`);
1855
+ console.log(` ${chalk2.hex("#D4A017")("framer-export")} ${chalk2.yellow("<url>")} ${chalk2.gray("[output-dir]")}`);
1856
+ console.log(` ${chalk2.hex("#D4A017")("fexport")} ${chalk2.yellow("<url>")} ${chalk2.gray("[output-dir]")}`);
1596
1857
  console.log("");
1597
1858
  console.log(chalk2.white.bold(" OPTIONS\n"));
1598
1859
  const opts = [
1599
1860
  ["--setup", "Launch the interactive setup assistant"],
1600
1861
  ["--platform <p>", "Force platform: framer, webflow, wix"],
1862
+ ["--subpages", "Crawl and export sub-pages"],
1601
1863
  ["--legacy-mode", "Use text input instead of arrow selection"],
1602
1864
  ["--help, -h", "Show this help message"]
1603
1865
  ];
@@ -1607,21 +1869,22 @@ function showHelp() {
1607
1869
  console.log("");
1608
1870
  console.log(chalk2.white.bold(" SUPPORTED PLATFORMS\n"));
1609
1871
  const platforms = [
1610
- ["Framer", "Auto-detected via .framer.app / .framer.ai URLs"],
1872
+ ["Framer", "Auto-detected via .framer.app / .framer.website URLs"],
1611
1873
  ["Webflow", "Auto-detected via .webflow.io URLs"],
1612
- ["Wix", "Auto-detected via .wixsite.com URLs"]
1874
+ ["Wix", "Auto-detected via .wixsite.com URLs + HTML analysis"]
1613
1875
  ];
1614
1876
  for (const [name, desc] of platforms) {
1615
- console.log(` ${chalk2.magenta(name.padEnd(12))} ${chalk2.gray(desc)}`);
1877
+ console.log(` ${chalk2.hex("#D4A017")(name.padEnd(12))} ${chalk2.gray(desc)}`);
1616
1878
  }
1617
1879
  console.log("");
1618
1880
  console.log(chalk2.white.bold(" EXAMPLES\n"));
1619
- console.log(` ${chalk2.gray("$")} ${chalk2.cyan("framer-export")} ${chalk2.yellow("https://mysite.framer.app")}`);
1620
- console.log(` ${chalk2.gray("$")} ${chalk2.cyan("framer-export")} ${chalk2.yellow("https://mysite.webflow.io")}`);
1621
- console.log(` ${chalk2.gray("$")} ${chalk2.cyan("framer-export")} ${chalk2.yellow("https://user.wixsite.com/my-site")}`);
1622
- console.log(` ${chalk2.gray("$")} ${chalk2.cyan("framer-export")} ${chalk2.green("--platform webflow")} ${chalk2.yellow("https://custom.com")}`);
1623
- console.log(` ${chalk2.gray("$")} ${chalk2.cyan("framer-export")} ${chalk2.green("--setup")}`);
1624
- console.log(` ${chalk2.gray("$")} ${chalk2.cyan("framer-export")} ${chalk2.green("--setup --legacy-mode")}`);
1881
+ console.log(` ${chalk2.gray("$")} ${chalk2.hex("#D4A017")("framer-export")} ${chalk2.yellow("https://mysite.framer.app")}`);
1882
+ console.log(` ${chalk2.gray("$")} ${chalk2.hex("#D4A017")("framer-export")} ${chalk2.yellow("https://mysite.webflow.io")}`);
1883
+ console.log(` ${chalk2.gray("$")} ${chalk2.hex("#D4A017")("framer-export")} ${chalk2.yellow("https://user.wixsite.com/my-site")}`);
1884
+ console.log(` ${chalk2.gray("$")} ${chalk2.hex("#D4A017")("framer-export")} ${chalk2.green("--platform webflow")} ${chalk2.yellow("https://custom.com")}`);
1885
+ console.log(` ${chalk2.gray("$")} ${chalk2.hex("#D4A017")("framer-export")} ${chalk2.green("--subpages")} ${chalk2.yellow("https://mysite.com")}`);
1886
+ console.log(` ${chalk2.gray("$")} ${chalk2.hex("#D4A017")("framer-export")} ${chalk2.green("--setup")}`);
1887
+ console.log(` ${chalk2.gray("$")} ${chalk2.hex("#D4A017")("framer-export")} ${chalk2.green("--setup --legacy-mode")}`);
1625
1888
  console.log("");
1626
1889
  }
1627
1890
 
@@ -1681,28 +1944,28 @@ async function main() {
1681
1944
  process.exit(0);
1682
1945
  }
1683
1946
  if (args.includes("--about")) {
1684
- const chalk9 = (await import("chalk")).default;
1947
+ const chalk10 = (await import("chalk")).default;
1685
1948
  showBanner();
1686
- console.log(` ${chalk9.white.bold("Framer Export")} ${chalk9.gray(`v${package_default.version}`)}`);
1687
- console.log(` ${chalk9.white(package_default.description)}
1949
+ console.log(` ${chalk10.white.bold("Framer Export")} ${chalk10.gray(`v${package_default.version}`)}`);
1950
+ console.log(` ${chalk10.white(package_default.description)}
1688
1951
  `);
1689
- console.log(` ${chalk9.white.bold("Author")} ${chalk9.cyan("Dany (danbenba)")}`);
1690
- console.log(` ${chalk9.white.bold("Portfolio")} ${chalk9.underline.cyan("https://github.com/danbenba")}`);
1691
- console.log(` ${chalk9.white.bold("GitHub")} ${chalk9.underline.cyan(package_default.repository.url.replace("git+", "").replace(".git", ""))}`);
1692
- console.log(` ${chalk9.white.bold("npm")} ${chalk9.underline.cyan(`https://www.npmjs.com/package/${package_default.name}`)}`);
1693
- console.log(` ${chalk9.white.bold("License")} ${chalk9.green(package_default.license)}`);
1694
- console.log(` ${chalk9.white.bold("Node")} ${chalk9.gray(`>=${package_default.engines.node}`)}`);
1952
+ console.log(` ${chalk10.white.bold("Author")} ${chalk10.hex("#D4A017")("Dany (danbenba)")}`);
1953
+ console.log(` ${chalk10.white.bold("Portfolio")} ${chalk10.underline.hex("#D4A017")("https://github.com/danbenba")}`);
1954
+ console.log(` ${chalk10.white.bold("GitHub")} ${chalk10.underline.hex("#D4A017")(package_default.repository.url.replace("git+", "").replace(".git", ""))}`);
1955
+ console.log(` ${chalk10.white.bold("npm")} ${chalk10.underline.hex("#D4A017")(`https://www.npmjs.com/package/${package_default.name}`)}`);
1956
+ console.log(` ${chalk10.white.bold("License")} ${chalk10.green(package_default.license)}`);
1957
+ console.log(` ${chalk10.white.bold("Node")} ${chalk10.gray(`>=${package_default.engines.node}`)}`);
1695
1958
  console.log("");
1696
1959
  process.exit(0);
1697
1960
  }
1698
1961
  checkForUpdates(VERSION).then((latest) => {
1699
1962
  if (!latest) return;
1700
- import("chalk").then((chalk9) => {
1963
+ import("chalk").then((chalk10) => {
1701
1964
  console.log("");
1702
1965
  console.log(
1703
- ` ${chalk9.default.yellow("\u21B3")} Update available: ${chalk9.default.gray(VERSION)} \u2192 ${chalk9.default.green(latest)}`
1966
+ ` ${chalk10.default.yellow("\u21B3")} Update available: ${chalk10.default.gray(VERSION)} \u2192 ${chalk10.default.green(latest)}`
1704
1967
  );
1705
- console.log(` ${chalk9.default.gray(" Run:")} ${chalk9.default.cyan("npm i -g framer-export@latest")}`);
1968
+ console.log(` ${chalk10.default.hex("#D4A017")(" Run:")} ${chalk10.default.hex("#B8860B")("npm i -g framer-export@latest")}`);
1706
1969
  console.log("");
1707
1970
  });
1708
1971
  });
@@ -1723,14 +1986,15 @@ async function main() {
1723
1986
  return;
1724
1987
  }
1725
1988
  const platformOverride = extractFlag(args, "--platform");
1989
+ const includeSubpages = hasFlag(args, "--subpages");
1726
1990
  showBanner();
1727
1991
  const url = args[0];
1728
1992
  try {
1729
1993
  new URL5(url);
1730
1994
  } catch {
1731
- const chalk9 = (await import("chalk")).default;
1732
- console.log(` ${chalk9.red("\u2717")} ${chalk9.red.bold("Invalid URL:")} ${chalk9.white(url)}`);
1733
- console.log(` ${chalk9.gray("Expected: https://yoursite.framer.app")}
1995
+ const chalk10 = (await import("chalk")).default;
1996
+ console.log(` ${chalk10.red("\u2717")} ${chalk10.red.bold("Invalid URL:")} ${chalk10.white(url)}`);
1997
+ console.log(` ${chalk10.gray("Expected: https://yoursite.framer.app")}
1734
1998
  `);
1735
1999
  process.exit(1);
1736
2000
  }
@@ -1740,12 +2004,12 @@ async function main() {
1740
2004
  const defaultDir = deriveOutputName2(url, detected);
1741
2005
  const out = args[1] || `./${defaultDir}`;
1742
2006
  try {
1743
- await new FramerExporter2(url, path7.resolve(out), platformOverride || void 0).run();
2007
+ await new FramerExporter2(url, path7.resolve(out), platformOverride || void 0).run(includeSubpages);
1744
2008
  } catch (e) {
1745
- const chalk9 = (await import("chalk")).default;
2009
+ const chalk10 = (await import("chalk")).default;
1746
2010
  console.log(`
1747
- ${chalk9.red("\u2717")} ${chalk9.red.bold("FAILED:")} ${chalk9.white(e.message)}`);
1748
- console.log(chalk9.gray(e.stack || ""));
2011
+ ${chalk10.red("\u2717")} ${chalk10.red.bold("FAILED:")} ${chalk10.white(e.message)}`);
2012
+ console.log(chalk10.gray(e.stack || ""));
1749
2013
  process.exit(1);
1750
2014
  }
1751
2015
  }