@mission-studio/puck 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,2282 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ Button: () => Button,
34
+ Card: () => Card,
35
+ Columns: () => Columns,
36
+ Container: () => Container,
37
+ CustomImage: () => CustomImage,
38
+ DEFAULT_THEME: () => DEFAULT_THEME,
39
+ Divider: () => Divider,
40
+ FeatureGrid: () => FeatureGrid,
41
+ FeaturesList: () => FeaturesList,
42
+ Footer: () => Footer,
43
+ Heading: () => Heading,
44
+ Icon: () => Icon,
45
+ Image: () => Image,
46
+ ImageCarousel: () => ImageCarousel,
47
+ Paragraph: () => Paragraph,
48
+ Popup: () => Popup,
49
+ Section: () => Section,
50
+ Spacer: () => Spacer,
51
+ TextBlock: () => TextBlock,
52
+ ThemeProvider: () => ThemeProvider,
53
+ Topbar: () => Topbar,
54
+ VideoEmbed: () => VideoEmbed,
55
+ allColorPresets: () => allColorPresets,
56
+ availableIcons: () => availableIcons,
57
+ borderRadiusScale: () => borderRadiusScale,
58
+ fontFamilies: () => fontFamilies,
59
+ fontSizes: () => fontSizes,
60
+ fontWeights: () => fontWeights,
61
+ getBorderRadiusCSS: () => getBorderRadiusCSS,
62
+ getClosestBorderRadiusValue: () => getClosestBorderRadiusValue,
63
+ getClosestSpacingValue: () => getClosestSpacingValue,
64
+ getFontSizeCSS: () => getFontSizeCSS,
65
+ getShadowCSS: () => getShadowCSS,
66
+ neutralColors: () => neutralColors,
67
+ shadowPresets: () => shadowPresets,
68
+ spacingScale: () => spacingScale,
69
+ useTheme: () => useTheme
70
+ });
71
+ module.exports = __toCommonJS(index_exports);
72
+
73
+ // entries/context.tsx
74
+ var import_react = require("react");
75
+ var import_jsx_runtime = require("react/jsx-runtime");
76
+ var EntriesContext = (0, import_react.createContext)(null);
77
+ function useEntries() {
78
+ const context = (0, import_react.useContext)(EntriesContext);
79
+ if (!context) {
80
+ return {
81
+ entries: [],
82
+ entryNames: [],
83
+ getEntry: () => void 0,
84
+ getEntryValue: () => void 0
85
+ };
86
+ }
87
+ return context;
88
+ }
89
+
90
+ // theme/context.tsx
91
+ var import_react2 = require("react");
92
+
93
+ // theme/defaults.ts
94
+ var DEFAULT_THEME = {
95
+ id: "default",
96
+ name: "Default Theme",
97
+ colors: {
98
+ primary: { color: "#3B82F6", opacity: 100 },
99
+ secondary: { color: "#8B5CF6", opacity: 100 },
100
+ accent: { color: "#10B981", opacity: 100 },
101
+ background: { color: "#FFFFFF", opacity: 100 },
102
+ foreground: { color: "#111827", opacity: 100 },
103
+ muted: { color: "#F3F4F6", opacity: 100 }
104
+ },
105
+ typography: {
106
+ fontFamily: {
107
+ heading: "system-ui, sans-serif",
108
+ body: "system-ui, sans-serif"
109
+ },
110
+ fontSize: {
111
+ base: "base",
112
+ heading: "4xl"
113
+ },
114
+ fontWeight: {
115
+ normal: 400,
116
+ heading: 700
117
+ }
118
+ },
119
+ spacing: {
120
+ xs: 8,
121
+ sm: 12,
122
+ md: 16,
123
+ lg: 24,
124
+ xl: 32
125
+ },
126
+ borders: {
127
+ radiusSmall: 4,
128
+ radiusMedium: 8,
129
+ radiusLarge: 16
130
+ },
131
+ shadows: {
132
+ small: "sm",
133
+ medium: "md",
134
+ large: "lg"
135
+ }
136
+ };
137
+
138
+ // theme/context.tsx
139
+ var import_jsx_runtime2 = require("react/jsx-runtime");
140
+ var ThemeContext = (0, import_react2.createContext)(null);
141
+ function ThemeProvider({
142
+ theme,
143
+ children
144
+ }) {
145
+ const activeTheme = theme ?? DEFAULT_THEME;
146
+ const contextValue = {
147
+ theme: activeTheme,
148
+ resolveColor: (key) => activeTheme.colors[key],
149
+ resolveSpacing: (key) => activeTheme.spacing[key],
150
+ resolveBorderRadius: (key) => activeTheme.borders[key],
151
+ resolveShadow: (key) => activeTheme.shadows[key]
152
+ };
153
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ThemeContext.Provider, { value: contextValue, children });
154
+ }
155
+ function useTheme() {
156
+ const context = (0, import_react2.useContext)(ThemeContext);
157
+ if (!context) {
158
+ return {
159
+ theme: DEFAULT_THEME,
160
+ resolveColor: (key) => DEFAULT_THEME.colors[key],
161
+ resolveSpacing: (key) => DEFAULT_THEME.spacing[key],
162
+ resolveBorderRadius: (key) => DEFAULT_THEME.borders[key],
163
+ resolveShadow: (key) => DEFAULT_THEME.shadows[key]
164
+ };
165
+ }
166
+ return context;
167
+ }
168
+
169
+ // utils/index.ts
170
+ var import_tailwind_merge = require("tailwind-merge");
171
+ var import_clsx = require("clsx");
172
+ function hexToRgba(hex, opacity) {
173
+ const sanitized = hex.replace("#", "");
174
+ const r = parseInt(sanitized.slice(0, 2), 16);
175
+ const g = parseInt(sanitized.slice(2, 4), 16);
176
+ const b = parseInt(sanitized.slice(4, 6), 16);
177
+ return `rgba(${r}, ${g}, ${b}, ${opacity / 100})`;
178
+ }
179
+ function cn(...inputs) {
180
+ return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
181
+ }
182
+
183
+ // components/page/Heading.tsx
184
+ var import_jsx_runtime3 = require("react/jsx-runtime");
185
+ var sizeMap = {
186
+ xs: "0.875rem",
187
+ sm: "1rem",
188
+ md: "1.25rem",
189
+ lg: "1.5rem",
190
+ xl: "2rem",
191
+ "2xl": "2.5rem",
192
+ "3xl": "3rem",
193
+ "4xl": "4rem"
194
+ };
195
+ var weightMap = {
196
+ normal: 400,
197
+ medium: 500,
198
+ semibold: 600,
199
+ bold: 700,
200
+ extrabold: 800
201
+ };
202
+ var letterSpacingMap = {
203
+ tight: "-0.025em",
204
+ normal: "0",
205
+ wide: "0.05em"
206
+ };
207
+ var lineHeightMap = {
208
+ tight: "1.1",
209
+ normal: "1.4",
210
+ relaxed: "1.6"
211
+ };
212
+ function isThemeableValue(value) {
213
+ return typeof value === "object" && value !== null && "useTheme" in value;
214
+ }
215
+ function isEntryBoundValue(value) {
216
+ return typeof value === "object" && value !== null && "useEntry" in value;
217
+ }
218
+ function Heading({
219
+ text,
220
+ level = "h2",
221
+ size = "2xl",
222
+ weight = "bold",
223
+ color,
224
+ align = "left",
225
+ letterSpacing = "normal",
226
+ lineHeight = "tight",
227
+ id
228
+ }) {
229
+ const { resolveColor: resolveColor2 } = useTheme();
230
+ const { getEntryValue } = useEntries();
231
+ const resolvedText = (() => {
232
+ if (!text) return "";
233
+ if (typeof text === "string") return text;
234
+ if (isEntryBoundValue(text)) {
235
+ if (text.useEntry) {
236
+ return String(getEntryValue(text.entryName, text.fieldKey) ?? "");
237
+ }
238
+ return text.value;
239
+ }
240
+ return "";
241
+ })();
242
+ const resolvedColor = (() => {
243
+ if (!color) return resolveColor2("foreground");
244
+ if (typeof color === "string") return { color, opacity: 100 };
245
+ if (isThemeableValue(color)) {
246
+ return color.useTheme ? resolveColor2(color.themeKey) : color.value;
247
+ }
248
+ if ("color" in color) return color;
249
+ return resolveColor2("foreground");
250
+ })();
251
+ const Tag = level;
252
+ const style = {
253
+ fontSize: sizeMap[size],
254
+ fontWeight: weightMap[weight],
255
+ color: hexToRgba(resolvedColor.color, resolvedColor.opacity),
256
+ textAlign: align,
257
+ letterSpacing: letterSpacingMap[letterSpacing],
258
+ lineHeight: lineHeightMap[lineHeight],
259
+ margin: 0
260
+ };
261
+ if (!resolvedText) return null;
262
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Tag, { id, style, children: resolvedText });
263
+ }
264
+
265
+ // components/page/Paragraph.tsx
266
+ var import_jsx_runtime4 = require("react/jsx-runtime");
267
+ var sizeMap2 = {
268
+ sm: "0.875rem",
269
+ base: "1rem",
270
+ lg: "1.125rem",
271
+ xl: "1.25rem"
272
+ };
273
+ var weightMap2 = {
274
+ normal: 400,
275
+ medium: 500,
276
+ semibold: 600
277
+ };
278
+ var lineHeightMap2 = {
279
+ tight: "1.4",
280
+ normal: "1.6",
281
+ relaxed: "1.75",
282
+ loose: "2"
283
+ };
284
+ function isThemeableValue2(value) {
285
+ return typeof value === "object" && value !== null && "useTheme" in value;
286
+ }
287
+ function isEntryBoundValue2(value) {
288
+ return typeof value === "object" && value !== null && "useEntry" in value;
289
+ }
290
+ function Paragraph({
291
+ text,
292
+ size = "base",
293
+ weight = "normal",
294
+ color,
295
+ align = "left",
296
+ lineHeight = "normal",
297
+ maxWidth,
298
+ id
299
+ }) {
300
+ const { resolveColor: resolveColor2 } = useTheme();
301
+ const { getEntryValue } = useEntries();
302
+ const resolvedText = (() => {
303
+ if (!text) return "";
304
+ if (typeof text === "string") return text;
305
+ if (isEntryBoundValue2(text)) {
306
+ if (text.useEntry) {
307
+ return String(getEntryValue(text.entryName, text.fieldKey) ?? "");
308
+ }
309
+ return text.value;
310
+ }
311
+ return "";
312
+ })();
313
+ const resolvedColor = (() => {
314
+ if (!color) return resolveColor2("foreground");
315
+ if (typeof color === "string") return { color, opacity: 100 };
316
+ if (isThemeableValue2(color)) {
317
+ return color.useTheme ? resolveColor2(color.themeKey) : color.value;
318
+ }
319
+ if ("color" in color) return color;
320
+ return resolveColor2("foreground");
321
+ })();
322
+ const style = {
323
+ fontSize: sizeMap2[size],
324
+ fontWeight: weightMap2[weight],
325
+ color: hexToRgba(resolvedColor.color, resolvedColor.opacity),
326
+ textAlign: align,
327
+ lineHeight: lineHeightMap2[lineHeight],
328
+ maxWidth: maxWidth || void 0,
329
+ margin: 0
330
+ };
331
+ if (!resolvedText) return null;
332
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { id, style, children: resolvedText });
333
+ }
334
+
335
+ // hooks/useGtmEvent.ts
336
+ function useGtmEvent() {
337
+ return (eventName, data) => {
338
+ if (typeof window === "undefined") return;
339
+ if (typeof window.gtag !== "function") {
340
+ console.warn("GTM not initialized. Make sure @next/third-parties/google GoogleTagManager is added to your layout.");
341
+ return;
342
+ }
343
+ const eventData = {
344
+ event: eventName,
345
+ ...data && { value: data }
346
+ };
347
+ window.gtag("event", eventName, data || {});
348
+ };
349
+ }
350
+
351
+ // hooks/useUtmParams.ts
352
+ var import_react3 = require("react");
353
+ function useUtmParams() {
354
+ const [utmParams, setUtmParams] = (0, import_react3.useState)({});
355
+ (0, import_react3.useEffect)(() => {
356
+ if (typeof window === "undefined") return;
357
+ const urlParams = new URLSearchParams(window.location.search);
358
+ const source = urlParams.get("utm_source");
359
+ const medium = urlParams.get("utm_medium");
360
+ const campaign = urlParams.get("utm_campaign");
361
+ const content = urlParams.get("utm_content");
362
+ const term = urlParams.get("utm_term");
363
+ const params = {};
364
+ if (source) {
365
+ params.source = source;
366
+ sessionStorage.setItem("utm_source", source);
367
+ } else {
368
+ const stored = sessionStorage.getItem("utm_source");
369
+ if (stored) params.source = stored;
370
+ }
371
+ if (medium) {
372
+ params.medium = medium;
373
+ sessionStorage.setItem("utm_medium", medium);
374
+ } else {
375
+ const stored = sessionStorage.getItem("utm_medium");
376
+ if (stored) params.medium = stored;
377
+ }
378
+ if (campaign) {
379
+ params.campaign = campaign;
380
+ sessionStorage.setItem("utm_campaign", campaign);
381
+ } else {
382
+ const stored = sessionStorage.getItem("utm_campaign");
383
+ if (stored) params.campaign = stored;
384
+ }
385
+ if (content) {
386
+ params.content = content;
387
+ sessionStorage.setItem("utm_content", content);
388
+ } else {
389
+ const stored = sessionStorage.getItem("utm_content");
390
+ if (stored) params.content = stored;
391
+ }
392
+ if (term) {
393
+ params.term = term;
394
+ sessionStorage.setItem("utm_term", term);
395
+ } else {
396
+ const stored = sessionStorage.getItem("utm_term");
397
+ if (stored) params.term = stored;
398
+ }
399
+ setUtmParams(params);
400
+ }, []);
401
+ return utmParams;
402
+ }
403
+
404
+ // components/page/Button.tsx
405
+ var import_jsx_runtime5 = require("react/jsx-runtime");
406
+ var sizeStyles = {
407
+ sm: { padding: "8px 16px", fontSize: "0.875rem" },
408
+ md: { padding: "12px 24px", fontSize: "1rem" },
409
+ lg: { padding: "16px 32px", fontSize: "1.125rem" },
410
+ xl: { padding: "20px 40px", fontSize: "1.25rem" }
411
+ };
412
+ var radiusMap = {
413
+ none: "0",
414
+ sm: "4px",
415
+ md: "8px",
416
+ lg: "16px",
417
+ full: "9999px"
418
+ };
419
+ function isThemeableValue3(value) {
420
+ return typeof value === "object" && value !== null && "useTheme" in value;
421
+ }
422
+ function isEntryBoundValue3(value) {
423
+ return typeof value === "object" && value !== null && "useEntry" in value;
424
+ }
425
+ function Button({
426
+ text,
427
+ href,
428
+ target = "_self",
429
+ variant = "solid",
430
+ size = "md",
431
+ color,
432
+ textColor,
433
+ borderRadius = "md",
434
+ fullWidth = false,
435
+ align = "center",
436
+ id
437
+ }) {
438
+ const { resolveColor: resolveColor2 } = useTheme();
439
+ const { getEntryValue } = useEntries();
440
+ const sendEvent = useGtmEvent();
441
+ const utm = useUtmParams();
442
+ const resolvedText = (() => {
443
+ if (!text) return "Button";
444
+ if (typeof text === "string") return text;
445
+ if (isEntryBoundValue3(text)) {
446
+ if (text.useEntry) {
447
+ return String(getEntryValue(text.entryName, text.fieldKey) ?? "Button");
448
+ }
449
+ return text.value;
450
+ }
451
+ return "Button";
452
+ })();
453
+ const handleClick = () => {
454
+ sendEvent("button_click", {
455
+ text: resolvedText,
456
+ href: href || void 0,
457
+ variant,
458
+ ...utm
459
+ });
460
+ };
461
+ const resolvedColor = (() => {
462
+ if (!color) return resolveColor2("primary");
463
+ if (typeof color === "string") return { color, opacity: 100 };
464
+ if (isThemeableValue3(color)) {
465
+ return color.useTheme ? resolveColor2(color.themeKey) : color.value;
466
+ }
467
+ if ("color" in color) return color;
468
+ return resolveColor2("primary");
469
+ })();
470
+ const resolvedTextColor = (() => {
471
+ if (!textColor) {
472
+ if (variant === "solid") return { color: "#FFFFFF", opacity: 100 };
473
+ return resolvedColor;
474
+ }
475
+ if (typeof textColor === "string")
476
+ return { color: textColor, opacity: 100 };
477
+ if (isThemeableValue3(textColor)) {
478
+ return textColor.useTheme ? resolveColor2(textColor.themeKey) : textColor.value;
479
+ }
480
+ if ("color" in textColor) return textColor;
481
+ return { color: "#FFFFFF", opacity: 100 };
482
+ })();
483
+ const bgColor = hexToRgba(resolvedColor.color, resolvedColor.opacity);
484
+ const fgColor = hexToRgba(resolvedTextColor.color, resolvedTextColor.opacity);
485
+ const baseStyle = {
486
+ ...sizeStyles[size],
487
+ borderRadius: radiusMap[borderRadius],
488
+ fontWeight: 600,
489
+ cursor: "pointer",
490
+ display: "inline-flex",
491
+ alignItems: "center",
492
+ justifyContent: "center",
493
+ textDecoration: "none",
494
+ transition: "opacity 0.2s, transform 0.2s",
495
+ width: fullWidth ? "100%" : "auto",
496
+ border: "none"
497
+ };
498
+ const variantStyles = {
499
+ solid: {
500
+ backgroundColor: bgColor,
501
+ color: fgColor
502
+ },
503
+ outline: {
504
+ backgroundColor: "transparent",
505
+ color: bgColor,
506
+ border: `2px solid ${bgColor}`
507
+ },
508
+ ghost: {
509
+ backgroundColor: "transparent",
510
+ color: bgColor
511
+ },
512
+ link: {
513
+ backgroundColor: "transparent",
514
+ color: bgColor,
515
+ padding: "0",
516
+ textDecoration: "underline"
517
+ }
518
+ };
519
+ const style = { ...baseStyle, ...variantStyles[variant] };
520
+ const wrapperStyle = {
521
+ display: "flex",
522
+ justifyContent: align === "left" ? "flex-start" : align === "right" ? "flex-end" : "center"
523
+ };
524
+ const content = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style, children: resolvedText });
525
+ if (href) {
526
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: wrapperStyle, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
527
+ "a",
528
+ {
529
+ id,
530
+ href,
531
+ target,
532
+ style,
533
+ rel: target === "_blank" ? "noopener noreferrer" : void 0,
534
+ onClick: handleClick,
535
+ children: resolvedText
536
+ }
537
+ ) });
538
+ }
539
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: wrapperStyle, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { id, type: "button", style, onClick: handleClick, children: resolvedText }) });
540
+ }
541
+
542
+ // components/page/Image.tsx
543
+ var import_jsx_runtime6 = require("react/jsx-runtime");
544
+ var widthMap = {
545
+ auto: "auto",
546
+ full: "100%",
547
+ sm: "300px",
548
+ md: "500px",
549
+ lg: "700px",
550
+ xl: "900px"
551
+ };
552
+ var aspectRatioMap = {
553
+ auto: void 0,
554
+ "1:1": "1 / 1",
555
+ "4:3": "4 / 3",
556
+ "16:9": "16 / 9",
557
+ "21:9": "21 / 9"
558
+ };
559
+ var radiusMap2 = {
560
+ none: "0",
561
+ sm: "4px",
562
+ md: "8px",
563
+ lg: "16px",
564
+ xl: "24px",
565
+ full: "9999px"
566
+ };
567
+ var shadowMap = {
568
+ none: "none",
569
+ sm: "0 1px 2px rgba(0,0,0,0.05)",
570
+ md: "0 4px 6px rgba(0,0,0,0.1)",
571
+ lg: "0 10px 15px rgba(0,0,0,0.1)",
572
+ xl: "0 20px 25px rgba(0,0,0,0.15)"
573
+ };
574
+ function isThemeableValue4(value) {
575
+ return typeof value === "object" && value !== null && "useTheme" in value;
576
+ }
577
+ function isEntryBoundValue4(value) {
578
+ return typeof value === "object" && value !== null && "useEntry" in value;
579
+ }
580
+ function Image({
581
+ src,
582
+ alt = "",
583
+ width = "full",
584
+ aspectRatio = "auto",
585
+ objectFit = "cover",
586
+ borderRadius = "none",
587
+ shadow = "none",
588
+ align = "center",
589
+ caption,
590
+ captionColor,
591
+ id
592
+ }) {
593
+ const { resolveColor: resolveColor2 } = useTheme();
594
+ const { getEntryValue } = useEntries();
595
+ const resolvedSrc = (() => {
596
+ if (!src) return "";
597
+ if (typeof src === "string") return src;
598
+ if (isEntryBoundValue4(src)) {
599
+ if (src.useEntry) {
600
+ return String(getEntryValue(src.entryName, src.fieldKey) ?? "");
601
+ }
602
+ return src.value;
603
+ }
604
+ return "";
605
+ })();
606
+ const resolvedCaption = (() => {
607
+ if (!caption) return "";
608
+ if (typeof caption === "string") return caption;
609
+ if (isEntryBoundValue4(caption)) {
610
+ if (caption.useEntry) {
611
+ return String(getEntryValue(caption.entryName, caption.fieldKey) ?? "");
612
+ }
613
+ return caption.value;
614
+ }
615
+ return "";
616
+ })();
617
+ const resolvedCaptionColor = (() => {
618
+ if (!captionColor) return resolveColor2("muted");
619
+ if (typeof captionColor === "string")
620
+ return { color: captionColor, opacity: 100 };
621
+ if (isThemeableValue4(captionColor)) {
622
+ return captionColor.useTheme ? resolveColor2(captionColor.themeKey) : captionColor.value;
623
+ }
624
+ if ("color" in captionColor) return captionColor;
625
+ return resolveColor2("muted");
626
+ })();
627
+ const wrapperStyle = {
628
+ display: "flex",
629
+ flexDirection: "column",
630
+ alignItems: align === "left" ? "flex-start" : align === "right" ? "flex-end" : "center",
631
+ gap: "8px"
632
+ };
633
+ const imageStyle = {
634
+ width: widthMap[width],
635
+ maxWidth: "100%",
636
+ aspectRatio: aspectRatioMap[aspectRatio],
637
+ objectFit,
638
+ borderRadius: radiusMap2[borderRadius],
639
+ boxShadow: shadowMap[shadow],
640
+ display: "block"
641
+ };
642
+ const captionStyle = {
643
+ fontSize: "0.875rem",
644
+ color: hexToRgba(resolvedCaptionColor.color, resolvedCaptionColor.opacity),
645
+ textAlign: align,
646
+ maxWidth: widthMap[width]
647
+ };
648
+ if (!resolvedSrc) {
649
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: wrapperStyle, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
650
+ "div",
651
+ {
652
+ style: {
653
+ ...imageStyle,
654
+ backgroundColor: "#e5e7eb",
655
+ display: "flex",
656
+ alignItems: "center",
657
+ justifyContent: "center",
658
+ minHeight: "200px",
659
+ color: "#9ca3af"
660
+ },
661
+ children: "No image"
662
+ }
663
+ ) });
664
+ }
665
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("figure", { id, style: { ...wrapperStyle, margin: 0 }, children: [
666
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("img", { src: resolvedSrc, alt, style: imageStyle, loading: "lazy" }),
667
+ resolvedCaption && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("figcaption", { style: captionStyle, children: resolvedCaption })
668
+ ] });
669
+ }
670
+
671
+ // components/page/ImageCarousel.tsx
672
+ var import_react4 = require("react");
673
+ var import_jsx_runtime7 = require("react/jsx-runtime");
674
+ var aspectRatioMap2 = {
675
+ "16:9": "16 / 9",
676
+ "4:3": "4 / 3",
677
+ "1:1": "1 / 1",
678
+ "21:9": "21 / 9"
679
+ };
680
+ var radiusMap3 = {
681
+ none: "0",
682
+ sm: "4px",
683
+ md: "8px",
684
+ lg: "16px"
685
+ };
686
+ function isThemeableValue5(value) {
687
+ return typeof value === "object" && value !== null && "useTheme" in value;
688
+ }
689
+ function ImageCarousel({
690
+ images = [],
691
+ aspectRatio = "16:9",
692
+ borderRadius = "none",
693
+ showDots = true,
694
+ showArrows = true,
695
+ arrowColor,
696
+ dotColor,
697
+ id
698
+ }) {
699
+ const [currentIndex, setCurrentIndex] = (0, import_react4.useState)(0);
700
+ const { resolveColor: resolveColor2 } = useTheme();
701
+ const sendEvent = useGtmEvent();
702
+ const utm = useUtmParams();
703
+ const resolvedArrowColor = (() => {
704
+ if (!arrowColor) return { color: "#FFFFFF", opacity: 100 };
705
+ if (typeof arrowColor === "string")
706
+ return { color: arrowColor, opacity: 100 };
707
+ if (isThemeableValue5(arrowColor)) {
708
+ return arrowColor.useTheme ? resolveColor2(arrowColor.themeKey) : arrowColor.value;
709
+ }
710
+ if ("color" in arrowColor) return arrowColor;
711
+ return { color: "#FFFFFF", opacity: 100 };
712
+ })();
713
+ const resolvedDotColor = (() => {
714
+ if (!dotColor) return resolveColor2("primary");
715
+ if (typeof dotColor === "string") return { color: dotColor, opacity: 100 };
716
+ if (isThemeableValue5(dotColor)) {
717
+ return dotColor.useTheme ? resolveColor2(dotColor.themeKey) : dotColor.value;
718
+ }
719
+ if ("color" in dotColor) return dotColor;
720
+ return resolveColor2("primary");
721
+ })();
722
+ const goToPrevious = () => {
723
+ const newIndex = currentIndex === 0 ? images.length - 1 : currentIndex - 1;
724
+ setCurrentIndex(newIndex);
725
+ sendEvent("carousel_navigate", {
726
+ direction: "previous",
727
+ slideIndex: newIndex,
728
+ totalSlides: images.length,
729
+ ...utm
730
+ });
731
+ };
732
+ const goToNext = () => {
733
+ const newIndex = currentIndex === images.length - 1 ? 0 : currentIndex + 1;
734
+ setCurrentIndex(newIndex);
735
+ sendEvent("carousel_navigate", {
736
+ direction: "next",
737
+ slideIndex: newIndex,
738
+ totalSlides: images.length,
739
+ ...utm
740
+ });
741
+ };
742
+ const goToSlide = (index) => {
743
+ setCurrentIndex(index);
744
+ sendEvent("carousel_navigate", {
745
+ direction: "direct",
746
+ slideIndex: index,
747
+ totalSlides: images.length,
748
+ ...utm
749
+ });
750
+ };
751
+ if (images.length === 0) {
752
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
753
+ "div",
754
+ {
755
+ style: {
756
+ aspectRatio: aspectRatioMap2[aspectRatio],
757
+ backgroundColor: "#e5e7eb",
758
+ borderRadius: radiusMap3[borderRadius],
759
+ display: "flex",
760
+ alignItems: "center",
761
+ justifyContent: "center",
762
+ color: "#9ca3af"
763
+ },
764
+ children: "No images"
765
+ }
766
+ );
767
+ }
768
+ const containerStyle = {
769
+ position: "relative",
770
+ aspectRatio: aspectRatioMap2[aspectRatio],
771
+ borderRadius: radiusMap3[borderRadius],
772
+ overflow: "hidden"
773
+ };
774
+ const slideContainerStyle = {
775
+ display: "flex",
776
+ transition: "transform 0.3s ease-in-out",
777
+ transform: `translateX(-${currentIndex * 100}%)`,
778
+ height: "100%"
779
+ };
780
+ const slideStyle = {
781
+ minWidth: "100%",
782
+ height: "100%"
783
+ };
784
+ const imageStyle = {
785
+ width: "100%",
786
+ height: "100%",
787
+ objectFit: "cover"
788
+ };
789
+ const arrowStyle = {
790
+ position: "absolute",
791
+ top: "50%",
792
+ transform: "translateY(-50%)",
793
+ backgroundColor: "rgba(0,0,0,0.5)",
794
+ color: hexToRgba(resolvedArrowColor.color, resolvedArrowColor.opacity),
795
+ border: "none",
796
+ borderRadius: "50%",
797
+ width: "40px",
798
+ height: "40px",
799
+ cursor: "pointer",
800
+ display: "flex",
801
+ alignItems: "center",
802
+ justifyContent: "center",
803
+ fontSize: "20px",
804
+ zIndex: 1
805
+ };
806
+ const dotsContainerStyle = {
807
+ position: "absolute",
808
+ bottom: "16px",
809
+ left: "50%",
810
+ transform: "translateX(-50%)",
811
+ display: "flex",
812
+ gap: "8px",
813
+ zIndex: 1
814
+ };
815
+ const dotStyle = (isActive) => ({
816
+ width: "10px",
817
+ height: "10px",
818
+ borderRadius: "50%",
819
+ border: "none",
820
+ cursor: "pointer",
821
+ backgroundColor: isActive ? hexToRgba(resolvedDotColor.color, resolvedDotColor.opacity) : "rgba(255,255,255,0.5)"
822
+ });
823
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { id, style: containerStyle, children: [
824
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: slideContainerStyle, children: images.map((image, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: slideStyle, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
825
+ "img",
826
+ {
827
+ src: image.src,
828
+ alt: image.alt || "",
829
+ style: imageStyle,
830
+ loading: "lazy"
831
+ }
832
+ ) }, index)) }),
833
+ showArrows && images.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
834
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
835
+ "button",
836
+ {
837
+ type: "button",
838
+ onClick: goToPrevious,
839
+ style: { ...arrowStyle, left: "16px" },
840
+ "aria-label": "Previous slide",
841
+ children: "\u2039"
842
+ }
843
+ ),
844
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
845
+ "button",
846
+ {
847
+ type: "button",
848
+ onClick: goToNext,
849
+ style: { ...arrowStyle, right: "16px" },
850
+ "aria-label": "Next slide",
851
+ children: "\u203A"
852
+ }
853
+ )
854
+ ] }),
855
+ showDots && images.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: dotsContainerStyle, children: images.map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
856
+ "button",
857
+ {
858
+ type: "button",
859
+ onClick: () => goToSlide(index),
860
+ style: dotStyle(index === currentIndex),
861
+ "aria-label": `Go to slide ${index + 1}`
862
+ },
863
+ index
864
+ )) })
865
+ ] });
866
+ }
867
+
868
+ // components/page/VideoEmbed.tsx
869
+ var import_jsx_runtime8 = require("react/jsx-runtime");
870
+ var aspectRatioMap3 = {
871
+ "16:9": "56.25%",
872
+ // 9/16 * 100
873
+ "4:3": "75%",
874
+ "1:1": "100%",
875
+ "21:9": "42.86%"
876
+ };
877
+ var radiusMap4 = {
878
+ none: "0",
879
+ sm: "4px",
880
+ md: "8px",
881
+ lg: "16px"
882
+ };
883
+ var maxWidthMap = {
884
+ sm: "400px",
885
+ md: "600px",
886
+ lg: "800px",
887
+ xl: "1000px",
888
+ full: "100%"
889
+ };
890
+ function isEntryBoundValue5(value) {
891
+ return typeof value === "object" && value !== null && "useEntry" in value;
892
+ }
893
+ function parseVideoUrl(url) {
894
+ const ytMatch = url.match(
895
+ /(?:youtube\.com\/(?:watch\?v=|embed\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})/
896
+ );
897
+ if (ytMatch) {
898
+ return {
899
+ type: "youtube",
900
+ embedUrl: `https://www.youtube.com/embed/${ytMatch[1]}`
901
+ };
902
+ }
903
+ const vimeoMatch = url.match(/(?:vimeo\.com\/)(\d+)/);
904
+ if (vimeoMatch) {
905
+ return {
906
+ type: "vimeo",
907
+ embedUrl: `https://player.vimeo.com/video/${vimeoMatch[1]}`
908
+ };
909
+ }
910
+ return { type: "unknown", embedUrl: url };
911
+ }
912
+ function VideoEmbed({
913
+ url,
914
+ aspectRatio = "16:9",
915
+ borderRadius = "none",
916
+ autoplay = false,
917
+ muted = false,
918
+ loop = false,
919
+ align = "center",
920
+ maxWidth = "full",
921
+ id
922
+ }) {
923
+ const { getEntryValue } = useEntries();
924
+ const resolvedUrl = (() => {
925
+ if (!url) return "";
926
+ if (typeof url === "string") return url;
927
+ if (isEntryBoundValue5(url)) {
928
+ if (url.useEntry) {
929
+ return String(getEntryValue(url.entryName, url.fieldKey) ?? "");
930
+ }
931
+ return url.value;
932
+ }
933
+ return "";
934
+ })();
935
+ if (!resolvedUrl) {
936
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
937
+ "div",
938
+ {
939
+ style: {
940
+ backgroundColor: "#1f2937",
941
+ borderRadius: radiusMap4[borderRadius],
942
+ aspectRatio: aspectRatio.replace(":", " / "),
943
+ display: "flex",
944
+ alignItems: "center",
945
+ justifyContent: "center",
946
+ color: "#9ca3af",
947
+ maxWidth: maxWidthMap[maxWidth],
948
+ marginLeft: align === "center" ? "auto" : align === "right" ? "auto" : void 0,
949
+ marginRight: align === "center" ? "auto" : align === "left" ? "auto" : void 0
950
+ },
951
+ children: "No video URL"
952
+ }
953
+ );
954
+ }
955
+ const { embedUrl } = parseVideoUrl(resolvedUrl);
956
+ const params = new URLSearchParams();
957
+ if (autoplay) params.set("autoplay", "1");
958
+ if (muted) params.set("mute", "1");
959
+ if (loop) params.set("loop", "1");
960
+ const finalUrl = params.toString() ? `${embedUrl}?${params.toString()}` : embedUrl;
961
+ const wrapperStyle = {
962
+ display: "flex",
963
+ justifyContent: align === "left" ? "flex-start" : align === "right" ? "flex-end" : "center"
964
+ };
965
+ const containerStyle = {
966
+ position: "relative",
967
+ width: "100%",
968
+ maxWidth: maxWidthMap[maxWidth],
969
+ paddingBottom: aspectRatioMap3[aspectRatio],
970
+ borderRadius: radiusMap4[borderRadius],
971
+ overflow: "hidden"
972
+ };
973
+ const iframeStyle = {
974
+ position: "absolute",
975
+ top: 0,
976
+ left: 0,
977
+ width: "100%",
978
+ height: "100%",
979
+ border: "none"
980
+ };
981
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { id, style: wrapperStyle, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: containerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
982
+ "iframe",
983
+ {
984
+ src: finalUrl,
985
+ style: iframeStyle,
986
+ allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",
987
+ allowFullScreen: true,
988
+ loading: "lazy"
989
+ }
990
+ ) }) });
991
+ }
992
+
993
+ // components/page/Icon.tsx
994
+ var import_jsx_runtime9 = require("react/jsx-runtime");
995
+ var sizeMap3 = {
996
+ sm: { size: "16px", strokeWidth: 2 },
997
+ md: { size: "24px", strokeWidth: 2 },
998
+ lg: { size: "32px", strokeWidth: 1.5 },
999
+ xl: { size: "48px", strokeWidth: 1.5 },
1000
+ "2xl": { size: "64px", strokeWidth: 1.5 }
1001
+ };
1002
+ var icons = {
1003
+ check: ({ size, color, strokeWidth }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1004
+ "svg",
1005
+ {
1006
+ width: size,
1007
+ height: size,
1008
+ viewBox: "0 0 24 24",
1009
+ fill: "none",
1010
+ stroke: color,
1011
+ strokeWidth,
1012
+ strokeLinecap: "round",
1013
+ strokeLinejoin: "round",
1014
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("polyline", { points: "20 6 9 17 4 12" })
1015
+ }
1016
+ ),
1017
+ x: ({ size, color, strokeWidth }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1018
+ "svg",
1019
+ {
1020
+ width: size,
1021
+ height: size,
1022
+ viewBox: "0 0 24 24",
1023
+ fill: "none",
1024
+ stroke: color,
1025
+ strokeWidth,
1026
+ strokeLinecap: "round",
1027
+ strokeLinejoin: "round",
1028
+ children: [
1029
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1030
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1031
+ ]
1032
+ }
1033
+ ),
1034
+ star: ({ size, color, strokeWidth }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1035
+ "svg",
1036
+ {
1037
+ width: size,
1038
+ height: size,
1039
+ viewBox: "0 0 24 24",
1040
+ fill: color,
1041
+ stroke: color,
1042
+ strokeWidth,
1043
+ strokeLinecap: "round",
1044
+ strokeLinejoin: "round",
1045
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("polygon", { points: "12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" })
1046
+ }
1047
+ ),
1048
+ heart: ({ size, color, strokeWidth }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1049
+ "svg",
1050
+ {
1051
+ width: size,
1052
+ height: size,
1053
+ viewBox: "0 0 24 24",
1054
+ fill: "none",
1055
+ stroke: color,
1056
+ strokeWidth,
1057
+ strokeLinecap: "round",
1058
+ strokeLinejoin: "round",
1059
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z" })
1060
+ }
1061
+ ),
1062
+ arrowRight: ({ size, color, strokeWidth }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1063
+ "svg",
1064
+ {
1065
+ width: size,
1066
+ height: size,
1067
+ viewBox: "0 0 24 24",
1068
+ fill: "none",
1069
+ stroke: color,
1070
+ strokeWidth,
1071
+ strokeLinecap: "round",
1072
+ strokeLinejoin: "round",
1073
+ children: [
1074
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "5", y1: "12", x2: "19", y2: "12" }),
1075
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("polyline", { points: "12 5 19 12 12 19" })
1076
+ ]
1077
+ }
1078
+ ),
1079
+ arrowLeft: ({ size, color, strokeWidth }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1080
+ "svg",
1081
+ {
1082
+ width: size,
1083
+ height: size,
1084
+ viewBox: "0 0 24 24",
1085
+ fill: "none",
1086
+ stroke: color,
1087
+ strokeWidth,
1088
+ strokeLinecap: "round",
1089
+ strokeLinejoin: "round",
1090
+ children: [
1091
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "19", y1: "12", x2: "5", y2: "12" }),
1092
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("polyline", { points: "12 19 5 12 12 5" })
1093
+ ]
1094
+ }
1095
+ ),
1096
+ mail: ({ size, color, strokeWidth }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1097
+ "svg",
1098
+ {
1099
+ width: size,
1100
+ height: size,
1101
+ viewBox: "0 0 24 24",
1102
+ fill: "none",
1103
+ stroke: color,
1104
+ strokeWidth,
1105
+ strokeLinecap: "round",
1106
+ strokeLinejoin: "round",
1107
+ children: [
1108
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z" }),
1109
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("polyline", { points: "22,6 12,13 2,6" })
1110
+ ]
1111
+ }
1112
+ ),
1113
+ phone: ({ size, color, strokeWidth }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1114
+ "svg",
1115
+ {
1116
+ width: size,
1117
+ height: size,
1118
+ viewBox: "0 0 24 24",
1119
+ fill: "none",
1120
+ stroke: color,
1121
+ strokeWidth,
1122
+ strokeLinecap: "round",
1123
+ strokeLinejoin: "round",
1124
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" })
1125
+ }
1126
+ ),
1127
+ mapPin: ({ size, color, strokeWidth }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1128
+ "svg",
1129
+ {
1130
+ width: size,
1131
+ height: size,
1132
+ viewBox: "0 0 24 24",
1133
+ fill: "none",
1134
+ stroke: color,
1135
+ strokeWidth,
1136
+ strokeLinecap: "round",
1137
+ strokeLinejoin: "round",
1138
+ children: [
1139
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" }),
1140
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("circle", { cx: "12", cy: "10", r: "3" })
1141
+ ]
1142
+ }
1143
+ ),
1144
+ zap: ({ size, color, strokeWidth }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1145
+ "svg",
1146
+ {
1147
+ width: size,
1148
+ height: size,
1149
+ viewBox: "0 0 24 24",
1150
+ fill: "none",
1151
+ stroke: color,
1152
+ strokeWidth,
1153
+ strokeLinecap: "round",
1154
+ strokeLinejoin: "round",
1155
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("polygon", { points: "13 2 3 14 12 14 11 22 21 10 12 10 13 2" })
1156
+ }
1157
+ ),
1158
+ shield: ({ size, color, strokeWidth }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1159
+ "svg",
1160
+ {
1161
+ width: size,
1162
+ height: size,
1163
+ viewBox: "0 0 24 24",
1164
+ fill: "none",
1165
+ stroke: color,
1166
+ strokeWidth,
1167
+ strokeLinecap: "round",
1168
+ strokeLinejoin: "round",
1169
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" })
1170
+ }
1171
+ ),
1172
+ users: ({ size, color, strokeWidth }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1173
+ "svg",
1174
+ {
1175
+ width: size,
1176
+ height: size,
1177
+ viewBox: "0 0 24 24",
1178
+ fill: "none",
1179
+ stroke: color,
1180
+ strokeWidth,
1181
+ strokeLinecap: "round",
1182
+ strokeLinejoin: "round",
1183
+ children: [
1184
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" }),
1185
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("circle", { cx: "9", cy: "7", r: "4" }),
1186
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M23 21v-2a4 4 0 0 0-3-3.87" }),
1187
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M16 3.13a4 4 0 0 1 0 7.75" })
1188
+ ]
1189
+ }
1190
+ )
1191
+ };
1192
+ function isThemeableValue6(value) {
1193
+ return typeof value === "object" && value !== null && "useTheme" in value;
1194
+ }
1195
+ function Icon({
1196
+ name = "check",
1197
+ size = "md",
1198
+ color,
1199
+ align = "center",
1200
+ id
1201
+ }) {
1202
+ const { resolveColor: resolveColor2 } = useTheme();
1203
+ const resolvedColor = (() => {
1204
+ if (!color) return resolveColor2("primary");
1205
+ if (typeof color === "string") return { color, opacity: 100 };
1206
+ if (isThemeableValue6(color)) {
1207
+ return color.useTheme ? resolveColor2(color.themeKey) : color.value;
1208
+ }
1209
+ if ("color" in color) return color;
1210
+ return resolveColor2("primary");
1211
+ })();
1212
+ const IconComponent = icons[name.toLowerCase()] || icons.check;
1213
+ const { size: iconSize, strokeWidth } = sizeMap3[size];
1214
+ const colorValue = hexToRgba(resolvedColor.color, resolvedColor.opacity);
1215
+ const wrapperStyle = {
1216
+ display: "flex",
1217
+ justifyContent: align === "left" ? "flex-start" : align === "right" ? "flex-end" : "center"
1218
+ };
1219
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { id, style: wrapperStyle, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1220
+ IconComponent,
1221
+ {
1222
+ size: iconSize,
1223
+ color: colorValue,
1224
+ strokeWidth
1225
+ }
1226
+ ) });
1227
+ }
1228
+ var availableIcons = Object.keys(icons);
1229
+
1230
+ // design-system/shadows.ts
1231
+ var shadowPresets = [
1232
+ { label: "None", value: "none", css: "none" },
1233
+ { label: "XS", value: "xs", css: "0 1px 2px 0 rgb(0 0 0 / 0.05)" },
1234
+ {
1235
+ label: "SM",
1236
+ value: "sm",
1237
+ css: "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)"
1238
+ },
1239
+ {
1240
+ label: "MD",
1241
+ value: "md",
1242
+ css: "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)"
1243
+ },
1244
+ {
1245
+ label: "LG",
1246
+ value: "lg",
1247
+ css: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)"
1248
+ },
1249
+ {
1250
+ label: "XL",
1251
+ value: "xl",
1252
+ css: "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)"
1253
+ },
1254
+ { label: "2XL", value: "2xl", css: "0 25px 50px -12px rgb(0 0 0 / 0.25)" },
1255
+ {
1256
+ label: "Inner",
1257
+ value: "inner",
1258
+ css: "inset 0 2px 4px 0 rgb(0 0 0 / 0.05)"
1259
+ }
1260
+ ];
1261
+ var getShadowCSS = (value) => {
1262
+ const preset = shadowPresets.find((p) => p.value === value);
1263
+ return preset?.css ?? "none";
1264
+ };
1265
+
1266
+ // components/page/Section.tsx
1267
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1268
+ function isThemeableValue7(value) {
1269
+ return typeof value === "object" && value !== null && "useTheme" in value;
1270
+ }
1271
+ function resolveBackgroundColor(bg, resolveColor2) {
1272
+ if (!bg) return void 0;
1273
+ if (typeof bg === "string") return bg;
1274
+ if (isThemeableValue7(bg)) {
1275
+ if (bg.useTheme) {
1276
+ const themeColor = resolveColor2(bg.themeKey);
1277
+ return hexToRgba(themeColor.color, themeColor.opacity);
1278
+ }
1279
+ return hexToRgba(bg.value.color, bg.value.opacity);
1280
+ }
1281
+ if ("color" in bg && "opacity" in bg) {
1282
+ return hexToRgba(bg.color, bg.opacity);
1283
+ }
1284
+ return void 0;
1285
+ }
1286
+ function getVisibilityClasses(visibility) {
1287
+ if (!visibility) return "";
1288
+ if (!visibility.mobile && !visibility.desktop) {
1289
+ return "hidden";
1290
+ }
1291
+ if (!visibility.mobile && visibility.desktop) {
1292
+ return "hidden md:block";
1293
+ }
1294
+ if (visibility.mobile && !visibility.desktop) {
1295
+ return "md:hidden";
1296
+ }
1297
+ return "";
1298
+ }
1299
+ function Section({
1300
+ children: _children,
1301
+ verticalPadding = 48,
1302
+ horizontalPadding = 32,
1303
+ gap = 24,
1304
+ backgroundColor,
1305
+ backgroundImage,
1306
+ shadow = "none",
1307
+ borderRadius = 0,
1308
+ contentMaxWidth = "1400px",
1309
+ anchorLink,
1310
+ visibility,
1311
+ puck
1312
+ }) {
1313
+ const { resolveColor: resolveColor2 } = useTheme();
1314
+ const DropZone = puck?.renderDropZone;
1315
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1316
+ "section",
1317
+ {
1318
+ id: anchorLink,
1319
+ className: cn("flex w-full flex-col", getVisibilityClasses(visibility)),
1320
+ style: {
1321
+ padding: `${verticalPadding}px ${horizontalPadding}px`,
1322
+ gap: `${gap}px`,
1323
+ backgroundColor: resolveBackgroundColor(backgroundColor, resolveColor2),
1324
+ backgroundImage: backgroundImage ? `url(${backgroundImage})` : void 0,
1325
+ backgroundSize: "cover",
1326
+ backgroundPosition: "center",
1327
+ boxShadow: getShadowCSS(shadow),
1328
+ borderRadius: `${borderRadius}px`
1329
+ },
1330
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mx-auto w-full", style: { maxWidth: contentMaxWidth }, children: DropZone && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DropZone, { zone: "content" }) })
1331
+ }
1332
+ );
1333
+ }
1334
+
1335
+ // components/page/Container.tsx
1336
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1337
+ var maxWidthMap2 = {
1338
+ sm: "640px",
1339
+ md: "768px",
1340
+ lg: "1024px",
1341
+ xl: "1280px",
1342
+ "2xl": "1536px",
1343
+ full: "100%"
1344
+ };
1345
+ var paddingMap = {
1346
+ none: "0",
1347
+ sm: "16px",
1348
+ md: "24px",
1349
+ lg: "32px",
1350
+ xl: "48px"
1351
+ };
1352
+ function isThemeableValue8(value) {
1353
+ return typeof value === "object" && value !== null && "useTheme" in value;
1354
+ }
1355
+ function Container({
1356
+ maxWidth = "lg",
1357
+ padding,
1358
+ paddingX = "md",
1359
+ paddingY = "none",
1360
+ backgroundColor,
1361
+ centered = true,
1362
+ id,
1363
+ puck
1364
+ }) {
1365
+ const { resolveColor: resolveColor2 } = useTheme();
1366
+ const DropZone = puck?.renderDropZone;
1367
+ const resolvedBgColor = (() => {
1368
+ if (!backgroundColor) return null;
1369
+ if (typeof backgroundColor === "string")
1370
+ return { color: backgroundColor, opacity: 100 };
1371
+ if (isThemeableValue8(backgroundColor)) {
1372
+ return backgroundColor.useTheme ? resolveColor2(backgroundColor.themeKey) : backgroundColor.value;
1373
+ }
1374
+ if ("color" in backgroundColor) return backgroundColor;
1375
+ return null;
1376
+ })();
1377
+ const effectivePaddingX = padding || paddingX;
1378
+ const effectivePaddingY = padding || paddingY;
1379
+ const style = {
1380
+ maxWidth: maxWidthMap2[maxWidth],
1381
+ marginLeft: centered ? "auto" : void 0,
1382
+ marginRight: centered ? "auto" : void 0,
1383
+ paddingLeft: paddingMap[effectivePaddingX],
1384
+ paddingRight: paddingMap[effectivePaddingX],
1385
+ paddingTop: paddingMap[effectivePaddingY],
1386
+ paddingBottom: paddingMap[effectivePaddingY],
1387
+ backgroundColor: resolvedBgColor ? hexToRgba(resolvedBgColor.color, resolvedBgColor.opacity) : void 0,
1388
+ width: "100%"
1389
+ };
1390
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { id, style, children: DropZone && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(DropZone, { zone: "container-content" }) });
1391
+ }
1392
+
1393
+ // components/page/Columns.tsx
1394
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1395
+ var gapMap = {
1396
+ none: "0",
1397
+ sm: "16px",
1398
+ md: "24px",
1399
+ lg: "32px",
1400
+ xl: "48px"
1401
+ };
1402
+ var alignMap = {
1403
+ top: "flex-start",
1404
+ center: "center",
1405
+ bottom: "flex-end",
1406
+ stretch: "stretch"
1407
+ };
1408
+ function Columns({
1409
+ columns = 2,
1410
+ gap = "md",
1411
+ verticalAlign = "top",
1412
+ stackOnMobile = true,
1413
+ id,
1414
+ puck
1415
+ }) {
1416
+ const DropZone = puck?.renderDropZone;
1417
+ const containerStyle = {
1418
+ display: "grid",
1419
+ gridTemplateColumns: `repeat(${columns}, 1fr)`,
1420
+ gap: gapMap[gap],
1421
+ alignItems: alignMap[verticalAlign]
1422
+ };
1423
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { id, style: containerStyle, children: Array.from({ length: columns }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { minWidth: 0 }, children: DropZone && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(DropZone, { zone: `column-${index}` }) }, index)) });
1424
+ }
1425
+
1426
+ // components/page/Card.tsx
1427
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1428
+ var borderWidthMap = {
1429
+ none: "0",
1430
+ thin: "1px",
1431
+ medium: "2px",
1432
+ thick: "4px"
1433
+ };
1434
+ var radiusMap5 = {
1435
+ none: "0",
1436
+ sm: "4px",
1437
+ md: "8px",
1438
+ lg: "16px",
1439
+ xl: "24px"
1440
+ };
1441
+ var shadowMap2 = {
1442
+ none: "none",
1443
+ sm: "0 1px 2px rgba(0,0,0,0.05)",
1444
+ md: "0 4px 6px rgba(0,0,0,0.1)",
1445
+ lg: "0 10px 15px rgba(0,0,0,0.1)",
1446
+ xl: "0 20px 25px rgba(0,0,0,0.15)"
1447
+ };
1448
+ var paddingMap2 = {
1449
+ none: "0",
1450
+ sm: "16px",
1451
+ md: "24px",
1452
+ lg: "32px",
1453
+ xl: "48px"
1454
+ };
1455
+ function isThemeableValue9(value) {
1456
+ return typeof value === "object" && value !== null && "useTheme" in value;
1457
+ }
1458
+ function Card({
1459
+ backgroundColor,
1460
+ borderColor,
1461
+ borderWidth = "thin",
1462
+ borderRadius = "md",
1463
+ shadow = "sm",
1464
+ padding = "md",
1465
+ id,
1466
+ puck
1467
+ }) {
1468
+ const { resolveColor: resolveColor2 } = useTheme();
1469
+ const DropZone = puck?.renderDropZone;
1470
+ const resolvedBgColor = (() => {
1471
+ if (!backgroundColor) return resolveColor2("background");
1472
+ if (typeof backgroundColor === "string")
1473
+ return { color: backgroundColor, opacity: 100 };
1474
+ if (isThemeableValue9(backgroundColor)) {
1475
+ return backgroundColor.useTheme ? resolveColor2(backgroundColor.themeKey) : backgroundColor.value;
1476
+ }
1477
+ if ("color" in backgroundColor) return backgroundColor;
1478
+ return resolveColor2("background");
1479
+ })();
1480
+ const resolvedBorderColor = (() => {
1481
+ if (!borderColor) return resolveColor2("muted");
1482
+ if (typeof borderColor === "string")
1483
+ return { color: borderColor, opacity: 100 };
1484
+ if (isThemeableValue9(borderColor)) {
1485
+ return borderColor.useTheme ? resolveColor2(borderColor.themeKey) : borderColor.value;
1486
+ }
1487
+ if ("color" in borderColor) return borderColor;
1488
+ return resolveColor2("muted");
1489
+ })();
1490
+ const style = {
1491
+ backgroundColor: hexToRgba(resolvedBgColor.color, resolvedBgColor.opacity),
1492
+ border: borderWidth !== "none" ? `${borderWidthMap[borderWidth]} solid ${hexToRgba(resolvedBorderColor.color, resolvedBorderColor.opacity)}` : "none",
1493
+ borderRadius: radiusMap5[borderRadius],
1494
+ boxShadow: shadowMap2[shadow],
1495
+ padding: paddingMap2[padding]
1496
+ };
1497
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { id, style, children: DropZone && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DropZone, { zone: "card-content" }) });
1498
+ }
1499
+
1500
+ // components/page/Divider.tsx
1501
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1502
+ var thicknessMap = {
1503
+ thin: "1px",
1504
+ medium: "2px",
1505
+ thick: "4px"
1506
+ };
1507
+ var widthMap2 = {
1508
+ full: "100%",
1509
+ "3/4": "75%",
1510
+ "1/2": "50%",
1511
+ "1/4": "25%"
1512
+ };
1513
+ var spacingMap = {
1514
+ sm: "16px",
1515
+ md: "24px",
1516
+ lg: "32px",
1517
+ xl: "48px"
1518
+ };
1519
+ function isThemeableValue10(value) {
1520
+ return typeof value === "object" && value !== null && "useTheme" in value;
1521
+ }
1522
+ function Divider({
1523
+ style: lineStyle = "solid",
1524
+ thickness = "thin",
1525
+ color,
1526
+ width = "full",
1527
+ align = "center",
1528
+ spacing = "md",
1529
+ id
1530
+ }) {
1531
+ const { resolveColor: resolveColor2 } = useTheme();
1532
+ const resolvedColor = (() => {
1533
+ if (!color) return resolveColor2("muted");
1534
+ if (typeof color === "string") return { color, opacity: 100 };
1535
+ if (isThemeableValue10(color)) {
1536
+ return color.useTheme ? resolveColor2(color.themeKey) : color.value;
1537
+ }
1538
+ if ("color" in color) return color;
1539
+ return resolveColor2("muted");
1540
+ })();
1541
+ const wrapperStyle = {
1542
+ display: "flex",
1543
+ justifyContent: align === "left" ? "flex-start" : align === "right" ? "flex-end" : "center",
1544
+ padding: `${spacingMap[spacing]} 0`
1545
+ };
1546
+ const hrStyle = {
1547
+ width: widthMap2[width],
1548
+ border: "none",
1549
+ borderTop: `${thicknessMap[thickness]} ${lineStyle} ${hexToRgba(resolvedColor.color, resolvedColor.opacity)}`,
1550
+ margin: 0
1551
+ };
1552
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { id, style: wrapperStyle, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("hr", { style: hrStyle }) });
1553
+ }
1554
+
1555
+ // components/page/Spacer.tsx
1556
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1557
+ var sizeMap4 = {
1558
+ xs: "8px",
1559
+ sm: "16px",
1560
+ md: "24px",
1561
+ lg: "32px",
1562
+ xl: "48px",
1563
+ "2xl": "64px",
1564
+ "3xl": "96px"
1565
+ };
1566
+ function Spacer({ size = "md", id }) {
1567
+ const style = {
1568
+ height: sizeMap4[size],
1569
+ width: "100%"
1570
+ };
1571
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { id, style, "aria-hidden": "true" });
1572
+ }
1573
+
1574
+ // components/page/TextBlock.tsx
1575
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1576
+ var alignmentMap = {
1577
+ left: "text-left",
1578
+ center: "text-center",
1579
+ right: "text-right"
1580
+ };
1581
+ var sizeMap5 = {
1582
+ small: "text-2xl",
1583
+ "medium-small": "text-3xl",
1584
+ medium: "text-4xl",
1585
+ large: "text-5xl",
1586
+ xlarge: "text-6xl"
1587
+ };
1588
+ function isThemeableValue11(value) {
1589
+ return typeof value === "object" && value !== null && "useTheme" in value;
1590
+ }
1591
+ function isEntryBoundValue6(value) {
1592
+ return typeof value === "object" && value !== null && "useEntry" in value;
1593
+ }
1594
+ function resolveColor(color, resolveThemeColor) {
1595
+ if (!color) return "#000000";
1596
+ if (typeof color === "string") return color;
1597
+ if (isThemeableValue11(color)) {
1598
+ if (color.useTheme) {
1599
+ const themeColor = resolveThemeColor(color.themeKey);
1600
+ return hexToRgba(themeColor.color, themeColor.opacity);
1601
+ }
1602
+ return hexToRgba(color.value.color, color.value.opacity);
1603
+ }
1604
+ if ("color" in color && "opacity" in color) {
1605
+ return hexToRgba(color.color, color.opacity);
1606
+ }
1607
+ return "#000000";
1608
+ }
1609
+ function resolveColorHex(color, resolveThemeColor) {
1610
+ if (!color) return "#000000";
1611
+ if (typeof color === "string") return color;
1612
+ if (isThemeableValue11(color)) {
1613
+ if (color.useTheme) {
1614
+ return resolveThemeColor(color.themeKey).color;
1615
+ }
1616
+ return color.value.color;
1617
+ }
1618
+ if ("color" in color) {
1619
+ return color.color;
1620
+ }
1621
+ return "#000000";
1622
+ }
1623
+ function TextBlock({
1624
+ title,
1625
+ subtitle,
1626
+ body,
1627
+ alignment = "left",
1628
+ textSize = "medium",
1629
+ textColor,
1630
+ subtitleBodyColor,
1631
+ useGradientText = false,
1632
+ gradientColor1,
1633
+ gradientColor2,
1634
+ anchorLink
1635
+ }) {
1636
+ const { resolveColor: resolveThemeColor } = useTheme();
1637
+ const { getEntryValue } = useEntries();
1638
+ const resolveText = (value) => {
1639
+ if (!value) return void 0;
1640
+ if (typeof value === "string") return value;
1641
+ if (isEntryBoundValue6(value)) {
1642
+ if (value.useEntry) {
1643
+ const entryVal = getEntryValue(value.entryName, value.fieldKey);
1644
+ return entryVal != null ? String(entryVal) : void 0;
1645
+ }
1646
+ return value.value;
1647
+ }
1648
+ return void 0;
1649
+ };
1650
+ const resolvedTitle = resolveText(title);
1651
+ const resolvedSubtitle = resolveText(subtitle);
1652
+ const resolvedBody = resolveText(body);
1653
+ const titleColorValue = resolveColor(textColor, resolveThemeColor);
1654
+ const subtitleColorValue = resolveColor(subtitleBodyColor, resolveThemeColor);
1655
+ const gradientStyle = useGradientText ? {
1656
+ backgroundImage: `linear-gradient(90deg, ${resolveColorHex(gradientColor1, resolveThemeColor)}, ${resolveColorHex(gradientColor2, resolveThemeColor)})`,
1657
+ WebkitBackgroundClip: "text",
1658
+ WebkitTextFillColor: "transparent",
1659
+ backgroundClip: "text"
1660
+ } : { color: titleColorValue };
1661
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
1662
+ "div",
1663
+ {
1664
+ id: anchorLink,
1665
+ className: cn("flex flex-col gap-4", alignmentMap[alignment]),
1666
+ children: [
1667
+ resolvedTitle && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1668
+ "h2",
1669
+ {
1670
+ className: cn("font-bold", sizeMap5[textSize]),
1671
+ style: gradientStyle,
1672
+ children: resolvedTitle
1673
+ }
1674
+ ),
1675
+ resolvedSubtitle && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-xl", style: { color: subtitleColorValue }, children: resolvedSubtitle }),
1676
+ resolvedBody && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1677
+ "div",
1678
+ {
1679
+ className: "prose max-w-none",
1680
+ style: { color: subtitleColorValue },
1681
+ dangerouslySetInnerHTML: { __html: resolvedBody }
1682
+ }
1683
+ )
1684
+ ]
1685
+ }
1686
+ );
1687
+ }
1688
+
1689
+ // components/page/CustomImage.tsx
1690
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1691
+ var alignmentMap2 = {
1692
+ left: "mr-auto",
1693
+ center: "mx-auto",
1694
+ right: "ml-auto"
1695
+ };
1696
+ function CustomImage({
1697
+ image,
1698
+ alt = "",
1699
+ maxWidth,
1700
+ alignment = "center",
1701
+ fitContent = false
1702
+ }) {
1703
+ if (!image) {
1704
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex h-48 w-full items-center justify-center bg-gray-200 text-gray-400", children: "No image" });
1705
+ }
1706
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1707
+ "img",
1708
+ {
1709
+ src: image,
1710
+ alt,
1711
+ className: cn(
1712
+ "block",
1713
+ alignmentMap2[alignment],
1714
+ fitContent && "h-full w-full object-cover"
1715
+ ),
1716
+ style: { maxWidth: maxWidth ? `${maxWidth}px` : void 0 }
1717
+ }
1718
+ );
1719
+ }
1720
+
1721
+ // components/page/FeaturesList.tsx
1722
+ var import_lucide_react = require("lucide-react");
1723
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1724
+ var sizeMap6 = {
1725
+ small: { icon: 24, title: "text-base", desc: "text-sm" },
1726
+ medium: { icon: 32, title: "text-lg", desc: "text-base" },
1727
+ large: { icon: 48, title: "text-xl", desc: "text-lg" }
1728
+ };
1729
+ function FeaturesList({
1730
+ features = [],
1731
+ align = "left",
1732
+ size = "medium",
1733
+ iconColor = "#000000",
1734
+ anchorLink
1735
+ }) {
1736
+ const sizeConfig = sizeMap6[size];
1737
+ const getIcon = (iconName) => {
1738
+ const formatted = iconName.charAt(0).toUpperCase() + iconName.slice(1);
1739
+ return import_lucide_react.icons[formatted] || null;
1740
+ };
1741
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1742
+ "div",
1743
+ {
1744
+ id: anchorLink,
1745
+ className: cn(
1746
+ "flex flex-col gap-6",
1747
+ align === "center" && "items-center text-center",
1748
+ align === "right" && "items-end text-right"
1749
+ ),
1750
+ children: features.map((feature, index) => {
1751
+ const IconComponent = feature.icon ? getIcon(feature.icon) : null;
1752
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1753
+ "div",
1754
+ {
1755
+ className: cn(
1756
+ "flex gap-4",
1757
+ align === "center" && "flex-col items-center",
1758
+ align === "right" && "flex-row-reverse"
1759
+ ),
1760
+ children: [
1761
+ feature.image ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1762
+ "img",
1763
+ {
1764
+ src: feature.image,
1765
+ alt: feature.title || "",
1766
+ className: "object-contain",
1767
+ style: { width: sizeConfig.icon, height: sizeConfig.icon }
1768
+ }
1769
+ ) : IconComponent ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1770
+ IconComponent,
1771
+ {
1772
+ size: sizeConfig.icon,
1773
+ style: { color: iconColor },
1774
+ className: "flex-shrink-0"
1775
+ }
1776
+ ) : null,
1777
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex flex-col gap-1", children: [
1778
+ feature.title && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h3", { className: cn("font-semibold", sizeConfig.title), children: feature.title }),
1779
+ feature.description && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: cn("text-gray-600", sizeConfig.desc), children: feature.description })
1780
+ ] })
1781
+ ]
1782
+ },
1783
+ index
1784
+ );
1785
+ })
1786
+ }
1787
+ );
1788
+ }
1789
+
1790
+ // components/page/FeatureGrid.tsx
1791
+ var import_lucide_react2 = require("lucide-react");
1792
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1793
+ var sizeMap7 = {
1794
+ small: { icon: 24, title: "text-base", desc: "text-sm" },
1795
+ medium: { icon: 32, title: "text-lg", desc: "text-base" },
1796
+ large: { icon: 48, title: "text-xl", desc: "text-lg" }
1797
+ };
1798
+ function FeatureGrid({
1799
+ heading,
1800
+ description,
1801
+ features = [],
1802
+ columns = 3,
1803
+ align = "left",
1804
+ size = "medium",
1805
+ iconColor = "#3B82F6",
1806
+ textColor = "#000000",
1807
+ anchorLink
1808
+ }) {
1809
+ const sizeConfig = sizeMap7[size];
1810
+ const getIcon = (iconName) => {
1811
+ const formatted = iconName.charAt(0).toUpperCase() + iconName.slice(1);
1812
+ return import_lucide_react2.icons[formatted] || null;
1813
+ };
1814
+ const columnClass = {
1815
+ 2: "grid-cols-1 md:grid-cols-2",
1816
+ 3: "grid-cols-1 md:grid-cols-2 lg:grid-cols-3",
1817
+ 4: "grid-cols-1 md:grid-cols-2 lg:grid-cols-4"
1818
+ };
1819
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { id: anchorLink, className: "flex flex-col gap-8", children: [
1820
+ (heading || description) && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1821
+ "div",
1822
+ {
1823
+ className: cn(
1824
+ "flex flex-col gap-2",
1825
+ align === "center" && "text-center",
1826
+ align === "right" && "text-right"
1827
+ ),
1828
+ children: [
1829
+ heading && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h2", { className: "text-3xl font-bold", style: { color: textColor }, children: heading }),
1830
+ description && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-gray-600", children: description })
1831
+ ]
1832
+ }
1833
+ ),
1834
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: cn("grid gap-6", columnClass[columns]), children: features.map((feature, index) => {
1835
+ const IconComponent = feature.icon ? getIcon(feature.icon) : null;
1836
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1837
+ "div",
1838
+ {
1839
+ className: cn(
1840
+ "flex flex-col gap-3 rounded-lg bg-gray-50 p-6",
1841
+ align === "center" && "items-center text-center"
1842
+ ),
1843
+ children: [
1844
+ feature.image ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1845
+ "img",
1846
+ {
1847
+ src: feature.image,
1848
+ alt: feature.title || "",
1849
+ className: "object-contain",
1850
+ style: { width: sizeConfig.icon, height: sizeConfig.icon }
1851
+ }
1852
+ ) : IconComponent ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1853
+ IconComponent,
1854
+ {
1855
+ size: sizeConfig.icon,
1856
+ style: { color: iconColor }
1857
+ }
1858
+ ) : null,
1859
+ feature.title && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1860
+ "h3",
1861
+ {
1862
+ className: cn("font-semibold", sizeConfig.title),
1863
+ style: { color: textColor },
1864
+ children: feature.title
1865
+ }
1866
+ ),
1867
+ feature.description && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: cn("text-gray-600", sizeConfig.desc), children: feature.description })
1868
+ ]
1869
+ },
1870
+ index
1871
+ );
1872
+ }) })
1873
+ ] });
1874
+ }
1875
+
1876
+ // components/page/Footer.tsx
1877
+ var import_lucide_react3 = require("lucide-react");
1878
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1879
+ function Footer({
1880
+ logo,
1881
+ copyright = "\xA9 2024 Company. All rights reserved.",
1882
+ backgroundColor = "#111827",
1883
+ textColor = "#ffffff",
1884
+ facebookUrl,
1885
+ instagramUrl,
1886
+ twitterUrl,
1887
+ puck
1888
+ }) {
1889
+ const DropZone = puck?.renderDropZone;
1890
+ const sendEvent = useGtmEvent();
1891
+ const utm = useUtmParams();
1892
+ const getSocialPlatform = (url) => {
1893
+ if (url.includes("facebook")) return "facebook";
1894
+ if (url.includes("instagram")) return "instagram";
1895
+ if (url.includes("twitter")) return "twitter";
1896
+ return "social";
1897
+ };
1898
+ const handleSocialClick = (url) => {
1899
+ const platform = getSocialPlatform(url);
1900
+ sendEvent("social_click", {
1901
+ platform,
1902
+ url,
1903
+ ...utm
1904
+ });
1905
+ };
1906
+ const socialLinks = [
1907
+ { url: facebookUrl, Icon: import_lucide_react3.Facebook },
1908
+ { url: instagramUrl, Icon: import_lucide_react3.Instagram },
1909
+ { url: twitterUrl, Icon: import_lucide_react3.Twitter }
1910
+ ].filter((link) => !!link.url);
1911
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1912
+ "footer",
1913
+ {
1914
+ className: "w-full px-6 py-8",
1915
+ style: { backgroundColor, color: textColor },
1916
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "mx-auto flex max-w-7xl flex-col items-center justify-between gap-6 md:flex-row", children: [
1917
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex items-center gap-4", children: logo && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("img", { src: logo, alt: "Logo", className: "h-8" }) }),
1918
+ DropZone && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DropZone, { zone: "footer-content" }),
1919
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex items-center gap-4", children: socialLinks.map(({ url, Icon: Icon3 }, index) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1920
+ "a",
1921
+ {
1922
+ href: url,
1923
+ target: "_blank",
1924
+ rel: "noopener noreferrer",
1925
+ className: "transition-opacity hover:opacity-80",
1926
+ onClick: () => handleSocialClick(url),
1927
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Icon3, { size: 24, style: { color: textColor } })
1928
+ },
1929
+ index
1930
+ )) }),
1931
+ copyright && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-sm opacity-80", children: copyright })
1932
+ ] })
1933
+ }
1934
+ );
1935
+ }
1936
+
1937
+ // components/page/Topbar.tsx
1938
+ var import_react5 = require("react");
1939
+ var import_link = __toESM(require("next/link"));
1940
+ var import_lucide_react4 = require("lucide-react");
1941
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1942
+ function Topbar({
1943
+ logo,
1944
+ logoUrl = "/",
1945
+ navItems = [],
1946
+ backgroundColor = "#ffffff",
1947
+ textColor = "#000000",
1948
+ maxWidth = "1400px",
1949
+ puck
1950
+ }) {
1951
+ const DropZone = puck?.renderDropZone;
1952
+ const [mobileMenuOpen, setMobileMenuOpen] = (0, import_react5.useState)(false);
1953
+ const sendEvent = useGtmEvent();
1954
+ const utm = useUtmParams();
1955
+ const handleNavClick = (item) => {
1956
+ sendEvent("nav_click", {
1957
+ name: item.name,
1958
+ url: item.url,
1959
+ linkType: item.linkType || "internal",
1960
+ ...utm
1961
+ });
1962
+ };
1963
+ const handleMobileMenuToggle = () => {
1964
+ const newState = !mobileMenuOpen;
1965
+ setMobileMenuOpen(newState);
1966
+ sendEvent("mobile_menu_toggle", {
1967
+ open: newState,
1968
+ ...utm
1969
+ });
1970
+ };
1971
+ const renderLink = (item, index) => {
1972
+ const className = "hover:opacity-80 transition-opacity";
1973
+ if (item.linkType === "external") {
1974
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1975
+ "a",
1976
+ {
1977
+ href: item.url,
1978
+ target: "_blank",
1979
+ rel: "noopener noreferrer",
1980
+ className,
1981
+ onClick: () => handleNavClick(item),
1982
+ children: item.name
1983
+ },
1984
+ index
1985
+ );
1986
+ }
1987
+ if (item.linkType === "scrollTo") {
1988
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1989
+ "a",
1990
+ {
1991
+ href: item.url,
1992
+ className,
1993
+ onClick: () => handleNavClick(item),
1994
+ children: item.name
1995
+ },
1996
+ index
1997
+ );
1998
+ }
1999
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2000
+ import_link.default,
2001
+ {
2002
+ href: item.url,
2003
+ className,
2004
+ onClick: () => handleNavClick(item),
2005
+ children: item.name
2006
+ },
2007
+ index
2008
+ );
2009
+ };
2010
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
2011
+ "nav",
2012
+ {
2013
+ className: "sticky top-0 z-50 w-full px-6 py-4",
2014
+ style: { backgroundColor, color: textColor },
2015
+ children: [
2016
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
2017
+ "div",
2018
+ {
2019
+ className: "mx-auto flex items-center justify-between",
2020
+ style: { maxWidth },
2021
+ children: [
2022
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2023
+ import_link.default,
2024
+ {
2025
+ href: logoUrl,
2026
+ className: "flex-shrink-0",
2027
+ onClick: () => sendEvent("nav_click", {
2028
+ name: "logo",
2029
+ url: logoUrl,
2030
+ linkType: "internal",
2031
+ ...utm
2032
+ }),
2033
+ children: logo ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("img", { src: logo, alt: "Logo", className: "h-8" }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-xl font-bold", children: "Logo" })
2034
+ }
2035
+ ),
2036
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "hidden items-center gap-8 md:flex", children: [
2037
+ navItems.map(renderLink),
2038
+ DropZone && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DropZone, { zone: "cta" })
2039
+ ] }),
2040
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { className: "md:hidden", onClick: handleMobileMenuToggle, children: mobileMenuOpen ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react4.X, { size: 24 }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react4.Menu, { size: 24 }) })
2041
+ ]
2042
+ }
2043
+ ),
2044
+ mobileMenuOpen && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
2045
+ "div",
2046
+ {
2047
+ className: "absolute top-full right-0 left-0 flex flex-col gap-4 px-6 py-4 md:hidden",
2048
+ style: { backgroundColor },
2049
+ children: [
2050
+ navItems.map(renderLink),
2051
+ DropZone && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DropZone, { zone: "cta" })
2052
+ ]
2053
+ }
2054
+ )
2055
+ ]
2056
+ }
2057
+ );
2058
+ }
2059
+
2060
+ // components/page/Popup.tsx
2061
+ var import_react6 = require("react");
2062
+ var import_lucide_react5 = require("lucide-react");
2063
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2064
+ function Icon2({ name, ...props }) {
2065
+ const formatted = name.charAt(0).toUpperCase() + name.slice(1);
2066
+ const IconComponent = import_lucide_react5.icons[formatted];
2067
+ if (!IconComponent) return null;
2068
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(IconComponent, { ...props });
2069
+ }
2070
+ var widthMap3 = {
2071
+ small: "max-w-sm",
2072
+ medium: "max-w-lg",
2073
+ large: "max-w-2xl"
2074
+ };
2075
+ var sizeMap8 = {
2076
+ small: "px-3 py-1.5 text-sm",
2077
+ medium: "px-4 py-2 text-base",
2078
+ large: "px-6 py-3 text-lg"
2079
+ };
2080
+ function Popup({
2081
+ ctaText = "Open",
2082
+ buttonColor = "#3B82F6",
2083
+ textColor = "#ffffff",
2084
+ icon,
2085
+ iconPosition = "left",
2086
+ size = "medium",
2087
+ width = "medium",
2088
+ textLink = false,
2089
+ puck
2090
+ }) {
2091
+ const [isOpen, setIsOpen] = (0, import_react6.useState)(false);
2092
+ const sendEvent = useGtmEvent();
2093
+ const utm = useUtmParams();
2094
+ const handleOpen = () => {
2095
+ setIsOpen(true);
2096
+ sendEvent("popup_open", {
2097
+ ctaText,
2098
+ type: textLink ? "link" : "button",
2099
+ ...utm
2100
+ });
2101
+ };
2102
+ const handleClose = () => {
2103
+ setIsOpen(false);
2104
+ sendEvent("popup_close", { ctaText, ...utm });
2105
+ };
2106
+ const trigger = textLink ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2107
+ "button",
2108
+ {
2109
+ onClick: handleOpen,
2110
+ className: "underline hover:opacity-80",
2111
+ style: { color: buttonColor },
2112
+ children: ctaText
2113
+ }
2114
+ ) : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
2115
+ "button",
2116
+ {
2117
+ onClick: handleOpen,
2118
+ className: cn(
2119
+ "flex items-center gap-2 rounded-full font-medium",
2120
+ sizeMap8[size]
2121
+ ),
2122
+ style: { backgroundColor: buttonColor, color: textColor },
2123
+ children: [
2124
+ icon && iconPosition === "left" && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Icon2, { name: icon, size: 18 }),
2125
+ ctaText,
2126
+ icon && iconPosition === "right" && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Icon2, { name: icon, size: 18 })
2127
+ ]
2128
+ }
2129
+ );
2130
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
2131
+ trigger,
2132
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2133
+ "div",
2134
+ {
2135
+ className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4",
2136
+ onClick: handleClose,
2137
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
2138
+ "div",
2139
+ {
2140
+ className: cn(
2141
+ "relative w-full rounded-lg bg-white p-6",
2142
+ widthMap3[width]
2143
+ ),
2144
+ onClick: (e) => e.stopPropagation(),
2145
+ children: [
2146
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2147
+ "button",
2148
+ {
2149
+ onClick: handleClose,
2150
+ className: "absolute top-4 right-4 text-gray-500 hover:text-gray-700",
2151
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react5.X, { size: 24 })
2152
+ }
2153
+ ),
2154
+ puck && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(puck.renderDropZone, { zone: "popup-content" })
2155
+ ]
2156
+ }
2157
+ )
2158
+ }
2159
+ )
2160
+ ] });
2161
+ }
2162
+
2163
+ // design-system/borders.ts
2164
+ var borderRadiusScale = [
2165
+ { label: "None", value: 0 },
2166
+ { label: "XS", value: 2 },
2167
+ { label: "SM", value: 4 },
2168
+ { label: "MD", value: 6 },
2169
+ { label: "LG", value: 8 },
2170
+ { label: "XL", value: 12 },
2171
+ { label: "2XL", value: 16 },
2172
+ { label: "3XL", value: 24 }
2173
+ ];
2174
+ var getClosestBorderRadiusValue = (value) => {
2175
+ return borderRadiusScale.reduce(
2176
+ (prev, curr) => Math.abs(curr.value - value) < Math.abs(prev.value - value) ? curr : prev
2177
+ ).value;
2178
+ };
2179
+ var getBorderRadiusCSS = (value) => {
2180
+ return `${value}px`;
2181
+ };
2182
+
2183
+ // design-system/colors.ts
2184
+ var neutralColors = [
2185
+ { label: "White", value: "#FFFFFF" },
2186
+ { label: "Gray 100", value: "#F3F4F6" },
2187
+ { label: "Gray 300", value: "#D1D5DB" },
2188
+ { label: "Gray 500", value: "#6B7280" },
2189
+ { label: "Gray 700", value: "#374151" },
2190
+ { label: "Gray 900", value: "#111827" },
2191
+ { label: "Black", value: "#000000" }
2192
+ ];
2193
+ var allColorPresets = [...neutralColors];
2194
+
2195
+ // design-system/spacing.ts
2196
+ var spacingScale = [
2197
+ { label: "None", value: 0 },
2198
+ { label: "2XS", value: 4 },
2199
+ { label: "XS", value: 8 },
2200
+ { label: "SM", value: 12 },
2201
+ { label: "MD", value: 16 },
2202
+ { label: "LG", value: 24 },
2203
+ { label: "XL", value: 32 },
2204
+ { label: "2XL", value: 48 },
2205
+ { label: "3XL", value: 64 },
2206
+ { label: "4XL", value: 96 }
2207
+ ];
2208
+ var getClosestSpacingValue = (value) => {
2209
+ return spacingScale.reduce(
2210
+ (prev, curr) => Math.abs(curr.value - value) < Math.abs(prev.value - value) ? curr : prev
2211
+ ).value;
2212
+ };
2213
+
2214
+ // design-system/typography.ts
2215
+ var fontFamilies = [
2216
+ { label: "System", value: "system-ui, sans-serif" },
2217
+ { label: "Sans", value: "ui-sans-serif, system-ui, sans-serif" },
2218
+ { label: "Serif", value: "ui-serif, Georgia, serif" },
2219
+ { label: "Mono", value: "ui-monospace, monospace" }
2220
+ ];
2221
+ var fontSizes = [
2222
+ { label: "XS", value: "xs", css: "0.75rem" },
2223
+ { label: "SM", value: "sm", css: "0.875rem" },
2224
+ { label: "Base", value: "base", css: "1rem" },
2225
+ { label: "LG", value: "lg", css: "1.125rem" },
2226
+ { label: "XL", value: "xl", css: "1.25rem" },
2227
+ { label: "2XL", value: "2xl", css: "1.5rem" },
2228
+ { label: "3XL", value: "3xl", css: "1.875rem" },
2229
+ { label: "4XL", value: "4xl", css: "2.25rem" },
2230
+ { label: "5XL", value: "5xl", css: "3rem" }
2231
+ ];
2232
+ var fontWeights = [
2233
+ { label: "Light", value: 300 },
2234
+ { label: "Normal", value: 400 },
2235
+ { label: "Medium", value: 500 },
2236
+ { label: "Semibold", value: 600 },
2237
+ { label: "Bold", value: 700 }
2238
+ ];
2239
+ var getFontSizeCSS = (value) => {
2240
+ const preset = fontSizes.find((p) => p.value === value);
2241
+ return preset?.css ?? "1rem";
2242
+ };
2243
+ // Annotate the CommonJS export names for ESM import in node:
2244
+ 0 && (module.exports = {
2245
+ Button,
2246
+ Card,
2247
+ Columns,
2248
+ Container,
2249
+ CustomImage,
2250
+ DEFAULT_THEME,
2251
+ Divider,
2252
+ FeatureGrid,
2253
+ FeaturesList,
2254
+ Footer,
2255
+ Heading,
2256
+ Icon,
2257
+ Image,
2258
+ ImageCarousel,
2259
+ Paragraph,
2260
+ Popup,
2261
+ Section,
2262
+ Spacer,
2263
+ TextBlock,
2264
+ ThemeProvider,
2265
+ Topbar,
2266
+ VideoEmbed,
2267
+ allColorPresets,
2268
+ availableIcons,
2269
+ borderRadiusScale,
2270
+ fontFamilies,
2271
+ fontSizes,
2272
+ fontWeights,
2273
+ getBorderRadiusCSS,
2274
+ getClosestBorderRadiusValue,
2275
+ getClosestSpacingValue,
2276
+ getFontSizeCSS,
2277
+ getShadowCSS,
2278
+ neutralColors,
2279
+ shadowPresets,
2280
+ spacingScale,
2281
+ useTheme
2282
+ });