@opensite/ui 2.7.1 → 2.7.2

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