@opensite/ui 2.0.2 → 2.0.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 (75) hide show
  1. package/dist/hero-ai-powered-carousel.cjs +152 -77
  2. package/dist/hero-ai-powered-carousel.d.cts +5 -13
  3. package/dist/hero-ai-powered-carousel.d.ts +5 -13
  4. package/dist/hero-ai-powered-carousel.js +152 -77
  5. package/dist/hero-announcement-badge.cjs +679 -665
  6. package/dist/hero-announcement-badge.d.cts +1 -1
  7. package/dist/hero-announcement-badge.d.ts +1 -1
  8. package/dist/hero-announcement-badge.js +689 -675
  9. package/dist/hero-badge-shadow-overlay.cjs +79 -32
  10. package/dist/hero-badge-shadow-overlay.js +80 -33
  11. package/dist/hero-centered-image-grid.cjs +106 -95
  12. package/dist/hero-centered-image-grid.d.cts +2 -14
  13. package/dist/hero-centered-image-grid.d.ts +2 -14
  14. package/dist/hero-centered-image-grid.js +106 -95
  15. package/dist/hero-community-survey-cta.cjs +149 -58
  16. package/dist/hero-community-survey-cta.d.cts +1 -1
  17. package/dist/hero-community-survey-cta.d.ts +1 -1
  18. package/dist/hero-community-survey-cta.js +149 -58
  19. package/dist/hero-design-carousel-portfolio.cjs +158 -66
  20. package/dist/hero-design-carousel-portfolio.d.cts +7 -11
  21. package/dist/hero-design-carousel-portfolio.d.ts +7 -11
  22. package/dist/hero-design-carousel-portfolio.js +158 -66
  23. package/dist/hero-event-registration.cjs +765 -718
  24. package/dist/hero-event-registration.js +761 -714
  25. package/dist/hero-fullscreen-background-image.cjs +746 -649
  26. package/dist/hero-fullscreen-background-image.d.cts +12 -4
  27. package/dist/hero-fullscreen-background-image.d.ts +12 -4
  28. package/dist/hero-fullscreen-background-image.js +746 -649
  29. package/dist/hero-fullscreen-logo-cta.cjs +89 -31
  30. package/dist/hero-fullscreen-logo-cta.js +89 -31
  31. package/dist/hero-gradient-avatars-rating.cjs +847 -816
  32. package/dist/hero-gradient-avatars-rating.d.cts +1 -13
  33. package/dist/hero-gradient-avatars-rating.d.ts +1 -13
  34. package/dist/hero-gradient-avatars-rating.js +844 -813
  35. package/dist/hero-gradient-client-focused.cjs +690 -629
  36. package/dist/hero-gradient-client-focused.d.cts +1 -1
  37. package/dist/hero-gradient-client-focused.d.ts +1 -1
  38. package/dist/hero-gradient-client-focused.js +689 -628
  39. package/dist/hero-grid-pattern-efficiency.cjs +59 -47
  40. package/dist/hero-grid-pattern-efficiency.d.cts +1 -8
  41. package/dist/hero-grid-pattern-efficiency.d.ts +1 -8
  42. package/dist/hero-grid-pattern-efficiency.js +59 -47
  43. package/dist/hero-logo-centered-screenshot.cjs +1 -1
  44. package/dist/hero-logo-centered-screenshot.js +1 -1
  45. package/dist/hero-marketplace-scattered-images.cjs +2 -6
  46. package/dist/hero-marketplace-scattered-images.d.cts +1 -4
  47. package/dist/hero-marketplace-scattered-images.d.ts +1 -4
  48. package/dist/hero-marketplace-scattered-images.js +2 -6
  49. package/dist/hero-pattern-logo-tech-stack.cjs +1 -1
  50. package/dist/hero-pattern-logo-tech-stack.js +1 -1
  51. package/dist/hero-platform-features-grid.cjs +5 -5
  52. package/dist/hero-platform-features-grid.js +5 -5
  53. package/dist/hero-simple-centered-image.cjs +140 -44
  54. package/dist/hero-simple-centered-image.d.cts +1 -1
  55. package/dist/hero-simple-centered-image.d.ts +1 -1
  56. package/dist/hero-simple-centered-image.js +140 -44
  57. package/dist/hero-spiral-pattern-cards.cjs +857 -809
  58. package/dist/hero-spiral-pattern-cards.d.cts +5 -1
  59. package/dist/hero-spiral-pattern-cards.d.ts +5 -1
  60. package/dist/hero-spiral-pattern-cards.js +856 -808
  61. package/dist/hero-split-geometric-shapes.cjs +754 -723
  62. package/dist/hero-split-geometric-shapes.d.cts +5 -1
  63. package/dist/hero-split-geometric-shapes.d.ts +5 -1
  64. package/dist/hero-split-geometric-shapes.js +748 -717
  65. package/dist/hero-task-timer-animated.cjs +698 -650
  66. package/dist/hero-task-timer-animated.d.cts +5 -1
  67. package/dist/hero-task-timer-animated.d.ts +5 -1
  68. package/dist/hero-task-timer-animated.js +697 -649
  69. package/dist/hero-ui-library-showcase.cjs +734 -719
  70. package/dist/hero-ui-library-showcase.d.cts +5 -1
  71. package/dist/hero-ui-library-showcase.d.ts +5 -1
  72. package/dist/hero-ui-library-showcase.js +732 -717
  73. package/dist/registry.cjs +1035 -788
  74. package/dist/registry.js +1035 -788
  75. package/package.json +1 -1
@@ -1,281 +1,459 @@
1
1
  "use client";
2
- import * as React from 'react';
3
- import React__default, { useMemo } from 'react';
2
+ import * as React3 from 'react';
3
+ import React3__default, { useMemo } from 'react';
4
4
  import { clsx } from 'clsx';
5
5
  import { twMerge } from 'tailwind-merge';
6
- import { cva } from 'class-variance-authority';
7
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
6
  import { Icon } from '@page-speed/icon';
7
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
9
8
  import * as AvatarPrimitive from '@radix-ui/react-avatar';
10
9
  import { Img } from '@page-speed/img';
10
+ import { cva } from 'class-variance-authority';
11
11
 
12
12
  // components/blocks/hero/hero-gradient-avatars-rating.tsx
13
13
  function cn(...inputs) {
14
14
  return twMerge(clsx(inputs));
15
15
  }
16
- function getNestedCardBg(parentBg, variant = "muted", options) {
17
- const isDark = parentBg === "dark" || parentBg === "secondary" || parentBg === "primary";
18
- if (isDark) {
19
- switch (variant) {
20
- case "muted":
21
- return "bg-background";
22
- case "card":
23
- return "bg-card";
24
- case "accent":
25
- return "bg-accent";
26
- case "subtle":
27
- return "bg-background/50";
28
- }
29
- } else {
30
- switch (variant) {
31
- case "muted":
32
- return "bg-muted";
33
- case "card":
34
- return "bg-card";
35
- case "accent":
36
- return "bg-accent";
37
- case "subtle":
38
- return "bg-muted/50";
39
- }
40
- }
16
+ var DEFAULT_ICON_API_KEY = "au382bi7fsh96w9h9xlrnat2jglx";
17
+ function DynamicIcon({ apiKey, ...props }) {
18
+ return /* @__PURE__ */ jsx(Icon, { ...props, apiKey: apiKey ?? DEFAULT_ICON_API_KEY });
41
19
  }
42
- function getTextColor(parentBg, variant = "default", options) {
43
- const isDark = parentBg === "dark" || parentBg === "secondary" || parentBg === "primary";
44
- if (isDark) {
45
- switch (variant) {
46
- case "default":
47
- return "text-foreground";
48
- case "muted":
49
- return "text-foreground/80";
50
- case "subtle":
51
- return "text-foreground/60";
52
- case "accent":
53
- return "text-accent-foreground";
54
- }
55
- } else {
56
- switch (variant) {
57
- case "default":
58
- return "text-foreground";
59
- case "muted":
60
- return "text-muted-foreground";
61
- case "subtle":
62
- return "text-muted-foreground/70";
63
- case "accent":
64
- return "text-primary";
20
+ function Avatar({
21
+ className,
22
+ ...props
23
+ }) {
24
+ return /* @__PURE__ */ jsx(
25
+ AvatarPrimitive.Root,
26
+ {
27
+ "data-slot": "avatar",
28
+ className: cn(
29
+ "relative flex size-8 shrink-0 overflow-hidden rounded-full",
30
+ className
31
+ ),
32
+ ...props
65
33
  }
66
- }
67
- }
68
- function normalizePhoneNumber(input) {
69
- const trimmed = input.trim();
70
- if (trimmed.toLowerCase().startsWith("tel:")) {
71
- return trimmed;
72
- }
73
- const match = trimmed.match(/^[\s\+\-\(\)]*(\d[\d\s\-\(\)\.]*\d)[\s\-]*(x|ext\.?|extension)?[\s\-]*(\d+)?$/i);
74
- if (match) {
75
- const mainNumber = match[1].replace(/[\s\-\(\)\.]/g, "");
76
- const extension = match[3];
77
- const normalized = mainNumber.length >= 10 && !trimmed.startsWith("+") ? `+${mainNumber}` : mainNumber;
78
- const withExtension = extension ? `${normalized};ext=${extension}` : normalized;
79
- return `tel:${withExtension}`;
80
- }
81
- const cleaned = trimmed.replace(/[\s\-\(\)\.]/g, "");
82
- return `tel:${cleaned}`;
83
- }
84
- function normalizeEmail(input) {
85
- const trimmed = input.trim();
86
- if (trimmed.toLowerCase().startsWith("mailto:")) {
87
- return trimmed;
88
- }
89
- return `mailto:${trimmed}`;
90
- }
91
- function isEmail(input) {
92
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
93
- return emailRegex.test(input.trim());
34
+ );
94
35
  }
95
- function isPhoneNumber(input) {
96
- const trimmed = input.trim();
97
- if (trimmed.toLowerCase().startsWith("tel:")) {
98
- return true;
99
- }
100
- const phoneRegex = /^[\s\+\-\(\)]*\d[\d\s\-\(\)\.]*\d[\s\-]*(x|ext\.?|extension)?[\s\-]*\d*$/i;
101
- return phoneRegex.test(trimmed);
36
+ function AvatarImage({
37
+ className,
38
+ ...props
39
+ }) {
40
+ return /* @__PURE__ */ jsx(
41
+ AvatarPrimitive.Image,
42
+ {
43
+ "data-slot": "avatar-image",
44
+ className: cn("aspect-square size-full", className),
45
+ ...props
46
+ }
47
+ );
102
48
  }
103
- function isInternalUrl(href) {
104
- if (typeof window === "undefined") {
105
- return href.startsWith("/") && !href.startsWith("//");
106
- }
107
- const trimmed = href.trim();
108
- if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
109
- return true;
49
+ var maxWidthStyles = {
50
+ sm: "max-w-screen-sm",
51
+ md: "max-w-screen-md",
52
+ lg: "max-w-screen-lg",
53
+ xl: "max-w-7xl",
54
+ "2xl": "max-w-screen-2xl",
55
+ "4xl": "max-w-[1536px]",
56
+ full: "max-w-full"
57
+ };
58
+ var Container = React3__default.forwardRef(
59
+ ({ children, maxWidth = "xl", className, as = "div", ...props }, ref) => {
60
+ const Component = as;
61
+ return /* @__PURE__ */ jsx(
62
+ Component,
63
+ {
64
+ ref,
65
+ className: cn(
66
+ "mx-auto w-full px-2 sm:px-4 lg:px-8",
67
+ maxWidthStyles[maxWidth],
68
+ className
69
+ ),
70
+ ...props,
71
+ children
72
+ }
73
+ );
110
74
  }
111
- try {
112
- const url = new URL(trimmed, window.location.href);
113
- const currentOrigin = window.location.origin;
114
- const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
115
- return normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin);
116
- } catch {
117
- return false;
75
+ );
76
+ Container.displayName = "Container";
77
+
78
+ // lib/patternSvgs.ts
79
+ var patternSvgs = {
80
+ squareAltGrid: "https://cdn.ing/assets/files/record/286187/4gpn0yq2ptra8iwlvmwwv860ggwv",
81
+ grid1: "https://cdn.ing/assets/files/record/286186/nbdflpgp4ostrno079hygibsflp3",
82
+ noise: "https://cdn.ing/assets/i/r/286188/zrqcp9hynh3j7p2laihwzfbujgrl/noise.png",
83
+ dots: "https://cdn.ing/assets/files/record/286198/yfsjx9thvtxzhl2qtshxyhkrm524",
84
+ dotPattern: "https://cdn.ing/assets/files/record/286192/7ig0cku8aqbboiza8nuk6hw0nnsr",
85
+ dotPattern2: "https://cdn.ing/assets/files/record/286189/arez6gd2s7isn9i1o6c7sexdq7bl",
86
+ circles: "https://cdn.ing/assets/files/record/286190/gtmia3sncjtzetdshc20zf1d3c17",
87
+ waves: "https://cdn.ing/assets/files/record/286191/mqlb33fzxz9cdth1bx7if0wmpkp1",
88
+ crossPattern: "https://cdn.ing/assets/files/record/286193/9yfqwdbnqaipbp7fsb3wbzzmq472",
89
+ architect: "https://cdn.ing/assets/files/record/286194/vgs88ugpvyhxu13wqgy0acvae6re",
90
+ tinyCheckers: "https://cdn.ing/assets/files/record/286195/65efaknsw8kcpf9o3c2gybytsl5b",
91
+ p6: "https://cdn.ing/assets/i/r/286196/6kl0rqnd6mjk8j7e525fo8fo0vkc/p6.webp"
92
+ };
93
+ var maskTop = "radial-gradient(ellipse 70% 60% at 50% 0%, #000 60%, transparent 100%)";
94
+ var maskBottom = "radial-gradient(ellipse 100% 80% at 50% 100%, #000 50%, transparent 90%)";
95
+ var maskCenter = "radial-gradient(ellipse 60% 60% at 50% 50%, #000 30%, transparent 70%)";
96
+ var maskTopLeft = "radial-gradient(ellipse 80% 80% at 0% 0%, #000 50%, transparent 90%)";
97
+ var maskTopRight = "radial-gradient(ellipse 80% 80% at 100% 0%, #000 50%, transparent 90%)";
98
+ var maskBottomLeft = "radial-gradient(ellipse 80% 80% at 0% 100%, #000 50%, transparent 90%)";
99
+ var maskBottomRight = "radial-gradient(ellipse 80% 80% at 100% 100%, #000 50%, transparent 90%)";
100
+ var circuitBoardPattern = (id, mask) => /* @__PURE__ */ jsxs(
101
+ "svg",
102
+ {
103
+ className: "h-full w-full",
104
+ xmlns: "http://www.w3.org/2000/svg",
105
+ style: mask ? {
106
+ maskImage: mask,
107
+ WebkitMaskImage: mask
108
+ } : void 0,
109
+ children: [
110
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs(
111
+ "pattern",
112
+ {
113
+ id,
114
+ x: "0",
115
+ y: "0",
116
+ width: "100",
117
+ height: "100",
118
+ patternUnits: "userSpaceOnUse",
119
+ children: [
120
+ /* @__PURE__ */ jsx(
121
+ "path",
122
+ {
123
+ d: "M0 50h40M60 50h40M50 0v40M50 60v40",
124
+ stroke: "hsl(var(--muted))",
125
+ strokeWidth: "1",
126
+ fill: "none"
127
+ }
128
+ ),
129
+ /* @__PURE__ */ jsx("circle", { cx: "50", cy: "50", r: "3", fill: "hsl(var(--muted))" }),
130
+ /* @__PURE__ */ jsx("circle", { cx: "0", cy: "50", r: "2", fill: "hsl(var(--muted))" }),
131
+ /* @__PURE__ */ jsx("circle", { cx: "100", cy: "50", r: "2", fill: "hsl(var(--muted))" }),
132
+ /* @__PURE__ */ jsx("circle", { cx: "50", cy: "0", r: "2", fill: "hsl(var(--muted))" }),
133
+ /* @__PURE__ */ jsx("circle", { cx: "50", cy: "100", r: "2", fill: "hsl(var(--muted))" })
134
+ ]
135
+ }
136
+ ) }),
137
+ /* @__PURE__ */ jsx("rect", { width: "100%", height: "100%", fill: `url(#${id})` })
138
+ ]
118
139
  }
119
- }
120
- function toRelativePath(href) {
121
- if (typeof window === "undefined") {
122
- return href;
140
+ );
141
+ var gridDotsPattern = (id, mask) => /* @__PURE__ */ jsxs(
142
+ "svg",
143
+ {
144
+ className: "h-full w-full",
145
+ xmlns: "http://www.w3.org/2000/svg",
146
+ style: mask ? {
147
+ maskImage: mask,
148
+ WebkitMaskImage: mask
149
+ } : void 0,
150
+ children: [
151
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs(
152
+ "pattern",
153
+ {
154
+ id,
155
+ x: "0",
156
+ y: "0",
157
+ width: "40",
158
+ height: "40",
159
+ patternUnits: "userSpaceOnUse",
160
+ children: [
161
+ /* @__PURE__ */ jsx(
162
+ "path",
163
+ {
164
+ d: "M0 20h40M20 0v40",
165
+ stroke: "hsl(var(--muted))",
166
+ strokeWidth: "0.5",
167
+ fill: "none"
168
+ }
169
+ ),
170
+ /* @__PURE__ */ jsx("circle", { cx: "20", cy: "20", r: "2", fill: "hsl(var(--muted))" })
171
+ ]
172
+ }
173
+ ) }),
174
+ /* @__PURE__ */ jsx("rect", { width: "100%", height: "100%", fill: `url(#${id})` })
175
+ ]
123
176
  }
124
- const trimmed = href.trim();
125
- if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
126
- return trimmed;
177
+ );
178
+ var gridPattern = (size, mask) => /* @__PURE__ */ jsx(
179
+ "div",
180
+ {
181
+ className: "h-full w-full bg-[linear-gradient(to_right,_hsl(var(--muted))_1px,_transparent_1px),linear-gradient(to_bottom,_hsl(var(--muted))_1px,_transparent_1px)]",
182
+ style: {
183
+ backgroundSize: `${size}px ${size}px`,
184
+ ...mask ? {
185
+ maskImage: mask,
186
+ WebkitMaskImage: mask
187
+ } : {}
188
+ }
127
189
  }
128
- try {
129
- const url = new URL(trimmed, window.location.href);
130
- const currentOrigin = window.location.origin;
131
- const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
132
- if (normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin)) {
133
- return url.pathname + url.search + url.hash;
190
+ );
191
+ var diagonalCrossPattern = (mask) => /* @__PURE__ */ jsx(
192
+ "div",
193
+ {
194
+ className: "h-full w-full",
195
+ style: {
196
+ backgroundImage: "repeating-linear-gradient(45deg, transparent, transparent 32px, hsl(var(--muted)) 32px, hsl(var(--muted)) 33px), repeating-linear-gradient(135deg, transparent, transparent 32px, hsl(var(--muted)) 32px, hsl(var(--muted)) 33px)",
197
+ ...mask ? {
198
+ maskImage: mask,
199
+ WebkitMaskImage: mask
200
+ } : {}
134
201
  }
135
- } catch {
136
202
  }
137
- return trimmed;
138
- }
139
- function useNavigation({
140
- href,
141
- onClick
142
- } = {}) {
143
- const linkType = React.useMemo(() => {
144
- if (!href || href.trim() === "") {
145
- return onClick ? "none" : "none";
146
- }
147
- const trimmed = href.trim();
148
- if (trimmed.toLowerCase().startsWith("mailto:") || isEmail(trimmed)) {
149
- return "mailto";
150
- }
151
- if (trimmed.toLowerCase().startsWith("tel:") || isPhoneNumber(trimmed)) {
152
- return "tel";
153
- }
154
- if (isInternalUrl(trimmed)) {
155
- return "internal";
156
- }
157
- try {
158
- new URL(trimmed, typeof window !== "undefined" ? window.location.href : "http://localhost");
159
- return "external";
160
- } catch {
161
- return "internal";
162
- }
163
- }, [href, onClick]);
164
- const normalizedHref = React.useMemo(() => {
165
- if (!href || href.trim() === "") {
166
- return void 0;
167
- }
168
- const trimmed = href.trim();
169
- switch (linkType) {
170
- case "tel":
171
- return normalizePhoneNumber(trimmed);
172
- case "mailto":
173
- return normalizeEmail(trimmed);
174
- case "internal":
175
- return toRelativePath(trimmed);
176
- case "external":
177
- return trimmed;
178
- default:
179
- return trimmed;
203
+ );
204
+ var dashedGridMaskBase = "repeating-linear-gradient(to right, black 0px, black 3px, transparent 3px, transparent 8px), repeating-linear-gradient(to bottom, black 0px, black 3px, transparent 3px, transparent 8px)";
205
+ var dashedGridPattern = (fadeMask) => {
206
+ const mask = fadeMask ? `${dashedGridMaskBase}, ${fadeMask}` : dashedGridMaskBase;
207
+ return /* @__PURE__ */ jsx(
208
+ "div",
209
+ {
210
+ className: "h-full w-full",
211
+ style: {
212
+ backgroundImage: "linear-gradient(to right, hsl(var(--muted)) 1px, transparent 1px), linear-gradient(to bottom, hsl(var(--muted)) 1px, transparent 1px)",
213
+ backgroundSize: "20px 20px",
214
+ backgroundPosition: "0 0, 0 0",
215
+ maskImage: mask,
216
+ WebkitMaskImage: mask,
217
+ maskComposite: "intersect",
218
+ WebkitMaskComposite: "source-in"
219
+ }
180
220
  }
181
- }, [href, linkType]);
182
- const target = React.useMemo(() => {
183
- switch (linkType) {
184
- case "external":
185
- return "_blank";
186
- case "internal":
187
- return "_self";
188
- case "mailto":
189
- case "tel":
190
- return void 0;
191
- default:
192
- return void 0;
221
+ );
222
+ };
223
+ var gradientGlow = (position) => /* @__PURE__ */ jsx(
224
+ "div",
225
+ {
226
+ className: cn(
227
+ "pointer-events-none absolute left-1/2 z-0 aspect-square w-3/4 -translate-x-1/2 rounded-full opacity-50 blur-3xl",
228
+ position === "top" ? "-top-1/4" : "-bottom-1/4"
229
+ ),
230
+ style: {
231
+ background: "radial-gradient(circle, hsl(var(--primary)) 0%, transparent 70%)"
193
232
  }
194
- }, [linkType]);
195
- const rel = React.useMemo(() => {
196
- if (linkType === "external") {
197
- return "noopener noreferrer";
233
+ }
234
+ );
235
+ var spotlight = (position) => /* @__PURE__ */ jsx(
236
+ "div",
237
+ {
238
+ className: cn(
239
+ "pointer-events-none absolute top-1/2 z-0 aspect-square w-3/4 -translate-y-1/2 rounded-full opacity-40 blur-3xl",
240
+ position === "left" ? "-left-1/4" : "-right-1/4"
241
+ ),
242
+ style: {
243
+ background: "radial-gradient(circle, hsl(var(--primary)) 0%, transparent 70%)"
198
244
  }
199
- return void 0;
200
- }, [linkType]);
201
- const isExternal = linkType === "external";
202
- const isInternal = linkType === "internal";
203
- const shouldUseRouter = isInternal && typeof normalizedHref === "string" && normalizedHref.startsWith("/");
204
- const handleClick = React.useCallback(
205
- (event) => {
206
- if (onClick) {
207
- try {
208
- onClick(event);
209
- } catch (error) {
210
- console.error("Error in user onClick handler:", error);
211
- }
212
- }
213
- if (event.defaultPrevented) {
214
- return;
245
+ }
246
+ );
247
+ var patternOverlays = {
248
+ circuitBoardBasic: () => circuitBoardPattern("circuit-board-basic"),
249
+ circuitBoardFadeTop: () => circuitBoardPattern("circuit-board-fade-top", maskTop),
250
+ circuitBoardFadeBottom: () => circuitBoardPattern("circuit-board-fade-bottom", maskBottom),
251
+ circuitBoardFadeCenter: () => circuitBoardPattern("circuit-board-fade-center", maskCenter),
252
+ circuitBoardFadeTopLeft: () => circuitBoardPattern("circuit-board-fade-top-left", maskTopLeft),
253
+ circuitBoardFadeTopRight: () => circuitBoardPattern("circuit-board-fade-top-right", maskTopRight),
254
+ circuitBoardFadeBottomLeft: () => circuitBoardPattern("circuit-board-fade-bottom-left", maskBottomLeft),
255
+ circuitBoardFadeBottomRight: () => circuitBoardPattern("circuit-board-fade-bottom-right", maskBottomRight),
256
+ dashedGridBasic: () => dashedGridPattern(),
257
+ dashedGridFadeTop: () => dashedGridPattern(maskTop),
258
+ dashedGridFadeBottom: () => dashedGridPattern(maskBottom),
259
+ dashedGridFadeCenter: () => dashedGridPattern(maskCenter),
260
+ dashedGridFadeTopLeft: () => dashedGridPattern(maskTopLeft),
261
+ dashedGridFadeTopRight: () => dashedGridPattern(maskTopRight),
262
+ dashedGridFadeBottomLeft: () => dashedGridPattern(maskBottomLeft),
263
+ dashedGridFadeBottomRight: () => dashedGridPattern(maskBottomRight),
264
+ diagonalCrossBasic: () => diagonalCrossPattern(),
265
+ diagonalCrossFadeTop: () => diagonalCrossPattern(maskTop),
266
+ diagonalCrossFadeBottom: () => diagonalCrossPattern(maskBottom),
267
+ diagonalCrossFadeCenter: () => diagonalCrossPattern(maskCenter),
268
+ diagonalCrossFadeTopLeft: () => diagonalCrossPattern(maskTopLeft),
269
+ diagonalCrossFadeTopRight: () => diagonalCrossPattern(maskTopRight),
270
+ diagonalCrossFadeBottomLeft: () => diagonalCrossPattern(maskBottomLeft),
271
+ diagonalCrossFadeBottomRight: () => diagonalCrossPattern(maskBottomRight),
272
+ gridBasic: () => gridPattern(40),
273
+ gridFadeTop: () => gridPattern(32, maskTop),
274
+ gridFadeBottom: () => gridPattern(32, maskBottom),
275
+ gridFadeCenter: () => gridPattern(40, maskCenter),
276
+ gridFadeTopLeft: () => gridPattern(32, maskTopLeft),
277
+ gridFadeTopRight: () => gridPattern(32, maskTopRight),
278
+ gridFadeBottomLeft: () => gridPattern(32, maskBottomLeft),
279
+ gridFadeBottomRight: () => gridPattern(32, maskBottomRight),
280
+ gridDotsBasic: () => gridDotsPattern("grid-dots-basic"),
281
+ gridDotsFadeCenter: () => gridDotsPattern("grid-dots-fade-center", maskCenter),
282
+ gradientGlowTop: () => gradientGlow("top"),
283
+ gradientGlowBottom: () => gradientGlow("bottom"),
284
+ spotlightLeft: () => spotlight("left"),
285
+ spotlightRight: () => spotlight("right")
286
+ };
287
+ var inlinePatternStyles = {
288
+ radialGradientTop: {
289
+ background: "radial-gradient(125% 125% at 50% 10%, hsl(var(--background)) 40%, hsl(var(--primary)) 100%)"
290
+ },
291
+ radialGradientBottom: {
292
+ background: "radial-gradient(125% 125% at 50% 90%, hsl(var(--background)) 40%, hsl(var(--primary)) 100%)"
293
+ }
294
+ };
295
+ function PatternBackground({
296
+ pattern,
297
+ opacity = 0.08,
298
+ className,
299
+ style
300
+ }) {
301
+ if (!pattern) {
302
+ return null;
303
+ }
304
+ if (pattern in inlinePatternStyles) {
305
+ const inlineStyle = inlinePatternStyles[pattern];
306
+ return /* @__PURE__ */ jsx(
307
+ "div",
308
+ {
309
+ className: cn("pointer-events-none absolute inset-0 z-0", className),
310
+ style: { ...inlineStyle, opacity, ...style },
311
+ "aria-hidden": "true"
215
312
  }
216
- if (shouldUseRouter && normalizedHref && event.button === 0 && // left-click only
217
- !event.metaKey && !event.altKey && !event.ctrlKey && !event.shiftKey) {
218
- if (typeof window !== "undefined") {
219
- const handler = window.__opensiteNavigationHandler;
220
- if (typeof handler === "function") {
221
- try {
222
- const handled = handler(normalizedHref, event.nativeEvent || event);
223
- if (handled !== false) {
224
- event.preventDefault();
225
- }
226
- } catch (error) {
227
- console.error("Error in navigation handler:", error);
228
- }
229
- }
230
- }
313
+ );
314
+ }
315
+ if (pattern in patternOverlays) {
316
+ const Overlay = patternOverlays[pattern];
317
+ return /* @__PURE__ */ jsx(
318
+ "div",
319
+ {
320
+ className: cn("pointer-events-none absolute inset-0 z-0", className),
321
+ style: { opacity, ...style },
322
+ "aria-hidden": "true",
323
+ children: Overlay()
231
324
  }
232
- },
233
- [onClick, shouldUseRouter, normalizedHref]
325
+ );
326
+ }
327
+ const patternUrl = pattern in patternSvgs ? patternSvgs[pattern] : pattern;
328
+ return /* @__PURE__ */ jsx(
329
+ "div",
330
+ {
331
+ className: cn("pointer-events-none absolute inset-0 z-0", className),
332
+ style: {
333
+ backgroundImage: `url(${patternUrl})`,
334
+ backgroundRepeat: "repeat",
335
+ backgroundSize: "auto",
336
+ opacity,
337
+ ...style
338
+ },
339
+ "aria-hidden": "true"
340
+ }
234
341
  );
235
- return {
236
- linkType,
237
- normalizedHref,
238
- target,
239
- rel,
240
- isExternal,
241
- isInternal,
242
- shouldUseRouter,
243
- handleClick
244
- };
245
342
  }
246
- var baseStyles = [
247
- // Layout
248
- "inline-flex items-center justify-center gap-2 whitespace-nowrap shrink-0",
249
- // Typography - using CSS variables with sensible defaults
250
- "font-[var(--button-font-family,inherit)]",
251
- "font-[var(--button-font-weight,500)]",
252
- "tracking-[var(--button-letter-spacing,0)]",
253
- "leading-[var(--button-line-height,1.25)]",
254
- "[text-transform:var(--button-text-transform,none)]",
255
- "text-sm",
256
- // Border radius
257
- "rounded-[var(--button-radius,var(--radius,0.375rem))]",
258
- // Smooth transition - using [transition:...] to set full shorthand property (not just transition-property)
259
- "[transition:var(--button-transition,all_250ms_cubic-bezier(0.4,0,0.2,1))]",
260
- // Box shadow (master level) - using [box-shadow:...] for complex multi-value shadows
261
- "[box-shadow:var(--button-shadow,none)]",
262
- "hover:[box-shadow:var(--button-shadow-hover,var(--button-shadow,none))]",
263
- // Disabled state
264
- "disabled:pointer-events-none disabled:opacity-50",
265
- // SVG handling
266
- "[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0",
267
- // Focus styles
268
- "outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
269
- // Invalid state
270
- "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
271
- ].join(" ");
272
- var buttonVariants = cva(baseStyles, {
273
- variants: {
274
- variant: {
275
- // Default (Primary) variant - full customization
276
- default: [
277
- "bg-[var(--button-default-bg,hsl(var(--primary)))]",
278
- "text-[var(--button-default-fg,hsl(var(--primary-foreground)))]",
343
+ var backgroundStyles = {
344
+ default: "bg-background text-foreground",
345
+ white: "bg-white text-dark",
346
+ gray: "bg-muted/30 text-foreground",
347
+ dark: "bg-foreground text-background",
348
+ transparent: "bg-transparent text-foreground",
349
+ gradient: "bg-linear-to-br from-primary via-primary/90 to-foreground text-primary-foreground",
350
+ primary: "bg-primary text-primary-foreground",
351
+ secondary: "bg-secondary text-secondary-foreground",
352
+ muted: "bg-muted text-muted-foreground"
353
+ };
354
+ var spacingStyles = {
355
+ none: "py-0 md:py-0",
356
+ sm: "py-12 md:py-16",
357
+ md: "py-16 md:py-24",
358
+ lg: "py-20 md:py-32",
359
+ xl: "py-24 md:py-40"
360
+ };
361
+ var predefinedSpacings = ["none", "sm", "md", "lg", "xl"];
362
+ var isPredefinedSpacing = (spacing) => predefinedSpacings.includes(spacing);
363
+ var Section = React3__default.forwardRef(
364
+ ({
365
+ id,
366
+ title,
367
+ subtitle,
368
+ children,
369
+ className,
370
+ style,
371
+ background = "default",
372
+ spacing = "lg",
373
+ pattern,
374
+ patternOpacity,
375
+ patternClassName,
376
+ containerClassName,
377
+ containerMaxWidth = "xl",
378
+ ...props
379
+ }, ref) => {
380
+ const effectivePatternOpacity = patternOpacity !== void 0 ? patternOpacity : pattern ? 1 : 0;
381
+ return /* @__PURE__ */ jsxs(
382
+ "section",
383
+ {
384
+ ref,
385
+ id,
386
+ className: cn(
387
+ "relative",
388
+ pattern ? "overflow-hidden" : null,
389
+ backgroundStyles[background],
390
+ isPredefinedSpacing(spacing) ? spacingStyles[spacing] : spacing,
391
+ className
392
+ ),
393
+ style,
394
+ ...props,
395
+ children: [
396
+ /* @__PURE__ */ jsx(
397
+ PatternBackground,
398
+ {
399
+ pattern,
400
+ opacity: effectivePatternOpacity,
401
+ className: patternClassName
402
+ }
403
+ ),
404
+ /* @__PURE__ */ jsxs(
405
+ Container,
406
+ {
407
+ maxWidth: containerMaxWidth,
408
+ className: cn("relative z-10", containerClassName),
409
+ children: [
410
+ (title || subtitle) && /* @__PURE__ */ jsxs("div", { className: "mb-6 text-center md:mb-16", children: [
411
+ subtitle && /* @__PURE__ */ jsx("p", { className: "mb-2 text-sm font-semibold uppercase tracking-wider", children: subtitle }),
412
+ title && /* @__PURE__ */ jsx("h2", { className: "text-3xl font-bold tracking-tight md:text-4xl lg:text-5xl", children: title })
413
+ ] }),
414
+ children
415
+ ]
416
+ }
417
+ )
418
+ ]
419
+ }
420
+ );
421
+ }
422
+ );
423
+ Section.displayName = "Section";
424
+ var baseStyles = [
425
+ // Layout
426
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap shrink-0",
427
+ // Typography - using CSS variables with sensible defaults
428
+ "font-[var(--button-font-family,inherit)]",
429
+ "font-[var(--button-font-weight,500)]",
430
+ "tracking-[var(--button-letter-spacing,0)]",
431
+ "leading-[var(--button-line-height,1.25)]",
432
+ "[text-transform:var(--button-text-transform,none)]",
433
+ "text-sm",
434
+ // Border radius
435
+ "rounded-[var(--button-radius,var(--radius,0.375rem))]",
436
+ // Smooth transition - using [transition:...] to set full shorthand property (not just transition-property)
437
+ "[transition:var(--button-transition,all_250ms_cubic-bezier(0.4,0,0.2,1))]",
438
+ // Box shadow (master level) - using [box-shadow:...] for complex multi-value shadows
439
+ "[box-shadow:var(--button-shadow,none)]",
440
+ "hover:[box-shadow:var(--button-shadow-hover,var(--button-shadow,none))]",
441
+ // Disabled state
442
+ "disabled:pointer-events-none disabled:opacity-50",
443
+ // SVG handling
444
+ "[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0",
445
+ // Focus styles
446
+ "outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
447
+ // Invalid state
448
+ "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
449
+ ].join(" ");
450
+ var buttonVariants = cva(baseStyles, {
451
+ variants: {
452
+ variant: {
453
+ // Default (Primary) variant - full customization
454
+ default: [
455
+ "bg-[var(--button-default-bg,hsl(var(--primary)))]",
456
+ "text-[var(--button-default-fg,hsl(var(--primary-foreground)))]",
279
457
  "border-[length:var(--button-default-border-width,0px)]",
280
458
  "border-[color:var(--button-default-border,transparent)]",
281
459
  "[box-shadow:var(--button-default-shadow,var(--button-shadow,none))]",
@@ -385,516 +563,351 @@ var buttonVariants = cva(baseStyles, {
385
563
  size: "default"
386
564
  }
387
565
  });
388
- var Pressable = React.forwardRef(
389
- ({
390
- children,
391
- className,
392
- href,
393
- onClick,
394
- variant,
395
- size,
396
- asButton = false,
397
- fallbackComponentType = "span",
398
- componentType,
399
- "aria-label": ariaLabel,
400
- "aria-describedby": ariaDescribedby,
401
- id,
402
- ...props
403
- }, ref) => {
404
- const navigation = useNavigation({ href, onClick });
405
- const {
406
- normalizedHref,
407
- target,
408
- rel,
409
- linkType,
410
- isInternal,
411
- handleClick
412
- } = navigation;
413
- const shouldRenderLink = normalizedHref && linkType !== "none";
414
- const shouldRenderButton = !shouldRenderLink && onClick;
415
- const effectiveComponentType = componentType || (shouldRenderLink ? "a" : shouldRenderButton ? "button" : fallbackComponentType);
416
- const finalComponentType = isInternal && shouldRenderLink ? "a" : effectiveComponentType;
417
- const shouldApplyButtonStyles = asButton || variant || size;
418
- const combinedClassName = cn(
419
- shouldApplyButtonStyles && buttonVariants({ variant, size }),
420
- className
421
- );
422
- const dataProps = Object.fromEntries(
423
- Object.entries(props).filter(([key]) => key.startsWith("data-"))
424
- );
425
- const buttonDataAttributes = shouldApplyButtonStyles ? {
426
- "data-slot": "button",
427
- "data-variant": variant ?? "default",
428
- "data-size": size ?? "default"
429
- } : {};
430
- const commonProps = {
431
- className: combinedClassName,
432
- onClick: handleClick,
433
- "aria-label": ariaLabel,
434
- "aria-describedby": ariaDescribedby,
435
- id,
436
- ...dataProps,
437
- ...buttonDataAttributes
438
- };
439
- if (finalComponentType === "a" && shouldRenderLink) {
440
- return /* @__PURE__ */ jsx(
441
- "a",
442
- {
443
- ref,
444
- href: normalizedHref,
445
- target,
446
- rel,
447
- ...commonProps,
448
- ...props,
449
- children
450
- }
451
- );
452
- }
453
- if (finalComponentType === "button") {
454
- return /* @__PURE__ */ jsx(
455
- "button",
456
- {
457
- ref,
458
- type: props.type || "button",
459
- ...commonProps,
460
- ...props,
461
- children
462
- }
463
- );
464
- }
465
- if (finalComponentType === "div") {
466
- return /* @__PURE__ */ jsx(
467
- "div",
468
- {
469
- ref,
470
- ...commonProps,
471
- children
472
- }
473
- );
474
- }
475
- return /* @__PURE__ */ jsx(
476
- "span",
477
- {
478
- ref,
479
- ...commonProps,
480
- children
481
- }
482
- );
566
+ function normalizePhoneNumber(input) {
567
+ const trimmed = input.trim();
568
+ if (trimmed.toLowerCase().startsWith("tel:")) {
569
+ return trimmed;
483
570
  }
484
- );
485
- Pressable.displayName = "Pressable";
486
- var DEFAULT_ICON_API_KEY = "au382bi7fsh96w9h9xlrnat2jglx";
487
- function DynamicIcon({ apiKey, ...props }) {
488
- return /* @__PURE__ */ jsx(Icon, { ...props, apiKey: apiKey ?? DEFAULT_ICON_API_KEY });
571
+ const match = trimmed.match(/^[\s\+\-\(\)]*(\d[\d\s\-\(\)\.]*\d)[\s\-]*(x|ext\.?|extension)?[\s\-]*(\d+)?$/i);
572
+ if (match) {
573
+ const mainNumber = match[1].replace(/[\s\-\(\)\.]/g, "");
574
+ const extension = match[3];
575
+ const normalized = mainNumber.length >= 10 && !trimmed.startsWith("+") ? `+${mainNumber}` : mainNumber;
576
+ const withExtension = extension ? `${normalized};ext=${extension}` : normalized;
577
+ return `tel:${withExtension}`;
578
+ }
579
+ const cleaned = trimmed.replace(/[\s\-\(\)\.]/g, "");
580
+ return `tel:${cleaned}`;
489
581
  }
490
- function Avatar({
491
- className,
492
- ...props
493
- }) {
494
- return /* @__PURE__ */ jsx(
495
- AvatarPrimitive.Root,
496
- {
497
- "data-slot": "avatar",
498
- className: cn(
499
- "relative flex size-8 shrink-0 overflow-hidden rounded-full",
500
- className
501
- ),
502
- ...props
503
- }
504
- );
582
+ function normalizeEmail(input) {
583
+ const trimmed = input.trim();
584
+ if (trimmed.toLowerCase().startsWith("mailto:")) {
585
+ return trimmed;
586
+ }
587
+ return `mailto:${trimmed}`;
505
588
  }
506
- function AvatarImage({
507
- className,
508
- ...props
509
- }) {
510
- return /* @__PURE__ */ jsx(
511
- AvatarPrimitive.Image,
512
- {
513
- "data-slot": "avatar-image",
514
- className: cn("aspect-square size-full", className),
515
- ...props
516
- }
517
- );
589
+ function isEmail(input) {
590
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
591
+ return emailRegex.test(input.trim());
518
592
  }
519
- var maxWidthStyles = {
520
- sm: "max-w-screen-sm",
521
- md: "max-w-screen-md",
522
- lg: "max-w-screen-lg",
523
- xl: "max-w-7xl",
524
- "2xl": "max-w-screen-2xl",
525
- "4xl": "max-w-[1536px]",
526
- full: "max-w-full"
527
- };
528
- var Container = React__default.forwardRef(
529
- ({ children, maxWidth = "xl", className, as = "div", ...props }, ref) => {
530
- const Component = as;
531
- return /* @__PURE__ */ jsx(
532
- Component,
533
- {
534
- ref,
535
- className: cn(
536
- "mx-auto w-full px-2 sm:px-4 lg:px-8",
537
- maxWidthStyles[maxWidth],
538
- className
539
- ),
540
- ...props,
541
- children
542
- }
543
- );
544
- }
545
- );
546
- Container.displayName = "Container";
547
-
548
- // lib/patternSvgs.ts
549
- var patternSvgs = {
550
- squareAltGrid: "https://cdn.ing/assets/files/record/286187/4gpn0yq2ptra8iwlvmwwv860ggwv",
551
- grid1: "https://cdn.ing/assets/files/record/286186/nbdflpgp4ostrno079hygibsflp3",
552
- noise: "https://cdn.ing/assets/i/r/286188/zrqcp9hynh3j7p2laihwzfbujgrl/noise.png",
553
- dots: "https://cdn.ing/assets/files/record/286198/yfsjx9thvtxzhl2qtshxyhkrm524",
554
- dotPattern: "https://cdn.ing/assets/files/record/286192/7ig0cku8aqbboiza8nuk6hw0nnsr",
555
- dotPattern2: "https://cdn.ing/assets/files/record/286189/arez6gd2s7isn9i1o6c7sexdq7bl",
556
- circles: "https://cdn.ing/assets/files/record/286190/gtmia3sncjtzetdshc20zf1d3c17",
557
- waves: "https://cdn.ing/assets/files/record/286191/mqlb33fzxz9cdth1bx7if0wmpkp1",
558
- crossPattern: "https://cdn.ing/assets/files/record/286193/9yfqwdbnqaipbp7fsb3wbzzmq472",
559
- architect: "https://cdn.ing/assets/files/record/286194/vgs88ugpvyhxu13wqgy0acvae6re",
560
- tinyCheckers: "https://cdn.ing/assets/files/record/286195/65efaknsw8kcpf9o3c2gybytsl5b",
561
- p6: "https://cdn.ing/assets/i/r/286196/6kl0rqnd6mjk8j7e525fo8fo0vkc/p6.webp"
562
- };
563
- var maskTop = "radial-gradient(ellipse 70% 60% at 50% 0%, #000 60%, transparent 100%)";
564
- var maskBottom = "radial-gradient(ellipse 100% 80% at 50% 100%, #000 50%, transparent 90%)";
565
- var maskCenter = "radial-gradient(ellipse 60% 60% at 50% 50%, #000 30%, transparent 70%)";
566
- var maskTopLeft = "radial-gradient(ellipse 80% 80% at 0% 0%, #000 50%, transparent 90%)";
567
- var maskTopRight = "radial-gradient(ellipse 80% 80% at 100% 0%, #000 50%, transparent 90%)";
568
- var maskBottomLeft = "radial-gradient(ellipse 80% 80% at 0% 100%, #000 50%, transparent 90%)";
569
- var maskBottomRight = "radial-gradient(ellipse 80% 80% at 100% 100%, #000 50%, transparent 90%)";
570
- var circuitBoardPattern = (id, mask) => /* @__PURE__ */ jsxs(
571
- "svg",
572
- {
573
- className: "h-full w-full",
574
- xmlns: "http://www.w3.org/2000/svg",
575
- style: mask ? {
576
- maskImage: mask,
577
- WebkitMaskImage: mask
578
- } : void 0,
579
- children: [
580
- /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs(
581
- "pattern",
582
- {
583
- id,
584
- x: "0",
585
- y: "0",
586
- width: "100",
587
- height: "100",
588
- patternUnits: "userSpaceOnUse",
589
- children: [
590
- /* @__PURE__ */ jsx(
591
- "path",
592
- {
593
- d: "M0 50h40M60 50h40M50 0v40M50 60v40",
594
- stroke: "hsl(var(--muted))",
595
- strokeWidth: "1",
596
- fill: "none"
597
- }
598
- ),
599
- /* @__PURE__ */ jsx("circle", { cx: "50", cy: "50", r: "3", fill: "hsl(var(--muted))" }),
600
- /* @__PURE__ */ jsx("circle", { cx: "0", cy: "50", r: "2", fill: "hsl(var(--muted))" }),
601
- /* @__PURE__ */ jsx("circle", { cx: "100", cy: "50", r: "2", fill: "hsl(var(--muted))" }),
602
- /* @__PURE__ */ jsx("circle", { cx: "50", cy: "0", r: "2", fill: "hsl(var(--muted))" }),
603
- /* @__PURE__ */ jsx("circle", { cx: "50", cy: "100", r: "2", fill: "hsl(var(--muted))" })
604
- ]
605
- }
606
- ) }),
607
- /* @__PURE__ */ jsx("rect", { width: "100%", height: "100%", fill: `url(#${id})` })
608
- ]
609
- }
610
- );
611
- var gridDotsPattern = (id, mask) => /* @__PURE__ */ jsxs(
612
- "svg",
613
- {
614
- className: "h-full w-full",
615
- xmlns: "http://www.w3.org/2000/svg",
616
- style: mask ? {
617
- maskImage: mask,
618
- WebkitMaskImage: mask
619
- } : void 0,
620
- children: [
621
- /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs(
622
- "pattern",
623
- {
624
- id,
625
- x: "0",
626
- y: "0",
627
- width: "40",
628
- height: "40",
629
- patternUnits: "userSpaceOnUse",
630
- children: [
631
- /* @__PURE__ */ jsx(
632
- "path",
633
- {
634
- d: "M0 20h40M20 0v40",
635
- stroke: "hsl(var(--muted))",
636
- strokeWidth: "0.5",
637
- fill: "none"
638
- }
639
- ),
640
- /* @__PURE__ */ jsx("circle", { cx: "20", cy: "20", r: "2", fill: "hsl(var(--muted))" })
641
- ]
642
- }
643
- ) }),
644
- /* @__PURE__ */ jsx("rect", { width: "100%", height: "100%", fill: `url(#${id})` })
645
- ]
593
+ function isPhoneNumber(input) {
594
+ const trimmed = input.trim();
595
+ if (trimmed.toLowerCase().startsWith("tel:")) {
596
+ return true;
646
597
  }
647
- );
648
- var gridPattern = (size, mask) => /* @__PURE__ */ jsx(
649
- "div",
650
- {
651
- className: "h-full w-full bg-[linear-gradient(to_right,_hsl(var(--muted))_1px,_transparent_1px),linear-gradient(to_bottom,_hsl(var(--muted))_1px,_transparent_1px)]",
652
- style: {
653
- backgroundSize: `${size}px ${size}px`,
654
- ...mask ? {
655
- maskImage: mask,
656
- WebkitMaskImage: mask
657
- } : {}
658
- }
598
+ const phoneRegex = /^[\s\+\-\(\)]*\d[\d\s\-\(\)\.]*\d[\s\-]*(x|ext\.?|extension)?[\s\-]*\d*$/i;
599
+ return phoneRegex.test(trimmed);
600
+ }
601
+ function isInternalUrl(href) {
602
+ if (typeof window === "undefined") {
603
+ return href.startsWith("/") && !href.startsWith("//");
659
604
  }
660
- );
661
- var diagonalCrossPattern = (mask) => /* @__PURE__ */ jsx(
662
- "div",
663
- {
664
- className: "h-full w-full",
665
- style: {
666
- backgroundImage: "repeating-linear-gradient(45deg, transparent, transparent 32px, hsl(var(--muted)) 32px, hsl(var(--muted)) 33px), repeating-linear-gradient(135deg, transparent, transparent 32px, hsl(var(--muted)) 32px, hsl(var(--muted)) 33px)",
667
- ...mask ? {
668
- maskImage: mask,
669
- WebkitMaskImage: mask
670
- } : {}
671
- }
605
+ const trimmed = href.trim();
606
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
607
+ return true;
672
608
  }
673
- );
674
- var dashedGridMaskBase = "repeating-linear-gradient(to right, black 0px, black 3px, transparent 3px, transparent 8px), repeating-linear-gradient(to bottom, black 0px, black 3px, transparent 3px, transparent 8px)";
675
- var dashedGridPattern = (fadeMask) => {
676
- const mask = fadeMask ? `${dashedGridMaskBase}, ${fadeMask}` : dashedGridMaskBase;
677
- return /* @__PURE__ */ jsx(
678
- "div",
679
- {
680
- className: "h-full w-full",
681
- style: {
682
- backgroundImage: "linear-gradient(to right, hsl(var(--muted)) 1px, transparent 1px), linear-gradient(to bottom, hsl(var(--muted)) 1px, transparent 1px)",
683
- backgroundSize: "20px 20px",
684
- backgroundPosition: "0 0, 0 0",
685
- maskImage: mask,
686
- WebkitMaskImage: mask,
687
- maskComposite: "intersect",
688
- WebkitMaskComposite: "source-in"
689
- }
690
- }
691
- );
692
- };
693
- var gradientGlow = (position) => /* @__PURE__ */ jsx(
694
- "div",
695
- {
696
- className: cn(
697
- "pointer-events-none absolute left-1/2 z-0 aspect-square w-3/4 -translate-x-1/2 rounded-full opacity-50 blur-3xl",
698
- position === "top" ? "-top-1/4" : "-bottom-1/4"
699
- ),
700
- style: {
701
- background: "radial-gradient(circle, hsl(var(--primary)) 0%, transparent 70%)"
702
- }
609
+ try {
610
+ const url = new URL(trimmed, window.location.href);
611
+ const currentOrigin = window.location.origin;
612
+ const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
613
+ return normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin);
614
+ } catch {
615
+ return false;
703
616
  }
704
- );
705
- var spotlight = (position) => /* @__PURE__ */ jsx(
706
- "div",
707
- {
708
- className: cn(
709
- "pointer-events-none absolute top-1/2 z-0 aspect-square w-3/4 -translate-y-1/2 rounded-full opacity-40 blur-3xl",
710
- position === "left" ? "-left-1/4" : "-right-1/4"
711
- ),
712
- style: {
713
- background: "radial-gradient(circle, hsl(var(--primary)) 0%, transparent 70%)"
714
- }
617
+ }
618
+ function toRelativePath(href) {
619
+ if (typeof window === "undefined") {
620
+ return href;
715
621
  }
716
- );
717
- var patternOverlays = {
718
- circuitBoardBasic: () => circuitBoardPattern("circuit-board-basic"),
719
- circuitBoardFadeTop: () => circuitBoardPattern("circuit-board-fade-top", maskTop),
720
- circuitBoardFadeBottom: () => circuitBoardPattern("circuit-board-fade-bottom", maskBottom),
721
- circuitBoardFadeCenter: () => circuitBoardPattern("circuit-board-fade-center", maskCenter),
722
- circuitBoardFadeTopLeft: () => circuitBoardPattern("circuit-board-fade-top-left", maskTopLeft),
723
- circuitBoardFadeTopRight: () => circuitBoardPattern("circuit-board-fade-top-right", maskTopRight),
724
- circuitBoardFadeBottomLeft: () => circuitBoardPattern("circuit-board-fade-bottom-left", maskBottomLeft),
725
- circuitBoardFadeBottomRight: () => circuitBoardPattern("circuit-board-fade-bottom-right", maskBottomRight),
726
- dashedGridBasic: () => dashedGridPattern(),
727
- dashedGridFadeTop: () => dashedGridPattern(maskTop),
728
- dashedGridFadeBottom: () => dashedGridPattern(maskBottom),
729
- dashedGridFadeCenter: () => dashedGridPattern(maskCenter),
730
- dashedGridFadeTopLeft: () => dashedGridPattern(maskTopLeft),
731
- dashedGridFadeTopRight: () => dashedGridPattern(maskTopRight),
732
- dashedGridFadeBottomLeft: () => dashedGridPattern(maskBottomLeft),
733
- dashedGridFadeBottomRight: () => dashedGridPattern(maskBottomRight),
734
- diagonalCrossBasic: () => diagonalCrossPattern(),
735
- diagonalCrossFadeTop: () => diagonalCrossPattern(maskTop),
736
- diagonalCrossFadeBottom: () => diagonalCrossPattern(maskBottom),
737
- diagonalCrossFadeCenter: () => diagonalCrossPattern(maskCenter),
738
- diagonalCrossFadeTopLeft: () => diagonalCrossPattern(maskTopLeft),
739
- diagonalCrossFadeTopRight: () => diagonalCrossPattern(maskTopRight),
740
- diagonalCrossFadeBottomLeft: () => diagonalCrossPattern(maskBottomLeft),
741
- diagonalCrossFadeBottomRight: () => diagonalCrossPattern(maskBottomRight),
742
- gridBasic: () => gridPattern(40),
743
- gridFadeTop: () => gridPattern(32, maskTop),
744
- gridFadeBottom: () => gridPattern(32, maskBottom),
745
- gridFadeCenter: () => gridPattern(40, maskCenter),
746
- gridFadeTopLeft: () => gridPattern(32, maskTopLeft),
747
- gridFadeTopRight: () => gridPattern(32, maskTopRight),
748
- gridFadeBottomLeft: () => gridPattern(32, maskBottomLeft),
749
- gridFadeBottomRight: () => gridPattern(32, maskBottomRight),
750
- gridDotsBasic: () => gridDotsPattern("grid-dots-basic"),
751
- gridDotsFadeCenter: () => gridDotsPattern("grid-dots-fade-center", maskCenter),
752
- gradientGlowTop: () => gradientGlow("top"),
753
- gradientGlowBottom: () => gradientGlow("bottom"),
754
- spotlightLeft: () => spotlight("left"),
755
- spotlightRight: () => spotlight("right")
756
- };
757
- var inlinePatternStyles = {
758
- radialGradientTop: {
759
- background: "radial-gradient(125% 125% at 50% 10%, hsl(var(--background)) 40%, hsl(var(--primary)) 100%)"
760
- },
761
- radialGradientBottom: {
762
- background: "radial-gradient(125% 125% at 50% 90%, hsl(var(--background)) 40%, hsl(var(--primary)) 100%)"
622
+ const trimmed = href.trim();
623
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
624
+ return trimmed;
763
625
  }
764
- };
765
- function PatternBackground({
766
- pattern,
767
- opacity = 0.08,
768
- className,
769
- style
770
- }) {
771
- if (!pattern) {
772
- return null;
626
+ try {
627
+ const url = new URL(trimmed, window.location.href);
628
+ const currentOrigin = window.location.origin;
629
+ const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
630
+ if (normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin)) {
631
+ return url.pathname + url.search + url.hash;
632
+ }
633
+ } catch {
773
634
  }
774
- if (pattern in inlinePatternStyles) {
775
- const inlineStyle = inlinePatternStyles[pattern];
776
- return /* @__PURE__ */ jsx(
777
- "div",
778
- {
779
- className: cn("pointer-events-none absolute inset-0 z-0", className),
780
- style: { ...inlineStyle, opacity, ...style },
781
- "aria-hidden": "true"
635
+ return trimmed;
636
+ }
637
+ function useNavigation({
638
+ href,
639
+ onClick
640
+ } = {}) {
641
+ const linkType = React3.useMemo(() => {
642
+ if (!href || href.trim() === "") {
643
+ return onClick ? "none" : "none";
644
+ }
645
+ const trimmed = href.trim();
646
+ if (trimmed.toLowerCase().startsWith("mailto:") || isEmail(trimmed)) {
647
+ return "mailto";
648
+ }
649
+ if (trimmed.toLowerCase().startsWith("tel:") || isPhoneNumber(trimmed)) {
650
+ return "tel";
651
+ }
652
+ if (isInternalUrl(trimmed)) {
653
+ return "internal";
654
+ }
655
+ try {
656
+ new URL(trimmed, typeof window !== "undefined" ? window.location.href : "http://localhost");
657
+ return "external";
658
+ } catch {
659
+ return "internal";
660
+ }
661
+ }, [href, onClick]);
662
+ const normalizedHref = React3.useMemo(() => {
663
+ if (!href || href.trim() === "") {
664
+ return void 0;
665
+ }
666
+ const trimmed = href.trim();
667
+ switch (linkType) {
668
+ case "tel":
669
+ return normalizePhoneNumber(trimmed);
670
+ case "mailto":
671
+ return normalizeEmail(trimmed);
672
+ case "internal":
673
+ return toRelativePath(trimmed);
674
+ case "external":
675
+ return trimmed;
676
+ default:
677
+ return trimmed;
678
+ }
679
+ }, [href, linkType]);
680
+ const target = React3.useMemo(() => {
681
+ switch (linkType) {
682
+ case "external":
683
+ return "_blank";
684
+ case "internal":
685
+ return "_self";
686
+ case "mailto":
687
+ case "tel":
688
+ return void 0;
689
+ default:
690
+ return void 0;
691
+ }
692
+ }, [linkType]);
693
+ const rel = React3.useMemo(() => {
694
+ if (linkType === "external") {
695
+ return "noopener noreferrer";
696
+ }
697
+ return void 0;
698
+ }, [linkType]);
699
+ const isExternal = linkType === "external";
700
+ const isInternal = linkType === "internal";
701
+ const shouldUseRouter = isInternal && typeof normalizedHref === "string" && normalizedHref.startsWith("/");
702
+ const handleClick = React3.useCallback(
703
+ (event) => {
704
+ if (onClick) {
705
+ try {
706
+ onClick(event);
707
+ } catch (error) {
708
+ console.error("Error in user onClick handler:", error);
709
+ }
782
710
  }
783
- );
784
- }
785
- if (pattern in patternOverlays) {
786
- const Overlay = patternOverlays[pattern];
787
- return /* @__PURE__ */ jsx(
788
- "div",
789
- {
790
- className: cn("pointer-events-none absolute inset-0 z-0", className),
791
- style: { opacity, ...style },
792
- "aria-hidden": "true",
793
- children: Overlay()
711
+ if (event.defaultPrevented) {
712
+ return;
713
+ }
714
+ if (shouldUseRouter && normalizedHref && event.button === 0 && // left-click only
715
+ !event.metaKey && !event.altKey && !event.ctrlKey && !event.shiftKey) {
716
+ if (typeof window !== "undefined") {
717
+ const handler = window.__opensiteNavigationHandler;
718
+ if (typeof handler === "function") {
719
+ try {
720
+ const handled = handler(normalizedHref, event.nativeEvent || event);
721
+ if (handled !== false) {
722
+ event.preventDefault();
723
+ }
724
+ } catch (error) {
725
+ console.error("Error in navigation handler:", error);
726
+ }
727
+ }
728
+ }
794
729
  }
795
- );
796
- }
797
- const patternUrl = pattern in patternSvgs ? patternSvgs[pattern] : pattern;
798
- return /* @__PURE__ */ jsx(
799
- "div",
800
- {
801
- className: cn("pointer-events-none absolute inset-0 z-0", className),
802
- style: {
803
- backgroundImage: `url(${patternUrl})`,
804
- backgroundRepeat: "repeat",
805
- backgroundSize: "auto",
806
- opacity,
807
- ...style
808
- },
809
- "aria-hidden": "true"
810
- }
730
+ },
731
+ [onClick, shouldUseRouter, normalizedHref]
811
732
  );
733
+ return {
734
+ linkType,
735
+ normalizedHref,
736
+ target,
737
+ rel,
738
+ isExternal,
739
+ isInternal,
740
+ shouldUseRouter,
741
+ handleClick
742
+ };
812
743
  }
813
- var backgroundStyles = {
814
- default: "bg-background text-foreground",
815
- white: "bg-white text-dark",
816
- gray: "bg-muted/30 text-foreground",
817
- dark: "bg-foreground text-background",
818
- transparent: "bg-transparent text-foreground",
819
- gradient: "bg-linear-to-br from-primary via-primary/90 to-foreground text-primary-foreground",
820
- primary: "bg-primary text-primary-foreground",
821
- secondary: "bg-secondary text-secondary-foreground",
822
- muted: "bg-muted text-muted-foreground"
823
- };
824
- var spacingStyles = {
825
- none: "py-0 md:py-0",
826
- sm: "py-12 md:py-16",
827
- md: "py-16 md:py-24",
828
- lg: "py-20 md:py-32",
829
- xl: "py-24 md:py-40"
830
- };
831
- var predefinedSpacings = ["none", "sm", "md", "lg", "xl"];
832
- var isPredefinedSpacing = (spacing) => predefinedSpacings.includes(spacing);
833
- var Section = React__default.forwardRef(
744
+ var Pressable = React3.forwardRef(
834
745
  ({
835
- id,
836
- title,
837
- subtitle,
838
746
  children,
839
747
  className,
840
- style,
841
- background = "default",
842
- spacing = "lg",
843
- pattern,
844
- patternOpacity,
845
- patternClassName,
846
- containerClassName,
847
- containerMaxWidth = "xl",
748
+ href,
749
+ onClick,
750
+ variant,
751
+ size,
752
+ asButton = false,
753
+ fallbackComponentType = "span",
754
+ componentType,
755
+ "aria-label": ariaLabel,
756
+ "aria-describedby": ariaDescribedby,
757
+ id,
848
758
  ...props
849
759
  }, ref) => {
850
- const effectivePatternOpacity = patternOpacity !== void 0 ? patternOpacity : pattern ? 1 : 0;
851
- return /* @__PURE__ */ jsxs(
852
- "section",
760
+ const navigation = useNavigation({ href, onClick });
761
+ const {
762
+ normalizedHref,
763
+ target,
764
+ rel,
765
+ linkType,
766
+ isInternal,
767
+ handleClick
768
+ } = navigation;
769
+ const shouldRenderLink = normalizedHref && linkType !== "none";
770
+ const shouldRenderButton = !shouldRenderLink && onClick;
771
+ const effectiveComponentType = componentType || (shouldRenderLink ? "a" : shouldRenderButton ? "button" : fallbackComponentType);
772
+ const finalComponentType = isInternal && shouldRenderLink ? "a" : effectiveComponentType;
773
+ const shouldApplyButtonStyles = asButton || variant || size;
774
+ const combinedClassName = cn(
775
+ shouldApplyButtonStyles && buttonVariants({ variant, size }),
776
+ className
777
+ );
778
+ const dataProps = Object.fromEntries(
779
+ Object.entries(props).filter(([key]) => key.startsWith("data-"))
780
+ );
781
+ const buttonDataAttributes = shouldApplyButtonStyles ? {
782
+ "data-slot": "button",
783
+ "data-variant": variant ?? "default",
784
+ "data-size": size ?? "default"
785
+ } : {};
786
+ const commonProps = {
787
+ className: combinedClassName,
788
+ onClick: handleClick,
789
+ "aria-label": ariaLabel,
790
+ "aria-describedby": ariaDescribedby,
791
+ id,
792
+ ...dataProps,
793
+ ...buttonDataAttributes
794
+ };
795
+ if (finalComponentType === "a" && shouldRenderLink) {
796
+ return /* @__PURE__ */ jsx(
797
+ "a",
798
+ {
799
+ ref,
800
+ href: normalizedHref,
801
+ target,
802
+ rel,
803
+ ...commonProps,
804
+ ...props,
805
+ children
806
+ }
807
+ );
808
+ }
809
+ if (finalComponentType === "button") {
810
+ return /* @__PURE__ */ jsx(
811
+ "button",
812
+ {
813
+ ref,
814
+ type: props.type || "button",
815
+ ...commonProps,
816
+ ...props,
817
+ children
818
+ }
819
+ );
820
+ }
821
+ if (finalComponentType === "div") {
822
+ return /* @__PURE__ */ jsx(
823
+ "div",
824
+ {
825
+ ref,
826
+ ...commonProps,
827
+ children
828
+ }
829
+ );
830
+ }
831
+ return /* @__PURE__ */ jsx(
832
+ "span",
853
833
  {
854
834
  ref,
855
- id,
835
+ ...commonProps,
836
+ children
837
+ }
838
+ );
839
+ }
840
+ );
841
+ Pressable.displayName = "Pressable";
842
+ var MOBILE_CLASSES = {
843
+ "fit-left": "items-start md:items-center",
844
+ "fit-center": "items-center",
845
+ "fit-right": "items-end md:items-center",
846
+ "full-left": "items-stretch md:items-center",
847
+ "full-center": "items-stretch md:items-center",
848
+ "full-right": "items-stretch md:items-center"
849
+ };
850
+ function BlockActions({
851
+ mobileConfig,
852
+ actionsClassName,
853
+ verticalSpacing = "mt-4 md:mt-8",
854
+ actions,
855
+ actionsSlot
856
+ }) {
857
+ const renderAction = React3.useCallback(
858
+ (action, idx) => {
859
+ const {
860
+ label,
861
+ icon,
862
+ iconAfter,
863
+ children,
864
+ href,
865
+ onClick,
866
+ className: actionClassName,
867
+ ...pressableProps
868
+ } = action;
869
+ return /* @__PURE__ */ jsx(
870
+ Pressable,
871
+ {
872
+ href,
873
+ onClick,
874
+ asButton: action.asButton || true,
875
+ className: actionClassName,
876
+ ...pressableProps,
877
+ children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
878
+ icon,
879
+ label,
880
+ iconAfter
881
+ ] })
882
+ },
883
+ idx
884
+ );
885
+ },
886
+ []
887
+ );
888
+ const width = mobileConfig?.width ?? "full";
889
+ const position = mobileConfig?.position ?? "center";
890
+ const mobileLayoutClass = MOBILE_CLASSES[`${width}-${position}`];
891
+ if (actionsSlot) {
892
+ return /* @__PURE__ */ jsx("div", { children: actionsSlot });
893
+ } else if (actions && actions?.length > 0) {
894
+ return /* @__PURE__ */ jsx(
895
+ "div",
896
+ {
856
897
  className: cn(
857
- "relative",
858
- pattern ? "overflow-hidden" : null,
859
- backgroundStyles[background],
860
- isPredefinedSpacing(spacing) ? spacingStyles[spacing] : spacing,
861
- className
898
+ "flex flex-col md:flex-row flex-wrap gap-4",
899
+ mobileLayoutClass,
900
+ actionsClassName,
901
+ verticalSpacing
862
902
  ),
863
- style,
864
- ...props,
865
- children: [
866
- /* @__PURE__ */ jsx(
867
- PatternBackground,
868
- {
869
- pattern,
870
- opacity: effectivePatternOpacity,
871
- className: patternClassName
872
- }
873
- ),
874
- /* @__PURE__ */ jsxs(
875
- Container,
876
- {
877
- maxWidth: containerMaxWidth,
878
- className: cn("relative z-10", containerClassName),
879
- children: [
880
- (title || subtitle) && /* @__PURE__ */ jsxs("div", { className: "mb-6 text-center md:mb-16", children: [
881
- subtitle && /* @__PURE__ */ jsx("p", { className: "mb-2 text-sm font-semibold uppercase tracking-wider", children: subtitle }),
882
- title && /* @__PURE__ */ jsx("h2", { className: "text-3xl font-bold tracking-tight md:text-4xl lg:text-5xl", children: title })
883
- ] }),
884
- children
885
- ]
886
- }
887
- )
888
- ]
903
+ children: actions.map((action, index) => renderAction(action, index))
889
904
  }
890
905
  );
906
+ } else {
907
+ return null;
891
908
  }
892
- );
893
- Section.displayName = "Section";
909
+ }
894
910
  function HeroGradientAvatarsRating({
895
- topLinkText,
896
- topLinkHref,
897
- topLinkSlot,
898
911
  heading,
899
912
  headingSubtitle,
900
913
  description,
@@ -908,11 +921,11 @@ function HeroGradientAvatarsRating({
908
921
  images,
909
922
  imagesSlot,
910
923
  background,
911
- spacing,
912
924
  pattern,
913
925
  patternOpacity,
914
926
  className,
915
- containerClassName,
927
+ containerClassName = "px-6 sm:px-6 md:px-8 lg:px-8",
928
+ spacing = "xl",
916
929
  contentClassName,
917
930
  headingClassName,
918
931
  descriptionClassName,
@@ -920,39 +933,6 @@ function HeroGradientAvatarsRating({
920
933
  imagesClassName,
921
934
  optixFlowConfig
922
935
  }) {
923
- const renderTopLink = useMemo(() => {
924
- if (topLinkSlot) return topLinkSlot;
925
- if (!topLinkText || !topLinkHref) return null;
926
- return /* @__PURE__ */ jsx(
927
- Pressable,
928
- {
929
- href: topLinkHref,
930
- className: cn("my-6 text-xs font-bold tracking-[0.3em] uppercase hover:underline", getTextColor(background, "muted")),
931
- children: topLinkText
932
- }
933
- );
934
- }, [topLinkSlot, topLinkText, topLinkHref]);
935
- const renderActions = useMemo(() => {
936
- if (actionsSlot) return actionsSlot;
937
- if (!actions || actions.length === 0) return null;
938
- return /* @__PURE__ */ jsx("div", { className: cn("flex w-full flex-col justify-center gap-3 sm:flex-row lg:justify-start", actionsClassName), children: actions.map((action, index) => {
939
- const { label, icon, iconAfter, children, className: actionClassName, ...pressableProps } = action;
940
- return /* @__PURE__ */ jsx(
941
- Pressable,
942
- {
943
- asButton: true,
944
- className: actionClassName,
945
- ...pressableProps,
946
- children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
947
- icon,
948
- label,
949
- iconAfter
950
- ] })
951
- },
952
- index
953
- );
954
- }) });
955
- }, [actionsSlot, actions, actionsClassName]);
956
936
  const renderAvatars = useMemo(() => {
957
937
  if (avatarsSlot) return avatarsSlot;
958
938
  if (!avatars || avatars.length === 0) return null;
@@ -980,65 +960,116 @@ function HeroGradientAvatarsRating({
980
960
  )),
981
961
  ratingValue && /* @__PURE__ */ jsx("span", { className: "font-semibold", children: ratingValue })
982
962
  ] }),
983
- ratingLabel && (typeof ratingLabel === "string" ? /* @__PURE__ */ jsx("p", { className: cn("text-sm font-medium", getTextColor(background, "muted")), children: ratingLabel }) : ratingLabel)
963
+ ratingLabel && (typeof ratingLabel === "string" ? /* @__PURE__ */ jsx("p", { className: cn("text-sm font-medium"), children: ratingLabel }) : ratingLabel)
984
964
  ] });
985
965
  }, [ratingValue, ratingLabel, starCount]);
986
966
  const renderImages = useMemo(() => {
987
967
  if (imagesSlot) return imagesSlot;
988
968
  if (!images || images.length === 0) return null;
989
- return /* @__PURE__ */ jsxs("div", { className: cn("relative grid gap-4 lg:grid-cols-2", imagesClassName), children: [
990
- images[0] && /* @__PURE__ */ jsx("div", { className: cn("relative aspect-3/4 w-full overflow-hidden rounded-lg", getNestedCardBg(background)), children: /* @__PURE__ */ jsx(
991
- Img,
992
- {
993
- src: images[0].src,
994
- alt: images[0].alt,
995
- className: cn("h-full w-full object-cover transition-transform duration-300 hover:scale-105", images[0].className),
996
- optixFlowConfig
997
- }
998
- ) }),
999
- images[1] && /* @__PURE__ */ jsx("div", { className: cn("relative aspect-3/4 w-full overflow-hidden rounded-lg lg:mt-8", getNestedCardBg(background)), children: /* @__PURE__ */ jsx(
1000
- Img,
1001
- {
1002
- src: images[1].src,
1003
- alt: images[1].alt,
1004
- className: cn("h-full w-full object-cover transition-transform duration-300 hover:scale-105", images[1].className),
1005
- optixFlowConfig
1006
- }
1007
- ) })
1008
- ] });
969
+ return /* @__PURE__ */ jsxs(
970
+ "div",
971
+ {
972
+ className: cn("relative grid gap-4 lg:grid-cols-2", imagesClassName),
973
+ children: [
974
+ images[0] && /* @__PURE__ */ jsx(
975
+ "div",
976
+ {
977
+ className: cn(
978
+ "relative aspect-3/4 w-full overflow-hidden rounded-xl shadow-xl"
979
+ ),
980
+ children: /* @__PURE__ */ jsx(
981
+ Img,
982
+ {
983
+ src: images[0].src,
984
+ alt: images[0].alt,
985
+ className: cn(
986
+ "h-full w-full object-cover transition-transform duration-300 hover:scale-105",
987
+ images[0].className
988
+ ),
989
+ optixFlowConfig
990
+ }
991
+ )
992
+ }
993
+ ),
994
+ images[1] && /* @__PURE__ */ jsx(
995
+ "div",
996
+ {
997
+ className: cn(
998
+ "relative aspect-3/4 w-full overflow-hidden rounded-lg lg:mt-8"
999
+ ),
1000
+ children: /* @__PURE__ */ jsx(
1001
+ Img,
1002
+ {
1003
+ src: images[1].src,
1004
+ alt: images[1].alt,
1005
+ className: cn(
1006
+ "h-full w-full object-cover transition-transform duration-300 hover:scale-105",
1007
+ images[1].className
1008
+ ),
1009
+ optixFlowConfig
1010
+ }
1011
+ )
1012
+ }
1013
+ )
1014
+ ]
1015
+ }
1016
+ );
1009
1017
  }, [imagesSlot, images, imagesClassName, optixFlowConfig]);
1010
- return /* @__PURE__ */ jsxs(
1018
+ return /* @__PURE__ */ jsx(
1011
1019
  Section,
1012
1020
  {
1013
1021
  background,
1014
1022
  spacing,
1015
1023
  pattern,
1016
1024
  patternOpacity,
1017
- className: cn(className),
1018
- children: [
1019
- /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-x-0 -top-20 -bottom-20 bg-[radial-gradient(ellipse_35%_15%_at_40%_55%,hsl(var(--accent))_0%,transparent_100%)] lg:bg-[radial-gradient(ellipse_12%_20%_at_60%_45%,hsl(var(--accent))_0%,transparent_100%)]" }),
1020
- /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-x-0 -top-20 -bottom-20 bg-[radial-gradient(ellipse_35%_20%_at_70%_75%,hsl(var(--accent))_0%,transparent_80%)] lg:bg-[radial-gradient(ellipse_15%_30%_at_70%_65%,hsl(var(--accent))_0%,transparent_80%)]" }),
1021
- /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-x-0 -top-20 -bottom-20 bg-[radial-gradient(hsl(var(--accent-foreground)/0.1)_1px,transparent_1px)] mask-[radial-gradient(ellipse_60%_60%_at_65%_50%,#000_0%,transparent_80%)] bg-size-[8px_8px]" }),
1022
- /* @__PURE__ */ jsx("div", { className: cn("relative z-10 container mx-auto px-4", containerClassName), children: /* @__PURE__ */ jsxs("div", { className: "grid items-center gap-8 lg:grid-cols-2", children: [
1023
- /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col items-center text-center lg:items-start lg:text-left", contentClassName), children: [
1024
- renderTopLink,
1025
- heading && /* @__PURE__ */ jsxs("h1", { className: cn("text-4xl font-semibold sm:text-5xl", headingClassName), children: [
1026
- typeof heading === "string" ? heading : heading,
1027
- headingSubtitle && /* @__PURE__ */ jsxs(Fragment, { children: [
1028
- /* @__PURE__ */ jsx("br", {}),
1029
- /* @__PURE__ */ jsx("span", { className: getTextColor(background, "muted"), children: headingSubtitle })
1025
+ className,
1026
+ containerClassName,
1027
+ children: /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsxs("div", { className: "grid items-center gap-8 lg:grid-cols-2", children: [
1028
+ /* @__PURE__ */ jsxs(
1029
+ "div",
1030
+ {
1031
+ className: cn(
1032
+ "flex flex-col items-center text-center lg:items-start lg:text-left",
1033
+ contentClassName
1034
+ ),
1035
+ children: [
1036
+ heading && /* @__PURE__ */ jsx(
1037
+ "h1",
1038
+ {
1039
+ className: cn(
1040
+ "text-4xl font-semibold sm:text-5xl",
1041
+ headingClassName
1042
+ ),
1043
+ children: typeof heading === "string" ? heading : heading
1044
+ }
1045
+ ),
1046
+ description && (typeof description === "string" ? /* @__PURE__ */ jsx(
1047
+ "p",
1048
+ {
1049
+ className: cn(
1050
+ "my-8 max-w-xl lg:text-lg",
1051
+ descriptionClassName
1052
+ ),
1053
+ children: description
1054
+ }
1055
+ ) : /* @__PURE__ */ jsx("div", { className: descriptionClassName, children: description })),
1056
+ /* @__PURE__ */ jsx(
1057
+ BlockActions,
1058
+ {
1059
+ actions,
1060
+ actionsSlot,
1061
+ actionsClassName
1062
+ }
1063
+ ),
1064
+ (avatars || avatarsSlot || ratingValue || ratingLabel) && /* @__PURE__ */ jsxs("div", { className: "mt-8 flex flex-col items-center gap-4 sm:flex-row sm:items-center", children: [
1065
+ renderAvatars,
1066
+ renderRating
1030
1067
  ] })
1031
- ] }),
1032
- description && (typeof description === "string" ? /* @__PURE__ */ jsx("p", { className: cn("my-8 max-w-xl lg:text-lg", getTextColor(background, "muted"), descriptionClassName), children: description }) : /* @__PURE__ */ jsx("div", { className: descriptionClassName, children: description })),
1033
- renderActions,
1034
- (avatars || avatarsSlot || ratingValue || ratingLabel) && /* @__PURE__ */ jsxs("div", { className: "mt-8 flex flex-col items-center gap-4 sm:flex-row sm:items-center", children: [
1035
- renderAvatars,
1036
- renderRating
1037
- ] })
1038
- ] }),
1039
- renderImages
1040
- ] }) })
1041
- ]
1068
+ ]
1069
+ }
1070
+ ),
1071
+ renderImages
1072
+ ] }) })
1042
1073
  }
1043
1074
  );
1044
1075
  }