@neowhale/storefront 0.2.42 → 0.2.44
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/client-D7_7p7ja.d.cts +669 -0
- package/dist/client-D7_7p7ja.d.ts +669 -0
- package/dist/index.d.cts +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/landing.global.js +358 -17
- package/dist/next/index.d.cts +117 -0
- package/dist/next/index.d.ts +117 -0
- package/dist/pixel-manager-Blj8hb-X.d.cts +10 -0
- package/dist/pixel-manager-DB8LLw9V.d.ts +10 -0
- package/dist/react/index.cjs +357 -18
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +536 -0
- package/dist/react/index.d.ts +536 -0
- package/dist/react/index.js +357 -18
- package/dist/react/index.js.map +1 -1
- package/package.json +1 -1
package/dist/landing.global.js
CHANGED
|
@@ -562,27 +562,62 @@ var WhaleStorefront = (function (exports) {
|
|
|
562
562
|
return /* @__PURE__ */ jsx("div", { style: { width: "100%", overflow: "hidden", position: "relative" }, children: [
|
|
563
563
|
/* @__PURE__ */ jsx("div", { style: {
|
|
564
564
|
display: "grid",
|
|
565
|
-
gridTemplateColumns:
|
|
566
|
-
gridTemplateRows:
|
|
565
|
+
gridTemplateColumns: "3fr 2fr",
|
|
566
|
+
gridTemplateRows: "auto",
|
|
567
567
|
gap: "2px"
|
|
568
|
-
}, children:
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
568
|
+
}, children: [
|
|
569
|
+
count > 0 && /* @__PURE__ */ jsx("div", { style: { gridRow: count >= 3 ? "span 2" : void 0, overflow: "hidden", background: theme.surface, maxHeight: "70vh" }, children: /* @__PURE__ */ jsx(
|
|
570
|
+
"img",
|
|
571
|
+
{
|
|
572
|
+
src: images[0].url,
|
|
573
|
+
alt: images[0].alt || "",
|
|
574
|
+
loading: "eager",
|
|
575
|
+
style: { width: "100%", height: "100%", objectFit: "cover", display: "block", minHeight: "40vh" }
|
|
576
|
+
}
|
|
577
|
+
) }),
|
|
578
|
+
count >= 2 && /* @__PURE__ */ jsx("div", { style: { overflow: "hidden", background: theme.surface }, children: /* @__PURE__ */ jsx(
|
|
579
|
+
"img",
|
|
580
|
+
{
|
|
581
|
+
src: images[1].url,
|
|
582
|
+
alt: images[1].alt || "",
|
|
583
|
+
loading: "eager",
|
|
584
|
+
style: { width: "100%", height: "100%", objectFit: "cover", display: "block", minHeight: "20vh", maxHeight: "35vh" }
|
|
585
|
+
}
|
|
586
|
+
) }),
|
|
587
|
+
count >= 3 && /* @__PURE__ */ jsx("div", { style: { overflow: "hidden", background: theme.surface }, children: /* @__PURE__ */ jsx(
|
|
588
|
+
"img",
|
|
589
|
+
{
|
|
590
|
+
src: images[2].url,
|
|
591
|
+
alt: images[2].alt || "",
|
|
592
|
+
loading: "lazy",
|
|
593
|
+
style: { width: "100%", height: "100%", objectFit: "cover", display: "block", minHeight: "20vh", maxHeight: "35vh" }
|
|
594
|
+
}
|
|
595
|
+
) }),
|
|
596
|
+
count >= 4 && /* @__PURE__ */ jsx("div", { style: { gridColumn: "1 / -1", display: "grid", gridTemplateColumns: count >= 5 ? "1fr 1fr" : "1fr", gap: "2px" }, children: [
|
|
597
|
+
/* @__PURE__ */ jsx("div", { style: { overflow: "hidden", background: theme.surface, maxHeight: "25vh" }, children: /* @__PURE__ */ jsx(
|
|
598
|
+
"img",
|
|
599
|
+
{
|
|
600
|
+
src: images[3].url,
|
|
601
|
+
alt: images[3].alt || "",
|
|
602
|
+
loading: "lazy",
|
|
603
|
+
style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
|
|
604
|
+
}
|
|
605
|
+
) }),
|
|
606
|
+
count >= 5 && /* @__PURE__ */ jsx("div", { style: { overflow: "hidden", background: theme.surface, maxHeight: "25vh" }, children: /* @__PURE__ */ jsx(
|
|
607
|
+
"img",
|
|
608
|
+
{
|
|
609
|
+
src: images[4].url,
|
|
610
|
+
alt: images[4].alt || "",
|
|
611
|
+
loading: "lazy",
|
|
612
|
+
style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
|
|
613
|
+
}
|
|
614
|
+
) })
|
|
615
|
+
] })
|
|
616
|
+
] }),
|
|
582
617
|
/* @__PURE__ */ jsx("div", { style: {
|
|
583
618
|
position: "absolute",
|
|
584
619
|
inset: 0,
|
|
585
|
-
background: "linear-gradient(to top, rgba(0,0,0,0.
|
|
620
|
+
background: "linear-gradient(to top, rgba(0,0,0,0.75) 0%, rgba(0,0,0,0.15) 35%, transparent 55%)",
|
|
586
621
|
pointerEvents: "none"
|
|
587
622
|
} }),
|
|
588
623
|
/* @__PURE__ */ jsx("div", { style: {
|
|
@@ -1041,6 +1076,302 @@ var WhaleStorefront = (function (exports) {
|
|
|
1041
1076
|
] }) });
|
|
1042
1077
|
}
|
|
1043
1078
|
|
|
1079
|
+
// src/react/components/sections/conversion-sections.tsx
|
|
1080
|
+
function TestimonialsSection({ section, theme }) {
|
|
1081
|
+
const c = section.content;
|
|
1082
|
+
const layout = section.config?.layout || "grid";
|
|
1083
|
+
const reviews = c.reviews || [];
|
|
1084
|
+
if (reviews.length === 0) return null;
|
|
1085
|
+
const overallRating = c.rating ?? 5;
|
|
1086
|
+
const reviewCount = c.review_count ?? reviews.length;
|
|
1087
|
+
return /* @__PURE__ */ jsx("div", { style: { padding: "3rem 1.5rem", maxWidth: 640, margin: "0 auto" }, children: [
|
|
1088
|
+
/* @__PURE__ */ jsx("div", { style: { textAlign: "center", marginBottom: "2rem" }, children: [
|
|
1089
|
+
c.heading && /* @__PURE__ */ jsx("h2", { style: {
|
|
1090
|
+
fontSize: "clamp(1.25rem, 4vw, 1.75rem)",
|
|
1091
|
+
fontWeight: 300,
|
|
1092
|
+
fontFamily: theme.fontDisplay || "inherit",
|
|
1093
|
+
margin: "0 0 0.75rem",
|
|
1094
|
+
lineHeight: 1.2,
|
|
1095
|
+
letterSpacing: "-0.02em",
|
|
1096
|
+
color: theme.fg
|
|
1097
|
+
}, children: /* @__PURE__ */ jsx(AnimatedText, { text: c.heading }) }),
|
|
1098
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: "0.5rem", marginBottom: "0.25rem" }, children: [
|
|
1099
|
+
/* @__PURE__ */ jsx(Stars, { rating: overallRating, color: theme.accent, size: 18 }),
|
|
1100
|
+
/* @__PURE__ */ jsx("span", { style: { fontSize: "1.1rem", fontWeight: 500, color: theme.fg }, children: /* @__PURE__ */ jsx(AnimatedText, { text: overallRating.toFixed(1) }) })
|
|
1101
|
+
] }),
|
|
1102
|
+
c.subtitle ? /* @__PURE__ */ jsx("p", { style: { fontSize: "0.8rem", color: theme.muted, margin: 0, letterSpacing: "0.1em", textTransform: "uppercase" }, children: c.subtitle }) : /* @__PURE__ */ jsx("p", { style: { fontSize: "0.8rem", color: theme.muted, margin: 0, letterSpacing: "0.1em", textTransform: "uppercase" }, children: [
|
|
1103
|
+
"from ",
|
|
1104
|
+
/* @__PURE__ */ jsx(AnimatedText, { text: String(reviewCount) }),
|
|
1105
|
+
" reviews"
|
|
1106
|
+
] })
|
|
1107
|
+
] }),
|
|
1108
|
+
/* @__PURE__ */ jsx("div", { style: {
|
|
1109
|
+
display: "grid",
|
|
1110
|
+
gridTemplateColumns: layout === "list" ? "1fr" : `repeat(${Math.min(reviews.length, 2)}, 1fr)`,
|
|
1111
|
+
gap: "0.75rem"
|
|
1112
|
+
}, children: reviews.map((review, i) => /* @__PURE__ */ jsx("div", { style: {
|
|
1113
|
+
background: theme.surface,
|
|
1114
|
+
border: `1px solid ${theme.fg}08`,
|
|
1115
|
+
padding: "1.25rem"
|
|
1116
|
+
}, children: [
|
|
1117
|
+
/* @__PURE__ */ jsx(Stars, { rating: review.rating ?? 5, color: theme.accent, size: 14 }),
|
|
1118
|
+
/* @__PURE__ */ jsx("p", { style: {
|
|
1119
|
+
fontSize: "0.88rem",
|
|
1120
|
+
color: `${theme.fg}CC`,
|
|
1121
|
+
margin: "0.75rem 0",
|
|
1122
|
+
lineHeight: 1.6,
|
|
1123
|
+
fontWeight: 300,
|
|
1124
|
+
fontStyle: "italic"
|
|
1125
|
+
}, children: [
|
|
1126
|
+
'"',
|
|
1127
|
+
review.text,
|
|
1128
|
+
'"'
|
|
1129
|
+
] }),
|
|
1130
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", alignItems: "baseline", gap: "0.375rem" }, children: [
|
|
1131
|
+
/* @__PURE__ */ jsx("span", { style: { fontSize: "0.8rem", fontWeight: 500, color: theme.fg }, children: review.name }),
|
|
1132
|
+
review.location && /* @__PURE__ */ jsx("span", { style: { fontSize: "0.7rem", color: theme.muted }, children: review.location })
|
|
1133
|
+
] })
|
|
1134
|
+
] }, i)) })
|
|
1135
|
+
] });
|
|
1136
|
+
}
|
|
1137
|
+
function Stars({ rating, color, size }) {
|
|
1138
|
+
return /* @__PURE__ */ jsx("span", { style: { display: "inline-flex", gap: "1px" }, children: [1, 2, 3, 4, 5].map((n) => /* @__PURE__ */ jsx(
|
|
1139
|
+
"svg",
|
|
1140
|
+
{
|
|
1141
|
+
width: size,
|
|
1142
|
+
height: size,
|
|
1143
|
+
viewBox: "0 0 20 20",
|
|
1144
|
+
fill: n <= Math.round(rating) ? color : "none",
|
|
1145
|
+
stroke: color,
|
|
1146
|
+
strokeWidth: 1.5,
|
|
1147
|
+
children: /* @__PURE__ */ jsx("path", { d: "M10 1.5l2.47 5.01 5.53.8-4 3.9.94 5.5L10 14.26 5.06 16.7l.94-5.5-4-3.9 5.53-.8z" })
|
|
1148
|
+
},
|
|
1149
|
+
n
|
|
1150
|
+
)) });
|
|
1151
|
+
}
|
|
1152
|
+
function ValueStackSection({ section, theme }) {
|
|
1153
|
+
const c = section.content;
|
|
1154
|
+
const items = c.items || [];
|
|
1155
|
+
if (items.length === 0) return null;
|
|
1156
|
+
return /* @__PURE__ */ jsx("div", { style: { padding: "3rem 1.5rem", maxWidth: 520, margin: "0 auto" }, children: /* @__PURE__ */ jsx("div", { style: { background: theme.surface, border: `1px solid ${theme.fg}08`, padding: "clamp(1.5rem, 5vw, 2.5rem)" }, children: [
|
|
1157
|
+
c.heading && /* @__PURE__ */ jsx("h2", { style: {
|
|
1158
|
+
fontSize: "clamp(1.25rem, 4vw, 1.5rem)",
|
|
1159
|
+
fontWeight: 300,
|
|
1160
|
+
fontFamily: theme.fontDisplay || "inherit",
|
|
1161
|
+
margin: "0 0 0.25rem",
|
|
1162
|
+
lineHeight: 1.2,
|
|
1163
|
+
letterSpacing: "-0.02em",
|
|
1164
|
+
color: theme.fg,
|
|
1165
|
+
textAlign: "center"
|
|
1166
|
+
}, children: c.heading }),
|
|
1167
|
+
c.subtitle && /* @__PURE__ */ jsx("p", { style: {
|
|
1168
|
+
fontSize: "0.8rem",
|
|
1169
|
+
color: theme.accent,
|
|
1170
|
+
margin: "0 0 1.5rem",
|
|
1171
|
+
letterSpacing: "0.15em",
|
|
1172
|
+
textTransform: "uppercase",
|
|
1173
|
+
textAlign: "center"
|
|
1174
|
+
}, children: c.subtitle }),
|
|
1175
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "0.625rem" }, children: items.map((item, i) => /* @__PURE__ */ jsx("div", { style: {
|
|
1176
|
+
display: "flex",
|
|
1177
|
+
alignItems: "flex-start",
|
|
1178
|
+
gap: "0.75rem",
|
|
1179
|
+
padding: "0.5rem 0",
|
|
1180
|
+
borderBottom: i < items.length - 1 ? `1px solid ${theme.fg}08` : void 0
|
|
1181
|
+
}, children: [
|
|
1182
|
+
/* @__PURE__ */ jsx("span", { style: { color: theme.accent, fontSize: "1rem", lineHeight: 1, flexShrink: 0, marginTop: "0.1rem" }, children: "\u2713" }),
|
|
1183
|
+
/* @__PURE__ */ jsx("span", { style: { flex: 1, fontSize: "0.9rem", color: `${theme.fg}CC`, fontWeight: 300, lineHeight: 1.5 }, children: item.text }),
|
|
1184
|
+
item.value && /* @__PURE__ */ jsx("span", { style: {
|
|
1185
|
+
fontSize: "0.8rem",
|
|
1186
|
+
color: theme.muted,
|
|
1187
|
+
fontWeight: 400,
|
|
1188
|
+
textDecoration: "line-through",
|
|
1189
|
+
flexShrink: 0
|
|
1190
|
+
}, children: item.value })
|
|
1191
|
+
] }, i)) }),
|
|
1192
|
+
(c.total_value || c.offer_label) && /* @__PURE__ */ jsx("div", { style: {
|
|
1193
|
+
marginTop: "1.5rem",
|
|
1194
|
+
padding: "1rem",
|
|
1195
|
+
background: `${theme.accent}0A`,
|
|
1196
|
+
border: `1px dashed ${theme.accent}30`,
|
|
1197
|
+
textAlign: "center"
|
|
1198
|
+
}, children: [
|
|
1199
|
+
c.total_value && /* @__PURE__ */ jsx("div", { style: { fontSize: "0.75rem", color: theme.muted, marginBottom: "0.25rem", letterSpacing: "0.1em", textTransform: "uppercase" }, children: [
|
|
1200
|
+
"Total value: ",
|
|
1201
|
+
/* @__PURE__ */ jsx("span", { style: { textDecoration: "line-through" }, children: c.total_value })
|
|
1202
|
+
] }),
|
|
1203
|
+
/* @__PURE__ */ jsx("div", { style: {
|
|
1204
|
+
fontSize: "clamp(1.25rem, 4vw, 1.5rem)",
|
|
1205
|
+
fontWeight: 500,
|
|
1206
|
+
fontFamily: theme.fontDisplay || "inherit",
|
|
1207
|
+
color: theme.accent
|
|
1208
|
+
}, children: c.offer_label || "Free" })
|
|
1209
|
+
] })
|
|
1210
|
+
] }) });
|
|
1211
|
+
}
|
|
1212
|
+
function FAQSection({ section, theme }) {
|
|
1213
|
+
const c = section.content;
|
|
1214
|
+
const items = c.items || [];
|
|
1215
|
+
if (items.length === 0) return null;
|
|
1216
|
+
return /* @__PURE__ */ jsx("div", { style: { padding: "2.5rem 1.5rem", maxWidth: 580, margin: "0 auto" }, children: [
|
|
1217
|
+
c.heading && /* @__PURE__ */ jsx("h2", { style: {
|
|
1218
|
+
fontSize: 11,
|
|
1219
|
+
fontWeight: 500,
|
|
1220
|
+
textTransform: "uppercase",
|
|
1221
|
+
letterSpacing: "0.25em",
|
|
1222
|
+
color: `${theme.fg}40`,
|
|
1223
|
+
margin: "0 0 1.25rem",
|
|
1224
|
+
textAlign: "center"
|
|
1225
|
+
}, children: c.heading }),
|
|
1226
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: 0 }, children: items.map((item, i) => /* @__PURE__ */ jsx(FAQItem, { question: item.question, answer: item.answer, theme }, i)) })
|
|
1227
|
+
] });
|
|
1228
|
+
}
|
|
1229
|
+
function FAQItem({ question, answer, theme }) {
|
|
1230
|
+
const [open, setOpen] = useState(false);
|
|
1231
|
+
return /* @__PURE__ */ jsx("div", { style: { borderBottom: `1px solid ${theme.fg}0A` }, children: [
|
|
1232
|
+
/* @__PURE__ */ jsx(
|
|
1233
|
+
"button",
|
|
1234
|
+
{
|
|
1235
|
+
onClick: () => setOpen(!open),
|
|
1236
|
+
style: {
|
|
1237
|
+
width: "100%",
|
|
1238
|
+
display: "flex",
|
|
1239
|
+
justifyContent: "space-between",
|
|
1240
|
+
alignItems: "center",
|
|
1241
|
+
padding: "1rem 0",
|
|
1242
|
+
background: "none",
|
|
1243
|
+
border: "none",
|
|
1244
|
+
cursor: "pointer",
|
|
1245
|
+
color: theme.fg,
|
|
1246
|
+
fontFamily: "inherit",
|
|
1247
|
+
textAlign: "left"
|
|
1248
|
+
},
|
|
1249
|
+
children: [
|
|
1250
|
+
/* @__PURE__ */ jsx("span", { style: { fontSize: "0.9rem", fontWeight: 400, lineHeight: 1.4 }, children: question }),
|
|
1251
|
+
/* @__PURE__ */ jsx("span", { style: {
|
|
1252
|
+
fontSize: "1.25rem",
|
|
1253
|
+
fontWeight: 200,
|
|
1254
|
+
color: theme.muted,
|
|
1255
|
+
transition: "transform 0.2s",
|
|
1256
|
+
transform: open ? "rotate(45deg)" : "none",
|
|
1257
|
+
flexShrink: 0,
|
|
1258
|
+
marginLeft: "1rem"
|
|
1259
|
+
}, children: "+" })
|
|
1260
|
+
]
|
|
1261
|
+
}
|
|
1262
|
+
),
|
|
1263
|
+
/* @__PURE__ */ jsx("div", { style: {
|
|
1264
|
+
maxHeight: open ? "20rem" : 0,
|
|
1265
|
+
overflow: "hidden",
|
|
1266
|
+
transition: "max-height 0.3s ease"
|
|
1267
|
+
}, children: /* @__PURE__ */ jsx("p", { style: {
|
|
1268
|
+
fontSize: "0.85rem",
|
|
1269
|
+
color: `${theme.fg}88`,
|
|
1270
|
+
lineHeight: 1.7,
|
|
1271
|
+
fontWeight: 300,
|
|
1272
|
+
margin: 0,
|
|
1273
|
+
padding: "0 0 1rem"
|
|
1274
|
+
}, children: answer }) })
|
|
1275
|
+
] });
|
|
1276
|
+
}
|
|
1277
|
+
function TrustBadgesSection({ section, theme }) {
|
|
1278
|
+
const c = section.content;
|
|
1279
|
+
const badges = c.badges || [];
|
|
1280
|
+
if (badges.length === 0) return null;
|
|
1281
|
+
return /* @__PURE__ */ jsx("div", { style: {
|
|
1282
|
+
padding: "1.25rem 1.5rem",
|
|
1283
|
+
borderTop: `1px solid ${theme.fg}08`,
|
|
1284
|
+
borderBottom: `1px solid ${theme.fg}08`
|
|
1285
|
+
}, children: /* @__PURE__ */ jsx("div", { style: {
|
|
1286
|
+
display: "flex",
|
|
1287
|
+
justifyContent: "center",
|
|
1288
|
+
alignItems: "center",
|
|
1289
|
+
gap: "clamp(1rem, 4vw, 2.5rem)",
|
|
1290
|
+
flexWrap: "wrap"
|
|
1291
|
+
}, children: badges.map((badge, i) => /* @__PURE__ */ jsx("div", { style: {
|
|
1292
|
+
display: "flex",
|
|
1293
|
+
alignItems: "center",
|
|
1294
|
+
gap: "0.375rem"
|
|
1295
|
+
}, children: [
|
|
1296
|
+
badge.icon && /* @__PURE__ */ jsx("span", { style: { fontSize: "0.9rem" }, children: badge.icon }),
|
|
1297
|
+
/* @__PURE__ */ jsx("span", { style: {
|
|
1298
|
+
fontSize: "0.7rem",
|
|
1299
|
+
fontWeight: 500,
|
|
1300
|
+
textTransform: "uppercase",
|
|
1301
|
+
letterSpacing: "0.15em",
|
|
1302
|
+
color: theme.muted
|
|
1303
|
+
}, children: badge.label })
|
|
1304
|
+
] }, i)) }) });
|
|
1305
|
+
}
|
|
1306
|
+
function CountdownSection({ section, theme }) {
|
|
1307
|
+
const c = section.content;
|
|
1308
|
+
const endDate = c.end_date ? new Date(c.end_date) : null;
|
|
1309
|
+
const [remaining, setRemaining] = useState(null);
|
|
1310
|
+
const [expired, setExpired] = useState(false);
|
|
1311
|
+
useEffect(() => {
|
|
1312
|
+
if (!endDate) return;
|
|
1313
|
+
function tick() {
|
|
1314
|
+
const diff = endDate.getTime() - Date.now();
|
|
1315
|
+
if (diff <= 0) {
|
|
1316
|
+
setExpired(true);
|
|
1317
|
+
return;
|
|
1318
|
+
}
|
|
1319
|
+
setRemaining({
|
|
1320
|
+
d: Math.floor(diff / 864e5),
|
|
1321
|
+
h: Math.floor(diff % 864e5 / 36e5),
|
|
1322
|
+
m: Math.floor(diff % 36e5 / 6e4),
|
|
1323
|
+
s: Math.floor(diff % 6e4 / 1e3)
|
|
1324
|
+
});
|
|
1325
|
+
}
|
|
1326
|
+
tick();
|
|
1327
|
+
const id = setInterval(tick, 1e3);
|
|
1328
|
+
return () => clearInterval(id);
|
|
1329
|
+
}, [endDate?.getTime()]);
|
|
1330
|
+
if (!endDate) return null;
|
|
1331
|
+
if (expired) {
|
|
1332
|
+
return c.expired_text ? /* @__PURE__ */ jsx("div", { style: { padding: "1.5rem", textAlign: "center" }, children: /* @__PURE__ */ jsx("p", { style: { fontSize: "0.85rem", color: theme.muted, margin: 0 }, children: c.expired_text }) }) : null;
|
|
1333
|
+
}
|
|
1334
|
+
if (!remaining) return null;
|
|
1335
|
+
const units = [
|
|
1336
|
+
{ label: "Days", value: remaining.d },
|
|
1337
|
+
{ label: "Hours", value: remaining.h },
|
|
1338
|
+
{ label: "Min", value: remaining.m },
|
|
1339
|
+
{ label: "Sec", value: remaining.s }
|
|
1340
|
+
];
|
|
1341
|
+
return /* @__PURE__ */ jsx("div", { style: { padding: "2rem 1.5rem", maxWidth: 480, margin: "0 auto", textAlign: "center" }, children: [
|
|
1342
|
+
c.heading && /* @__PURE__ */ jsx("p", { style: {
|
|
1343
|
+
fontSize: "0.8rem",
|
|
1344
|
+
color: theme.accent,
|
|
1345
|
+
margin: "0 0 1rem",
|
|
1346
|
+
letterSpacing: "0.15em",
|
|
1347
|
+
textTransform: "uppercase"
|
|
1348
|
+
}, children: c.heading }),
|
|
1349
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", justifyContent: "center", gap: "0.5rem" }, children: units.map((u) => /* @__PURE__ */ jsx("div", { style: {
|
|
1350
|
+
minWidth: "clamp(3.5rem, 12vw, 4.5rem)",
|
|
1351
|
+
padding: "0.75rem 0.25rem",
|
|
1352
|
+
background: theme.surface,
|
|
1353
|
+
border: `1px solid ${theme.fg}08`
|
|
1354
|
+
}, children: [
|
|
1355
|
+
/* @__PURE__ */ jsx("div", { style: {
|
|
1356
|
+
fontFamily: theme.fontDisplay || "inherit",
|
|
1357
|
+
fontSize: "clamp(1.5rem, 5vw, 2rem)",
|
|
1358
|
+
fontWeight: 300,
|
|
1359
|
+
lineHeight: 1,
|
|
1360
|
+
color: theme.fg,
|
|
1361
|
+
fontVariantNumeric: "tabular-nums"
|
|
1362
|
+
}, children: String(u.value).padStart(2, "0") }),
|
|
1363
|
+
/* @__PURE__ */ jsx("div", { style: {
|
|
1364
|
+
fontSize: "0.6rem",
|
|
1365
|
+
fontWeight: 500,
|
|
1366
|
+
textTransform: "uppercase",
|
|
1367
|
+
letterSpacing: "0.2em",
|
|
1368
|
+
color: theme.muted,
|
|
1369
|
+
marginTop: "0.375rem"
|
|
1370
|
+
}, children: u.label })
|
|
1371
|
+
] }, u.label)) })
|
|
1372
|
+
] });
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1044
1375
|
// src/react/components/section-renderer.tsx
|
|
1045
1376
|
function SectionRenderer({
|
|
1046
1377
|
section,
|
|
@@ -1076,6 +1407,16 @@ var WhaleStorefront = (function (exports) {
|
|
|
1076
1407
|
return /* @__PURE__ */ jsx(SocialLinksSection, { section, theme });
|
|
1077
1408
|
case "lead_capture":
|
|
1078
1409
|
return /* @__PURE__ */ jsx(LeadCaptureSection, { section, data, theme, onEvent });
|
|
1410
|
+
case "testimonials":
|
|
1411
|
+
return /* @__PURE__ */ jsx(TestimonialsSection, { section, theme });
|
|
1412
|
+
case "value_stack":
|
|
1413
|
+
return /* @__PURE__ */ jsx(ValueStackSection, { section, theme });
|
|
1414
|
+
case "faq":
|
|
1415
|
+
return /* @__PURE__ */ jsx(FAQSection, { section, theme });
|
|
1416
|
+
case "trust_badges":
|
|
1417
|
+
return /* @__PURE__ */ jsx(TrustBadgesSection, { section, theme });
|
|
1418
|
+
case "countdown":
|
|
1419
|
+
return /* @__PURE__ */ jsx(CountdownSection, { section, theme });
|
|
1079
1420
|
case "divider":
|
|
1080
1421
|
return /* @__PURE__ */ jsx(DividerSection, { theme });
|
|
1081
1422
|
default:
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { F as WhaleStorefrontConfig, W as WhaleClient, r as Product } from '../client-D7_7p7ja.cjs';
|
|
2
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Security headers for Next.js storefronts.
|
|
6
|
+
*/
|
|
7
|
+
declare const securityHeaders: {
|
|
8
|
+
key: string;
|
|
9
|
+
value: string;
|
|
10
|
+
}[];
|
|
11
|
+
/**
|
|
12
|
+
* Returns a Next.js `headers()` config with security headers applied to all routes.
|
|
13
|
+
* Use in next.config.ts:
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { withSecurityHeaders } from '@neowhale/storefront/next'
|
|
17
|
+
* export default { headers: withSecurityHeaders() }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
declare function withSecurityHeaders(extra?: {
|
|
21
|
+
key: string;
|
|
22
|
+
value: string;
|
|
23
|
+
}[]): () => Promise<{
|
|
24
|
+
source: string;
|
|
25
|
+
headers: {
|
|
26
|
+
key: string;
|
|
27
|
+
value: string;
|
|
28
|
+
}[];
|
|
29
|
+
}[]>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Gateway rewrite rule for Next.js.
|
|
33
|
+
* Proxies client-side /api/gw/* requests to whale-gateway to avoid CORS.
|
|
34
|
+
*
|
|
35
|
+
* Usage in next.config.ts:
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { whaleGatewayRewrite } from '@neowhale/storefront/next'
|
|
38
|
+
* export default {
|
|
39
|
+
* async rewrites() {
|
|
40
|
+
* return [whaleGatewayRewrite()]
|
|
41
|
+
* }
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
declare function whaleGatewayRewrite(gatewayUrl?: string, proxyPath?: string): {
|
|
46
|
+
source: string;
|
|
47
|
+
destination: string;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Creates a server-side WhaleClient.
|
|
52
|
+
* Reads from env vars by default — override with explicit config.
|
|
53
|
+
*/
|
|
54
|
+
declare function createServerClient(config?: Partial<WhaleStorefrontConfig>): WhaleClient;
|
|
55
|
+
/**
|
|
56
|
+
* Server-side: fetch all published products with ISR caching.
|
|
57
|
+
* Drop-in replacement for Flora's `getAllProducts()`.
|
|
58
|
+
*/
|
|
59
|
+
declare function getAllProducts(options?: {
|
|
60
|
+
/** Revalidate interval in seconds. Defaults to 60. */
|
|
61
|
+
revalidate?: number;
|
|
62
|
+
/** Filter function to exclude products (e.g. hidden categories, out of stock) */
|
|
63
|
+
filter?: (product: Product) => boolean;
|
|
64
|
+
/** Override client config */
|
|
65
|
+
client?: WhaleClient;
|
|
66
|
+
}): Promise<Product[]>;
|
|
67
|
+
|
|
68
|
+
interface ImageLoaderParams {
|
|
69
|
+
src: string;
|
|
70
|
+
width: number;
|
|
71
|
+
quality?: number;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Creates a Next.js custom image loader that proxies Supabase images through gateway.
|
|
75
|
+
*
|
|
76
|
+
* Usage in a loader file (e.g. src/lib/image-loader.ts):
|
|
77
|
+
* ```ts
|
|
78
|
+
* import { createImageLoader } from '@neowhale/storefront/next'
|
|
79
|
+
* export default createImageLoader({
|
|
80
|
+
* storeId: process.env.NEXT_PUBLIC_STORE_ID!,
|
|
81
|
+
* gatewayUrl: 'https://whale-gateway.fly.dev',
|
|
82
|
+
* supabaseHost: 'your-project.supabase.co',
|
|
83
|
+
* signingSecret: process.env.NEXT_PUBLIC_MEDIA_SIGNING_SECRET!,
|
|
84
|
+
* })
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
declare function createImageLoader(config: {
|
|
88
|
+
storeId: string;
|
|
89
|
+
gatewayUrl: string;
|
|
90
|
+
supabaseHost: string;
|
|
91
|
+
signingSecret: string;
|
|
92
|
+
}): (params: ImageLoaderParams) => string;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Creates a Next.js middleware that protects routes requiring authentication.
|
|
96
|
+
*
|
|
97
|
+
* Checks for a session token cookie or localStorage indicator.
|
|
98
|
+
* Since middleware runs on the edge and can't access localStorage,
|
|
99
|
+
* this checks for a cookie-based token instead.
|
|
100
|
+
*
|
|
101
|
+
* Usage in middleware.ts:
|
|
102
|
+
* ```ts
|
|
103
|
+
* import { createAuthMiddleware } from '@neowhale/storefront/next'
|
|
104
|
+
* export const middleware = createAuthMiddleware({
|
|
105
|
+
* protectedPaths: ['/account'],
|
|
106
|
+
* loginPath: '/account',
|
|
107
|
+
* })
|
|
108
|
+
* export const config = { matcher: ['/account/:path*'] }
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
declare function createAuthMiddleware(options: {
|
|
112
|
+
protectedPaths: string[];
|
|
113
|
+
loginPath: string;
|
|
114
|
+
cookieName?: string;
|
|
115
|
+
}): (request: NextRequest) => NextResponse<unknown>;
|
|
116
|
+
|
|
117
|
+
export { createAuthMiddleware, createImageLoader, createServerClient, getAllProducts, securityHeaders, whaleGatewayRewrite, withSecurityHeaders };
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { F as WhaleStorefrontConfig, W as WhaleClient, r as Product } from '../client-D7_7p7ja.js';
|
|
2
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Security headers for Next.js storefronts.
|
|
6
|
+
*/
|
|
7
|
+
declare const securityHeaders: {
|
|
8
|
+
key: string;
|
|
9
|
+
value: string;
|
|
10
|
+
}[];
|
|
11
|
+
/**
|
|
12
|
+
* Returns a Next.js `headers()` config with security headers applied to all routes.
|
|
13
|
+
* Use in next.config.ts:
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { withSecurityHeaders } from '@neowhale/storefront/next'
|
|
17
|
+
* export default { headers: withSecurityHeaders() }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
declare function withSecurityHeaders(extra?: {
|
|
21
|
+
key: string;
|
|
22
|
+
value: string;
|
|
23
|
+
}[]): () => Promise<{
|
|
24
|
+
source: string;
|
|
25
|
+
headers: {
|
|
26
|
+
key: string;
|
|
27
|
+
value: string;
|
|
28
|
+
}[];
|
|
29
|
+
}[]>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Gateway rewrite rule for Next.js.
|
|
33
|
+
* Proxies client-side /api/gw/* requests to whale-gateway to avoid CORS.
|
|
34
|
+
*
|
|
35
|
+
* Usage in next.config.ts:
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { whaleGatewayRewrite } from '@neowhale/storefront/next'
|
|
38
|
+
* export default {
|
|
39
|
+
* async rewrites() {
|
|
40
|
+
* return [whaleGatewayRewrite()]
|
|
41
|
+
* }
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
declare function whaleGatewayRewrite(gatewayUrl?: string, proxyPath?: string): {
|
|
46
|
+
source: string;
|
|
47
|
+
destination: string;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Creates a server-side WhaleClient.
|
|
52
|
+
* Reads from env vars by default — override with explicit config.
|
|
53
|
+
*/
|
|
54
|
+
declare function createServerClient(config?: Partial<WhaleStorefrontConfig>): WhaleClient;
|
|
55
|
+
/**
|
|
56
|
+
* Server-side: fetch all published products with ISR caching.
|
|
57
|
+
* Drop-in replacement for Flora's `getAllProducts()`.
|
|
58
|
+
*/
|
|
59
|
+
declare function getAllProducts(options?: {
|
|
60
|
+
/** Revalidate interval in seconds. Defaults to 60. */
|
|
61
|
+
revalidate?: number;
|
|
62
|
+
/** Filter function to exclude products (e.g. hidden categories, out of stock) */
|
|
63
|
+
filter?: (product: Product) => boolean;
|
|
64
|
+
/** Override client config */
|
|
65
|
+
client?: WhaleClient;
|
|
66
|
+
}): Promise<Product[]>;
|
|
67
|
+
|
|
68
|
+
interface ImageLoaderParams {
|
|
69
|
+
src: string;
|
|
70
|
+
width: number;
|
|
71
|
+
quality?: number;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Creates a Next.js custom image loader that proxies Supabase images through gateway.
|
|
75
|
+
*
|
|
76
|
+
* Usage in a loader file (e.g. src/lib/image-loader.ts):
|
|
77
|
+
* ```ts
|
|
78
|
+
* import { createImageLoader } from '@neowhale/storefront/next'
|
|
79
|
+
* export default createImageLoader({
|
|
80
|
+
* storeId: process.env.NEXT_PUBLIC_STORE_ID!,
|
|
81
|
+
* gatewayUrl: 'https://whale-gateway.fly.dev',
|
|
82
|
+
* supabaseHost: 'your-project.supabase.co',
|
|
83
|
+
* signingSecret: process.env.NEXT_PUBLIC_MEDIA_SIGNING_SECRET!,
|
|
84
|
+
* })
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
declare function createImageLoader(config: {
|
|
88
|
+
storeId: string;
|
|
89
|
+
gatewayUrl: string;
|
|
90
|
+
supabaseHost: string;
|
|
91
|
+
signingSecret: string;
|
|
92
|
+
}): (params: ImageLoaderParams) => string;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Creates a Next.js middleware that protects routes requiring authentication.
|
|
96
|
+
*
|
|
97
|
+
* Checks for a session token cookie or localStorage indicator.
|
|
98
|
+
* Since middleware runs on the edge and can't access localStorage,
|
|
99
|
+
* this checks for a cookie-based token instead.
|
|
100
|
+
*
|
|
101
|
+
* Usage in middleware.ts:
|
|
102
|
+
* ```ts
|
|
103
|
+
* import { createAuthMiddleware } from '@neowhale/storefront/next'
|
|
104
|
+
* export const middleware = createAuthMiddleware({
|
|
105
|
+
* protectedPaths: ['/account'],
|
|
106
|
+
* loginPath: '/account',
|
|
107
|
+
* })
|
|
108
|
+
* export const config = { matcher: ['/account/:path*'] }
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
declare function createAuthMiddleware(options: {
|
|
112
|
+
protectedPaths: string[];
|
|
113
|
+
loginPath: string;
|
|
114
|
+
cookieName?: string;
|
|
115
|
+
}): (request: NextRequest) => NextResponse<unknown>;
|
|
116
|
+
|
|
117
|
+
export { createAuthMiddleware, createImageLoader, createServerClient, getAllProducts, securityHeaders, whaleGatewayRewrite, withSecurityHeaders };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { p as PixelConfig } from './client-D7_7p7ja.cjs';
|
|
2
|
+
|
|
3
|
+
declare class PixelManager {
|
|
4
|
+
private providers;
|
|
5
|
+
constructor(configs: PixelConfig[]);
|
|
6
|
+
initialize(): Promise<void>;
|
|
7
|
+
track(event: string, params?: Record<string, unknown>): void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export { PixelManager as P };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { p as PixelConfig } from './client-D7_7p7ja.js';
|
|
2
|
+
|
|
3
|
+
declare class PixelManager {
|
|
4
|
+
private providers;
|
|
5
|
+
constructor(configs: PixelConfig[]);
|
|
6
|
+
initialize(): Promise<void>;
|
|
7
|
+
track(event: string, params?: Record<string, unknown>): void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export { PixelManager as P };
|