@frontlit/page-builder 0.1.0-alpha.2 → 0.1.0-alpha.4

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.
Files changed (98) hide show
  1. package/README.md +32 -0
  2. package/dist/blocks/index.d.ts +33 -21
  3. package/dist/blocks/index.js +3 -3
  4. package/dist/builder/index.d.ts +7 -8
  5. package/dist/builder/index.js +6 -5
  6. package/dist/{button-Bzt1GDO-.d.ts → button-OLKN3wPf.d.ts} +2 -2
  7. package/dist/{chunk-H4P5MFJI.js → chunk-36QHCIPM.js} +205 -251
  8. package/dist/chunk-36QHCIPM.js.map +1 -0
  9. package/dist/chunk-BBI7UHOA.js +56 -0
  10. package/dist/chunk-BBI7UHOA.js.map +1 -0
  11. package/dist/{chunk-KQKSLI3L.js → chunk-GIKTOAQS.js} +335 -122
  12. package/dist/chunk-GIKTOAQS.js.map +1 -0
  13. package/dist/chunk-HWOVSHIW.js +4 -0
  14. package/dist/{chunk-RUYOL7JZ.js.map → chunk-HWOVSHIW.js.map} +1 -1
  15. package/dist/{chunk-HDINUNI2.js → chunk-IU4KATI2.js} +69 -96
  16. package/dist/chunk-IU4KATI2.js.map +1 -0
  17. package/dist/{chunk-SGNRWWG3.js → chunk-J7Z4UW45.js} +530 -135
  18. package/dist/chunk-J7Z4UW45.js.map +1 -0
  19. package/dist/{chunk-UO7XGBGM.js → chunk-K4WCLHMS.js} +1182 -1033
  20. package/dist/chunk-K4WCLHMS.js.map +1 -0
  21. package/dist/components/index.d.ts +33 -8
  22. package/dist/components/index.js +42 -2
  23. package/dist/components/index.js.map +1 -1
  24. package/dist/data-slots.d.ts +3 -3
  25. package/dist/fonts/archivo/archivo-latin-variable.woff2 +0 -0
  26. package/dist/fonts/hanken-grotesk/hanken-grotesk-latin-variable.woff2 +0 -0
  27. package/dist/fonts/jetbrains-mono/jetbrains-mono-latin-variable.woff2 +0 -0
  28. package/dist/fonts/spline-sans-mono/spline-sans-mono-latin-variable.woff2 +0 -0
  29. package/dist/heading-DQCxQt38.d.ts +20 -0
  30. package/dist/image-Bk8kPXwP.d.ts +52 -0
  31. package/dist/index.d.ts +17 -10
  32. package/dist/index.js +7 -6
  33. package/dist/models/index.d.ts +5 -5
  34. package/dist/models/index.js +1 -1
  35. package/dist/{page-W3hQga4w.d.ts → page-B5Gmm-Ys.d.ts} +1 -1
  36. package/dist/primitives/index.d.ts +44 -9
  37. package/dist/primitives/index.js +1 -1
  38. package/dist/renderer/index.d.ts +12 -8
  39. package/dist/renderer/index.js +5 -4
  40. package/dist/{section-background-MsdE40Rk.d.ts → section-background-6V_LCi5e.d.ts} +1 -1
  41. package/dist/server/index.d.ts +103 -0
  42. package/dist/server/index.js +2649 -0
  43. package/dist/server/index.js.map +1 -0
  44. package/dist/server/islands/code-snippet.d.ts +17 -0
  45. package/dist/server/islands/code-snippet.js +72 -0
  46. package/dist/server/islands/code-snippet.js.map +1 -0
  47. package/dist/server/islands/email-form.d.ts +50 -0
  48. package/dist/server/islands/email-form.js +406 -0
  49. package/dist/server/islands/email-form.js.map +1 -0
  50. package/dist/server/islands/header-mobile-menu.d.ts +22 -0
  51. package/dist/server/islands/header-mobile-menu.js +422 -0
  52. package/dist/server/islands/header-mobile-menu.js.map +1 -0
  53. package/dist/server/islands/inline-embed.d.ts +28 -0
  54. package/dist/server/islands/inline-embed.js +84 -0
  55. package/dist/server/islands/inline-embed.js.map +1 -0
  56. package/dist/server/islands/marquee-track.d.ts +18 -0
  57. package/dist/server/islands/marquee-track.js +67 -0
  58. package/dist/server/islands/marquee-track.js.map +1 -0
  59. package/dist/server/islands/nav-link.d.ts +37 -0
  60. package/dist/server/islands/nav-link.js +67 -0
  61. package/dist/server/islands/nav-link.js.map +1 -0
  62. package/dist/server/islands/support-form.d.ts +17 -0
  63. package/dist/server/islands/support-form.js +469 -0
  64. package/dist/server/islands/support-form.js.map +1 -0
  65. package/dist/server/islands/theme-mode-switcher.d.ts +38 -0
  66. package/dist/server/islands/theme-mode-switcher.js +169 -0
  67. package/dist/server/islands/theme-mode-switcher.js.map +1 -0
  68. package/dist/server/islands/video-with-preview.d.ts +13 -0
  69. package/dist/server/islands/video-with-preview.js +269 -0
  70. package/dist/server/islands/video-with-preview.js.map +1 -0
  71. package/dist/server/primitives.d.ts +200 -0
  72. package/dist/server/primitives.js +888 -0
  73. package/dist/server/primitives.js.map +1 -0
  74. package/dist/server/schema.d.ts +11308 -0
  75. package/dist/server/schema.js +6179 -0
  76. package/dist/server/schema.js.map +1 -0
  77. package/dist/server/theme-CF3fIKvw.d.ts +9 -0
  78. package/dist/server/theme-style-5_AGy-4V.d.ts +183 -0
  79. package/dist/server/theme-style-BPaMwk88.d.ts +183 -0
  80. package/dist/server/theme.d.ts +28 -0
  81. package/dist/server/theme.js +1671 -0
  82. package/dist/server/theme.js.map +1 -0
  83. package/dist/server/widget-YH9BrOwY.d.ts +77 -0
  84. package/dist/styles.css +121 -15
  85. package/dist/{theme-style-Cbl7NM-T.d.ts → theme-style-BVd5tOsc.d.ts} +20 -0
  86. package/dist/theme.css +12 -0
  87. package/dist/{widget-B_RoG6se.d.ts → widget-CpE2HdgU.d.ts} +17 -14
  88. package/package.json +60 -12
  89. package/schema/page.v1.json +3855 -0
  90. package/schema/site.v1.json +3811 -0
  91. package/dist/alignment-dZDzN96G.d.ts +0 -5
  92. package/dist/chunk-H4P5MFJI.js.map +0 -1
  93. package/dist/chunk-HDINUNI2.js.map +0 -1
  94. package/dist/chunk-KQKSLI3L.js.map +0 -1
  95. package/dist/chunk-RUYOL7JZ.js +0 -4
  96. package/dist/chunk-SGNRWWG3.js.map +0 -1
  97. package/dist/chunk-UO7XGBGM.js.map +0 -1
  98. package/dist/image-DAWVx1zQ.d.ts +0 -31
@@ -0,0 +1,2649 @@
1
+ // src/server/page-renderer.tsx
2
+ import { useId as useId2 } from "react";
3
+
4
+ // src/registry-names.ts
5
+ var LAYOUT_BLOCK_NAMES = ["header", "footer"];
6
+
7
+ // src/renderer/generate-theme-styles.ts
8
+ import convert from "color-convert";
9
+ function formatHSL(hsl) {
10
+ return `${hsl[0]} ${hsl[1]}% ${hsl[2]}%`;
11
+ }
12
+ var SHORT_OR_LONG_HEX = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i;
13
+ var HEX_WITH_ALPHA = /^#([0-9a-f]{4}|[0-9a-f]{8})$/i;
14
+ var CSS_COLOR_FUNCTION = /^(oklch|oklab|lab|lch|hwb|hsla?|rgba?|color)\(\s*[-+0-9a-z%.,/\s]+\)$/i;
15
+ function resolveThemeColor(value) {
16
+ const color = value?.trim();
17
+ if (!color) return "";
18
+ if (SHORT_OR_LONG_HEX.test(color)) {
19
+ return `hsl(${formatHSL(convert.hex.hsl(color.replace("#", "")))})`;
20
+ }
21
+ if (HEX_WITH_ALPHA.test(color) || CSS_COLOR_FUNCTION.test(color)) return color;
22
+ return "";
23
+ }
24
+ function generateThemeStyles(theme, selector = ".pb-theme") {
25
+ const colors = theme?.theme?.colors;
26
+ if (!colors) {
27
+ return "";
28
+ }
29
+ const { light, dark } = colors;
30
+ if (!light || !dark) {
31
+ return "";
32
+ }
33
+ const block = (c) => `
34
+ --background: ${resolveThemeColor(c.background)};
35
+ --foreground: ${resolveThemeColor(c.foreground)};
36
+ --card: ${resolveThemeColor(c.card)};
37
+ --card-foreground: ${resolveThemeColor(c.cardForeground)};
38
+ --popover: ${resolveThemeColor(c.popover)};
39
+ --popover-foreground: ${resolveThemeColor(c.popoverForeground)};
40
+ --primary: ${resolveThemeColor(c.primary)};
41
+ --primary-foreground: ${resolveThemeColor(c.primaryForeground)};
42
+ --secondary: ${resolveThemeColor(c.secondary)};
43
+ --secondary-foreground: ${resolveThemeColor(c.secondaryForeground)};
44
+ --muted: ${resolveThemeColor(c.muted)};
45
+ --muted-foreground: ${resolveThemeColor(c.mutedForeground)};
46
+ --accent: ${resolveThemeColor(c.accent)};
47
+ --accent-foreground: ${resolveThemeColor(c.accentForeground)};
48
+ --destructive: ${resolveThemeColor(c.destructive)};
49
+ --border: ${resolveThemeColor(c.border)};
50
+ --input: ${resolveThemeColor(c.input)};
51
+ --ring: ${resolveThemeColor(c.ring)};
52
+ --chart-1: ${resolveThemeColor(c.chart1)};
53
+ --chart-2: ${resolveThemeColor(c.chart2)};
54
+ --chart-3: ${resolveThemeColor(c.chart3)};
55
+ --chart-4: ${resolveThemeColor(c.chart4)};
56
+ --chart-5: ${resolveThemeColor(c.chart5)};
57
+ --sidebar-background: ${resolveThemeColor(c.sidebar)};
58
+ --sidebar-foreground: ${resolveThemeColor(c.sidebarForeground)};
59
+ --sidebar-primary: ${resolveThemeColor(c.sidebarPrimary)};
60
+ --sidebar-primary-foreground: ${resolveThemeColor(c.sidebarPrimaryForeground)};
61
+ --sidebar-accent: ${resolveThemeColor(c.sidebarAccent)};
62
+ --sidebar-accent-foreground: ${resolveThemeColor(c.sidebarAccentForeground)};
63
+ --sidebar-border: ${resolveThemeColor(c.sidebarBorder)};
64
+ --sidebar-ring: ${resolveThemeColor(c.sidebarRing)};
65
+ --shadow-2xs: ${c.shadow2xs ?? ""};
66
+ --shadow-xs: ${c.shadowXs ?? ""};
67
+ --shadow-sm: ${c.shadowSm ?? ""};
68
+ --shadow-md: ${c.shadowMd ?? ""};
69
+ --shadow-lg: ${c.shadowLg ?? ""};
70
+ --shadow-xl: ${c.shadowXl ?? ""};
71
+ --shadow-2xl: ${c.shadow2xl ?? ""};
72
+ `;
73
+ return `
74
+ ${selector} {
75
+ ${block(light)}
76
+ }
77
+ ${selector}:is(.dark, .dark *) {
78
+ ${block(dark)}
79
+ }
80
+ `;
81
+ }
82
+
83
+ // src/primitives/lib/utils.ts
84
+ import { clsx } from "clsx";
85
+ import { twMerge } from "tailwind-merge";
86
+ function cn(...inputs) {
87
+ return twMerge(clsx(inputs));
88
+ }
89
+
90
+ // src/blocks/header/widget.tsx
91
+ import clsx2 from "clsx";
92
+
93
+ // src/components/image.tsx
94
+ import { jsx } from "react/jsx-runtime";
95
+ var imageAttributesResolver = null;
96
+ function setImageAttributesResolver(resolver) {
97
+ imageAttributesResolver = resolver;
98
+ }
99
+ var roundedMap = {
100
+ 0: "rounded-none",
101
+ 1: "rounded-sm",
102
+ 2: "rounded",
103
+ 3: "rounded-md",
104
+ 4: "rounded-lg",
105
+ 5: "rounded-xl",
106
+ 6: "rounded-2xl",
107
+ 7: "rounded-3xl",
108
+ 8: "rounded-full"
109
+ };
110
+ var objectFitClass = {
111
+ cover: "object-cover",
112
+ contain: "object-contain",
113
+ fill: "object-fill",
114
+ none: "object-none",
115
+ "scale-down": "object-scale-down"
116
+ };
117
+ var Image = (props) => {
118
+ const {
119
+ src,
120
+ alt = "",
121
+ defaultImage,
122
+ priority = false,
123
+ loading = priority ? "eager" : "lazy",
124
+ sizes,
125
+ noDefaultImage = false,
126
+ className = "",
127
+ classes = "",
128
+ width = "w-full",
129
+ height = "h-auto",
130
+ objectFit = "cover",
131
+ borderRadius
132
+ } = props;
133
+ const source = src || defaultImage;
134
+ const radiusClass = typeof borderRadius === "number" ? roundedMap[borderRadius] ?? "rounded" : borderRadius;
135
+ if (!source) {
136
+ if (noDefaultImage) return null;
137
+ return /* @__PURE__ */ jsx(
138
+ "div",
139
+ {
140
+ className: cn(
141
+ "relative aspect-video overflow-hidden bg-muted",
142
+ width,
143
+ height,
144
+ radiusClass,
145
+ classes,
146
+ className
147
+ )
148
+ }
149
+ );
150
+ }
151
+ const optimized = imageAttributesResolver?.({ src: source, alt, sizes, priority });
152
+ return /* @__PURE__ */ jsx(
153
+ "div",
154
+ {
155
+ className: cn(
156
+ "relative aspect-video overflow-hidden",
157
+ width,
158
+ height,
159
+ radiusClass,
160
+ classes,
161
+ className
162
+ ),
163
+ children: /* @__PURE__ */ jsx(
164
+ "img",
165
+ {
166
+ src: source,
167
+ alt,
168
+ sizes,
169
+ loading,
170
+ decoding: "async",
171
+ fetchPriority: priority ? "high" : void 0,
172
+ ...optimized,
173
+ className: cn(
174
+ "absolute inset-0 h-full w-full",
175
+ radiusClass,
176
+ objectFitClass[objectFit]
177
+ )
178
+ }
179
+ )
180
+ }
181
+ );
182
+ };
183
+
184
+ // src/blocks/header/widget.tsx
185
+ import { NavLink as NavLink2 } from "./islands/nav-link.js";
186
+
187
+ // src/primitives/components/ui/badge.tsx
188
+ import { cva } from "class-variance-authority";
189
+ import { jsx as jsx2 } from "react/jsx-runtime";
190
+ var badgeVariants = cva(
191
+ "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
192
+ {
193
+ variants: {
194
+ variant: {
195
+ default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
196
+ secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
197
+ destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
198
+ outline: "text-foreground"
199
+ }
200
+ },
201
+ defaultVariants: {
202
+ variant: "default"
203
+ }
204
+ }
205
+ );
206
+ function Badge({ className, variant, ...props }) {
207
+ return /* @__PURE__ */ jsx2("div", { className: cn(badgeVariants({ variant }), className), ...props });
208
+ }
209
+
210
+ // src/primitives/badge.tsx
211
+ import { jsx as jsx3 } from "react/jsx-runtime";
212
+ var Badge2 = ({
213
+ variant = "default",
214
+ children,
215
+ className = "",
216
+ style = {},
217
+ theme,
218
+ ...props
219
+ }) => {
220
+ const typographyStyles = theme?.typography?.caption;
221
+ const buttonStyles = theme?.interactives?.button;
222
+ const classes = cn(
223
+ // Base styles
224
+ // "bg-secondary",
225
+ // Theme typography from caption
226
+ typographyStyles?.fontFamily,
227
+ typographyStyles?.fontSize,
228
+ typographyStyles?.fontWeight,
229
+ typographyStyles?.lineHeight,
230
+ typographyStyles?.letterSpacing,
231
+ typographyStyles?.textTransform,
232
+ buttonStyles?.border?.width,
233
+ buttonStyles?.border?.radius,
234
+ buttonStyles?.border?.style,
235
+ className
236
+ );
237
+ return /* @__PURE__ */ jsx3(
238
+ Badge,
239
+ {
240
+ variant,
241
+ className: classes,
242
+ style: {
243
+ ...style,
244
+ backgroundColor: style.backgroundColor,
245
+ color: style.color
246
+ },
247
+ ...props,
248
+ children
249
+ }
250
+ );
251
+ };
252
+
253
+ // src/primitives/components/ui/button.tsx
254
+ import { Slot } from "@radix-ui/react-slot";
255
+ import { cva as cva2 } from "class-variance-authority";
256
+ import * as React from "react";
257
+ import { jsx as jsx4 } from "react/jsx-runtime";
258
+ var buttonVariants = cva2(
259
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
260
+ {
261
+ variants: {
262
+ variant: {
263
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
264
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
265
+ outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
266
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
267
+ ghost: "hover:bg-accent hover:text-accent-foreground",
268
+ link: "text-primary underline-offset-4 hover:underline"
269
+ },
270
+ size: {
271
+ default: "h-10 px-4 py-2",
272
+ sm: "h-9 rounded-md px-3",
273
+ lg: "h-11 rounded-md px-8",
274
+ icon: "h-10 w-10"
275
+ }
276
+ },
277
+ defaultVariants: {
278
+ variant: "default",
279
+ size: "default"
280
+ }
281
+ }
282
+ );
283
+ var Button = React.forwardRef(
284
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
285
+ const Comp = asChild ? Slot : "button";
286
+ return /* @__PURE__ */ jsx4(
287
+ Comp,
288
+ {
289
+ className: cn(buttonVariants({ variant, size, className })),
290
+ ref,
291
+ ...props
292
+ }
293
+ );
294
+ }
295
+ );
296
+ Button.displayName = "Button";
297
+
298
+ // src/primitives/button.tsx
299
+ import { jsx as jsx5 } from "react/jsx-runtime";
300
+ var Button2 = ({
301
+ variant = "default",
302
+ size = "default",
303
+ disabled = false,
304
+ children,
305
+ className = "",
306
+ theme,
307
+ ...props
308
+ }) => {
309
+ const buttonStyles = theme?.interactives?.button;
310
+ const typographyStyles = theme?.typography?.button;
311
+ const isIcon = size === "icon";
312
+ const classes = cn(
313
+ // Base styles
314
+ "",
315
+ // Theme typography
316
+ typographyStyles?.fontFamily,
317
+ typographyStyles?.fontSize,
318
+ typographyStyles?.fontWeight,
319
+ typographyStyles?.lineHeight,
320
+ typographyStyles?.letterSpacing,
321
+ typographyStyles?.textTransform,
322
+ typographyStyles?.textDecoration,
323
+ typographyStyles?.textOverflow,
324
+ // Theme interactivity. Icon buttons stay square — CTA padding
325
+ // would stretch them off the size="icon" box.
326
+ !isIcon && buttonStyles?.padding?.x,
327
+ !isIcon && buttonStyles?.padding?.y,
328
+ buttonStyles?.border?.width,
329
+ buttonStyles?.border?.radius,
330
+ buttonStyles?.border?.style,
331
+ // buttonStyles?.border?.color,
332
+ buttonStyles?.shadow,
333
+ // Theme disabled states
334
+ disabled && buttonStyles?.disabled?.opacity,
335
+ disabled && buttonStyles?.disabled?.cursor,
336
+ disabled && buttonStyles?.disabled?.color,
337
+ disabled && buttonStyles?.disabled?.background,
338
+ disabled && buttonStyles?.disabled?.border,
339
+ // User overrides
340
+ buttonStyles?.custom,
341
+ className
342
+ );
343
+ return /* @__PURE__ */ jsx5(
344
+ Button,
345
+ {
346
+ variant,
347
+ size,
348
+ disabled,
349
+ className: classes,
350
+ ...props,
351
+ children
352
+ }
353
+ );
354
+ };
355
+
356
+ // src/primitives/caption.tsx
357
+ import { jsx as jsx6 } from "react/jsx-runtime";
358
+ var Caption = ({
359
+ children,
360
+ className = "",
361
+ theme,
362
+ ...props
363
+ }) => {
364
+ const typographyStyles = theme?.typography?.caption;
365
+ const classes = cn(
366
+ // Base styles
367
+ "text-xs leading-7 text-muted-foreground",
368
+ // Theme overrides
369
+ typographyStyles?.fontFamily,
370
+ typographyStyles?.fontSize,
371
+ typographyStyles?.fontWeight,
372
+ typographyStyles?.lineHeight,
373
+ typographyStyles?.letterSpacing,
374
+ typographyStyles?.textTransform,
375
+ typographyStyles?.textDecoration,
376
+ typographyStyles?.textOverflow,
377
+ className
378
+ );
379
+ return /* @__PURE__ */ jsx6("span", { className: classes, ...props, children });
380
+ };
381
+
382
+ // src/primitives/heading.tsx
383
+ import { jsx as jsx7 } from "react/jsx-runtime";
384
+ var FLUID_MIN_VIEWPORT = 360;
385
+ var FLUID_MAX_VIEWPORT = 1280;
386
+ var TAILWIND_TEXT_PX = {
387
+ "text-xs": 12,
388
+ "text-sm": 14,
389
+ "text-base": 16,
390
+ "text-lg": 18,
391
+ "text-xl": 20,
392
+ "text-2xl": 24,
393
+ "text-3xl": 30,
394
+ "text-4xl": 36,
395
+ "text-5xl": 48,
396
+ "text-6xl": 60,
397
+ "text-7xl": 72,
398
+ "text-8xl": 96,
399
+ "text-9xl": 128
400
+ };
401
+ var rem = (px) => `${+(px / 16).toFixed(4)}rem`;
402
+ function fluidFontSize({ min, max }) {
403
+ const slope = (max - min) / (FLUID_MAX_VIEWPORT - FLUID_MIN_VIEWPORT);
404
+ const intercept = min - slope * FLUID_MIN_VIEWPORT;
405
+ return `clamp(${rem(Math.min(min, max))}, ${rem(intercept)} + ${+(slope * 100).toFixed(4)}vw, ${rem(Math.max(min, max))})`;
406
+ }
407
+ function themeSize(typography) {
408
+ if (typography?.fluid) return fluidFontSize(typography.fluid);
409
+ const px = TAILWIND_TEXT_PX[typography?.fontSize ?? ""];
410
+ return px ? rem(px) : void 0;
411
+ }
412
+ function createHeading(displayName, defaultTag, baseClasses, getTypography) {
413
+ const Heading = ({
414
+ children,
415
+ className = "",
416
+ theme,
417
+ as: Tag = defaultTag,
418
+ sizeClassName,
419
+ style,
420
+ ...props
421
+ }) => {
422
+ const typography = getTypography(theme);
423
+ const fluid = typography?.fluid;
424
+ const classes = cn(
425
+ baseClasses,
426
+ typography?.fontSize,
427
+ // A class (not an inline font-size) so `sizeClassName` still wins.
428
+ fluid && "text-[length:var(--pb-theme-size)]",
429
+ sizeClassName,
430
+ typography?.fontFamily,
431
+ typography?.fontWeight,
432
+ typography?.lineHeight,
433
+ typography?.letterSpacing,
434
+ typography?.textTransform,
435
+ typography?.textDecoration,
436
+ typography?.textOverflow,
437
+ className
438
+ );
439
+ return /* @__PURE__ */ jsx7(
440
+ Tag,
441
+ {
442
+ className: classes,
443
+ style: { "--pb-theme-size": themeSize(typography), ...style },
444
+ ...props,
445
+ children
446
+ }
447
+ );
448
+ };
449
+ Heading.displayName = displayName;
450
+ return Heading;
451
+ }
452
+
453
+ // src/primitives/header4.tsx
454
+ var Header4 = createHeading(
455
+ "Header4",
456
+ "h4",
457
+ "scroll-m-20 text-xl font-semibold tracking-normal",
458
+ (theme) => theme?.typography?.header4
459
+ );
460
+
461
+ // src/primitives/card.tsx
462
+ import { jsx as jsx8 } from "react/jsx-runtime";
463
+ var PageCard = ({
464
+ isLink,
465
+ children,
466
+ className = "",
467
+ theme,
468
+ ...props
469
+ }) => {
470
+ const cardStyles = theme?.interactives?.card;
471
+ const classes = cn(
472
+ // Base styles
473
+ "bg-card text-card-foreground",
474
+ // Theme interactivity
475
+ cardStyles?.border?.width,
476
+ cardStyles?.border?.radius,
477
+ cardStyles?.border?.style,
478
+ cardStyles?.shadow,
479
+ isLink ? "cursor-pointer" : "",
480
+ // User overrides
481
+ cardStyles?.custom,
482
+ className
483
+ );
484
+ return /* @__PURE__ */ jsx8("div", { className: classes, ...props, children });
485
+ };
486
+ var PageCardContent = ({
487
+ children,
488
+ className = "",
489
+ theme,
490
+ ...props
491
+ }) => {
492
+ const cardStyles = theme?.interactives?.card;
493
+ const classes = cn(
494
+ // Base styles
495
+ "p-4",
496
+ // Theme interactivity
497
+ cardStyles?.padding?.x,
498
+ cardStyles?.padding?.y,
499
+ className
500
+ );
501
+ return /* @__PURE__ */ jsx8("div", { className: classes, ...props, children });
502
+ };
503
+ var PageCardHeader = ({
504
+ children,
505
+ className = "",
506
+ theme,
507
+ ...props
508
+ }) => {
509
+ const classes = cn(
510
+ // Base styles
511
+ "pb-4",
512
+ className
513
+ );
514
+ return /* @__PURE__ */ jsx8("div", { className: classes, ...props, children: /* @__PURE__ */ jsx8(Header4, { theme, children }) });
515
+ };
516
+
517
+ // src/primitives/display.tsx
518
+ var Display = createHeading(
519
+ "Display",
520
+ "h1",
521
+ "scroll-m-20 text-balance text-5xl font-bold tracking-tight",
522
+ (theme) => theme?.typography?.display ?? theme?.typography?.header1
523
+ );
524
+
525
+ // src/primitives/header1.tsx
526
+ var Header1 = createHeading(
527
+ "Header1",
528
+ "h1",
529
+ "scroll-m-20 text-balance text-4xl font-bold tracking-tight",
530
+ (theme) => theme?.typography?.header1
531
+ );
532
+
533
+ // src/primitives/header2.tsx
534
+ var Header2 = createHeading(
535
+ "Header2",
536
+ "h2",
537
+ "scroll-m-20 text-balance text-3xl font-bold tracking-tight",
538
+ (theme) => theme?.typography?.header2
539
+ );
540
+
541
+ // src/primitives/header3.tsx
542
+ var Header3 = createHeading(
543
+ "Header3",
544
+ "h3",
545
+ "scroll-m-20 text-2xl font-semibold tracking-normal",
546
+ (theme) => theme?.typography?.header3
547
+ );
548
+
549
+ // src/primitives/link.tsx
550
+ import { jsx as jsx9 } from "react/jsx-runtime";
551
+ var Link = ({
552
+ children,
553
+ className = "",
554
+ theme,
555
+ disabled = false,
556
+ style,
557
+ ...props
558
+ }) => {
559
+ const typographyStyles = theme?.typography?.link;
560
+ const linkStyles = theme?.interactives?.link;
561
+ const classes = cn(
562
+ // Base styles
563
+ "font-medium cursor-pointer",
564
+ // Theme typography
565
+ typographyStyles?.fontFamily,
566
+ typographyStyles?.fontSize,
567
+ typographyStyles?.fontWeight,
568
+ typographyStyles?.lineHeight,
569
+ typographyStyles?.letterSpacing,
570
+ typographyStyles?.textTransform,
571
+ typographyStyles?.textDecoration,
572
+ typographyStyles?.textOverflow,
573
+ // Theme interactivity
574
+ linkStyles?.padding?.x,
575
+ linkStyles?.padding?.y,
576
+ linkStyles?.border?.width,
577
+ linkStyles?.border?.radius,
578
+ linkStyles?.border?.style,
579
+ // Theme disabled states
580
+ disabled && linkStyles?.disabled?.color,
581
+ disabled && linkStyles?.disabled?.background,
582
+ disabled && linkStyles?.disabled?.border,
583
+ disabled && linkStyles?.disabled?.opacity,
584
+ disabled && linkStyles?.disabled?.cursor,
585
+ // User overrides
586
+ linkStyles?.custom,
587
+ className
588
+ );
589
+ return /* @__PURE__ */ jsx9(
590
+ "span",
591
+ {
592
+ className: classes,
593
+ style: {
594
+ ...style,
595
+ textShadow: linkStyles?.textShadow || void 0
596
+ },
597
+ ...props,
598
+ children
599
+ }
600
+ );
601
+ };
602
+
603
+ // src/primitives/preheader.tsx
604
+ import { jsx as jsx10 } from "react/jsx-runtime";
605
+ var Preheader = ({
606
+ children,
607
+ className = "",
608
+ theme,
609
+ ...props
610
+ }) => {
611
+ const typographyStyles = theme?.typography?.preheader;
612
+ const classes = cn(
613
+ // Base styles
614
+ "text-sm font-medium uppercase tracking-wide",
615
+ // Theme typography
616
+ typographyStyles?.fontFamily,
617
+ typographyStyles?.fontSize,
618
+ typographyStyles?.fontWeight,
619
+ typographyStyles?.lineHeight,
620
+ typographyStyles?.letterSpacing,
621
+ typographyStyles?.textTransform,
622
+ typographyStyles?.textDecoration,
623
+ typographyStyles?.textOverflow,
624
+ className
625
+ );
626
+ return /* @__PURE__ */ jsx10("p", { className: classes, ...props, children });
627
+ };
628
+
629
+ // src/primitives/section.tsx
630
+ import React2 from "react";
631
+
632
+ // src/models/media.ts
633
+ function getMediaUrl(media) {
634
+ if (!media) return null;
635
+ if (typeof media === "string") return media.trim() || null;
636
+ if (typeof media === "object") {
637
+ const obj = media;
638
+ const url = obj.url ?? obj.file ?? obj.src;
639
+ return typeof url === "string" && url.trim() ? url.trim() : null;
640
+ }
641
+ return null;
642
+ }
643
+ function getMediaAlt(media) {
644
+ if (!media || typeof media !== "object") return "";
645
+ const obj = media;
646
+ const alt = obj.alt ?? obj.caption ?? obj.title;
647
+ return typeof alt === "string" ? alt : "";
648
+ }
649
+
650
+ // src/primitives/section.tsx
651
+ import { Fragment, jsx as jsx11, jsxs } from "react/jsx-runtime";
652
+ function resolveBackgroundLayer(background) {
653
+ const attachment = background.backgroundAttachment || "scroll";
654
+ if (background.type === "color") {
655
+ return {
656
+ className: "[background-color:var(--pb-bg)] dark:[background-color:var(--pb-bg-dark,var(--pb-bg))]",
657
+ style: {
658
+ "--pb-bg": background.backgroundColor,
659
+ "--pb-bg-dark": background.backgroundColorDark
660
+ }
661
+ };
662
+ }
663
+ if (background.type === "image") {
664
+ const bgUrl = getMediaUrl(background.media);
665
+ return {
666
+ style: {
667
+ backgroundImage: bgUrl ? `url(${bgUrl})` : void 0,
668
+ backgroundSize: background.backgroundSize || "cover",
669
+ backgroundPosition: background.backgroundPosition || "center",
670
+ backgroundRepeat: background.backgroundRepeat || "no-repeat",
671
+ backgroundAttachment: attachment,
672
+ maskImage: background.maskImage,
673
+ WebkitMaskImage: background.maskImage
674
+ }
675
+ };
676
+ }
677
+ return {
678
+ className: "[background-image:var(--pb-bg-image)] dark:[background-image:var(--pb-bg-image-dark,var(--pb-bg-image))]",
679
+ style: {
680
+ "--pb-bg-image": background.backgroundImage,
681
+ "--pb-bg-image-dark": background.backgroundImageDark,
682
+ backgroundSize: background.gradientBackgroundSize || "cover",
683
+ backgroundPosition: background.gradientBackgroundPosition || "center",
684
+ backgroundRepeat: background.gradientBackgroundRepeat || "no-repeat",
685
+ backgroundAttachment: attachment,
686
+ maskImage: background.gradientMaskImage,
687
+ WebkitMaskImage: background.gradientMaskImage
688
+ }
689
+ };
690
+ }
691
+ var Section = ({
692
+ children,
693
+ className = "",
694
+ theme,
695
+ background,
696
+ component = "section",
697
+ ...props
698
+ }) => {
699
+ const classes = cn(
700
+ "bg-background text-foreground relative",
701
+ component === "section" && theme?.structure?.section?.dividers && "border-t border-border",
702
+ className
703
+ );
704
+ const backgroundLayer = background ? resolveBackgroundLayer(background) : null;
705
+ const isFixed = background && background.type !== "color" && background.backgroundAttachment === "fixed";
706
+ return /* @__PURE__ */ jsx11(Fragment, { children: React2.createElement(
707
+ component,
708
+ {
709
+ // `overflow-clip` keeps a fixed-attachment layer painted
710
+ // only within the section bounds without creating a new
711
+ // scroll container (unlike overflow-hidden in some cases).
712
+ className: cn(classes, isFixed && "overflow-clip"),
713
+ ...props
714
+ },
715
+ /* @__PURE__ */ jsxs(Fragment, { children: [
716
+ backgroundLayer && /* @__PURE__ */ jsx11(
717
+ "div",
718
+ {
719
+ "aria-hidden": true,
720
+ className: cn(
721
+ "pointer-events-none absolute inset-0 z-0",
722
+ backgroundLayer.className
723
+ ),
724
+ style: backgroundLayer.style
725
+ }
726
+ ),
727
+ background && background.type === "image" && /* @__PURE__ */ jsx11(
728
+ "div",
729
+ {
730
+ "aria-hidden": true,
731
+ className: "pointer-events-none absolute inset-0 z-[1] [background-color:var(--pb-overlay)] dark:[background-color:var(--pb-overlay-dark,var(--pb-overlay))]",
732
+ style: {
733
+ "--pb-overlay": background?.overlay?.color,
734
+ "--pb-overlay-dark": background?.overlay?.colorDark,
735
+ opacity: background?.overlay?.opacity ? background.overlay.opacity / 10 : 0,
736
+ mixBlendMode: background?.overlay?.blendMode
737
+ }
738
+ }
739
+ ),
740
+ background && background.type === "image" && /* @__PURE__ */ jsx11(
741
+ "div",
742
+ {
743
+ "aria-hidden": true,
744
+ className: "pointer-events-none absolute inset-0 z-[2]",
745
+ style: {
746
+ backdropFilter: background?.blur ? `blur(${background?.blur}px)` : void 0
747
+ }
748
+ }
749
+ ),
750
+ /* @__PURE__ */ jsx11(
751
+ "div",
752
+ {
753
+ className: cn(
754
+ "mx-auto z-[3] relative overflow-hidden",
755
+ `lg:${theme?.structure?.page?.width || "max-w-6xl"}`,
756
+ theme?.structure?.section?.padding?.x || "px-4",
757
+ theme?.structure?.section?.padding?.y || "py-4"
758
+ ),
759
+ children
760
+ }
761
+ )
762
+ ] })
763
+ ) });
764
+ };
765
+
766
+ // src/primitives/subheader1.tsx
767
+ import { jsx as jsx12 } from "react/jsx-runtime";
768
+ var Subheader1 = ({
769
+ children,
770
+ className = "",
771
+ theme,
772
+ component = "h5",
773
+ ...props
774
+ }) => {
775
+ const typographyStyles = theme?.typography?.subheader1;
776
+ const classes = cn(
777
+ typographyStyles?.fontFamily || "font-sans",
778
+ typographyStyles?.fontSize || "text-lg",
779
+ typographyStyles?.fontWeight || "font-medium",
780
+ typographyStyles?.lineHeight || "leading-relaxed",
781
+ typographyStyles?.letterSpacing || "tracking-normal",
782
+ typographyStyles?.textTransform,
783
+ typographyStyles?.textDecoration,
784
+ typographyStyles?.textOverflow,
785
+ className
786
+ );
787
+ return component === "h5" ? /* @__PURE__ */ jsx12("h5", { className: classes, ...props, children }) : /* @__PURE__ */ jsx12("span", { className: classes, ...props, children });
788
+ };
789
+
790
+ // src/primitives/text1.tsx
791
+ import { jsx as jsx13 } from "react/jsx-runtime";
792
+ var Text1 = ({
793
+ children,
794
+ className = "",
795
+ theme,
796
+ component = "p",
797
+ ...props
798
+ }) => {
799
+ const typographyStyles = theme?.typography?.text1;
800
+ const classes = cn(
801
+ // Base styles
802
+ "text-base",
803
+ // Theme overrides
804
+ typographyStyles?.fontFamily,
805
+ typographyStyles?.fontSize,
806
+ typographyStyles?.fontWeight,
807
+ typographyStyles?.lineHeight,
808
+ typographyStyles?.letterSpacing,
809
+ typographyStyles?.textTransform,
810
+ typographyStyles?.textDecoration,
811
+ typographyStyles?.textOverflow,
812
+ className
813
+ );
814
+ return component === "p" ? /* @__PURE__ */ jsx13("p", { className: classes, ...props, children }) : /* @__PURE__ */ jsx13("span", { className: classes, ...props, children });
815
+ };
816
+
817
+ // src/primitives/text2.tsx
818
+ import { jsx as jsx14 } from "react/jsx-runtime";
819
+ var Text2 = ({
820
+ children,
821
+ className = "",
822
+ theme,
823
+ component = "p",
824
+ ...props
825
+ }) => {
826
+ const typographyStyles = theme?.typography?.text2;
827
+ const classes = cn(
828
+ // Base styles
829
+ "text-sm",
830
+ // Theme overrides
831
+ typographyStyles?.fontFamily,
832
+ typographyStyles?.fontSize,
833
+ typographyStyles?.fontWeight,
834
+ typographyStyles?.lineHeight,
835
+ typographyStyles?.letterSpacing,
836
+ typographyStyles?.textTransform,
837
+ typographyStyles?.textDecoration,
838
+ typographyStyles?.textOverflow,
839
+ className
840
+ );
841
+ return component === "p" ? /* @__PURE__ */ jsx14("p", { className: classes, ...props, children }) : /* @__PURE__ */ jsx14("span", { className: classes, ...props, children });
842
+ };
843
+
844
+ // src/blocks/header/header-link.tsx
845
+ import { NavLink } from "./islands/nav-link.js";
846
+ import { jsx as jsx15 } from "react/jsx-runtime";
847
+ function HeaderLink({
848
+ link,
849
+ theme,
850
+ onClick,
851
+ fullWidth = false
852
+ }) {
853
+ if (link.isButton) {
854
+ return /* @__PURE__ */ jsx15(NavLink, { href: link.href, onClick, children: /* @__PURE__ */ jsx15(
855
+ Button2,
856
+ {
857
+ size: fullWidth ? void 0 : "sm",
858
+ theme,
859
+ className: fullWidth ? "w-full" : void 0,
860
+ children: link.label
861
+ }
862
+ ) });
863
+ }
864
+ return /* @__PURE__ */ jsx15(NavLink, { href: link.href, onClick, className: "no-underline", children: /* @__PURE__ */ jsx15(Link, { theme, className: "no-underline", children: link.label }) });
865
+ }
866
+
867
+ // src/blocks/header/widget.tsx
868
+ import { HeaderMobileMenu } from "./islands/header-mobile-menu.js";
869
+ import { jsx as jsx16, jsxs as jsxs2 } from "react/jsx-runtime";
870
+ function HeaderWidget({
871
+ settings: {
872
+ logoCorners,
873
+ links = [],
874
+ ctaLabel,
875
+ ctaHref,
876
+ linkAlignment = "left",
877
+ layout = "fixed",
878
+ backdropBlur = false,
879
+ cssId,
880
+ maxWidth,
881
+ verticalPadding,
882
+ background
883
+ },
884
+ state: { theme },
885
+ pageData
886
+ }) {
887
+ const overriddenTheme = JSON.parse(JSON.stringify(theme.theme));
888
+ overriddenTheme.structure.page.width = maxWidth || theme.theme.structure.page.width;
889
+ overriddenTheme.structure.section.padding.y = verticalPadding || theme.theme.structure.section.padding.y;
890
+ const isFloating = layout === "floating";
891
+ const isCentered = layout === "centered";
892
+ const isFixed = !isFloating;
893
+ const primaryLinks = links.filter((link) => !link.isButton);
894
+ const buttonLinks = links.filter((link) => link.isButton);
895
+ const resolvedLogoImage = pageData.siteLogoUrl;
896
+ const resolvedLogoText = pageData.siteTitle;
897
+ const resolvedLogoAlt = pageData.siteLogoAlt || resolvedLogoText || "";
898
+ const effectiveLogoCorners = logoCorners ?? 2;
899
+ const logo = /* @__PURE__ */ jsx16(NavLink2, { href: "/", className: "no-underline", children: /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
900
+ resolvedLogoImage && /* @__PURE__ */ jsx16(
901
+ Image,
902
+ {
903
+ src: resolvedLogoImage,
904
+ alt: resolvedLogoAlt,
905
+ width: "w-8",
906
+ height: "h-8",
907
+ sizes: "32px",
908
+ className: "aspect-square shrink-0",
909
+ borderRadius: effectiveLogoCorners
910
+ }
911
+ ),
912
+ resolvedLogoText && /* @__PURE__ */ jsx16(Header4, { theme: overriddenTheme, as: "span", children: resolvedLogoText })
913
+ ] }) });
914
+ const ctaAndMenu = /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-3", children: [
915
+ buttonLinks.map((link) => /* @__PURE__ */ jsx16("div", { className: "hidden lg:!block", children: /* @__PURE__ */ jsx16(HeaderLink, { link, theme: overriddenTheme }) }, link.id)),
916
+ ctaLabel && ctaHref && /* @__PURE__ */ jsx16("div", { className: "hidden lg:!block", children: /* @__PURE__ */ jsx16(NavLink2, { href: ctaHref, children: /* @__PURE__ */ jsx16(Button2, { theme: overriddenTheme, size: "sm", children: ctaLabel }) }) }),
917
+ /* @__PURE__ */ jsx16("div", { className: "lg:hidden", children: /* @__PURE__ */ jsx16(
918
+ HeaderMobileMenu,
919
+ {
920
+ links,
921
+ ctaLabel,
922
+ ctaHref,
923
+ theme: overriddenTheme
924
+ }
925
+ ) })
926
+ ] });
927
+ let mainContent;
928
+ if (isCentered) {
929
+ const half = Math.ceil(primaryLinks.length / 2);
930
+ const leftLinks = primaryLinks.slice(0, half);
931
+ const rightLinks = primaryLinks.slice(half);
932
+ mainContent = /* @__PURE__ */ jsxs2("div", { className: "grid w-full grid-cols-[1fr_auto_1fr] items-center gap-4", children: [
933
+ /* @__PURE__ */ jsx16("div", { className: "hidden items-center justify-end gap-6 lg:!flex", children: leftLinks.map((link) => /* @__PURE__ */ jsx16(HeaderLink, { link, theme: overriddenTheme }, link.id)) }),
934
+ /* @__PURE__ */ jsx16("div", { className: "flex justify-center", children: logo }),
935
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-end gap-3", children: [
936
+ /* @__PURE__ */ jsx16("div", { className: "hidden items-center gap-6 lg:!flex", children: rightLinks.map((link) => /* @__PURE__ */ jsx16(HeaderLink, { link, theme: overriddenTheme }, link.id)) }),
937
+ ctaAndMenu
938
+ ] })
939
+ ] });
940
+ } else {
941
+ mainContent = /* @__PURE__ */ jsxs2("div", { className: "flex w-full items-center justify-between gap-4", children: [
942
+ logo,
943
+ /* @__PURE__ */ jsx16(
944
+ "div",
945
+ {
946
+ className: clsx2(
947
+ "hidden items-center gap-6 lg:!flex lg:!grow",
948
+ linkAlignment === "right" ? "justify-end" : linkAlignment === "center" ? "justify-center" : "justify-start"
949
+ ),
950
+ children: primaryLinks.map((link) => /* @__PURE__ */ jsx16(HeaderLink, { link, theme: overriddenTheme }, link.id))
951
+ }
952
+ ),
953
+ ctaAndMenu
954
+ ] });
955
+ }
956
+ return /* @__PURE__ */ jsx16(
957
+ Section,
958
+ {
959
+ theme: overriddenTheme,
960
+ component: "header",
961
+ id: cssId,
962
+ background,
963
+ className: clsx2(
964
+ "sticky top-0 z-20",
965
+ isFixed && "border-b",
966
+ isFixed && backdropBlur && "bg-transparent backdrop-blur-2xl",
967
+ isFixed && !backdropBlur && "bg-background",
968
+ !isFixed && "bg-transparent"
969
+ ),
970
+ children: isFloating ? /* @__PURE__ */ jsx16(
971
+ "div",
972
+ {
973
+ className: clsx2(
974
+ "p-2",
975
+ overriddenTheme.interactives?.card?.border?.width ?? "border",
976
+ overriddenTheme.interactives?.card?.border?.radius ?? "rounded-xl",
977
+ overriddenTheme.interactives?.card?.border?.style,
978
+ overriddenTheme.interactives?.card?.shadow ?? "shadow-md",
979
+ backdropBlur ? "bg-transparent backdrop-blur-2xl" : "bg-card text-card-foreground"
980
+ ),
981
+ children: mainContent
982
+ }
983
+ ) : mainContent
984
+ }
985
+ );
986
+ }
987
+
988
+ // src/utils/generate-unique-id.ts
989
+ function generateUniqueId() {
990
+ return Math.random().toString(36).slice(2) + Date.now().toString(36);
991
+ }
992
+
993
+ // src/blocks/header/defaults.ts
994
+ var headerDefaults = {
995
+ logoCorners: 2,
996
+ links: [
997
+ { id: generateUniqueId(), label: "Features", href: "/#features" },
998
+ { id: generateUniqueId(), label: "Pricing", href: "/#pricing" },
999
+ { id: generateUniqueId(), label: "Docs", href: "/docs" },
1000
+ { id: generateUniqueId(), label: "Blog", href: "/blog" }
1001
+ ],
1002
+ ctaLabel: "Get started",
1003
+ ctaHref: "/help",
1004
+ linkAlignment: "left",
1005
+ layout: "fixed",
1006
+ backdropBlur: false,
1007
+ // Slider value 1. Keeps a new header compact instead of inheriting the
1008
+ // theme's content-section padding (`py-12` / slider 5 on most themes).
1009
+ verticalPadding: "py-4"
1010
+ };
1011
+
1012
+ // src/blocks/_shared/title.ts
1013
+ import React3 from "react";
1014
+ function titleProps({
1015
+ titleLevel,
1016
+ titleSize
1017
+ }, defaultLevel = "h2", baseSizeClassName) {
1018
+ const { mobile, tablet, desktop } = titleSize ?? {};
1019
+ const size = (value) => value ? `${value}px` : "var(--pb-theme-size, 1em)";
1020
+ return {
1021
+ as: titleLevel ?? defaultLevel,
1022
+ sizeClassName: cn(
1023
+ baseSizeClassName,
1024
+ mobile && "text-[length:var(--pb-title-mobile)]",
1025
+ (mobile || tablet) && "md:text-[length:var(--pb-title-tablet)]",
1026
+ (tablet || desktop) && "lg:text-[length:var(--pb-title-desktop)]"
1027
+ ),
1028
+ style: {
1029
+ "--pb-title-mobile": mobile ? size(mobile) : void 0,
1030
+ "--pb-title-tablet": mobile || tablet ? size(tablet) : void 0,
1031
+ "--pb-title-desktop": tablet || desktop ? size(desktop) : void 0
1032
+ }
1033
+ };
1034
+ }
1035
+ var HIGHLIGHT_CLASSES = {
1036
+ color: "text-primary",
1037
+ marker: "bg-primary px-[0.15em] text-primary-foreground [box-decoration-break:clone]"
1038
+ };
1039
+ function renderTitle(title, theme) {
1040
+ if (!title?.includes("*")) return title;
1041
+ const className = HIGHLIGHT_CLASSES[theme?.highlight ?? "color"];
1042
+ return title.split(/(\*[^*]+\*)/).map(
1043
+ (part, index) => /^\*[^*]+\*$/.test(part) ? React3.createElement("span", { key: index, className }, part.slice(1, -1)) : part
1044
+ );
1045
+ }
1046
+
1047
+ // src/blocks/hero/widget.tsx
1048
+ import { NavLink as NavLink3 } from "./islands/nav-link.js";
1049
+
1050
+ // src/components/text-renderer.ts
1051
+ import { TextRenderer } from "@frontlit/text-editor/renderer";
1052
+
1053
+ // src/blocks/hero/widget.tsx
1054
+ import { VideoWithPreview } from "./islands/video-with-preview.js";
1055
+ import { CodeSnippet } from "./islands/code-snippet.js";
1056
+
1057
+ // src/utils/is-video.ts
1058
+ function isVideo(youtubeLink, media) {
1059
+ return Boolean(
1060
+ youtubeLink || media && RegExp("video/").test(media?.mimeType || "")
1061
+ );
1062
+ }
1063
+
1064
+ // src/blocks/hero/widget.tsx
1065
+ import clsx3 from "clsx";
1066
+ import { jsx as jsx17, jsxs as jsxs3 } from "react/jsx-runtime";
1067
+ var roundedMap2 = {
1068
+ 0: "rounded-none",
1069
+ 1: "rounded-sm",
1070
+ 2: "rounded",
1071
+ 3: "rounded-md",
1072
+ 4: "rounded-lg",
1073
+ 5: "rounded-xl",
1074
+ 6: "rounded-2xl",
1075
+ 7: "rounded-3xl",
1076
+ 8: "rounded-full"
1077
+ };
1078
+ function HeroWidget({
1079
+ settings: {
1080
+ preTitle,
1081
+ title,
1082
+ description,
1083
+ buttonCaption,
1084
+ buttonAction,
1085
+ media,
1086
+ youtubeLink,
1087
+ alignment = "right",
1088
+ mediaRadius = 3,
1089
+ contentAlignment = "left",
1090
+ secondaryButtonAction,
1091
+ secondaryButtonCaption,
1092
+ smallPrint,
1093
+ command,
1094
+ titleLevel,
1095
+ titleSize,
1096
+ cssId,
1097
+ maxWidth,
1098
+ verticalPadding,
1099
+ background,
1100
+ layout = "normal"
1101
+ },
1102
+ state: { theme }
1103
+ }) {
1104
+ const overriddenTheme = JSON.parse(JSON.stringify(theme.theme));
1105
+ overriddenTheme.structure.page.width = maxWidth || theme.theme.structure.page.width;
1106
+ overriddenTheme.structure.section.padding.y = verticalPadding || theme.theme.structure.section.padding.y;
1107
+ const mediaUrl = getMediaUrl(media);
1108
+ const hasHeroGraphic = Boolean(youtubeLink || mediaUrl);
1109
+ const direction = alignment === "right" ? "md:!flex-row-reverse" : "md:!flex-row";
1110
+ const isCentered = layout === "centered" || layout === "media-below";
1111
+ const graphic = hasHeroGraphic && /* @__PURE__ */ jsx17(
1112
+ "div",
1113
+ {
1114
+ className: `w-full overflow-hidden ${roundedMap2[mediaRadius] ?? "rounded-md"}`,
1115
+ children: isVideo(youtubeLink, media) ? /* @__PURE__ */ jsx17(
1116
+ VideoWithPreview,
1117
+ {
1118
+ videoUrl: youtubeLink || mediaUrl || "",
1119
+ title: getMediaAlt(media) || media?.caption || "",
1120
+ thumbnailUrl: media?.thumbnail || media?.thumbnailUrl || ""
1121
+ }
1122
+ ) : /* @__PURE__ */ jsx17(
1123
+ Image,
1124
+ {
1125
+ src: mediaUrl || "",
1126
+ alt: getMediaAlt(media),
1127
+ borderRadius: mediaRadius,
1128
+ priority: true
1129
+ }
1130
+ )
1131
+ }
1132
+ );
1133
+ const textContent = /* @__PURE__ */ jsxs3(
1134
+ "div",
1135
+ {
1136
+ className: clsx3(
1137
+ "flex flex-col gap-4",
1138
+ isCentered || contentAlignment === "center" ? "items-center text-center" : "items-start justify-center h-full"
1139
+ ),
1140
+ children: [
1141
+ preTitle && /* @__PURE__ */ jsx17(Preheader, { theme: overriddenTheme, className: "text-muted-foreground", children: preTitle }),
1142
+ /* @__PURE__ */ jsx17(Display, { theme: overriddenTheme, ...titleProps({ titleLevel, titleSize }, "h1"), children: renderTitle(title, overriddenTheme) }),
1143
+ description && /* @__PURE__ */ jsx17(Subheader1, { theme: overriddenTheme, component: "span", children: /* @__PURE__ */ jsx17(TextRenderer, { json: description, theme: overriddenTheme }) }),
1144
+ /* @__PURE__ */ jsxs3(
1145
+ "div",
1146
+ {
1147
+ className: clsx3(
1148
+ "flex flex-col md:!flex-row gap-2 w-full",
1149
+ (isCentered || contentAlignment === "center") && "md:!justify-center"
1150
+ ),
1151
+ children: [
1152
+ buttonAction && buttonCaption && /* @__PURE__ */ jsx17(NavLink3, { href: buttonAction, children: /* @__PURE__ */ jsx17(Button2, { theme: overriddenTheme, className: "w-full md:min-w-[150px]", children: buttonCaption }) }),
1153
+ secondaryButtonAction && secondaryButtonCaption && /* @__PURE__ */ jsx17(NavLink3, { href: secondaryButtonAction, children: /* @__PURE__ */ jsx17(
1154
+ Button2,
1155
+ {
1156
+ theme: overriddenTheme,
1157
+ variant: "secondary",
1158
+ className: "w-full md:min-w-[150px]",
1159
+ children: secondaryButtonCaption
1160
+ }
1161
+ ) })
1162
+ ]
1163
+ }
1164
+ ),
1165
+ command && /* @__PURE__ */ jsx17(
1166
+ CodeSnippet,
1167
+ {
1168
+ code: command,
1169
+ prompt: "$",
1170
+ theme: overriddenTheme,
1171
+ className: "max-w-xl"
1172
+ }
1173
+ ),
1174
+ smallPrint && /* @__PURE__ */ jsx17(Caption, { theme: overriddenTheme, children: smallPrint })
1175
+ ]
1176
+ }
1177
+ );
1178
+ let mainContent;
1179
+ if (layout === "centered") {
1180
+ mainContent = /* @__PURE__ */ jsx17("div", { className: "mx-auto flex max-w-2xl flex-col gap-4", children: textContent });
1181
+ } else if (layout === "media-below") {
1182
+ mainContent = /* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-10", children: [
1183
+ /* @__PURE__ */ jsx17("div", { className: "mx-auto flex max-w-2xl flex-col gap-4", children: textContent }),
1184
+ graphic && /* @__PURE__ */ jsx17("div", { className: "w-full", children: graphic })
1185
+ ] });
1186
+ } else {
1187
+ mainContent = /* @__PURE__ */ jsxs3("div", { className: clsx3("flex flex-col gap-8", direction), children: [
1188
+ graphic && /* @__PURE__ */ jsx17("div", { className: "w-full md:w-1/2 flex items-center", children: graphic }),
1189
+ /* @__PURE__ */ jsx17("div", { className: `w-full ${hasHeroGraphic ? "md:w-1/2" : ""}`, children: textContent })
1190
+ ] });
1191
+ }
1192
+ return /* @__PURE__ */ jsx17(Section, { theme: overriddenTheme, id: cssId, background, children: layout === "card" ? /* @__PURE__ */ jsx17(PageCard, { theme: overriddenTheme, children: /* @__PURE__ */ jsx17(PageCardContent, { theme: overriddenTheme, children: mainContent }) }) : mainContent });
1193
+ }
1194
+
1195
+ // src/blocks/hero/defaults.ts
1196
+ var heroDefaults = {
1197
+ title: "Run your whole business from one front office",
1198
+ buttonCaption: "See features",
1199
+ buttonAction: "/#features",
1200
+ secondaryButtonCaption: "Read the docs",
1201
+ secondaryButtonAction: "/docs",
1202
+ alignment: "right",
1203
+ contentAlignment: "left",
1204
+ mediaRadius: 3,
1205
+ layout: "normal"
1206
+ };
1207
+
1208
+ // src/blocks/content/widget.tsx
1209
+ import clsx4 from "clsx";
1210
+ import { jsx as jsx18, jsxs as jsxs4 } from "react/jsx-runtime";
1211
+ var roundedMap3 = {
1212
+ 0: "rounded-none",
1213
+ 1: "rounded-sm",
1214
+ 2: "rounded",
1215
+ 3: "rounded-md",
1216
+ 4: "rounded-lg",
1217
+ 5: "rounded-xl",
1218
+ 6: "rounded-2xl",
1219
+ 7: "rounded-3xl",
1220
+ 8: "rounded-full"
1221
+ };
1222
+ function ContentWidget({
1223
+ settings: {
1224
+ title,
1225
+ titleLevel,
1226
+ titleSize,
1227
+ body,
1228
+ media,
1229
+ alignment = "left",
1230
+ headerAlignment = "left",
1231
+ mediaRadius = 3,
1232
+ layout = "side",
1233
+ cssId,
1234
+ maxWidth,
1235
+ verticalPadding,
1236
+ background
1237
+ },
1238
+ state: { theme }
1239
+ }) {
1240
+ const overriddenTheme = JSON.parse(JSON.stringify(theme.theme));
1241
+ overriddenTheme.structure.page.width = maxWidth || theme.theme.structure.page.width;
1242
+ overriddenTheme.structure.section.padding.y = verticalPadding || theme.theme.structure.section.padding.y;
1243
+ const mediaUrl = getMediaUrl(media);
1244
+ const mediaAlt = getMediaAlt(media);
1245
+ const hasMedia = Boolean(mediaUrl);
1246
+ const sideBySide = layout !== "stacked" && layout !== "overlay";
1247
+ const direction = alignment === "right" ? "md:!flex-row-reverse" : "md:!flex-row";
1248
+ if (layout === "overlay") {
1249
+ const textPosition = alignment === "right" ? "items-end text-right" : "items-start text-left";
1250
+ return /* @__PURE__ */ jsx18(Section, { theme: overriddenTheme, id: cssId, background, children: /* @__PURE__ */ jsxs4("div", { className: "relative min-h-[420px] w-full overflow-hidden rounded-xl", children: [
1251
+ hasMedia && /* @__PURE__ */ jsx18(
1252
+ Image,
1253
+ {
1254
+ src: mediaUrl || "",
1255
+ alt: mediaAlt,
1256
+ width: "w-full",
1257
+ height: "h-full",
1258
+ className: "absolute inset-0",
1259
+ borderRadius: 0
1260
+ }
1261
+ ),
1262
+ /* @__PURE__ */ jsx18("div", { className: "absolute inset-0 bg-gradient-to-t from-black/70 via-black/20 to-transparent" }),
1263
+ /* @__PURE__ */ jsx18(
1264
+ "div",
1265
+ {
1266
+ className: clsx4(
1267
+ "relative flex h-full flex-col justify-end gap-4 p-6 md:p-10",
1268
+ textPosition
1269
+ ),
1270
+ children: /* @__PURE__ */ jsxs4("div", { className: "max-w-lg text-white", children: [
1271
+ title && /* @__PURE__ */ jsx18(
1272
+ Header2,
1273
+ {
1274
+ theme: overriddenTheme,
1275
+ ...titleProps({ titleLevel, titleSize }),
1276
+ children: renderTitle(title, overriddenTheme)
1277
+ }
1278
+ ),
1279
+ body && /* @__PURE__ */ jsx18(TextRenderer, { json: body, theme: overriddenTheme })
1280
+ ] })
1281
+ }
1282
+ )
1283
+ ] }) });
1284
+ }
1285
+ return /* @__PURE__ */ jsx18(Section, { theme: overriddenTheme, id: cssId, background, children: /* @__PURE__ */ jsxs4("div", { className: clsx4("flex flex-col gap-8", sideBySide && direction), children: [
1286
+ hasMedia && /* @__PURE__ */ jsx18("div", { className: clsx4("flex w-full items-center", sideBySide && "md:w-1/2"), children: /* @__PURE__ */ jsx18(
1287
+ "div",
1288
+ {
1289
+ className: `w-full overflow-hidden ${roundedMap3[mediaRadius] ?? "rounded-md"}`,
1290
+ children: /* @__PURE__ */ jsx18(Image, { src: mediaUrl || "", alt: mediaAlt, borderRadius: mediaRadius })
1291
+ }
1292
+ ) }),
1293
+ /* @__PURE__ */ jsx18("div", { className: clsx4("w-full", hasMedia && sideBySide && "md:w-1/2"), children: /* @__PURE__ */ jsxs4(
1294
+ "div",
1295
+ {
1296
+ className: clsx4(
1297
+ "flex h-full flex-col justify-center gap-4",
1298
+ headerAlignment === "center" ? "items-center text-center" : "items-start"
1299
+ ),
1300
+ children: [
1301
+ title && /* @__PURE__ */ jsx18(
1302
+ Header2,
1303
+ {
1304
+ theme: overriddenTheme,
1305
+ ...titleProps({ titleLevel, titleSize }),
1306
+ children: renderTitle(title, overriddenTheme)
1307
+ }
1308
+ ),
1309
+ body && /* @__PURE__ */ jsx18(TextRenderer, { json: body, theme: overriddenTheme })
1310
+ ]
1311
+ }
1312
+ ) })
1313
+ ] }) });
1314
+ }
1315
+
1316
+ // src/blocks/content/defaults.ts
1317
+ var contentDefaults = {
1318
+ title: "One dashboard, every channel",
1319
+ body: {
1320
+ type: "doc",
1321
+ content: [
1322
+ {
1323
+ type: "paragraph",
1324
+ content: [
1325
+ {
1326
+ type: "text",
1327
+ text: "FrontLit brings your website, content, customer support, and audience engagement into one connected front office."
1328
+ }
1329
+ ]
1330
+ }
1331
+ ]
1332
+ },
1333
+ alignment: "left",
1334
+ headerAlignment: "left",
1335
+ mediaRadius: 3
1336
+ };
1337
+
1338
+ // src/blocks/featured/widget.tsx
1339
+ import clsx5 from "clsx";
1340
+ import * as Icons from "lucide-react";
1341
+ import { jsx as jsx19, jsxs as jsxs5 } from "react/jsx-runtime";
1342
+ function resolveIcon(name) {
1343
+ if (!name) return Icons.Sparkles;
1344
+ const icon = Icons[name];
1345
+ return icon ?? Icons.Sparkles;
1346
+ }
1347
+ function FeaturedWidget({
1348
+ settings: {
1349
+ title,
1350
+ titleLevel,
1351
+ titleSize,
1352
+ description,
1353
+ headerAlignment = "center",
1354
+ items,
1355
+ layout = "grid",
1356
+ cssId,
1357
+ maxWidth,
1358
+ verticalPadding,
1359
+ background
1360
+ },
1361
+ state: { theme }
1362
+ }) {
1363
+ const overriddenTheme = JSON.parse(JSON.stringify(theme.theme));
1364
+ overriddenTheme.structure.page.width = maxWidth || theme.theme.structure.page.width;
1365
+ overriddenTheme.structure.section.padding.y = verticalPadding || theme.theme.structure.section.padding.y;
1366
+ return /* @__PURE__ */ jsx19(Section, { theme: overriddenTheme, id: cssId, background, children: /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-8", children: [
1367
+ /* @__PURE__ */ jsxs5(
1368
+ "div",
1369
+ {
1370
+ className: clsx5(
1371
+ "flex flex-col gap-4",
1372
+ headerAlignment === "center" ? "items-center text-center" : "items-start"
1373
+ ),
1374
+ children: [
1375
+ /* @__PURE__ */ jsx19(Header1, { theme: overriddenTheme, ...titleProps({ titleLevel, titleSize }), children: renderTitle(title, overriddenTheme) }),
1376
+ description && /* @__PURE__ */ jsx19(Subheader1, { theme: overriddenTheme, component: "span", children: /* @__PURE__ */ jsx19(TextRenderer, { json: description, theme: overriddenTheme }) })
1377
+ ]
1378
+ }
1379
+ ),
1380
+ items && items.length > 0 && layout === "numbered" && /* @__PURE__ */ jsx19("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8", children: items.map((item, index) => /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2", children: [
1381
+ /* @__PURE__ */ jsx19("span", { className: "text-3xl font-bold text-primary/30", children: String(index + 1).padStart(2, "0") }),
1382
+ /* @__PURE__ */ jsx19(Header4, { theme: overriddenTheme, children: item.title }),
1383
+ item.description && /* @__PURE__ */ jsx19(Text2, { theme: overriddenTheme, children: item.description })
1384
+ ] }, index)) }),
1385
+ items && items.length > 0 && layout !== "numbered" && /* @__PURE__ */ jsx19(
1386
+ "div",
1387
+ {
1388
+ className: clsx5(
1389
+ layout === "list" && "flex flex-col gap-4",
1390
+ layout === "compact" && "grid grid-cols-2 md:grid-cols-4 gap-4 items-stretch",
1391
+ layout !== "list" && layout !== "compact" && "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 items-stretch"
1392
+ ),
1393
+ children: items.map((item, index) => {
1394
+ const Icon = resolveIcon(item.icon);
1395
+ return /* @__PURE__ */ jsx19(PageCard, { theme: overriddenTheme, children: /* @__PURE__ */ jsxs5(
1396
+ PageCardContent,
1397
+ {
1398
+ theme: overriddenTheme,
1399
+ className: clsx5(
1400
+ "h-full flex gap-3",
1401
+ layout === "list" ? "flex-row items-start" : "flex-col",
1402
+ layout === "compact" && "items-center text-center gap-2"
1403
+ ),
1404
+ children: [
1405
+ /* @__PURE__ */ jsx19(
1406
+ "div",
1407
+ {
1408
+ className: clsx5(
1409
+ "flex shrink-0 items-center justify-center rounded-md bg-primary/10 text-primary",
1410
+ layout === "compact" ? "h-8 w-8" : "h-10 w-10"
1411
+ ),
1412
+ children: /* @__PURE__ */ jsx19(Icon, { className: "h-5 w-5" })
1413
+ }
1414
+ ),
1415
+ /* @__PURE__ */ jsxs5(
1416
+ "div",
1417
+ {
1418
+ className: clsx5(
1419
+ "flex flex-col gap-2",
1420
+ layout === "compact" && "items-center gap-1"
1421
+ ),
1422
+ children: [
1423
+ /* @__PURE__ */ jsx19(Header4, { theme: overriddenTheme, children: item.title }),
1424
+ item.description && layout !== "compact" && /* @__PURE__ */ jsx19(Text2, { theme: overriddenTheme, children: item.description })
1425
+ ]
1426
+ }
1427
+ )
1428
+ ]
1429
+ }
1430
+ ) }, index);
1431
+ })
1432
+ }
1433
+ )
1434
+ ] }) });
1435
+ }
1436
+
1437
+ // src/blocks/featured/defaults.ts
1438
+ var featuredDefaults = {
1439
+ title: "Everything you need to run your business online",
1440
+ headerAlignment: "center",
1441
+ items: [
1442
+ {
1443
+ title: "Website",
1444
+ description: "Design and publish beautiful pages with a drag-and-drop editor.",
1445
+ icon: "Globe"
1446
+ },
1447
+ {
1448
+ title: "Content",
1449
+ description: "Publish articles, documentation, and product updates from one content system.",
1450
+ icon: "Newspaper"
1451
+ },
1452
+ {
1453
+ title: "Support",
1454
+ description: "Support customers with a shared inbox, ticketing, help center, and AI answers.",
1455
+ icon: "LifeBuoy"
1456
+ },
1457
+ {
1458
+ title: "Engage",
1459
+ description: "Grow your audience and send email without leaving FrontLit.",
1460
+ icon: "Mail"
1461
+ }
1462
+ ]
1463
+ };
1464
+
1465
+ // src/blocks/faq/widget.tsx
1466
+ import { useId } from "react";
1467
+ import clsx6 from "clsx";
1468
+ import { ChevronDown } from "lucide-react";
1469
+ import { jsx as jsx20, jsxs as jsxs6 } from "react/jsx-runtime";
1470
+ function FaqWidget({
1471
+ settings: {
1472
+ title,
1473
+ titleLevel,
1474
+ titleSize,
1475
+ headerAlignment = "left",
1476
+ items = [],
1477
+ layout = "list",
1478
+ cssId,
1479
+ maxWidth,
1480
+ verticalPadding,
1481
+ background
1482
+ },
1483
+ state: { theme }
1484
+ }) {
1485
+ const overriddenTheme = JSON.parse(JSON.stringify(theme.theme));
1486
+ overriddenTheme.structure.page.width = maxWidth || theme.theme.structure.page.width;
1487
+ overriddenTheme.structure.section.padding.y = verticalPadding || theme.theme.structure.section.padding.y;
1488
+ const groupName = useId();
1489
+ return /* @__PURE__ */ jsx20(Section, { theme: overriddenTheme, id: cssId, background, children: /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-6", children: [
1490
+ title && /* @__PURE__ */ jsx20(
1491
+ "div",
1492
+ {
1493
+ className: clsx6(
1494
+ "flex flex-col",
1495
+ headerAlignment === "center" ? "items-center text-center" : "items-start"
1496
+ ),
1497
+ children: /* @__PURE__ */ jsx20(Header2, { theme: overriddenTheme, ...titleProps({ titleLevel, titleSize }), children: renderTitle(title, overriddenTheme) })
1498
+ }
1499
+ ),
1500
+ items.length > 0 && (() => {
1501
+ const renderItem = (item, index) => /* @__PURE__ */ jsxs6(
1502
+ "details",
1503
+ {
1504
+ name: groupName,
1505
+ open: index === 0,
1506
+ className: clsx6(
1507
+ "group",
1508
+ layout === "cards" ? "rounded-lg border border-border bg-card px-4 py-4" : layout === "columns" ? "border-b border-border py-4" : "py-4"
1509
+ ),
1510
+ children: [
1511
+ /* @__PURE__ */ jsxs6("summary", { className: "flex w-full cursor-pointer list-none items-center justify-between gap-4 text-left [&::-webkit-details-marker]:hidden", children: [
1512
+ /* @__PURE__ */ jsx20(Text1, { theme: overriddenTheme, className: "font-medium", children: item.question }),
1513
+ /* @__PURE__ */ jsx20(ChevronDown, { className: "h-4 w-4 shrink-0 transition-transform group-open:rotate-180" })
1514
+ ] }),
1515
+ /* @__PURE__ */ jsx20("div", { className: "pt-3", children: /* @__PURE__ */ jsx20(Text1, { theme: overriddenTheme, className: "text-muted-foreground", children: item.answer }) })
1516
+ ]
1517
+ },
1518
+ item.id
1519
+ );
1520
+ if (layout === "columns") {
1521
+ const half = Math.ceil(items.length / 2);
1522
+ const left = items.slice(0, half);
1523
+ const right = items.slice(half);
1524
+ return /* @__PURE__ */ jsxs6("div", { className: "grid grid-cols-1 gap-x-10 md:grid-cols-2", children: [
1525
+ /* @__PURE__ */ jsx20("div", { className: "flex flex-col", children: left.map((item, i) => renderItem(item, i)) }),
1526
+ /* @__PURE__ */ jsx20("div", { className: "flex flex-col", children: right.map((item, i) => renderItem(item, half + i)) })
1527
+ ] });
1528
+ }
1529
+ return /* @__PURE__ */ jsx20(
1530
+ "div",
1531
+ {
1532
+ className: layout === "cards" ? "flex flex-col gap-3" : "flex flex-col divide-y divide-border border-b border-t border-border",
1533
+ children: items.map((item, index) => renderItem(item, index))
1534
+ }
1535
+ );
1536
+ })()
1537
+ ] }) });
1538
+ }
1539
+
1540
+ // src/blocks/faq/defaults.ts
1541
+ var faqDefaults = {
1542
+ title: "Frequently asked questions",
1543
+ headerAlignment: "left",
1544
+ items: [
1545
+ {
1546
+ id: generateUniqueId(),
1547
+ question: "What can I build with FrontLit?",
1548
+ answer: "A marketing website, articles, documentation, product updates, customer support, and email \u2014 all from one connected dashboard."
1549
+ },
1550
+ {
1551
+ id: generateUniqueId(),
1552
+ question: "Do I need to know how to code?",
1553
+ answer: "No. Every page is assembled from ready-made blocks like this one, and you can customize copy, media and layout without touching code."
1554
+ },
1555
+ {
1556
+ id: generateUniqueId(),
1557
+ question: "Can I use my own domain?",
1558
+ answer: "Yes, every FrontLit site can be connected to a custom domain in a few clicks."
1559
+ },
1560
+ {
1561
+ id: generateUniqueId(),
1562
+ question: "Is there a free plan?",
1563
+ answer: "Yes, you can get started for free and upgrade as your audience grows."
1564
+ }
1565
+ ]
1566
+ };
1567
+
1568
+ // src/blocks/pricing/widget.tsx
1569
+ import clsx7 from "clsx";
1570
+ import { NavLink as NavLink4 } from "./islands/nav-link.js";
1571
+ import { jsx as jsx21, jsxs as jsxs7 } from "react/jsx-runtime";
1572
+ function PricingWidget({
1573
+ settings: {
1574
+ title,
1575
+ titleLevel,
1576
+ titleSize,
1577
+ description,
1578
+ headerAlignment = "center",
1579
+ tiers,
1580
+ layout = "grid",
1581
+ cssId,
1582
+ maxWidth,
1583
+ verticalPadding,
1584
+ background
1585
+ },
1586
+ state: { theme }
1587
+ }) {
1588
+ const overriddenTheme = JSON.parse(JSON.stringify(theme.theme));
1589
+ overriddenTheme.structure.page.width = maxWidth || theme.theme.structure.page.width;
1590
+ overriddenTheme.structure.section.padding.y = verticalPadding || theme.theme.structure.section.padding.y;
1591
+ return /* @__PURE__ */ jsx21(Section, { theme: overriddenTheme, id: cssId, background, children: /* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-8", children: [
1592
+ /* @__PURE__ */ jsxs7(
1593
+ "div",
1594
+ {
1595
+ className: clsx7(
1596
+ "flex flex-col gap-4",
1597
+ headerAlignment === "center" ? "items-center text-center" : "items-start"
1598
+ ),
1599
+ children: [
1600
+ /* @__PURE__ */ jsx21(Header1, { theme: overriddenTheme, ...titleProps({ titleLevel, titleSize }), children: renderTitle(title, overriddenTheme) }),
1601
+ description && /* @__PURE__ */ jsx21(Subheader1, { theme: overriddenTheme, component: "span", children: /* @__PURE__ */ jsx21(TextRenderer, { json: description, theme: overriddenTheme }) })
1602
+ ]
1603
+ }
1604
+ ),
1605
+ tiers && tiers.length > 0 && /* @__PURE__ */ jsx21(
1606
+ "div",
1607
+ {
1608
+ className: layout === "stacked" ? "mx-auto flex w-full max-w-xl flex-col gap-6" : "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 items-stretch",
1609
+ children: tiers.map((tier, index) => /* @__PURE__ */ jsx21(
1610
+ PageCard,
1611
+ {
1612
+ theme: overriddenTheme,
1613
+ className: clsx7(
1614
+ tier.highlighted && "ring-2 ring-primary",
1615
+ layout === "highlight" && tier.highlighted && "relative z-10 shadow-xl md:-translate-y-3"
1616
+ ),
1617
+ children: /* @__PURE__ */ jsxs7(
1618
+ PageCardContent,
1619
+ {
1620
+ theme: overriddenTheme,
1621
+ className: "h-full flex flex-col gap-4",
1622
+ children: [
1623
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between gap-2", children: [
1624
+ /* @__PURE__ */ jsx21(Preheader, { theme: overriddenTheme, children: tier.name }),
1625
+ tier.highlighted && /* @__PURE__ */ jsx21(Badge2, { theme: overriddenTheme, children: "Most popular" })
1626
+ ] }),
1627
+ /* @__PURE__ */ jsx21(PageCardHeader, { theme: overriddenTheme, children: tier.price }),
1628
+ tier.description && /* @__PURE__ */ jsx21(Text1, { theme: overriddenTheme, children: tier.description }),
1629
+ tier.features && tier.features.length > 0 && /* @__PURE__ */ jsx21("div", { className: "grow flex flex-col gap-2", children: tier.features.map((feature, i) => /* @__PURE__ */ jsx21(Text2, { theme: overriddenTheme, children: feature }, i)) }),
1630
+ tier.buttonAction && tier.buttonCaption && /* @__PURE__ */ jsx21(NavLink4, { href: tier.buttonAction, className: "w-full mt-auto", children: /* @__PURE__ */ jsx21(
1631
+ Button2,
1632
+ {
1633
+ theme: overriddenTheme,
1634
+ variant: tier.highlighted ? "default" : "secondary",
1635
+ className: "w-full",
1636
+ children: tier.buttonCaption
1637
+ }
1638
+ ) })
1639
+ ]
1640
+ }
1641
+ )
1642
+ },
1643
+ index
1644
+ ))
1645
+ }
1646
+ )
1647
+ ] }) });
1648
+ }
1649
+
1650
+ // src/blocks/pricing/defaults.ts
1651
+ var pricingDefaults = {
1652
+ title: "Simple, transparent pricing",
1653
+ headerAlignment: "center",
1654
+ tiers: [
1655
+ {
1656
+ name: "Starter",
1657
+ price: "$0/mo",
1658
+ description: "For hobby sites and side projects.",
1659
+ features: ["1 website", "FrontLit branding", "Community support"],
1660
+ buttonCaption: "Get started",
1661
+ buttonAction: "/help"
1662
+ },
1663
+ {
1664
+ name: "Pro",
1665
+ price: "$29/mo",
1666
+ description: "For growing businesses that need more.",
1667
+ features: ["5 websites", "Custom domain", "Blog + Email", "Priority support"],
1668
+ buttonCaption: "Talk to us",
1669
+ buttonAction: "/help",
1670
+ highlighted: true
1671
+ },
1672
+ {
1673
+ name: "Business",
1674
+ price: "$79/mo",
1675
+ description: "For teams that need scale and control.",
1676
+ features: [
1677
+ "Unlimited websites",
1678
+ "Help desk & chatbot",
1679
+ "Team seats",
1680
+ "Dedicated support"
1681
+ ],
1682
+ buttonCaption: "Contact sales",
1683
+ buttonAction: "/help"
1684
+ }
1685
+ ]
1686
+ };
1687
+
1688
+ // src/blocks/banner/widget.tsx
1689
+ import clsx8 from "clsx";
1690
+ import { NavLink as NavLink5 } from "./islands/nav-link.js";
1691
+ import { Fragment as Fragment2, jsx as jsx22, jsxs as jsxs8 } from "react/jsx-runtime";
1692
+ function BannerWidget({
1693
+ settings: {
1694
+ title,
1695
+ titleLevel,
1696
+ titleSize,
1697
+ description,
1698
+ buttonCaption,
1699
+ buttonAction,
1700
+ secondaryButtonCaption,
1701
+ secondaryButtonAction,
1702
+ contentAlignment = "center",
1703
+ layout = "stacked",
1704
+ cssId,
1705
+ maxWidth,
1706
+ verticalPadding,
1707
+ background
1708
+ },
1709
+ state: { theme }
1710
+ }) {
1711
+ const overriddenTheme = JSON.parse(JSON.stringify(theme.theme));
1712
+ overriddenTheme.structure.page.width = maxWidth || theme.theme.structure.page.width;
1713
+ overriddenTheme.structure.section.padding.y = verticalPadding || theme.theme.structure.section.padding.y;
1714
+ const isCentered = contentAlignment === "center";
1715
+ const isSplit = layout === "split";
1716
+ const isBoxed = layout === "boxed";
1717
+ const heading = /* @__PURE__ */ jsxs8(Fragment2, { children: [
1718
+ /* @__PURE__ */ jsx22(Header1, { theme: overriddenTheme, ...titleProps({ titleLevel, titleSize }), children: renderTitle(title, overriddenTheme) }),
1719
+ description && /* @__PURE__ */ jsx22(Subheader1, { theme: overriddenTheme, component: "span", children: /* @__PURE__ */ jsx22(TextRenderer, { json: description, theme: overriddenTheme }) })
1720
+ ] });
1721
+ const buttons = (buttonAction || secondaryButtonAction) && /* @__PURE__ */ jsxs8(
1722
+ "div",
1723
+ {
1724
+ className: clsx8(
1725
+ "flex flex-col md:!flex-row gap-2 w-full md:w-auto",
1726
+ isSplit ? "shrink-0" : "mt-2",
1727
+ !isSplit && isCentered ? "md:!justify-center" : ""
1728
+ ),
1729
+ children: [
1730
+ buttonAction && buttonCaption && /* @__PURE__ */ jsx22(NavLink5, { href: buttonAction, children: /* @__PURE__ */ jsx22(Button2, { theme: overriddenTheme, className: "w-full md:min-w-[150px]", children: buttonCaption }) }),
1731
+ secondaryButtonAction && secondaryButtonCaption && /* @__PURE__ */ jsx22(NavLink5, { href: secondaryButtonAction, children: /* @__PURE__ */ jsx22(
1732
+ Button2,
1733
+ {
1734
+ theme: overriddenTheme,
1735
+ variant: "secondary",
1736
+ className: "w-full md:min-w-[150px]",
1737
+ children: secondaryButtonCaption
1738
+ }
1739
+ ) })
1740
+ ]
1741
+ }
1742
+ );
1743
+ const content = isSplit ? /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-6 md:!flex-row md:items-center md:justify-between", children: [
1744
+ /* @__PURE__ */ jsx22("div", { className: "flex flex-col items-start gap-4", children: heading }),
1745
+ buttons
1746
+ ] }) : /* @__PURE__ */ jsxs8(
1747
+ "div",
1748
+ {
1749
+ className: clsx8(
1750
+ "flex flex-col gap-4",
1751
+ isCentered ? "items-center text-center" : "items-start"
1752
+ ),
1753
+ children: [
1754
+ heading,
1755
+ buttons
1756
+ ]
1757
+ }
1758
+ );
1759
+ return /* @__PURE__ */ jsx22(Section, { theme: overriddenTheme, id: cssId, background, children: isBoxed ? /* @__PURE__ */ jsx22(PageCard, { theme: overriddenTheme, className: "mx-auto max-w-3xl", children: /* @__PURE__ */ jsx22(
1760
+ PageCardContent,
1761
+ {
1762
+ theme: overriddenTheme,
1763
+ className: "items-center p-8 text-center md:p-12",
1764
+ children: content
1765
+ }
1766
+ ) }) : content });
1767
+ }
1768
+
1769
+ // src/blocks/banner/defaults.ts
1770
+ var bannerDefaults = {
1771
+ title: "Ready to launch your site?",
1772
+ buttonCaption: "Contact us",
1773
+ buttonAction: "/help",
1774
+ secondaryButtonCaption: "Read the docs",
1775
+ secondaryButtonAction: "/docs",
1776
+ contentAlignment: "center"
1777
+ };
1778
+
1779
+ // src/blocks/email-form/widget.tsx
1780
+ import clsx9 from "clsx";
1781
+ import { EmailForm } from "./islands/email-form.js";
1782
+ import { jsx as jsx23, jsxs as jsxs9 } from "react/jsx-runtime";
1783
+ function EmailFormWidget({
1784
+ settings: {
1785
+ title,
1786
+ titleLevel,
1787
+ titleSize,
1788
+ description,
1789
+ buttonCaption = "Subscribe",
1790
+ successMessage = "Thanks for subscribing!",
1791
+ alignment = "left",
1792
+ layout = "stacked",
1793
+ cssId,
1794
+ maxWidth,
1795
+ verticalPadding,
1796
+ background
1797
+ },
1798
+ state: { theme },
1799
+ pageData,
1800
+ editing
1801
+ }) {
1802
+ const overriddenTheme = JSON.parse(JSON.stringify(theme.theme));
1803
+ overriddenTheme.structure.page.width = maxWidth || theme.theme.structure.page.width;
1804
+ overriddenTheme.structure.section.padding.y = verticalPadding || theme.theme.structure.section.padding.y;
1805
+ const descriptionNode = description && /* @__PURE__ */ jsx23(Subheader1, { theme: overriddenTheme, component: "span", children: /* @__PURE__ */ jsx23(TextRenderer, { json: description, theme: overriddenTheme }) });
1806
+ const heading = layout === "inline" ? /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-1", children: [
1807
+ /* @__PURE__ */ jsx23(
1808
+ Header1,
1809
+ {
1810
+ theme: overriddenTheme,
1811
+ ...titleProps({ titleLevel, titleSize }, "h2", "text-xl"),
1812
+ children: renderTitle(title, overriddenTheme)
1813
+ }
1814
+ ),
1815
+ descriptionNode
1816
+ ] }) : /* @__PURE__ */ jsxs9(
1817
+ "div",
1818
+ {
1819
+ className: clsx9(
1820
+ "flex flex-col gap-4",
1821
+ layout === "split" ? "items-start" : "contents"
1822
+ ),
1823
+ children: [
1824
+ /* @__PURE__ */ jsx23(Header1, { theme: overriddenTheme, ...titleProps({ titleLevel, titleSize }), children: renderTitle(title, overriddenTheme) }),
1825
+ descriptionNode
1826
+ ]
1827
+ }
1828
+ );
1829
+ return /* @__PURE__ */ jsx23(Section, { theme: overriddenTheme, id: cssId, background, children: /* @__PURE__ */ jsx23(
1830
+ EmailForm,
1831
+ {
1832
+ theme: overriddenTheme,
1833
+ layout,
1834
+ alignment,
1835
+ buttonCaption,
1836
+ successMessage,
1837
+ pageData,
1838
+ editing,
1839
+ heading
1840
+ }
1841
+ ) });
1842
+ }
1843
+
1844
+ // src/blocks/email-form/defaults.ts
1845
+ var emailFormDefaults = {
1846
+ title: "Get product updates in your inbox",
1847
+ buttonCaption: "Subscribe",
1848
+ successMessage: "Thanks for subscribing! Check your inbox soon.",
1849
+ alignment: "left"
1850
+ };
1851
+
1852
+ // src/blocks/support-form/widget.tsx
1853
+ import clsx10 from "clsx";
1854
+ import { SupportForm } from "./islands/support-form.js";
1855
+ import { jsx as jsx24, jsxs as jsxs10 } from "react/jsx-runtime";
1856
+ function SupportFormWidget({
1857
+ settings: {
1858
+ title,
1859
+ titleLevel,
1860
+ titleSize,
1861
+ description,
1862
+ buttonCaption = "Submit ticket",
1863
+ successMessage = "Thanks \u2014 we've got your ticket and will reply by email soon.",
1864
+ alignment = "left",
1865
+ cssId,
1866
+ maxWidth,
1867
+ verticalPadding,
1868
+ background
1869
+ },
1870
+ state: { theme },
1871
+ pageData,
1872
+ editing
1873
+ }) {
1874
+ const overriddenTheme = JSON.parse(JSON.stringify(theme.theme));
1875
+ overriddenTheme.structure.page.width = maxWidth || theme.theme.structure.page.width;
1876
+ overriddenTheme.structure.section.padding.y = verticalPadding || theme.theme.structure.section.padding.y;
1877
+ const isCentered = alignment === "center";
1878
+ return /* @__PURE__ */ jsxs10(Section, { theme: overriddenTheme, id: cssId, background, children: [
1879
+ /* @__PURE__ */ jsxs10(
1880
+ "div",
1881
+ {
1882
+ className: clsx10(
1883
+ "flex flex-col gap-4",
1884
+ isCentered ? "items-center text-center" : "items-start"
1885
+ ),
1886
+ children: [
1887
+ /* @__PURE__ */ jsx24(Header1, { theme: overriddenTheme, ...titleProps({ titleLevel, titleSize }), children: renderTitle(title, overriddenTheme) }),
1888
+ description && /* @__PURE__ */ jsx24(Subheader1, { theme: overriddenTheme, component: "span", children: /* @__PURE__ */ jsx24(TextRenderer, { json: description, theme: overriddenTheme }) })
1889
+ ]
1890
+ }
1891
+ ),
1892
+ /* @__PURE__ */ jsx24(
1893
+ SupportForm,
1894
+ {
1895
+ theme: overriddenTheme,
1896
+ buttonCaption,
1897
+ successMessage,
1898
+ pageData,
1899
+ editing
1900
+ }
1901
+ )
1902
+ ] });
1903
+ }
1904
+
1905
+ // src/blocks/support-form/defaults.ts
1906
+ var supportFormDefaults = {
1907
+ title: "Need help?",
1908
+ buttonCaption: "Submit ticket",
1909
+ successMessage: "Thanks \u2014 we've got your ticket and will reply by email soon.",
1910
+ alignment: "left"
1911
+ };
1912
+
1913
+ // src/blocks/footer/widget.tsx
1914
+ import { NavLink as NavLink6 } from "./islands/nav-link.js";
1915
+ import { jsx as jsx25, jsxs as jsxs11 } from "react/jsx-runtime";
1916
+ function FooterWidget({
1917
+ settings: {
1918
+ tagline: ownTagline,
1919
+ columns = [],
1920
+ copyrightText,
1921
+ layout = "columns",
1922
+ showThemeSwitcher = true,
1923
+ cssId,
1924
+ maxWidth,
1925
+ verticalPadding,
1926
+ background
1927
+ },
1928
+ state: { theme },
1929
+ pageData,
1930
+ themeSwitcher
1931
+ }) {
1932
+ const logoText = pageData.siteTitle;
1933
+ const tagline = ownTagline || pageData.siteSubtitle;
1934
+ const overriddenTheme = JSON.parse(JSON.stringify(theme.theme));
1935
+ overriddenTheme.structure.page.width = maxWidth || theme.theme.structure.page.width;
1936
+ overriddenTheme.structure.section.padding.y = verticalPadding || theme.theme.structure.section.padding.y;
1937
+ const colorModeControl = showThemeSwitcher ? themeSwitcher : null;
1938
+ return /* @__PURE__ */ jsxs11(
1939
+ Section,
1940
+ {
1941
+ theme: overriddenTheme,
1942
+ component: "footer",
1943
+ id: cssId,
1944
+ background,
1945
+ className: "border-t",
1946
+ children: [
1947
+ layout === "minimal" ? /* @__PURE__ */ jsxs11("div", { className: "flex w-full flex-wrap items-center justify-between gap-4", children: [
1948
+ logoText && /* @__PURE__ */ jsx25(Header4, { theme: overriddenTheme, as: "p", children: logoText }),
1949
+ /* @__PURE__ */ jsxs11("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-2", children: [
1950
+ columns.flatMap(
1951
+ (column) => column.links.map((link) => /* @__PURE__ */ jsx25(
1952
+ NavLink6,
1953
+ {
1954
+ href: link.href,
1955
+ className: "no-underline",
1956
+ children: /* @__PURE__ */ jsx25(Link, { theme: overriddenTheme, className: "text-xs", children: link.label })
1957
+ },
1958
+ `${column.id}-${link.id}`
1959
+ ))
1960
+ ),
1961
+ copyrightText && /* @__PURE__ */ jsx25(Caption, { theme: overriddenTheme, children: copyrightText }),
1962
+ colorModeControl
1963
+ ] })
1964
+ ] }) : layout === "centered" ? /* @__PURE__ */ jsxs11("div", { className: "flex w-full flex-col items-center gap-6 text-center", children: [
1965
+ /* @__PURE__ */ jsxs11("div", { className: "flex max-w-sm flex-col items-center gap-3", children: [
1966
+ logoText && /* @__PURE__ */ jsx25(Header3, { theme: overriddenTheme, as: "p", children: logoText }),
1967
+ tagline && /* @__PURE__ */ jsx25(Text2, { theme: overriddenTheme, children: tagline })
1968
+ ] }),
1969
+ /* @__PURE__ */ jsx25("div", { className: "flex flex-wrap justify-center gap-x-6 gap-y-2", children: columns.flatMap(
1970
+ (column) => column.links.map((link) => /* @__PURE__ */ jsx25(
1971
+ NavLink6,
1972
+ {
1973
+ href: link.href,
1974
+ className: "no-underline",
1975
+ children: /* @__PURE__ */ jsx25(Link, { theme: overriddenTheme, className: "text-xs", children: link.label })
1976
+ },
1977
+ `${column.id}-${link.id}`
1978
+ ))
1979
+ ) })
1980
+ ] }) : /* @__PURE__ */ jsxs11("div", { className: "flex w-full flex-col gap-8 lg:!flex-row lg:justify-between", children: [
1981
+ /* @__PURE__ */ jsxs11("div", { className: "flex max-w-sm flex-col gap-3", children: [
1982
+ logoText && /* @__PURE__ */ jsx25(Header3, { theme: overriddenTheme, as: "p", children: logoText }),
1983
+ tagline && /* @__PURE__ */ jsx25(Text2, { theme: overriddenTheme, children: tagline })
1984
+ ] }),
1985
+ /* @__PURE__ */ jsx25("div", { className: "flex flex-col flex-wrap gap-8 lg:!flex-row", children: columns.map((column) => /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-3 lg:min-w-[140px]", children: [
1986
+ /* @__PURE__ */ jsx25(Header4, { theme: overriddenTheme, className: "text-sm", children: column.title }),
1987
+ /* @__PURE__ */ jsx25("div", { className: "flex flex-col gap-2", children: column.links.map((link) => /* @__PURE__ */ jsx25(NavLink6, { href: link.href, className: "no-underline", children: /* @__PURE__ */ jsx25(Link, { theme: overriddenTheme, className: "text-xs", children: link.label }) }, link.id)) })
1988
+ ] }, column.id)) })
1989
+ ] }),
1990
+ (copyrightText || colorModeControl) && layout !== "minimal" && /* @__PURE__ */ jsxs11(
1991
+ "div",
1992
+ {
1993
+ className: layout === "centered" ? "mt-8 flex flex-col items-center gap-4 border-t pt-6 text-center" : "mt-8 flex items-center justify-between gap-4 border-t pt-6",
1994
+ children: [
1995
+ copyrightText && /* @__PURE__ */ jsx25(Caption, { theme: overriddenTheme, children: copyrightText }),
1996
+ colorModeControl && /* @__PURE__ */ jsx25("div", { className: layout === "centered" ? void 0 : "ml-auto", children: colorModeControl })
1997
+ ]
1998
+ }
1999
+ )
2000
+ ]
2001
+ }
2002
+ );
2003
+ }
2004
+
2005
+ // src/blocks/footer/defaults.ts
2006
+ var footerDefaults = {
2007
+ showThemeSwitcher: true,
2008
+ columns: [
2009
+ {
2010
+ id: generateUniqueId(),
2011
+ title: "Product",
2012
+ links: [
2013
+ {
2014
+ id: generateUniqueId(),
2015
+ label: "Features",
2016
+ href: "/#features"
2017
+ },
2018
+ { id: generateUniqueId(), label: "Pricing", href: "/#pricing" },
2019
+ {
2020
+ id: generateUniqueId(),
2021
+ label: "Changelog",
2022
+ href: "/changelog"
2023
+ }
2024
+ ]
2025
+ },
2026
+ {
2027
+ id: generateUniqueId(),
2028
+ title: "Resources",
2029
+ links: [
2030
+ { id: generateUniqueId(), label: "Blog", href: "/blog" },
2031
+ { id: generateUniqueId(), label: "Help center", href: "/help" },
2032
+ { id: generateUniqueId(), label: "Docs", href: "/docs" }
2033
+ ]
2034
+ },
2035
+ {
2036
+ id: generateUniqueId(),
2037
+ title: "Legal",
2038
+ links: [
2039
+ {
2040
+ id: generateUniqueId(),
2041
+ label: "Terms of use",
2042
+ href: "/terms"
2043
+ },
2044
+ {
2045
+ id: generateUniqueId(),
2046
+ label: "Privacy policy",
2047
+ href: "/privacy"
2048
+ }
2049
+ ]
2050
+ }
2051
+ ],
2052
+ copyrightText: "\xA9 FrontLit. All rights reserved."
2053
+ };
2054
+
2055
+ // src/blocks/rich-text/widget.tsx
2056
+ import { jsx as jsx26 } from "react/jsx-runtime";
2057
+ function RichTextWidget({
2058
+ settings: { text, alignment = "left", cssId, maxWidth, verticalPadding, background },
2059
+ state: { theme }
2060
+ }) {
2061
+ const overriddenTheme = JSON.parse(JSON.stringify(theme.theme));
2062
+ overriddenTheme.structure.page.width = maxWidth || theme.theme.structure.page.width;
2063
+ overriddenTheme.structure.section.padding.y = verticalPadding || theme.theme.structure.section.padding.y;
2064
+ if (!text) return null;
2065
+ return /* @__PURE__ */ jsx26(Section, { theme: overriddenTheme, id: cssId, background, children: /* @__PURE__ */ jsx26("div", { style: { textAlign: alignment }, children: /* @__PURE__ */ jsx26(Text1, { theme: overriddenTheme, component: "span", children: /* @__PURE__ */ jsx26(TextRenderer, { json: text, theme: overriddenTheme }) }) }) });
2066
+ }
2067
+
2068
+ // src/blocks/rich-text/defaults.ts
2069
+ var richTextDefaults = {
2070
+ text: {
2071
+ type: "doc",
2072
+ content: [
2073
+ {
2074
+ type: "paragraph",
2075
+ content: [
2076
+ {
2077
+ type: "text",
2078
+ text: "Write anything here \u2014 an announcement, a longer explanation, or a passage of prose that doesn't need a title or media."
2079
+ }
2080
+ ]
2081
+ }
2082
+ ]
2083
+ },
2084
+ alignment: "left"
2085
+ };
2086
+
2087
+ // src/blocks/grid/widget.tsx
2088
+ import clsx11 from "clsx";
2089
+ import * as Icons2 from "lucide-react";
2090
+ import { NavLink as NavLink7 } from "./islands/nav-link.js";
2091
+ import { Fragment as Fragment3, jsx as jsx27, jsxs as jsxs12 } from "react/jsx-runtime";
2092
+ function resolveIcon2(name) {
2093
+ if (!name) return null;
2094
+ return Icons2[name] ?? null;
2095
+ }
2096
+ function GridItemCard({ item, theme }) {
2097
+ const Icon = resolveIcon2(item.icon);
2098
+ const mediaUrl = getMediaUrl(item.media);
2099
+ const mediaAlt = getMediaAlt(item.media);
2100
+ const hasMedia = Boolean(mediaUrl);
2101
+ const isOverlay = item.mediaAlignment === "overlay";
2102
+ const mediaFirst = item.mediaAlignment !== "bottom";
2103
+ if (isOverlay) {
2104
+ const card = /* @__PURE__ */ jsx27(PageCard, { theme, isLink: Boolean(item.buttonAction), children: /* @__PURE__ */ jsxs12("div", { className: "relative aspect-[4/5] w-full overflow-hidden", children: [
2105
+ hasMedia && /* @__PURE__ */ jsx27(
2106
+ Image,
2107
+ {
2108
+ src: mediaUrl || "",
2109
+ alt: mediaAlt,
2110
+ className: "absolute inset-0",
2111
+ width: "w-full",
2112
+ height: "h-full",
2113
+ objectFit: "cover",
2114
+ borderRadius: 0
2115
+ }
2116
+ ),
2117
+ /* @__PURE__ */ jsx27("div", { className: "absolute inset-0 bg-gradient-to-t from-black/70 via-black/10 to-transparent" }),
2118
+ /* @__PURE__ */ jsx27("div", { className: "absolute inset-x-0 bottom-0 p-4", children: /* @__PURE__ */ jsx27(Header4, { theme, className: "text-white", children: item.title }) })
2119
+ ] }) });
2120
+ return item.buttonAction ? /* @__PURE__ */ jsx27(NavLink7, { href: item.buttonAction, className: "block", children: card }) : card;
2121
+ }
2122
+ const media = hasMedia ? /* @__PURE__ */ jsx27("div", { className: "overflow-hidden rounded-md", children: /* @__PURE__ */ jsx27(Image, { src: mediaUrl || "", alt: mediaAlt }) }) : Icon ? /* @__PURE__ */ jsx27("div", { className: "flex h-10 w-10 items-center justify-center rounded-md bg-primary/10 text-primary", children: /* @__PURE__ */ jsx27(Icon, { className: "h-5 w-5" }) }) : null;
2123
+ const text = /* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-2", children: [
2124
+ /* @__PURE__ */ jsx27(Header4, { theme, children: item.title }),
2125
+ item.description && /* @__PURE__ */ jsx27(Text2, { theme, children: item.description }),
2126
+ item.buttonAction && item.buttonCaption && /* @__PURE__ */ jsx27(NavLink7, { href: item.buttonAction, className: "mt-2", children: /* @__PURE__ */ jsx27(Button2, { theme, variant: "secondary", size: "sm", children: item.buttonCaption }) })
2127
+ ] });
2128
+ return /* @__PURE__ */ jsx27(PageCard, { theme, children: /* @__PURE__ */ jsx27(PageCardContent, { theme, className: "flex h-full flex-col gap-3", children: mediaFirst ? /* @__PURE__ */ jsxs12(Fragment3, { children: [
2129
+ media,
2130
+ text
2131
+ ] }) : /* @__PURE__ */ jsxs12(Fragment3, { children: [
2132
+ text,
2133
+ media
2134
+ ] }) }) });
2135
+ }
2136
+ function GridWidget({
2137
+ settings: {
2138
+ title,
2139
+ titleLevel,
2140
+ titleSize,
2141
+ description,
2142
+ headerAlignment = "center",
2143
+ buttonCaption,
2144
+ buttonAction,
2145
+ items,
2146
+ columns = 3,
2147
+ cssId,
2148
+ maxWidth,
2149
+ verticalPadding,
2150
+ background
2151
+ },
2152
+ state: { theme }
2153
+ }) {
2154
+ const overriddenTheme = JSON.parse(JSON.stringify(theme.theme));
2155
+ overriddenTheme.structure.page.width = maxWidth || theme.theme.structure.page.width;
2156
+ overriddenTheme.structure.section.padding.y = verticalPadding || theme.theme.structure.section.padding.y;
2157
+ return /* @__PURE__ */ jsx27(Section, { theme: overriddenTheme, id: cssId, background, children: /* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-8", children: [
2158
+ /* @__PURE__ */ jsxs12(
2159
+ "div",
2160
+ {
2161
+ className: clsx11(
2162
+ "flex flex-col gap-4",
2163
+ headerAlignment === "center" ? "items-center text-center" : "items-start"
2164
+ ),
2165
+ children: [
2166
+ /* @__PURE__ */ jsx27(Header1, { theme: overriddenTheme, ...titleProps({ titleLevel, titleSize }), children: renderTitle(title, overriddenTheme) }),
2167
+ description && /* @__PURE__ */ jsx27(Subheader1, { theme: overriddenTheme, component: "span", children: /* @__PURE__ */ jsx27(TextRenderer, { json: description, theme: overriddenTheme }) }),
2168
+ buttonAction && buttonCaption && /* @__PURE__ */ jsx27(NavLink7, { href: buttonAction, className: "mt-2", children: /* @__PURE__ */ jsx27(Button2, { theme: overriddenTheme, children: buttonCaption }) })
2169
+ ]
2170
+ }
2171
+ ),
2172
+ items && items.length > 0 && /* @__PURE__ */ jsx27(
2173
+ "div",
2174
+ {
2175
+ className: clsx11(
2176
+ "grid grid-cols-1 md:grid-cols-2 gap-6 items-stretch",
2177
+ columns === 3 ? "lg:grid-cols-3" : "lg:grid-cols-2"
2178
+ ),
2179
+ children: items.map((item, index) => /* @__PURE__ */ jsx27(GridItemCard, { item, theme: overriddenTheme }, index))
2180
+ }
2181
+ )
2182
+ ] }) });
2183
+ }
2184
+
2185
+ // src/blocks/grid/defaults.ts
2186
+ var gridDefaults = {
2187
+ title: "Everything you need, in one place",
2188
+ headerAlignment: "center",
2189
+ columns: 3,
2190
+ items: [
2191
+ {
2192
+ title: "Website builder",
2193
+ description: "Design and publish pages with a drag-and-drop editor.",
2194
+ icon: "LayoutTemplate",
2195
+ mediaAlignment: "top",
2196
+ buttonCaption: "See features",
2197
+ buttonAction: "/#features"
2198
+ },
2199
+ {
2200
+ title: "Blog",
2201
+ description: "Publish articles and grow your audience.",
2202
+ icon: "Newspaper",
2203
+ mediaAlignment: "top",
2204
+ buttonCaption: "Read articles",
2205
+ buttonAction: "/blog"
2206
+ },
2207
+ {
2208
+ title: "Help desk",
2209
+ description: "Support your customers with a shared inbox.",
2210
+ icon: "Headset",
2211
+ mediaAlignment: "top",
2212
+ buttonCaption: "Contact us",
2213
+ buttonAction: "/help"
2214
+ }
2215
+ ]
2216
+ };
2217
+
2218
+ // src/blocks/media/widget.tsx
2219
+ import { VideoWithPreview as VideoWithPreview2 } from "./islands/video-with-preview.js";
2220
+ import { jsx as jsx28 } from "react/jsx-runtime";
2221
+ var roundedMap4 = {
2222
+ 0: "rounded-none",
2223
+ 1: "rounded-sm",
2224
+ 2: "rounded",
2225
+ 3: "rounded-md",
2226
+ 4: "rounded-lg",
2227
+ 5: "rounded-xl",
2228
+ 6: "rounded-2xl",
2229
+ 7: "rounded-3xl",
2230
+ 8: "rounded-full"
2231
+ };
2232
+ function MediaWidget({
2233
+ settings: {
2234
+ media,
2235
+ youtubeLink,
2236
+ mediaRadius = 2,
2237
+ aspectRatio = "16/9",
2238
+ objectFit = "cover",
2239
+ hasBorder = true,
2240
+ playVideoInModal = false,
2241
+ cssId,
2242
+ maxWidth,
2243
+ verticalPadding,
2244
+ background
2245
+ },
2246
+ state: { theme }
2247
+ }) {
2248
+ const overriddenTheme = JSON.parse(JSON.stringify(theme.theme));
2249
+ overriddenTheme.structure.page.width = maxWidth || theme.theme.structure.page.width;
2250
+ overriddenTheme.structure.section.padding.y = verticalPadding || theme.theme.structure.section.padding.y;
2251
+ const isVideoContent = isVideo(youtubeLink, media);
2252
+ return /* @__PURE__ */ jsx28(Section, { theme: overriddenTheme, id: cssId, background, children: /* @__PURE__ */ jsx28(
2253
+ "div",
2254
+ {
2255
+ className: cn(
2256
+ "overflow-hidden",
2257
+ roundedMap4[mediaRadius] ?? "rounded",
2258
+ hasBorder && (overriddenTheme.interactives?.card?.border?.width || "border")
2259
+ ),
2260
+ children: isVideoContent ? /* @__PURE__ */ jsx28(
2261
+ VideoWithPreview2,
2262
+ {
2263
+ videoUrl: youtubeLink || getMediaUrl(media) || "",
2264
+ title: getMediaAlt(media) || media?.caption || "",
2265
+ thumbnailUrl: media?.thumbnail || media?.thumbnailUrl || "",
2266
+ aspectRatio,
2267
+ modal: playVideoInModal
2268
+ }
2269
+ ) : /* @__PURE__ */ jsx28(
2270
+ Image,
2271
+ {
2272
+ src: getMediaUrl(media) || "",
2273
+ alt: getMediaAlt(media),
2274
+ objectFit,
2275
+ borderRadius: mediaRadius
2276
+ }
2277
+ )
2278
+ }
2279
+ ) });
2280
+ }
2281
+
2282
+ // src/blocks/media/defaults.ts
2283
+ var mediaDefaults = {
2284
+ mediaRadius: 2,
2285
+ aspectRatio: "16/9",
2286
+ objectFit: "cover",
2287
+ hasBorder: true,
2288
+ playVideoInModal: false
2289
+ };
2290
+
2291
+ // src/blocks/marquee/widget.tsx
2292
+ import React5 from "react";
2293
+ import * as Icons3 from "lucide-react";
2294
+ import { NavLink as NavLink8 } from "./islands/nav-link.js";
2295
+ import { MarqueeTrack } from "./islands/marquee-track.js";
2296
+ import { Fragment as Fragment4, jsx as jsx29, jsxs as jsxs13 } from "react/jsx-runtime";
2297
+ function resolveIcon3(name) {
2298
+ if (!name) return null;
2299
+ return Icons3[name] ?? null;
2300
+ }
2301
+ function MarqueeWidget({
2302
+ settings: {
2303
+ items = [],
2304
+ direction = "right",
2305
+ speed = 60,
2306
+ pauseOnHover = true,
2307
+ fadeWidth = 50,
2308
+ itemBackgroundColor,
2309
+ itemForegroundColor,
2310
+ itemBorderColor,
2311
+ itemBorderRadius = 12,
2312
+ itemBorderWidth = 1,
2313
+ itemBorderStyle = "solid",
2314
+ cssId,
2315
+ maxWidth,
2316
+ verticalPadding,
2317
+ background
2318
+ },
2319
+ state: { theme }
2320
+ }) {
2321
+ const overriddenTheme = JSON.parse(JSON.stringify(theme.theme));
2322
+ overriddenTheme.structure.page.width = maxWidth || theme.theme.structure.page.width;
2323
+ overriddenTheme.structure.section.padding.y = verticalPadding || theme.theme.structure.section.padding.y;
2324
+ if (items.length === 0) return null;
2325
+ const itemStyle = {
2326
+ backgroundColor: itemBackgroundColor || void 0,
2327
+ color: itemForegroundColor || void 0,
2328
+ borderColor: itemBorderColor || void 0,
2329
+ borderRadius: itemBorderRadius,
2330
+ borderWidth: itemBorderStyle === "none" ? 0 : itemBorderWidth,
2331
+ borderStyle: itemBorderStyle === "none" ? void 0 : itemBorderStyle
2332
+ };
2333
+ const renderItem = (item) => {
2334
+ const Icon = resolveIcon3(item.icon);
2335
+ const content = /* @__PURE__ */ jsx29(
2336
+ "div",
2337
+ {
2338
+ className: "mx-2 flex min-h-[80px] min-w-[160px] items-center justify-center px-6",
2339
+ style: itemStyle,
2340
+ children: Icon ? /* @__PURE__ */ jsx29(Icon, { className: "h-8 w-8" }) : /* @__PURE__ */ jsx29("span", { className: "whitespace-nowrap text-sm font-medium", children: item.text })
2341
+ }
2342
+ );
2343
+ return item.href ? /* @__PURE__ */ jsx29(NavLink8, { href: item.href, openInSameTab: false, children: content }, item.id) : /* @__PURE__ */ jsx29(React5.Fragment, { children: content }, item.id);
2344
+ };
2345
+ return /* @__PURE__ */ jsx29(Section, { theme: overriddenTheme, id: cssId, background, children: /* @__PURE__ */ jsxs13("div", { className: "relative", "aria-hidden": "true", children: [
2346
+ /* @__PURE__ */ jsx29(MarqueeTrack, { speed, direction, pauseOnHover, children: items.map(renderItem) }),
2347
+ fadeWidth > 0 && /* @__PURE__ */ jsxs13(Fragment4, { children: [
2348
+ /* @__PURE__ */ jsx29(
2349
+ "div",
2350
+ {
2351
+ className: "pointer-events-none absolute inset-y-0 left-0 z-10",
2352
+ style: {
2353
+ width: fadeWidth,
2354
+ background: "linear-gradient(to right, var(--background), transparent)"
2355
+ }
2356
+ }
2357
+ ),
2358
+ /* @__PURE__ */ jsx29(
2359
+ "div",
2360
+ {
2361
+ className: "pointer-events-none absolute inset-y-0 right-0 z-10",
2362
+ style: {
2363
+ width: fadeWidth,
2364
+ background: "linear-gradient(to left, var(--background), transparent)"
2365
+ }
2366
+ }
2367
+ )
2368
+ ] })
2369
+ ] }) });
2370
+ }
2371
+
2372
+ // src/blocks/marquee/defaults.ts
2373
+ var marqueeDefaults = {
2374
+ items: [
2375
+ { id: generateUniqueId(), text: "Website" },
2376
+ { id: generateUniqueId(), text: "Content" },
2377
+ { id: generateUniqueId(), text: "Support" },
2378
+ { id: generateUniqueId(), text: "Engage" }
2379
+ ],
2380
+ direction: "right",
2381
+ speed: 60,
2382
+ pauseOnHover: true,
2383
+ fadeWidth: 50,
2384
+ itemForegroundColor: "",
2385
+ itemBackgroundColor: "",
2386
+ itemBorderColor: "",
2387
+ itemBorderRadius: 12,
2388
+ itemBorderWidth: 1,
2389
+ itemBorderStyle: "solid"
2390
+ };
2391
+
2392
+ // src/blocks/embed/widget.tsx
2393
+ import { Code2 } from "lucide-react";
2394
+ import { InlineEmbed } from "./islands/inline-embed.js";
2395
+ import { jsx as jsx30, jsxs as jsxs14 } from "react/jsx-runtime";
2396
+ var aspectRatioMap = {
2397
+ "16:9": 16 / 9,
2398
+ "4:3": 4 / 3,
2399
+ "1:1": 1
2400
+ };
2401
+ function EmbedWidget({
2402
+ settings: {
2403
+ contentType = "url",
2404
+ content,
2405
+ aspectRatio = "default",
2406
+ height = 500,
2407
+ cssId,
2408
+ maxWidth,
2409
+ verticalPadding,
2410
+ background
2411
+ },
2412
+ state: { theme },
2413
+ editing
2414
+ }) {
2415
+ const overriddenTheme = JSON.parse(JSON.stringify(theme.theme));
2416
+ overriddenTheme.structure.page.width = maxWidth || theme.theme.structure.page.width;
2417
+ overriddenTheme.structure.section.padding.y = verticalPadding || theme.theme.structure.section.padding.y;
2418
+ if (!content) {
2419
+ if (!editing) return null;
2420
+ return /* @__PURE__ */ jsx30(Section, { theme: overriddenTheme, id: cssId, background, children: /* @__PURE__ */ jsxs14("div", { className: "flex min-h-48 flex-col items-center justify-center gap-3 rounded-lg border border-dashed border-border bg-muted/30 px-6 py-12 text-center", children: [
2421
+ /* @__PURE__ */ jsx30("span", { className: "flex h-10 w-10 items-center justify-center rounded-full border border-border bg-background text-muted-foreground", children: /* @__PURE__ */ jsx30(Code2, { className: "h-4 w-4" }) }),
2422
+ /* @__PURE__ */ jsxs14("div", { children: [
2423
+ /* @__PURE__ */ jsx30("p", { className: "font-semibold text-foreground", children: "Embed external content" }),
2424
+ /* @__PURE__ */ jsx30("p", { className: "mt-1 max-w-md text-sm text-muted-foreground", children: "Paste an embed URL or script snippet in the block settings." })
2425
+ ] })
2426
+ ] }) });
2427
+ }
2428
+ const isScript = contentType === "script";
2429
+ const ratio = aspectRatio !== "default" ? aspectRatioMap[aspectRatio] : void 0;
2430
+ const containerStyle = ratio ? { position: "relative", paddingTop: `${100 / ratio}%` } : { position: "relative", height: isScript ? void 0 : height };
2431
+ const fillStyle = ratio ? { position: "absolute", inset: 0, width: "100%", height: "100%" } : { width: "100%", height: "100%" };
2432
+ return /* @__PURE__ */ jsx30(Section, { theme: overriddenTheme, id: cssId, background, children: /* @__PURE__ */ jsxs14("div", { style: containerStyle, children: [
2433
+ isScript ? /* @__PURE__ */ jsx30(InlineEmbed, { content, style: ratio ? fillStyle : void 0 }) : /* @__PURE__ */ jsx30(
2434
+ "iframe",
2435
+ {
2436
+ src: content,
2437
+ style: fillStyle,
2438
+ allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",
2439
+ allowFullScreen: true,
2440
+ title: "Embedded content"
2441
+ }
2442
+ ),
2443
+ editing && /* @__PURE__ */ jsx30("div", { className: "absolute inset-0" })
2444
+ ] }) });
2445
+ }
2446
+
2447
+ // src/blocks/embed/defaults.ts
2448
+ var embedDefaults = {
2449
+ contentType: "url",
2450
+ content: "",
2451
+ aspectRatio: "default",
2452
+ height: 500
2453
+ };
2454
+
2455
+ // src/blocks/code-snippet/widget.tsx
2456
+ import clsx12 from "clsx";
2457
+ import { CodeSnippet as CodeSnippet2 } from "./islands/code-snippet.js";
2458
+ import { jsx as jsx31, jsxs as jsxs15 } from "react/jsx-runtime";
2459
+ function CodeSnippetWidget({
2460
+ settings: {
2461
+ code,
2462
+ showPrompt = true,
2463
+ caption,
2464
+ contentAlignment = "center",
2465
+ cssId,
2466
+ maxWidth,
2467
+ verticalPadding,
2468
+ background
2469
+ },
2470
+ state: { theme }
2471
+ }) {
2472
+ const overriddenTheme = JSON.parse(JSON.stringify(theme.theme));
2473
+ overriddenTheme.structure.page.width = maxWidth || theme.theme.structure.page.width;
2474
+ overriddenTheme.structure.section.padding.y = verticalPadding || theme.theme.structure.section.padding.y;
2475
+ if (!code) return null;
2476
+ return /* @__PURE__ */ jsx31(Section, { theme: overriddenTheme, id: cssId, background, children: /* @__PURE__ */ jsxs15(
2477
+ "div",
2478
+ {
2479
+ className: clsx12(
2480
+ "flex w-full max-w-2xl flex-col gap-3",
2481
+ contentAlignment === "center" ? "mx-auto items-center" : "items-start"
2482
+ ),
2483
+ children: [
2484
+ /* @__PURE__ */ jsx31(
2485
+ CodeSnippet2,
2486
+ {
2487
+ code,
2488
+ prompt: showPrompt ? "$" : void 0,
2489
+ theme: overriddenTheme
2490
+ }
2491
+ ),
2492
+ caption && /* @__PURE__ */ jsx31(Caption, { theme: overriddenTheme, children: caption })
2493
+ ]
2494
+ }
2495
+ ) });
2496
+ }
2497
+
2498
+ // src/blocks/code-snippet/defaults.ts
2499
+ var codeSnippetDefaults = {
2500
+ code: "curl -fsSL https://example.com/install.sh | sh",
2501
+ showPrompt: true,
2502
+ contentAlignment: "center"
2503
+ };
2504
+
2505
+ // src/blocks/data-slot/widget.tsx
2506
+ import { LockKeyhole } from "lucide-react";
2507
+ import { jsx as jsx32, jsxs as jsxs16 } from "react/jsx-runtime";
2508
+ function DataSlotWidget({
2509
+ data,
2510
+ editing,
2511
+ settings: { slot, cssId, maxWidth, verticalPadding, background },
2512
+ state: { theme }
2513
+ }) {
2514
+ const overriddenTheme = JSON.parse(JSON.stringify(theme.theme));
2515
+ overriddenTheme.structure.page.width = maxWidth || theme.theme.structure.page.width;
2516
+ overriddenTheme.structure.section.padding.y = verticalPadding || theme.theme.structure.section.padding.y;
2517
+ if (data !== void 0) {
2518
+ return /* @__PURE__ */ jsx32(Section, { theme: overriddenTheme, id: cssId, background, children: data });
2519
+ }
2520
+ if (!editing) return null;
2521
+ return /* @__PURE__ */ jsx32(
2522
+ Section,
2523
+ {
2524
+ theme: overriddenTheme,
2525
+ id: cssId,
2526
+ background,
2527
+ className: "border-y border-dashed border-border bg-muted/30",
2528
+ children: /* @__PURE__ */ jsxs16("div", { className: "flex flex-col items-center gap-3 text-center", children: [
2529
+ /* @__PURE__ */ jsx32("span", { className: "flex h-10 w-10 items-center justify-center rounded-full border border-border bg-background text-muted-foreground", children: /* @__PURE__ */ jsx32(LockKeyhole, { className: "h-4 w-4" }) }),
2530
+ /* @__PURE__ */ jsxs16("div", { children: [
2531
+ /* @__PURE__ */ jsx32("p", { className: "font-semibold text-foreground", children: "Data slot" }),
2532
+ /* @__PURE__ */ jsxs16("p", { className: "mt-1 text-sm text-muted-foreground", children: [
2533
+ "The embedding application resolves data for ",
2534
+ String(slot || "this slot"),
2535
+ " ",
2536
+ "here."
2537
+ ] })
2538
+ ] })
2539
+ ] })
2540
+ }
2541
+ );
2542
+ }
2543
+
2544
+ // src/server/registry.ts
2545
+ var serverBlockRegistry = {
2546
+ header: { widget: HeaderWidget, getDefaultSettings: () => headerDefaults },
2547
+ hero: { widget: HeroWidget, getDefaultSettings: () => heroDefaults },
2548
+ content: { widget: ContentWidget, getDefaultSettings: () => contentDefaults },
2549
+ featured: { widget: FeaturedWidget, getDefaultSettings: () => featuredDefaults },
2550
+ faq: { widget: FaqWidget, getDefaultSettings: () => faqDefaults },
2551
+ pricing: { widget: PricingWidget, getDefaultSettings: () => pricingDefaults },
2552
+ banner: { widget: BannerWidget, getDefaultSettings: () => bannerDefaults },
2553
+ "email-form": {
2554
+ widget: EmailFormWidget,
2555
+ getDefaultSettings: () => emailFormDefaults
2556
+ },
2557
+ "support-form": {
2558
+ widget: SupportFormWidget,
2559
+ getDefaultSettings: () => supportFormDefaults
2560
+ },
2561
+ footer: { widget: FooterWidget, getDefaultSettings: () => footerDefaults },
2562
+ "rich-text": { widget: RichTextWidget, getDefaultSettings: () => richTextDefaults },
2563
+ grid: { widget: GridWidget, getDefaultSettings: () => gridDefaults },
2564
+ media: { widget: MediaWidget, getDefaultSettings: () => mediaDefaults },
2565
+ marquee: { widget: MarqueeWidget, getDefaultSettings: () => marqueeDefaults },
2566
+ embed: { widget: EmbedWidget, getDefaultSettings: () => embedDefaults },
2567
+ "code-snippet": {
2568
+ widget: CodeSnippetWidget,
2569
+ getDefaultSettings: () => codeSnippetDefaults
2570
+ },
2571
+ "data-slot": { widget: DataSlotWidget }
2572
+ };
2573
+
2574
+ // src/server/page-renderer.tsx
2575
+ import { jsx as jsx33, jsxs as jsxs17 } from "react/jsx-runtime";
2576
+ function ServerPageRenderer({
2577
+ layout,
2578
+ theme,
2579
+ pageData,
2580
+ children,
2581
+ dataSlots,
2582
+ themeSwitcher,
2583
+ overlay,
2584
+ className
2585
+ }) {
2586
+ const themeScope = `pb-${useId2().replace(/[^a-zA-Z0-9_-]/g, "")}`;
2587
+ const header = layout.find((widget) => widget.name === "header");
2588
+ const footer = layout.find((widget) => widget.name === "footer");
2589
+ const body = layout.filter((widget) => !LAYOUT_BLOCK_NAMES.includes(widget.name));
2590
+ function renderInstance(instance) {
2591
+ const definition = serverBlockRegistry[instance.name];
2592
+ if (!definition) return null;
2593
+ const Widget = definition.widget;
2594
+ const settings = { ...definition.getDefaultSettings?.(), ...instance.settings };
2595
+ return /* @__PURE__ */ jsx33(
2596
+ Widget,
2597
+ {
2598
+ settings,
2599
+ state: { theme },
2600
+ pageData,
2601
+ data: instance.name === "data-slot" ? dataSlots?.[String(settings.slot ?? "")] : void 0,
2602
+ themeSwitcher: instance.name === "footer" ? themeSwitcher : void 0
2603
+ },
2604
+ instance.widgetId
2605
+ );
2606
+ }
2607
+ return /* @__PURE__ */ jsxs17(
2608
+ "div",
2609
+ {
2610
+ "data-pb-theme": themeScope,
2611
+ className: cn(
2612
+ "pb-theme flex min-h-full flex-col bg-background text-foreground",
2613
+ className
2614
+ ),
2615
+ children: [
2616
+ /* @__PURE__ */ jsx33("style", { children: generateThemeStyles(theme, `[data-pb-theme="${themeScope}"]`) }),
2617
+ header && renderInstance(header),
2618
+ /* @__PURE__ */ jsx33("div", { className: "flex flex-1 flex-col", children: children !== void 0 && !body.some((instance) => instance.name === "data-slot") ? children : body.map(renderInstance) }),
2619
+ footer && renderInstance(footer),
2620
+ overlay
2621
+ ]
2622
+ }
2623
+ );
2624
+ }
2625
+
2626
+ // src/data-slots.ts
2627
+ async function loadDataSlots(layout, loaders, pageData) {
2628
+ const slots = layout.filter((instance) => instance.name === "data-slot");
2629
+ const resolved = await Promise.all(
2630
+ slots.map(async (instance) => {
2631
+ const slot = instance.settings?.slot;
2632
+ if (typeof slot !== "string" || !slot) return null;
2633
+ const loader = loaders[slot];
2634
+ if (!loader) return null;
2635
+ return [slot, await loader({ slot, instance, pageData })];
2636
+ })
2637
+ );
2638
+ const output = {};
2639
+ for (const entry of resolved) {
2640
+ if (entry) output[entry[0]] = entry[1];
2641
+ }
2642
+ return output;
2643
+ }
2644
+ export {
2645
+ ServerPageRenderer,
2646
+ loadDataSlots,
2647
+ setImageAttributesResolver
2648
+ };
2649
+ //# sourceMappingURL=index.js.map