@opensite/ui 1.8.6 → 1.8.8

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