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 +670 -406
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
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.
|
|
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
|
|
100
|
+
const gold = chalk.hex("#D4A017").bold;
|
|
101
101
|
const gray = chalk.gray;
|
|
102
102
|
console.log("");
|
|
103
|
-
ASCII_ART.forEach((
|
|
104
|
-
console.log(" " +
|
|
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
|
|
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(
|
|
275
|
+
_cooking.log(line);
|
|
269
276
|
} else {
|
|
270
|
-
console.log(
|
|
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
|
-
|
|
280
|
-
|
|
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
|
|
283
|
-
if (_cooking) _cooking.log(
|
|
284
|
-
else console.warn(
|
|
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
|
-
|
|
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
|
-
|
|
407
|
-
|
|
408
|
-
|
|
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/
|
|
847
|
-
import fs3 from "fs/promises";
|
|
848
|
-
import path4 from "path";
|
|
1156
|
+
// src/cli/box.ts
|
|
849
1157
|
import chalk4 from "chalk";
|
|
850
|
-
function
|
|
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
|
|
855
|
-
const isSmall =
|
|
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(
|
|
876
|
-
console.log(
|
|
877
|
-
console.log(
|
|
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(
|
|
880
|
-
}
|
|
881
|
-
const
|
|
882
|
-
if (
|
|
883
|
-
const
|
|
884
|
-
const
|
|
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(` ${
|
|
1268
|
+
console.log(` ${color(label)} ${chalk5.white(String(cnt))} ${chalk5.gray(type)}`);
|
|
887
1269
|
} else {
|
|
888
|
-
console.log(
|
|
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(
|
|
1274
|
+
console.log(boxBot(w));
|
|
901
1275
|
}
|
|
902
1276
|
console.log("");
|
|
903
|
-
const
|
|
1277
|
+
const cdCmd = "cd " + path4.basename(exporter.outDir) + " && node serve.cjs";
|
|
904
1278
|
if (!isSmall) {
|
|
905
|
-
console.log(
|
|
906
|
-
console.log(
|
|
907
|
-
console.log(
|
|
908
|
-
|
|
909
|
-
|
|
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(
|
|
912
|
-
console.log(` ${
|
|
1288
|
+
console.log(chalk5.bold.white(" To serve locally:"));
|
|
1289
|
+
console.log(` ${G2(cdCmd)}`);
|
|
913
1290
|
}
|
|
914
1291
|
console.log("");
|
|
915
|
-
console.log(
|
|
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
|
|
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 =
|
|
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
|
-
},
|
|
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
|
|
1202
|
-
const
|
|
1203
|
-
const
|
|
1204
|
-
const
|
|
1205
|
-
const shimmer = this.renderShimmer(
|
|
1206
|
-
const
|
|
1207
|
-
const
|
|
1208
|
-
|
|
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
|
|
1218
|
-
result +=
|
|
1393
|
+
const g = Math.floor(160 + t * 95);
|
|
1394
|
+
result += chalk6.rgb(g, g, g)(text[i]);
|
|
1219
1395
|
} else {
|
|
1220
|
-
result +=
|
|
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
|
|
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(
|
|
1297
|
-
info("Source : " +
|
|
1298
|
-
info("Output : " +
|
|
1299
|
-
info("Platform : " +
|
|
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(
|
|
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: " +
|
|
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
|
|
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(` ${
|
|
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(` ${
|
|
1626
|
+
console.log(` ${chalk8.hex("#D4A017")(">")} ${chalk8.white.bold(options[i].label)}`);
|
|
1363
1627
|
} else {
|
|
1364
|
-
console.log(` ${
|
|
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(` ${
|
|
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
|
|
1415
|
-
function getWidth3() {
|
|
1416
|
-
return process.stdout.columns || 80;
|
|
1417
|
-
}
|
|
1678
|
+
import chalk9 from "chalk";
|
|
1418
1679
|
function drawHeader(title) {
|
|
1419
|
-
const
|
|
1420
|
-
|
|
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
|
-
${
|
|
1683
|
+
${chalk9.hex("#D4A017")("\u25CF")} ${chalk9.bold.white(title)}`);
|
|
1426
1684
|
return;
|
|
1427
1685
|
}
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
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(
|
|
1449
|
-
console.log(
|
|
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 ?
|
|
1453
|
-
const prompt = ` ${
|
|
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(` ${
|
|
1710
|
+
console.log(` ${chalk9.red("\u2717")} ${chalk9.red("Invalid URL. Enter a valid URL (https://...)")}
|
|
1466
1711
|
`);
|
|
1467
1712
|
}
|
|
1468
1713
|
}
|
|
1469
|
-
console.log(` ${
|
|
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(` ${
|
|
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(` ${
|
|
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" ?
|
|
1484
|
-
{ label: `Webflow${detected.name === "webflow" ?
|
|
1485
|
-
{ label: `Wix${detected.name === "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 ?
|
|
1493
|
-
const prompt = ` ${
|
|
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(` ${
|
|
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(` ${
|
|
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(` ${
|
|
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(
|
|
1533
|
-
console.log(
|
|
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(
|
|
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(
|
|
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
|
-
${
|
|
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.
|
|
1594
|
-
console.log(` ${chalk2.
|
|
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.
|
|
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.
|
|
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.
|
|
1620
|
-
console.log(` ${chalk2.gray("$")} ${chalk2.
|
|
1621
|
-
console.log(` ${chalk2.gray("$")} ${chalk2.
|
|
1622
|
-
console.log(` ${chalk2.gray("$")} ${chalk2.
|
|
1623
|
-
console.log(` ${chalk2.gray("$")} ${chalk2.
|
|
1624
|
-
console.log(` ${chalk2.gray("$")} ${chalk2.
|
|
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
|
|
1947
|
+
const chalk10 = (await import("chalk")).default;
|
|
1685
1948
|
showBanner();
|
|
1686
|
-
console.log(` ${
|
|
1687
|
-
console.log(` ${
|
|
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(` ${
|
|
1690
|
-
console.log(` ${
|
|
1691
|
-
console.log(` ${
|
|
1692
|
-
console.log(` ${
|
|
1693
|
-
console.log(` ${
|
|
1694
|
-
console.log(` ${
|
|
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((
|
|
1963
|
+
import("chalk").then((chalk10) => {
|
|
1701
1964
|
console.log("");
|
|
1702
1965
|
console.log(
|
|
1703
|
-
` ${
|
|
1966
|
+
` ${chalk10.default.yellow("\u21B3")} Update available: ${chalk10.default.gray(VERSION)} \u2192 ${chalk10.default.green(latest)}`
|
|
1704
1967
|
);
|
|
1705
|
-
console.log(` ${
|
|
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
|
|
1732
|
-
console.log(` ${
|
|
1733
|
-
console.log(` ${
|
|
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
|
|
2009
|
+
const chalk10 = (await import("chalk")).default;
|
|
1746
2010
|
console.log(`
|
|
1747
|
-
${
|
|
1748
|
-
console.log(
|
|
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
|
}
|