@opensite/ui 2.0.2 → 2.0.4

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