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