@neowhale/storefront 0.2.35 → 0.2.36
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/landing.global.js +352 -471
- package/dist/react/index.cjs +343 -470
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +9 -0
- package/dist/react/index.d.ts +9 -0
- package/dist/react/index.js +343 -470
- package/dist/react/index.js.map +1 -1
- package/package.json +1 -1
package/dist/landing.global.js
CHANGED
|
@@ -384,8 +384,19 @@ var WhaleStorefront = (function (exports) {
|
|
|
384
384
|
R2.createElement;
|
|
385
385
|
var Fragment2 = R2.Fragment;
|
|
386
386
|
|
|
387
|
-
// src/react/components/
|
|
388
|
-
|
|
387
|
+
// src/react/components/sections/shared.tsx
|
|
388
|
+
function trackClick(tracking, label, url, position) {
|
|
389
|
+
if (!tracking?.gatewayUrl || !tracking?.code) return;
|
|
390
|
+
const body = JSON.stringify({ label, url, position });
|
|
391
|
+
if (typeof navigator !== "undefined" && navigator.sendBeacon) {
|
|
392
|
+
navigator.sendBeacon(
|
|
393
|
+
`${tracking.gatewayUrl}/q/${encodeURIComponent(tracking.code)}/click`,
|
|
394
|
+
new Blob([body], { type: "application/json" })
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
var NUM_SPLIT = /(\$?[\d,]+\.?\d*[+★%]?)/g;
|
|
399
|
+
var NUM_TEST = /^\$?[\d,]+\.?\d*[+★%]?$/;
|
|
389
400
|
function easeOutQuart(t) {
|
|
390
401
|
return 1 - Math.pow(1 - t, 4);
|
|
391
402
|
}
|
|
@@ -442,147 +453,71 @@ var WhaleStorefront = (function (exports) {
|
|
|
442
453
|
] });
|
|
443
454
|
}
|
|
444
455
|
function AnimatedText({ text }) {
|
|
445
|
-
const parts = text.split(
|
|
456
|
+
const parts = text.split(NUM_SPLIT);
|
|
446
457
|
return /* @__PURE__ */ jsx(Fragment2, { children: parts.map(
|
|
447
|
-
(part, i) =>
|
|
458
|
+
(part, i) => NUM_TEST.test(part) ? /* @__PURE__ */ jsx(AnimatedNumber, { raw: part }, i) : part
|
|
448
459
|
) });
|
|
449
460
|
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
const body = JSON.stringify({ label, url, position });
|
|
453
|
-
if (typeof navigator !== "undefined" && navigator.sendBeacon) {
|
|
454
|
-
navigator.sendBeacon(
|
|
455
|
-
`${tracking.gatewayUrl}/q/${encodeURIComponent(tracking.code)}/click`,
|
|
456
|
-
new Blob([body], { type: "application/json" })
|
|
457
|
-
);
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
function SectionRenderer({
|
|
461
|
-
section,
|
|
462
|
-
data,
|
|
463
|
-
theme,
|
|
464
|
-
tracking,
|
|
465
|
-
onEvent
|
|
466
|
-
}) {
|
|
467
|
-
const [showCOA, setShowCOA] = useState(false);
|
|
468
|
-
const el = (() => {
|
|
469
|
-
switch (section.type) {
|
|
470
|
-
case "hero":
|
|
471
|
-
return /* @__PURE__ */ jsx(HeroSection, { section, theme, tracking, onEvent });
|
|
472
|
-
case "text":
|
|
473
|
-
return /* @__PURE__ */ jsx(TextSection, { section, theme });
|
|
474
|
-
case "image":
|
|
475
|
-
return /* @__PURE__ */ jsx(ImageSection, { section, theme });
|
|
476
|
-
case "video":
|
|
477
|
-
return /* @__PURE__ */ jsx(VideoSection, { section, theme });
|
|
478
|
-
case "gallery":
|
|
479
|
-
return /* @__PURE__ */ jsx(GallerySection, { section, theme });
|
|
480
|
-
case "cta":
|
|
481
|
-
return /* @__PURE__ */ jsx(CTASection, { section, theme, tracking, onEvent });
|
|
482
|
-
case "stats":
|
|
483
|
-
return /* @__PURE__ */ jsx(StatsSection, { section, theme });
|
|
484
|
-
case "product_card":
|
|
485
|
-
return /* @__PURE__ */ jsx(ProductCardSection, { section, data, theme, tracking });
|
|
486
|
-
case "coa_viewer":
|
|
487
|
-
return /* @__PURE__ */ jsx(COAViewerSection, { section, data, theme, onShowCOA: () => setShowCOA(true), tracking });
|
|
488
|
-
case "social_links":
|
|
489
|
-
return /* @__PURE__ */ jsx(SocialLinksSection, { section, theme });
|
|
490
|
-
case "lead_capture":
|
|
491
|
-
return /* @__PURE__ */ jsx(LeadCaptureSection, { section, data, theme, onEvent });
|
|
492
|
-
case "divider":
|
|
493
|
-
return /* @__PURE__ */ jsx(DividerSection, { theme });
|
|
494
|
-
default:
|
|
495
|
-
return null;
|
|
496
|
-
}
|
|
497
|
-
})();
|
|
498
|
-
const sectionRef = useRef(null);
|
|
499
|
-
useEffect(() => {
|
|
500
|
-
const el2 = sectionRef.current;
|
|
501
|
-
if (!el2 || typeof IntersectionObserver === "undefined") return;
|
|
502
|
-
const obs = new IntersectionObserver(
|
|
503
|
-
([entry]) => {
|
|
504
|
-
if (entry.isIntersecting) {
|
|
505
|
-
onEvent?.("section_view", {
|
|
506
|
-
section_id: section.id,
|
|
507
|
-
section_type: section.type
|
|
508
|
-
});
|
|
509
|
-
obs.disconnect();
|
|
510
|
-
}
|
|
511
|
-
},
|
|
512
|
-
{ threshold: 0.5 }
|
|
513
|
-
);
|
|
514
|
-
obs.observe(el2);
|
|
515
|
-
return () => obs.disconnect();
|
|
516
|
-
}, [section.id, section.type, onEvent]);
|
|
517
|
-
return /* @__PURE__ */ jsxs("div", { ref: sectionRef, "data-section-id": section.id, "data-section-type": section.type, children: [
|
|
518
|
-
el,
|
|
519
|
-
showCOA && data?.coa && /* @__PURE__ */ jsx(COAModal, { coa: data.coa, theme, onClose: () => setShowCOA(false) })
|
|
520
|
-
] });
|
|
521
|
-
}
|
|
461
|
+
|
|
462
|
+
// src/react/components/sections/content-sections.tsx
|
|
522
463
|
function HeroSection({ section, theme, tracking, onEvent }) {
|
|
523
464
|
const { title, subtitle, background_image, cta_text, cta_url } = section.content;
|
|
524
|
-
return /* @__PURE__ */ jsxs(
|
|
525
|
-
"
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
465
|
+
return /* @__PURE__ */ jsxs("div", { style: {
|
|
466
|
+
position: "relative",
|
|
467
|
+
minHeight: "60vh",
|
|
468
|
+
display: "flex",
|
|
469
|
+
flexDirection: "column",
|
|
470
|
+
justifyContent: "center",
|
|
471
|
+
alignItems: "center",
|
|
472
|
+
textAlign: "center",
|
|
473
|
+
padding: "3rem 1.5rem",
|
|
474
|
+
backgroundImage: background_image ? `url(${background_image})` : void 0,
|
|
475
|
+
backgroundSize: "cover",
|
|
476
|
+
backgroundPosition: "center"
|
|
477
|
+
}, children: [
|
|
478
|
+
background_image && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, background: "rgba(0,0,0,0.5)" } }),
|
|
479
|
+
/* @__PURE__ */ jsxs("div", { style: { position: "relative", zIndex: 1, maxWidth: 640 }, children: [
|
|
480
|
+
title && /* @__PURE__ */ jsx("h1", { style: {
|
|
481
|
+
fontSize: "clamp(2rem, 8vw, 3rem)",
|
|
482
|
+
fontWeight: 300,
|
|
483
|
+
fontFamily: theme.fontDisplay || "inherit",
|
|
484
|
+
margin: "0 0 1rem",
|
|
485
|
+
lineHeight: 1.15,
|
|
486
|
+
letterSpacing: "-0.02em",
|
|
487
|
+
color: theme.fg
|
|
488
|
+
}, children: /* @__PURE__ */ jsx(AnimatedText, { text: title }) }),
|
|
489
|
+
subtitle && /* @__PURE__ */ jsx("p", { style: {
|
|
490
|
+
fontSize: "0.85rem",
|
|
491
|
+
color: theme.accent,
|
|
492
|
+
margin: "0 0 2rem",
|
|
493
|
+
lineHeight: 1.6,
|
|
494
|
+
textTransform: "uppercase",
|
|
495
|
+
letterSpacing: "0.15em"
|
|
496
|
+
}, children: subtitle }),
|
|
497
|
+
cta_text && cta_url && /* @__PURE__ */ jsx(
|
|
498
|
+
"a",
|
|
499
|
+
{
|
|
500
|
+
href: cta_url,
|
|
501
|
+
onClick: () => {
|
|
502
|
+
trackClick(tracking, cta_text, cta_url);
|
|
503
|
+
onEvent?.("cta_click", { label: cta_text, url: cta_url });
|
|
504
|
+
},
|
|
505
|
+
style: {
|
|
506
|
+
display: "inline-block",
|
|
507
|
+
padding: "0.875rem 2rem",
|
|
508
|
+
background: theme.fg,
|
|
509
|
+
color: theme.bg,
|
|
510
|
+
textDecoration: "none",
|
|
553
511
|
fontSize: "0.85rem",
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
href: cta_url,
|
|
564
|
-
onClick: () => {
|
|
565
|
-
trackClick(tracking, cta_text, cta_url);
|
|
566
|
-
onEvent?.("cta_click", { label: cta_text, url: cta_url });
|
|
567
|
-
},
|
|
568
|
-
style: {
|
|
569
|
-
display: "inline-block",
|
|
570
|
-
padding: "0.875rem 2rem",
|
|
571
|
-
background: theme.fg,
|
|
572
|
-
color: theme.bg,
|
|
573
|
-
textDecoration: "none",
|
|
574
|
-
fontSize: "0.85rem",
|
|
575
|
-
fontWeight: 500,
|
|
576
|
-
letterSpacing: "0.08em",
|
|
577
|
-
textTransform: "uppercase"
|
|
578
|
-
},
|
|
579
|
-
children: cta_text
|
|
580
|
-
}
|
|
581
|
-
)
|
|
582
|
-
] })
|
|
583
|
-
]
|
|
584
|
-
}
|
|
585
|
-
);
|
|
512
|
+
fontWeight: 500,
|
|
513
|
+
letterSpacing: "0.08em",
|
|
514
|
+
textTransform: "uppercase"
|
|
515
|
+
},
|
|
516
|
+
children: cta_text
|
|
517
|
+
}
|
|
518
|
+
)
|
|
519
|
+
] })
|
|
520
|
+
] });
|
|
586
521
|
}
|
|
587
522
|
function TextSection({ section, theme }) {
|
|
588
523
|
const { heading, body } = section.content;
|
|
@@ -604,14 +539,7 @@ var WhaleStorefront = (function (exports) {
|
|
|
604
539
|
const contained = section.config?.contained !== false;
|
|
605
540
|
if (!url) return null;
|
|
606
541
|
return /* @__PURE__ */ jsxs("div", { style: { padding: contained ? "1.5rem" : 0, maxWidth: contained ? 640 : void 0, margin: contained ? "0 auto" : void 0 }, children: [
|
|
607
|
-
/* @__PURE__ */ jsx(
|
|
608
|
-
"img",
|
|
609
|
-
{
|
|
610
|
-
src: url,
|
|
611
|
-
alt: alt || "",
|
|
612
|
-
style: { width: "100%", display: "block", objectFit: "cover" }
|
|
613
|
-
}
|
|
614
|
-
),
|
|
542
|
+
/* @__PURE__ */ jsx("img", { src: url, alt: alt || "", style: { width: "100%", display: "block", objectFit: "cover" } }),
|
|
615
543
|
caption && /* @__PURE__ */ jsx("p", { style: { fontSize: "0.8rem", color: theme.muted, textAlign: "center", marginTop: "0.75rem" }, children: caption })
|
|
616
544
|
] });
|
|
617
545
|
}
|
|
@@ -619,37 +547,41 @@ var WhaleStorefront = (function (exports) {
|
|
|
619
547
|
const { url, poster } = section.content;
|
|
620
548
|
if (!url) return null;
|
|
621
549
|
const isEmbed = url.includes("youtube") || url.includes("youtu.be") || url.includes("vimeo");
|
|
622
|
-
return /* @__PURE__ */ jsx("div", { style: { padding: "1.5rem", maxWidth: 640, margin: "0 auto" }, children: isEmbed ? /* @__PURE__ */ jsx("div", { style: { position: "relative", paddingBottom: "56.25%", height: 0 }, children: /* @__PURE__ */ jsx(
|
|
623
|
-
"iframe",
|
|
624
|
-
{
|
|
625
|
-
src: toEmbedUrl(url),
|
|
626
|
-
style: { position: "absolute", top: 0, left: 0, width: "100%", height: "100%", border: "none" },
|
|
627
|
-
allow: "autoplay; fullscreen",
|
|
628
|
-
title: "Video"
|
|
629
|
-
}
|
|
630
|
-
) }) : /* @__PURE__ */ jsx(
|
|
631
|
-
"video",
|
|
632
|
-
{
|
|
633
|
-
src: url,
|
|
634
|
-
poster,
|
|
635
|
-
controls: true,
|
|
636
|
-
style: { width: "100%", display: "block", background: theme.surface }
|
|
637
|
-
}
|
|
638
|
-
) });
|
|
550
|
+
return /* @__PURE__ */ jsx("div", { style: { padding: "1.5rem", maxWidth: 640, margin: "0 auto" }, children: isEmbed ? /* @__PURE__ */ jsx("div", { style: { position: "relative", paddingBottom: "56.25%", height: 0 }, children: /* @__PURE__ */ jsx("iframe", { src: toEmbedUrl(url), style: { position: "absolute", top: 0, left: 0, width: "100%", height: "100%", border: "none" }, allow: "autoplay; fullscreen", title: "Video" }) }) : /* @__PURE__ */ jsx("video", { src: url, poster, controls: true, style: { width: "100%", display: "block", background: theme.surface } }) });
|
|
639
551
|
}
|
|
640
552
|
function GallerySection({ section, theme }) {
|
|
641
553
|
const { images } = section.content;
|
|
642
554
|
const columns = section.config?.columns || 3;
|
|
643
555
|
if (!images || images.length === 0) return null;
|
|
644
|
-
return /* @__PURE__ */ jsx("div", { style: { padding: "1.5rem", maxWidth: 800, margin: "0 auto" }, children: /* @__PURE__ */ jsx("div", { style: { display: "grid", gridTemplateColumns: `repeat(${columns}, 1fr)`, gap: "0.5rem" }, children: images.map((img, i) => /* @__PURE__ */ jsx("div", { style: { aspectRatio: "1", overflow: "hidden", background: theme.surface }, children: /* @__PURE__ */ jsx(
|
|
645
|
-
|
|
556
|
+
return /* @__PURE__ */ jsx("div", { style: { padding: "1.5rem", maxWidth: 800, margin: "0 auto" }, children: /* @__PURE__ */ jsx("div", { style: { display: "grid", gridTemplateColumns: `repeat(${columns}, 1fr)`, gap: "0.5rem" }, children: images.map((img, i) => /* @__PURE__ */ jsx("div", { style: { aspectRatio: "1", overflow: "hidden", background: theme.surface }, children: /* @__PURE__ */ jsx("img", { src: img.url, alt: img.alt || "", style: { width: "100%", height: "100%", objectFit: "cover", display: "block" } }) }, i)) }) });
|
|
557
|
+
}
|
|
558
|
+
function SocialLinksSection({ section, theme }) {
|
|
559
|
+
const { links } = section.content;
|
|
560
|
+
if (!links || links.length === 0) return null;
|
|
561
|
+
return /* @__PURE__ */ jsx("div", { style: { padding: "1.5rem", display: "flex", justifyContent: "center", gap: "1.5rem", flexWrap: "wrap" }, children: links.map((link, i) => /* @__PURE__ */ jsx(
|
|
562
|
+
"a",
|
|
646
563
|
{
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
564
|
+
href: link.url,
|
|
565
|
+
target: "_blank",
|
|
566
|
+
rel: "noopener noreferrer",
|
|
567
|
+
style: { color: theme.muted, textDecoration: "none", fontSize: "0.85rem", fontWeight: 500, textTransform: "capitalize", letterSpacing: "0.03em" },
|
|
568
|
+
children: link.platform
|
|
569
|
+
},
|
|
570
|
+
i
|
|
571
|
+
)) });
|
|
572
|
+
}
|
|
573
|
+
function DividerSection({ theme }) {
|
|
574
|
+
return /* @__PURE__ */ jsx("div", { style: { padding: "1rem 1.5rem", maxWidth: 640, margin: "0 auto" }, children: /* @__PURE__ */ jsx("hr", { style: { border: "none", borderTop: `1px solid ${theme.fg}0A`, margin: 0 } }) });
|
|
575
|
+
}
|
|
576
|
+
function toEmbedUrl(url) {
|
|
577
|
+
const ytMatch = url.match(/(?:youtube\.com\/watch\?v=|youtu\.be\/)([\w-]+)/);
|
|
578
|
+
if (ytMatch) return `https://www.youtube.com/embed/${ytMatch[1]}`;
|
|
579
|
+
const vimeoMatch = url.match(/vimeo\.com\/(\d+)/);
|
|
580
|
+
if (vimeoMatch) return `https://player.vimeo.com/video/${vimeoMatch[1]}`;
|
|
581
|
+
return url;
|
|
652
582
|
}
|
|
583
|
+
|
|
584
|
+
// src/react/components/sections/interactive-sections.tsx
|
|
653
585
|
function CTASection({ section, theme, tracking, onEvent }) {
|
|
654
586
|
const { title, subtitle, buttons } = section.content;
|
|
655
587
|
if (!buttons || buttons.length === 0) return null;
|
|
@@ -711,29 +643,15 @@ var WhaleStorefront = (function (exports) {
|
|
|
711
643
|
if (!stats || stats.length === 0) return null;
|
|
712
644
|
if (layout === "list") {
|
|
713
645
|
return /* @__PURE__ */ jsx("div", { style: { padding: "1.5rem", maxWidth: 640, margin: "0 auto" }, children: stats.map((stat, i) => /* @__PURE__ */ jsxs("div", { children: [
|
|
714
|
-
/* @__PURE__ */ jsxs("div", { style: {
|
|
715
|
-
|
|
716
|
-
justifyContent: "space-between",
|
|
717
|
-
alignItems: "baseline",
|
|
718
|
-
padding: "0.625rem 0"
|
|
719
|
-
}, children: [
|
|
720
|
-
/* @__PURE__ */ jsx("span", { style: {
|
|
721
|
-
fontSize: 12,
|
|
722
|
-
textTransform: "uppercase",
|
|
723
|
-
letterSpacing: "0.15em",
|
|
724
|
-
color: `${theme.fg}66`
|
|
725
|
-
}, children: stat.label }),
|
|
646
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "baseline", padding: "0.625rem 0" }, children: [
|
|
647
|
+
/* @__PURE__ */ jsx("span", { style: { fontSize: 12, textTransform: "uppercase", letterSpacing: "0.15em", color: `${theme.fg}66` }, children: stat.label }),
|
|
726
648
|
/* @__PURE__ */ jsx("span", { style: { fontSize: 14, fontWeight: 300, color: `${theme.fg}CC` }, children: /* @__PURE__ */ jsx(AnimatedText, { text: stat.value }) })
|
|
727
649
|
] }),
|
|
728
650
|
i < stats.length - 1 && /* @__PURE__ */ jsx("hr", { style: { border: "none", borderTop: `1px solid ${theme.fg}0A`, margin: 0 } })
|
|
729
651
|
] }, i)) });
|
|
730
652
|
}
|
|
731
653
|
const columns = Math.min(stats.length, 4);
|
|
732
|
-
return /* @__PURE__ */ jsx("div", { style: { padding: "1.5rem", maxWidth: 640, margin: "0 auto" }, children: /* @__PURE__ */ jsx("div", { style: {
|
|
733
|
-
display: "grid",
|
|
734
|
-
gridTemplateColumns: `repeat(${columns}, 1fr)`,
|
|
735
|
-
border: `1px solid ${theme.fg}0F`
|
|
736
|
-
}, children: stats.map((stat, i) => /* @__PURE__ */ jsxs("div", { style: {
|
|
654
|
+
return /* @__PURE__ */ jsx("div", { style: { padding: "1.5rem", maxWidth: 640, margin: "0 auto" }, children: /* @__PURE__ */ jsx("div", { style: { display: "grid", gridTemplateColumns: `repeat(${columns}, 1fr)`, border: `1px solid ${theme.fg}0F` }, children: stats.map((stat, i) => /* @__PURE__ */ jsxs("div", { style: {
|
|
737
655
|
padding: "1.25rem 0.5rem",
|
|
738
656
|
textAlign: "center",
|
|
739
657
|
borderRight: i < stats.length - 1 ? `1px solid ${theme.fg}0F` : void 0
|
|
@@ -792,13 +710,7 @@ var WhaleStorefront = (function (exports) {
|
|
|
792
710
|
] })
|
|
793
711
|
] }) });
|
|
794
712
|
}
|
|
795
|
-
function COAViewerSection({
|
|
796
|
-
section,
|
|
797
|
-
data,
|
|
798
|
-
theme,
|
|
799
|
-
onShowCOA,
|
|
800
|
-
tracking
|
|
801
|
-
}) {
|
|
713
|
+
function COAViewerSection({ section, data, theme, onShowCOA, tracking }) {
|
|
802
714
|
const coa = data?.coa;
|
|
803
715
|
const c = section.content;
|
|
804
716
|
if (!coa) return null;
|
|
@@ -837,6 +749,30 @@ var WhaleStorefront = (function (exports) {
|
|
|
837
749
|
onShowCOA();
|
|
838
750
|
}, style: buttonStyle, children: buttonLabel }) });
|
|
839
751
|
}
|
|
752
|
+
function COAModal({ coa, theme, onClose }) {
|
|
753
|
+
return /* @__PURE__ */ jsxs("div", { style: { position: "fixed", inset: 0, zIndex: 9999, background: "rgba(0,0,0,0.95)", display: "flex", flexDirection: "column" }, children: [
|
|
754
|
+
/* @__PURE__ */ jsxs("div", { style: {
|
|
755
|
+
display: "flex",
|
|
756
|
+
justifyContent: "space-between",
|
|
757
|
+
alignItems: "center",
|
|
758
|
+
padding: "0.75rem 1rem",
|
|
759
|
+
borderBottom: `1px solid ${theme.fg}10`
|
|
760
|
+
}, children: [
|
|
761
|
+
/* @__PURE__ */ jsx("span", { style: { color: "#fff", fontWeight: 500, fontSize: "0.85rem" }, children: coa.document_name || "Lab Results" }),
|
|
762
|
+
/* @__PURE__ */ jsx("button", { onClick: onClose, style: {
|
|
763
|
+
background: `${theme.fg}10`,
|
|
764
|
+
border: "none",
|
|
765
|
+
color: "#fff",
|
|
766
|
+
fontSize: "0.85rem",
|
|
767
|
+
cursor: "pointer",
|
|
768
|
+
padding: "0.375rem 0.75rem"
|
|
769
|
+
}, children: "Close" })
|
|
770
|
+
] }),
|
|
771
|
+
/* @__PURE__ */ jsx("iframe", { src: coa.url, style: { flex: 1, border: "none", background: "#fff" }, title: "Lab Results" })
|
|
772
|
+
] });
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// src/react/components/sections/lead-capture-section.tsx
|
|
840
776
|
function LeadCaptureSection({ section, data, theme, onEvent }) {
|
|
841
777
|
const c = section.content;
|
|
842
778
|
const [firstName, setFirstName] = useState("");
|
|
@@ -847,13 +783,17 @@ var WhaleStorefront = (function (exports) {
|
|
|
847
783
|
const gatewayUrl = c.gateway_url || data.gatewayUrl || "https://whale-gateway.fly.dev";
|
|
848
784
|
const storeId = c.store_id || data.store?.id;
|
|
849
785
|
const slug = c.landing_page_slug || data.landing_page?.slug;
|
|
786
|
+
const heading = c.heading || "get 10% off your first visit.";
|
|
787
|
+
const subtitle = c.subtitle || "drop your email and we will send you the code.";
|
|
788
|
+
const buttonText = c.button_text || "Claim My Discount";
|
|
789
|
+
const successHeading = c.success_heading || "You\u2019re in!";
|
|
790
|
+
const successMessage = c.success_message || "Check your inbox for the discount code.";
|
|
850
791
|
async function handleSubmit(e) {
|
|
851
792
|
e.preventDefault();
|
|
852
793
|
if (!email || !storeId) return;
|
|
853
794
|
setStatus("loading");
|
|
854
795
|
setErrorMsg("");
|
|
855
796
|
const urlParams = typeof window !== "undefined" ? new URLSearchParams(window.location.search) : null;
|
|
856
|
-
const analyticsData = data.analyticsContext;
|
|
857
797
|
try {
|
|
858
798
|
const res = await fetch(`${gatewayUrl}/v1/stores/${storeId}/storefront/leads`, {
|
|
859
799
|
method: "POST",
|
|
@@ -869,8 +809,8 @@ var WhaleStorefront = (function (exports) {
|
|
|
869
809
|
if (newsletterOptIn) t.push(c.newsletter_tag || "newsletter-subscriber");
|
|
870
810
|
return t.length > 0 ? t : void 0;
|
|
871
811
|
})(),
|
|
872
|
-
visitor_id:
|
|
873
|
-
session_id:
|
|
812
|
+
visitor_id: data.analyticsContext?.visitorId || void 0,
|
|
813
|
+
session_id: data.analyticsContext?.sessionId || void 0,
|
|
874
814
|
utm_source: urlParams?.get("utm_source") || void 0,
|
|
875
815
|
utm_medium: urlParams?.get("utm_medium") || void 0,
|
|
876
816
|
utm_campaign: urlParams?.get("utm_campaign") || void 0,
|
|
@@ -888,11 +828,6 @@ var WhaleStorefront = (function (exports) {
|
|
|
888
828
|
setStatus("error");
|
|
889
829
|
}
|
|
890
830
|
}
|
|
891
|
-
const heading = c.heading || "get 10% off your first visit.";
|
|
892
|
-
const subtitle = c.subtitle || "drop your email and we will send you the code.";
|
|
893
|
-
const buttonText = c.button_text || "Claim My Discount";
|
|
894
|
-
const successHeading = c.success_heading || "You\u2019re in!";
|
|
895
|
-
const successMessage = c.success_message || "Check your inbox for the discount code.";
|
|
896
831
|
const inputStyle = {
|
|
897
832
|
flex: 1,
|
|
898
833
|
minWidth: 0,
|
|
@@ -907,41 +842,10 @@ var WhaleStorefront = (function (exports) {
|
|
|
907
842
|
fontFamily: "inherit",
|
|
908
843
|
transition: "border-color 0.2s"
|
|
909
844
|
};
|
|
845
|
+
if (status === "success") return /* @__PURE__ */ jsx(SuccessState, { theme, heading: successHeading, message: successMessage, couponCode: c.coupon_code });
|
|
910
846
|
return /* @__PURE__ */ jsxs("div", { style: { padding: "3.5rem 1.5rem", maxWidth: 560, margin: "0 auto" }, children: [
|
|
911
847
|
/* @__PURE__ */ jsx("style", { children: `@keyframes lc-spin { to { transform: rotate(360deg) } }` }),
|
|
912
|
-
/* @__PURE__ */
|
|
913
|
-
background: theme.surface,
|
|
914
|
-
border: `1px solid ${theme.fg}12`,
|
|
915
|
-
padding: "clamp(2rem, 6vw, 3rem)"
|
|
916
|
-
}, children: status === "success" ? /* @__PURE__ */ jsxs("div", { style: { textAlign: "center" }, children: [
|
|
917
|
-
/* @__PURE__ */ jsx("h2", { style: {
|
|
918
|
-
fontSize: "clamp(1.5rem, 5vw, 2rem)",
|
|
919
|
-
fontWeight: 300,
|
|
920
|
-
fontFamily: theme.fontDisplay || "inherit",
|
|
921
|
-
margin: "0 0 0.75rem",
|
|
922
|
-
lineHeight: 1.2,
|
|
923
|
-
letterSpacing: "-0.02em",
|
|
924
|
-
color: theme.fg
|
|
925
|
-
}, children: successHeading }),
|
|
926
|
-
/* @__PURE__ */ jsx("p", { style: {
|
|
927
|
-
fontSize: "0.9rem",
|
|
928
|
-
color: `${theme.fg}99`,
|
|
929
|
-
margin: "0 0 1.5rem",
|
|
930
|
-
lineHeight: 1.6,
|
|
931
|
-
fontWeight: 300
|
|
932
|
-
}, children: successMessage }),
|
|
933
|
-
c.coupon_code && /* @__PURE__ */ jsx("div", { style: {
|
|
934
|
-
display: "inline-block",
|
|
935
|
-
padding: "0.75rem 2rem",
|
|
936
|
-
background: `${theme.fg}08`,
|
|
937
|
-
border: `1px dashed ${theme.fg}30`,
|
|
938
|
-
fontSize: "clamp(1.25rem, 4vw, 1.75rem)",
|
|
939
|
-
fontWeight: 500,
|
|
940
|
-
fontFamily: "monospace",
|
|
941
|
-
letterSpacing: "0.12em",
|
|
942
|
-
color: theme.accent
|
|
943
|
-
}, children: c.coupon_code })
|
|
944
|
-
] }) : /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
848
|
+
/* @__PURE__ */ jsxs("div", { style: { background: theme.surface, border: `1px solid ${theme.fg}12`, padding: "clamp(2rem, 6vw, 3rem)" }, children: [
|
|
945
849
|
/* @__PURE__ */ jsxs("div", { style: { textAlign: "center", marginBottom: "clamp(1.5rem, 4vw, 2rem)" }, children: [
|
|
946
850
|
/* @__PURE__ */ jsx("h2", { style: {
|
|
947
851
|
fontSize: "clamp(1.5rem, 5vw, 2.25rem)",
|
|
@@ -963,27 +867,8 @@ var WhaleStorefront = (function (exports) {
|
|
|
963
867
|
] }),
|
|
964
868
|
/* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
|
|
965
869
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "0.75rem", flexWrap: "wrap" }, children: [
|
|
966
|
-
/* @__PURE__ */ jsx(
|
|
967
|
-
|
|
968
|
-
{
|
|
969
|
-
type: "text",
|
|
970
|
-
placeholder: "First name",
|
|
971
|
-
value: firstName,
|
|
972
|
-
onChange: (e) => setFirstName(e.target.value),
|
|
973
|
-
style: inputStyle
|
|
974
|
-
}
|
|
975
|
-
),
|
|
976
|
-
/* @__PURE__ */ jsx(
|
|
977
|
-
"input",
|
|
978
|
-
{
|
|
979
|
-
type: "email",
|
|
980
|
-
placeholder: "Email address",
|
|
981
|
-
value: email,
|
|
982
|
-
onChange: (e) => setEmail(e.target.value),
|
|
983
|
-
required: true,
|
|
984
|
-
style: inputStyle
|
|
985
|
-
}
|
|
986
|
-
)
|
|
870
|
+
/* @__PURE__ */ jsx("input", { type: "text", placeholder: "First name", value: firstName, onChange: (e) => setFirstName(e.target.value), style: inputStyle }),
|
|
871
|
+
/* @__PURE__ */ jsx("input", { type: "email", placeholder: "Email address", value: email, onChange: (e) => setEmail(e.target.value), required: true, style: inputStyle })
|
|
987
872
|
] }),
|
|
988
873
|
c.show_newsletter_opt_in !== false && /* @__PURE__ */ jsxs("label", { style: {
|
|
989
874
|
display: "flex",
|
|
@@ -1001,123 +886,140 @@ var WhaleStorefront = (function (exports) {
|
|
|
1001
886
|
type: "checkbox",
|
|
1002
887
|
checked: newsletterOptIn,
|
|
1003
888
|
onChange: (e) => setNewsletterOptIn(e.target.checked),
|
|
1004
|
-
style: {
|
|
1005
|
-
width: 16,
|
|
1006
|
-
height: 16,
|
|
1007
|
-
accentColor: theme.accent,
|
|
1008
|
-
cursor: "pointer",
|
|
1009
|
-
flexShrink: 0
|
|
1010
|
-
}
|
|
889
|
+
style: { width: 16, height: 16, accentColor: theme.accent, cursor: "pointer", flexShrink: 0 }
|
|
1011
890
|
}
|
|
1012
891
|
),
|
|
1013
892
|
c.newsletter_label || "Also sign me up for the newsletter \u2014 new drops, deals, and company news."
|
|
1014
893
|
] }),
|
|
1015
894
|
status === "error" && errorMsg && /* @__PURE__ */ jsx("p", { style: { fontSize: "0.8rem", color: "#e55", margin: 0, fontWeight: 400 }, children: errorMsg }),
|
|
1016
|
-
/* @__PURE__ */ jsxs(
|
|
1017
|
-
"
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
}
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
borderTopColor: theme.bg,
|
|
1047
|
-
borderRadius: "50%",
|
|
1048
|
-
animation: "lc-spin 0.8s linear infinite"
|
|
1049
|
-
} }),
|
|
1050
|
-
buttonText
|
|
1051
|
-
]
|
|
1052
|
-
}
|
|
1053
|
-
)
|
|
895
|
+
/* @__PURE__ */ jsxs("button", { type: "submit", disabled: status === "loading", style: {
|
|
896
|
+
width: "100%",
|
|
897
|
+
padding: "0.875rem",
|
|
898
|
+
background: theme.fg,
|
|
899
|
+
color: theme.bg,
|
|
900
|
+
border: "none",
|
|
901
|
+
fontSize: "0.85rem",
|
|
902
|
+
fontWeight: 500,
|
|
903
|
+
cursor: status === "loading" ? "wait" : "pointer",
|
|
904
|
+
letterSpacing: "0.08em",
|
|
905
|
+
textTransform: "uppercase",
|
|
906
|
+
fontFamily: "inherit",
|
|
907
|
+
display: "flex",
|
|
908
|
+
alignItems: "center",
|
|
909
|
+
justifyContent: "center",
|
|
910
|
+
gap: "0.5rem",
|
|
911
|
+
opacity: status === "loading" ? 0.7 : 1,
|
|
912
|
+
transition: "opacity 0.2s"
|
|
913
|
+
}, children: [
|
|
914
|
+
status === "loading" && /* @__PURE__ */ jsx("span", { style: {
|
|
915
|
+
display: "inline-block",
|
|
916
|
+
width: 16,
|
|
917
|
+
height: 16,
|
|
918
|
+
border: `2px solid ${theme.bg}40`,
|
|
919
|
+
borderTopColor: theme.bg,
|
|
920
|
+
borderRadius: "50%",
|
|
921
|
+
animation: "lc-spin 0.8s linear infinite"
|
|
922
|
+
} }),
|
|
923
|
+
buttonText
|
|
924
|
+
] })
|
|
1054
925
|
] })
|
|
1055
|
-
] })
|
|
926
|
+
] })
|
|
1056
927
|
] });
|
|
1057
928
|
}
|
|
1058
|
-
function
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
}
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
929
|
+
function SuccessState({ theme, heading, message, couponCode }) {
|
|
930
|
+
return /* @__PURE__ */ jsx("div", { style: { padding: "3.5rem 1.5rem", maxWidth: 560, margin: "0 auto" }, children: /* @__PURE__ */ jsxs("div", { style: { background: theme.surface, border: `1px solid ${theme.fg}12`, padding: "clamp(2rem, 6vw, 3rem)", textAlign: "center" }, children: [
|
|
931
|
+
/* @__PURE__ */ jsx("h2", { style: {
|
|
932
|
+
fontSize: "clamp(1.5rem, 5vw, 2rem)",
|
|
933
|
+
fontWeight: 300,
|
|
934
|
+
fontFamily: theme.fontDisplay || "inherit",
|
|
935
|
+
margin: "0 0 0.75rem",
|
|
936
|
+
lineHeight: 1.2,
|
|
937
|
+
letterSpacing: "-0.02em",
|
|
938
|
+
color: theme.fg
|
|
939
|
+
}, children: heading }),
|
|
940
|
+
/* @__PURE__ */ jsx("p", { style: { fontSize: "0.9rem", color: `${theme.fg}99`, margin: "0 0 1.5rem", lineHeight: 1.6, fontWeight: 300 }, children: message }),
|
|
941
|
+
couponCode && /* @__PURE__ */ jsx("div", { style: {
|
|
942
|
+
display: "inline-block",
|
|
943
|
+
padding: "0.75rem 2rem",
|
|
944
|
+
background: `${theme.fg}08`,
|
|
945
|
+
border: `1px dashed ${theme.fg}30`,
|
|
946
|
+
fontSize: "clamp(1.25rem, 4vw, 1.75rem)",
|
|
947
|
+
fontWeight: 500,
|
|
948
|
+
fontFamily: "monospace",
|
|
949
|
+
letterSpacing: "0.12em",
|
|
950
|
+
color: theme.accent
|
|
951
|
+
}, children: couponCode })
|
|
952
|
+
] }) });
|
|
1082
953
|
}
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
954
|
+
|
|
955
|
+
// src/react/components/section-renderer.tsx
|
|
956
|
+
function SectionRenderer({
|
|
957
|
+
section,
|
|
958
|
+
data,
|
|
959
|
+
theme,
|
|
960
|
+
tracking,
|
|
961
|
+
onEvent
|
|
962
|
+
}) {
|
|
963
|
+
const [showCOA, setShowCOA] = useState(false);
|
|
964
|
+
const el = (() => {
|
|
965
|
+
switch (section.type) {
|
|
966
|
+
case "hero":
|
|
967
|
+
return /* @__PURE__ */ jsx(HeroSection, { section, theme, tracking, onEvent });
|
|
968
|
+
case "text":
|
|
969
|
+
return /* @__PURE__ */ jsx(TextSection, { section, theme });
|
|
970
|
+
case "image":
|
|
971
|
+
return /* @__PURE__ */ jsx(ImageSection, { section, theme });
|
|
972
|
+
case "video":
|
|
973
|
+
return /* @__PURE__ */ jsx(VideoSection, { section, theme });
|
|
974
|
+
case "gallery":
|
|
975
|
+
return /* @__PURE__ */ jsx(GallerySection, { section, theme });
|
|
976
|
+
case "cta":
|
|
977
|
+
return /* @__PURE__ */ jsx(CTASection, { section, theme, tracking, onEvent });
|
|
978
|
+
case "stats":
|
|
979
|
+
return /* @__PURE__ */ jsx(StatsSection, { section, theme });
|
|
980
|
+
case "product_card":
|
|
981
|
+
return /* @__PURE__ */ jsx(ProductCardSection, { section, data, theme, tracking });
|
|
982
|
+
case "coa_viewer":
|
|
983
|
+
return /* @__PURE__ */ jsx(COAViewerSection, { section, data, theme, onShowCOA: () => setShowCOA(true), tracking });
|
|
984
|
+
case "social_links":
|
|
985
|
+
return /* @__PURE__ */ jsx(SocialLinksSection, { section, theme });
|
|
986
|
+
case "lead_capture":
|
|
987
|
+
return /* @__PURE__ */ jsx(LeadCaptureSection, { section, data, theme, onEvent });
|
|
988
|
+
case "divider":
|
|
989
|
+
return /* @__PURE__ */ jsx(DividerSection, { theme });
|
|
990
|
+
default:
|
|
991
|
+
return null;
|
|
992
|
+
}
|
|
993
|
+
})();
|
|
994
|
+
const sectionRef = useRef(null);
|
|
995
|
+
useEffect(() => {
|
|
996
|
+
const el2 = sectionRef.current;
|
|
997
|
+
if (!el2 || typeof IntersectionObserver === "undefined") return;
|
|
998
|
+
const obs = new IntersectionObserver(
|
|
999
|
+
([entry]) => {
|
|
1000
|
+
if (entry.isIntersecting) {
|
|
1001
|
+
onEvent?.("section_view", { section_id: section.id, section_type: section.type });
|
|
1002
|
+
obs.disconnect();
|
|
1106
1003
|
}
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1004
|
+
},
|
|
1005
|
+
{ threshold: 0.5 }
|
|
1006
|
+
);
|
|
1007
|
+
obs.observe(el2);
|
|
1008
|
+
return () => obs.disconnect();
|
|
1009
|
+
}, [section.id, section.type, onEvent]);
|
|
1010
|
+
return /* @__PURE__ */ jsxs("div", { ref: sectionRef, "data-section-id": section.id, "data-section-type": section.type, children: [
|
|
1011
|
+
el,
|
|
1012
|
+
showCOA && data?.coa && /* @__PURE__ */ jsx(COAModal, { coa: data.coa, theme, onClose: () => setShowCOA(false) })
|
|
1110
1013
|
] });
|
|
1111
1014
|
}
|
|
1112
|
-
function toEmbedUrl(url) {
|
|
1113
|
-
const ytMatch = url.match(/(?:youtube\.com\/watch\?v=|youtu\.be\/)([\w-]+)/);
|
|
1114
|
-
if (ytMatch) return `https://www.youtube.com/embed/${ytMatch[1]}`;
|
|
1115
|
-
const vimeoMatch = url.match(/vimeo\.com\/(\d+)/);
|
|
1116
|
-
if (vimeoMatch) return `https://player.vimeo.com/video/${vimeoMatch[1]}`;
|
|
1117
|
-
return url;
|
|
1118
|
-
}
|
|
1119
1015
|
|
|
1120
1016
|
// src/react/components/landing-page.tsx
|
|
1017
|
+
function getInlinedData() {
|
|
1018
|
+
if (typeof window !== "undefined" && window.__LANDING_DATA__) {
|
|
1019
|
+
return window.__LANDING_DATA__;
|
|
1020
|
+
}
|
|
1021
|
+
return null;
|
|
1022
|
+
}
|
|
1121
1023
|
function LandingPage({
|
|
1122
1024
|
slug,
|
|
1123
1025
|
gatewayUrl = "https://whale-gateway.fly.dev",
|
|
@@ -1128,47 +1030,43 @@ var WhaleStorefront = (function (exports) {
|
|
|
1128
1030
|
analyticsContext,
|
|
1129
1031
|
enableAnalytics = true
|
|
1130
1032
|
}) {
|
|
1131
|
-
const
|
|
1132
|
-
const [
|
|
1033
|
+
const inlined = useRef(getInlinedData()).current;
|
|
1034
|
+
const [state, setState] = useState(inlined ? "ready" : "loading");
|
|
1035
|
+
const [data, setData] = useState(inlined);
|
|
1133
1036
|
const [errorMsg, setErrorMsg] = useState("");
|
|
1134
1037
|
useEffect(() => {
|
|
1135
1038
|
if (!slug) return;
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
const json = window.__LANDING_DATA__;
|
|
1139
|
-
setData(json);
|
|
1140
|
-
setState("ready");
|
|
1141
|
-
onDataLoaded?.(json);
|
|
1039
|
+
if (data) {
|
|
1040
|
+
onDataLoaded?.(data);
|
|
1142
1041
|
return;
|
|
1143
1042
|
}
|
|
1043
|
+
let cancelled = false;
|
|
1144
1044
|
async function load() {
|
|
1145
1045
|
try {
|
|
1146
1046
|
const res = await fetch(`${gatewayUrl}/l/${encodeURIComponent(slug)}`);
|
|
1147
|
-
if (
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
}
|
|
1152
|
-
if (res.status === 410) {
|
|
1153
|
-
setState("expired");
|
|
1154
|
-
return;
|
|
1155
|
-
}
|
|
1156
|
-
if (!res.ok) {
|
|
1157
|
-
const body = await res.json().catch(() => ({}));
|
|
1158
|
-
throw new Error(body?.error?.message ?? `Failed to load: ${res.status}`);
|
|
1159
|
-
}
|
|
1160
|
-
const json = await res.json();
|
|
1161
|
-
setData(json);
|
|
1162
|
-
setState("ready");
|
|
1163
|
-
onDataLoaded?.(json);
|
|
1047
|
+
if (cancelled) return;
|
|
1048
|
+
if (res.status === 404) {
|
|
1049
|
+
setState("not_found");
|
|
1050
|
+
return;
|
|
1164
1051
|
}
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1052
|
+
if (res.status === 410) {
|
|
1053
|
+
setState("expired");
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
1056
|
+
if (!res.ok) {
|
|
1057
|
+
const body = await res.json().catch(() => ({}));
|
|
1058
|
+
throw new Error(body?.error?.message ?? `Failed to load: ${res.status}`);
|
|
1171
1059
|
}
|
|
1060
|
+
const json = await res.json();
|
|
1061
|
+
setData(json);
|
|
1062
|
+
setState("ready");
|
|
1063
|
+
onDataLoaded?.(json);
|
|
1064
|
+
} catch (err) {
|
|
1065
|
+
if (cancelled) return;
|
|
1066
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
1067
|
+
setErrorMsg(e.message);
|
|
1068
|
+
setState("error");
|
|
1069
|
+
onError?.(e);
|
|
1172
1070
|
}
|
|
1173
1071
|
}
|
|
1174
1072
|
load();
|
|
@@ -1176,12 +1074,22 @@ var WhaleStorefront = (function (exports) {
|
|
|
1176
1074
|
cancelled = true;
|
|
1177
1075
|
};
|
|
1178
1076
|
}, [slug, gatewayUrl]);
|
|
1179
|
-
if (state === "loading") return /* @__PURE__ */ jsx(
|
|
1180
|
-
if (state === "not_found") return /* @__PURE__ */ jsx(
|
|
1181
|
-
if (state === "expired") return /* @__PURE__ */ jsx(
|
|
1182
|
-
if (state === "error") return /* @__PURE__ */ jsx(
|
|
1077
|
+
if (state === "loading") return /* @__PURE__ */ jsx(StateScreen, { title: "", loading: true });
|
|
1078
|
+
if (state === "not_found") return /* @__PURE__ */ jsx(StateScreen, { title: "Page Not Found", subtitle: "This page does not exist or has been removed." });
|
|
1079
|
+
if (state === "expired") return /* @__PURE__ */ jsx(StateScreen, { title: "Page Expired", subtitle: "This page is no longer active." });
|
|
1080
|
+
if (state === "error") return /* @__PURE__ */ jsx(StateScreen, { title: "Something Went Wrong", subtitle: errorMsg || "Please try again later." });
|
|
1183
1081
|
if (!data) return null;
|
|
1184
|
-
return /* @__PURE__ */ jsx(
|
|
1082
|
+
return /* @__PURE__ */ jsx(
|
|
1083
|
+
PageLayout,
|
|
1084
|
+
{
|
|
1085
|
+
data,
|
|
1086
|
+
gatewayUrl,
|
|
1087
|
+
renderSection,
|
|
1088
|
+
onEvent,
|
|
1089
|
+
analyticsContext,
|
|
1090
|
+
enableAnalytics
|
|
1091
|
+
}
|
|
1092
|
+
);
|
|
1185
1093
|
}
|
|
1186
1094
|
function isSectionVisible(section, urlParams) {
|
|
1187
1095
|
const vis = section.config?.visibility;
|
|
@@ -1204,8 +1112,8 @@ var WhaleStorefront = (function (exports) {
|
|
|
1204
1112
|
const trackerRef = useRef(null);
|
|
1205
1113
|
useEffect(() => {
|
|
1206
1114
|
if (!enableAnalytics || typeof window === "undefined") return;
|
|
1207
|
-
const
|
|
1208
|
-
if (!
|
|
1115
|
+
const config = window.__LANDING_ANALYTICS__;
|
|
1116
|
+
if (!config?.slug) return;
|
|
1209
1117
|
let visitorId = localStorage.getItem("wt_vid") || "";
|
|
1210
1118
|
if (!visitorId) {
|
|
1211
1119
|
visitorId = crypto.randomUUID();
|
|
@@ -1217,8 +1125,8 @@ var WhaleStorefront = (function (exports) {
|
|
|
1217
1125
|
sessionStorage.setItem("wt_sid", sessionId);
|
|
1218
1126
|
}
|
|
1219
1127
|
Promise.resolve().then(() => (init_tracker(), tracker_exports)).then(({ BehavioralTracker: BehavioralTracker2 }) => {
|
|
1220
|
-
const gwUrl =
|
|
1221
|
-
const slug =
|
|
1128
|
+
const gwUrl = config.gatewayUrl || gatewayUrl;
|
|
1129
|
+
const slug = config.slug;
|
|
1222
1130
|
const utmParams = new URLSearchParams(window.location.search);
|
|
1223
1131
|
const tracker = new BehavioralTracker2({
|
|
1224
1132
|
sessionId,
|
|
@@ -1229,65 +1137,44 @@ var WhaleStorefront = (function (exports) {
|
|
|
1229
1137
|
event_data: e.data,
|
|
1230
1138
|
session_id: batch.session_id,
|
|
1231
1139
|
visitor_id: batch.visitor_id,
|
|
1232
|
-
campaign_id:
|
|
1140
|
+
campaign_id: config.campaignId || utmParams.get("utm_campaign_id") || void 0,
|
|
1233
1141
|
utm_source: utmParams.get("utm_source") || void 0,
|
|
1234
1142
|
utm_medium: utmParams.get("utm_medium") || void 0,
|
|
1235
1143
|
utm_campaign: utmParams.get("utm_campaign") || void 0
|
|
1236
1144
|
}));
|
|
1237
|
-
|
|
1238
|
-
if (typeof navigator !== "undefined" && navigator.sendBeacon) {
|
|
1239
|
-
navigator.sendBeacon(
|
|
1240
|
-
`${gwUrl}/l/${encodeURIComponent(slug)}/events`,
|
|
1241
|
-
new Blob([body], { type: "application/json" })
|
|
1242
|
-
);
|
|
1243
|
-
} else {
|
|
1244
|
-
await fetch(`${gwUrl}/l/${encodeURIComponent(slug)}/events`, {
|
|
1245
|
-
method: "POST",
|
|
1246
|
-
headers: { "Content-Type": "application/json" },
|
|
1247
|
-
body,
|
|
1248
|
-
keepalive: true
|
|
1249
|
-
});
|
|
1250
|
-
}
|
|
1145
|
+
sendEvents(gwUrl, slug, events);
|
|
1251
1146
|
}
|
|
1252
1147
|
});
|
|
1253
1148
|
tracker.setPageContext(window.location.href, window.location.pathname);
|
|
1254
1149
|
tracker.start();
|
|
1255
1150
|
trackerRef.current = tracker;
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
utm_source: utmParams.get("utm_source") || void 0,
|
|
1264
|
-
utm_medium: utmParams.get("utm_medium") || void 0,
|
|
1265
|
-
utm_campaign: utmParams.get("utm_campaign") || void 0
|
|
1266
|
-
}]
|
|
1267
|
-
});
|
|
1268
|
-
if (navigator.sendBeacon) {
|
|
1269
|
-
navigator.sendBeacon(
|
|
1270
|
-
`${gwUrl}/l/${encodeURIComponent(slug)}/events`,
|
|
1271
|
-
new Blob([pageViewBody], { type: "application/json" })
|
|
1272
|
-
);
|
|
1273
|
-
} else {
|
|
1274
|
-
fetch(`${gwUrl}/l/${encodeURIComponent(slug)}/events`, {
|
|
1275
|
-
method: "POST",
|
|
1276
|
-
headers: { "Content-Type": "application/json" },
|
|
1277
|
-
body: pageViewBody,
|
|
1278
|
-
keepalive: true
|
|
1279
|
-
}).catch(() => {
|
|
1280
|
-
});
|
|
1281
|
-
}
|
|
1151
|
+
sendEvents(gwUrl, slug, [{
|
|
1152
|
+
event_type: "page_view",
|
|
1153
|
+
event_data: { referrer: document.referrer, url: window.location.href },
|
|
1154
|
+
session_id: sessionId,
|
|
1155
|
+
visitor_id: visitorId,
|
|
1156
|
+
campaign_id: config.campaignId || void 0
|
|
1157
|
+
}]);
|
|
1282
1158
|
}).catch(() => {
|
|
1283
1159
|
});
|
|
1284
1160
|
return () => {
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
trackerRef.current = null;
|
|
1288
|
-
}
|
|
1161
|
+
trackerRef.current?.stop();
|
|
1162
|
+
trackerRef.current = null;
|
|
1289
1163
|
};
|
|
1290
1164
|
}, [enableAnalytics, gatewayUrl]);
|
|
1165
|
+
const handleEvent = useCallback((event, eventData) => {
|
|
1166
|
+
onEvent?.(event, eventData);
|
|
1167
|
+
if (!enableAnalytics || typeof window === "undefined") return;
|
|
1168
|
+
const config = window.__LANDING_ANALYTICS__;
|
|
1169
|
+
if (!config?.slug) return;
|
|
1170
|
+
sendEvents(config.gatewayUrl || gatewayUrl, config.slug, [{
|
|
1171
|
+
event_type: event,
|
|
1172
|
+
event_data: eventData,
|
|
1173
|
+
session_id: sessionStorage.getItem("wt_sid") || void 0,
|
|
1174
|
+
visitor_id: localStorage.getItem("wt_vid") || void 0,
|
|
1175
|
+
campaign_id: config.campaignId || void 0
|
|
1176
|
+
}]);
|
|
1177
|
+
}, [onEvent, enableAnalytics, gatewayUrl]);
|
|
1291
1178
|
const theme = {
|
|
1292
1179
|
bg: lp.background_color || store?.theme?.background || "#050505",
|
|
1293
1180
|
fg: lp.text_color || store?.theme?.foreground || "#fafafa",
|
|
@@ -1306,11 +1193,9 @@ var WhaleStorefront = (function (exports) {
|
|
|
1306
1193
|
lp.custom_css && /* @__PURE__ */ jsx("style", { children: lp.custom_css }),
|
|
1307
1194
|
logoUrl && /* @__PURE__ */ jsx("div", { style: { padding: "1.5rem", display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ jsx("img", { src: logoUrl, alt: store?.name || "Store", style: { height: 40, objectFit: "contain" } }) }),
|
|
1308
1195
|
sorted.map((section) => {
|
|
1309
|
-
const defaultRenderer = () => /* @__PURE__ */ jsx(SectionRenderer, { section, data: sectionData, theme, onEvent }, section.id);
|
|
1310
|
-
if (renderSection) {
|
|
1311
|
-
|
|
1312
|
-
}
|
|
1313
|
-
return /* @__PURE__ */ jsx(SectionRenderer, { section, data: sectionData, theme, onEvent }, section.id);
|
|
1196
|
+
const defaultRenderer = () => /* @__PURE__ */ jsx(SectionRenderer, { section, data: sectionData, theme, onEvent: handleEvent }, section.id);
|
|
1197
|
+
if (renderSection) return /* @__PURE__ */ jsx("div", { children: renderSection(section, defaultRenderer) }, section.id);
|
|
1198
|
+
return /* @__PURE__ */ jsx(SectionRenderer, { section, data: sectionData, theme, onEvent: handleEvent }, section.id);
|
|
1314
1199
|
}),
|
|
1315
1200
|
store?.name && /* @__PURE__ */ jsx("div", { style: { padding: "2rem 1.5rem", borderTop: `1px solid ${theme.surface}`, textAlign: "center" }, children: /* @__PURE__ */ jsxs("p", { style: { fontSize: "0.75rem", color: theme.muted, margin: 0 }, children: [
|
|
1316
1201
|
"Powered by ",
|
|
@@ -1318,7 +1203,17 @@ var WhaleStorefront = (function (exports) {
|
|
|
1318
1203
|
] }) })
|
|
1319
1204
|
] });
|
|
1320
1205
|
}
|
|
1321
|
-
|
|
1206
|
+
function sendEvents(gwUrl, slug, events) {
|
|
1207
|
+
const body = JSON.stringify({ events });
|
|
1208
|
+
const url = `${gwUrl}/l/${encodeURIComponent(slug)}/events`;
|
|
1209
|
+
if (typeof navigator !== "undefined" && navigator.sendBeacon) {
|
|
1210
|
+
navigator.sendBeacon(url, new Blob([body], { type: "application/json" }));
|
|
1211
|
+
} else {
|
|
1212
|
+
fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body, keepalive: true }).catch(() => {
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
var screenStyle = {
|
|
1322
1217
|
minHeight: "100dvh",
|
|
1323
1218
|
display: "flex",
|
|
1324
1219
|
justifyContent: "center",
|
|
@@ -1329,28 +1224,14 @@ var WhaleStorefront = (function (exports) {
|
|
|
1329
1224
|
textAlign: "center",
|
|
1330
1225
|
padding: "2rem"
|
|
1331
1226
|
};
|
|
1332
|
-
function
|
|
1333
|
-
return /* @__PURE__ */ jsx("div", { style:
|
|
1334
|
-
/* @__PURE__ */
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
/* @__PURE__ */ jsx("h1", { style: { fontSize: "1.5rem", marginBottom: "0.5rem" }, children: "Page Not Found" }),
|
|
1341
|
-
/* @__PURE__ */ jsx("p", { style: { color: "#888" }, children: "This page does not exist or has been removed." })
|
|
1342
|
-
] }) });
|
|
1343
|
-
}
|
|
1344
|
-
function DefaultExpired() {
|
|
1345
|
-
return /* @__PURE__ */ jsx("div", { style: containerStyle, children: /* @__PURE__ */ jsxs("div", { children: [
|
|
1346
|
-
/* @__PURE__ */ jsx("h1", { style: { fontSize: "1.5rem", marginBottom: "0.5rem" }, children: "Page Expired" }),
|
|
1347
|
-
/* @__PURE__ */ jsx("p", { style: { color: "#888" }, children: "This page is no longer active." })
|
|
1348
|
-
] }) });
|
|
1349
|
-
}
|
|
1350
|
-
function DefaultError({ message }) {
|
|
1351
|
-
return /* @__PURE__ */ jsx("div", { style: containerStyle, children: /* @__PURE__ */ jsxs("div", { children: [
|
|
1352
|
-
/* @__PURE__ */ jsx("h1", { style: { fontSize: "1.5rem", marginBottom: "0.5rem" }, children: "Something Went Wrong" }),
|
|
1353
|
-
/* @__PURE__ */ jsx("p", { style: { color: "#888" }, children: message || "Please try again later." })
|
|
1227
|
+
function StateScreen({ title, subtitle, loading }) {
|
|
1228
|
+
return /* @__PURE__ */ jsx("div", { style: screenStyle, children: /* @__PURE__ */ jsxs("div", { children: [
|
|
1229
|
+
loading && /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1230
|
+
/* @__PURE__ */ jsx("div", { style: { width: 32, height: 32, border: "2px solid #333", borderTopColor: "#fafafa", borderRadius: "50%", animation: "spin 0.8s linear infinite", margin: "0 auto 1rem" } }),
|
|
1231
|
+
/* @__PURE__ */ jsx("style", { children: `@keyframes spin { to { transform: rotate(360deg) } }` })
|
|
1232
|
+
] }),
|
|
1233
|
+
title && /* @__PURE__ */ jsx("h1", { style: { fontSize: "1.5rem", marginBottom: "0.5rem" }, children: title }),
|
|
1234
|
+
subtitle && /* @__PURE__ */ jsx("p", { style: { color: "#888" }, children: subtitle })
|
|
1354
1235
|
] }) });
|
|
1355
1236
|
}
|
|
1356
1237
|
|