@opensite/ui 1.2.4 → 1.2.6
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.
- package/dist/feature-accordion-image.cjs +101 -27
- package/dist/feature-accordion-image.js +101 -27
- package/dist/feature-animated-carousel.cjs +809 -321
- package/dist/feature-animated-carousel.d.cts +29 -1
- package/dist/feature-animated-carousel.d.ts +29 -1
- package/dist/feature-animated-carousel.js +807 -319
- package/dist/feature-card-grid-linked.cjs +1 -1
- package/dist/feature-card-grid-linked.js +1 -1
- package/dist/feature-carousel-progress.cjs +35 -10
- package/dist/feature-carousel-progress.js +35 -10
- package/dist/feature-checklist-image.cjs +1 -1
- package/dist/feature-checklist-image.js +1 -1
- package/dist/feature-icon-grid-muted.cjs +521 -15
- package/dist/feature-icon-grid-muted.d.cts +5 -1
- package/dist/feature-icon-grid-muted.d.ts +5 -1
- package/dist/feature-icon-grid-muted.js +521 -15
- package/dist/feature-image-cards-three-column.cjs +146 -75
- package/dist/feature-image-cards-three-column.d.cts +5 -1
- package/dist/feature-image-cards-three-column.d.ts +5 -1
- package/dist/feature-image-cards-three-column.js +146 -75
- package/dist/feature-numbered-cards.cjs +1 -1
- package/dist/feature-numbered-cards.js +1 -1
- package/dist/feature-stats-highlight.cjs +25 -39
- package/dist/feature-stats-highlight.js +25 -39
- package/dist/registry.cjs +767 -402
- package/dist/registry.js +767 -402
- package/package.json +1 -1
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var React6 = require('react');
|
|
5
5
|
var framerMotion = require('framer-motion');
|
|
6
6
|
var clsx = require('clsx');
|
|
7
7
|
var tailwindMerge = require('tailwind-merge');
|
|
8
8
|
var img = require('@page-speed/img');
|
|
9
9
|
var jsxRuntime = require('react/jsx-runtime');
|
|
10
|
+
var classVarianceAuthority = require('class-variance-authority');
|
|
10
11
|
|
|
11
12
|
function _interopNamespace(e) {
|
|
12
13
|
if (e && e.__esModule) return e;
|
|
@@ -26,42 +27,12 @@ function _interopNamespace(e) {
|
|
|
26
27
|
return Object.freeze(n);
|
|
27
28
|
}
|
|
28
29
|
|
|
29
|
-
var
|
|
30
|
+
var React6__namespace = /*#__PURE__*/_interopNamespace(React6);
|
|
30
31
|
|
|
31
32
|
// components/blocks/features/feature-animated-carousel.tsx
|
|
32
33
|
function cn(...inputs) {
|
|
33
34
|
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
34
35
|
}
|
|
35
|
-
function getNestedCardBg(parentBg, variant = "muted", options) {
|
|
36
|
-
const isDark = parentBg === "dark" || parentBg === "secondary" || parentBg === "primary";
|
|
37
|
-
if (isDark) {
|
|
38
|
-
switch (variant) {
|
|
39
|
-
case "muted":
|
|
40
|
-
return "bg-background";
|
|
41
|
-
case "card":
|
|
42
|
-
return "bg-card";
|
|
43
|
-
case "accent":
|
|
44
|
-
return "bg-accent";
|
|
45
|
-
case "subtle":
|
|
46
|
-
return "bg-background/50";
|
|
47
|
-
}
|
|
48
|
-
} else {
|
|
49
|
-
switch (variant) {
|
|
50
|
-
case "muted":
|
|
51
|
-
return "bg-muted";
|
|
52
|
-
case "card":
|
|
53
|
-
return "bg-card";
|
|
54
|
-
case "accent":
|
|
55
|
-
return "bg-accent";
|
|
56
|
-
case "subtle":
|
|
57
|
-
return "bg-muted/50";
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
function getNestedCardTextColor(parentBg, options) {
|
|
62
|
-
const isDark = parentBg === "dark" || parentBg === "secondary" || parentBg === "primary";
|
|
63
|
-
return isDark ? "text-foreground" : "";
|
|
64
|
-
}
|
|
65
36
|
var svgCache = /* @__PURE__ */ new Map();
|
|
66
37
|
function DynamicIcon({
|
|
67
38
|
name,
|
|
@@ -70,10 +41,10 @@ function DynamicIcon({
|
|
|
70
41
|
className,
|
|
71
42
|
alt
|
|
72
43
|
}) {
|
|
73
|
-
const [svgContent, setSvgContent] =
|
|
74
|
-
const [isLoading, setIsLoading] =
|
|
75
|
-
const [error, setError] =
|
|
76
|
-
const { url, iconName } =
|
|
44
|
+
const [svgContent, setSvgContent] = React6__namespace.useState(null);
|
|
45
|
+
const [isLoading, setIsLoading] = React6__namespace.useState(true);
|
|
46
|
+
const [error, setError] = React6__namespace.useState(null);
|
|
47
|
+
const { url, iconName } = React6__namespace.useMemo(() => {
|
|
77
48
|
const separator = name.includes("/") ? "/" : ":";
|
|
78
49
|
const [prefix, iconName2] = name.split(separator);
|
|
79
50
|
const baseUrl = `https://icons.opensite.ai/api/icon/${prefix}/${iconName2}?format=svg&width=${size}&height=${size}`;
|
|
@@ -82,7 +53,7 @@ function DynamicIcon({
|
|
|
82
53
|
iconName: iconName2
|
|
83
54
|
};
|
|
84
55
|
}, [name, size]);
|
|
85
|
-
|
|
56
|
+
React6__namespace.useEffect(() => {
|
|
86
57
|
let isMounted = true;
|
|
87
58
|
const fetchSvg = async () => {
|
|
88
59
|
const cached = svgCache.get(url);
|
|
@@ -176,7 +147,7 @@ var maxWidthStyles = {
|
|
|
176
147
|
"4xl": "max-w-[1536px]",
|
|
177
148
|
full: "max-w-full"
|
|
178
149
|
};
|
|
179
|
-
var Container =
|
|
150
|
+
var Container = React6__namespace.default.forwardRef(
|
|
180
151
|
({ children, maxWidth = "xl", className, as = "div", ...props }, ref) => {
|
|
181
152
|
const Component = as;
|
|
182
153
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -481,7 +452,7 @@ var spacingStyles = {
|
|
|
481
452
|
};
|
|
482
453
|
var predefinedSpacings = ["none", "sm", "md", "lg", "xl"];
|
|
483
454
|
var isPredefinedSpacing = (spacing) => predefinedSpacings.includes(spacing);
|
|
484
|
-
var Section =
|
|
455
|
+
var Section = React6__namespace.default.forwardRef(
|
|
485
456
|
({
|
|
486
457
|
id,
|
|
487
458
|
title,
|
|
@@ -542,271 +513,728 @@ var Section = React4__namespace.default.forwardRef(
|
|
|
542
513
|
}
|
|
543
514
|
);
|
|
544
515
|
Section.displayName = "Section";
|
|
545
|
-
var
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
516
|
+
var baseStyles = [
|
|
517
|
+
// Layout
|
|
518
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap shrink-0",
|
|
519
|
+
// Typography - using CSS variables with sensible defaults
|
|
520
|
+
"font-[var(--button-font-family,inherit)]",
|
|
521
|
+
"font-[var(--button-font-weight,500)]",
|
|
522
|
+
"tracking-[var(--button-letter-spacing,0)]",
|
|
523
|
+
"leading-[var(--button-line-height,1.25)]",
|
|
524
|
+
"[text-transform:var(--button-text-transform,none)]",
|
|
525
|
+
"text-sm",
|
|
526
|
+
// Border radius
|
|
527
|
+
"rounded-[var(--button-radius,var(--radius,0.375rem))]",
|
|
528
|
+
// Smooth transition - using [transition:...] to set full shorthand property (not just transition-property)
|
|
529
|
+
"[transition:var(--button-transition,all_250ms_cubic-bezier(0.4,0,0.2,1))]",
|
|
530
|
+
// Box shadow (master level) - using [box-shadow:...] for complex multi-value shadows
|
|
531
|
+
"[box-shadow:var(--button-shadow,none)]",
|
|
532
|
+
"hover:[box-shadow:var(--button-shadow-hover,var(--button-shadow,none))]",
|
|
533
|
+
// Disabled state
|
|
534
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
535
|
+
// SVG handling
|
|
536
|
+
"[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0",
|
|
537
|
+
// Focus styles
|
|
538
|
+
"outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
539
|
+
// Invalid state
|
|
540
|
+
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
|
|
541
|
+
].join(" ");
|
|
542
|
+
var buttonVariants = classVarianceAuthority.cva(baseStyles, {
|
|
543
|
+
variants: {
|
|
544
|
+
variant: {
|
|
545
|
+
// Default (Primary) variant - full customization
|
|
546
|
+
default: [
|
|
547
|
+
"bg-[var(--button-default-bg,hsl(var(--primary)))]",
|
|
548
|
+
"text-[var(--button-default-fg,hsl(var(--primary-foreground)))]",
|
|
549
|
+
"border-[length:var(--button-default-border-width,0px)]",
|
|
550
|
+
"border-[color:var(--button-default-border,transparent)]",
|
|
551
|
+
"[box-shadow:var(--button-default-shadow,var(--button-shadow,none))]",
|
|
552
|
+
"hover:bg-[var(--button-default-hover-bg,hsl(var(--primary)/0.9))]",
|
|
553
|
+
"hover:text-[var(--button-default-hover-fg,var(--button-default-fg,hsl(var(--primary-foreground))))]",
|
|
554
|
+
"hover:border-[color:var(--button-default-hover-border,var(--button-default-border,transparent))]",
|
|
555
|
+
"hover:[box-shadow:var(--button-default-shadow-hover,var(--button-shadow-hover,var(--button-default-shadow,var(--button-shadow,none))))]"
|
|
556
|
+
].join(" "),
|
|
557
|
+
// Destructive variant - full customization
|
|
558
|
+
destructive: [
|
|
559
|
+
"bg-[var(--button-destructive-bg,hsl(var(--destructive)))]",
|
|
560
|
+
"text-[var(--button-destructive-fg,white)]",
|
|
561
|
+
"border-[length:var(--button-destructive-border-width,0px)]",
|
|
562
|
+
"border-[color:var(--button-destructive-border,transparent)]",
|
|
563
|
+
"[box-shadow:var(--button-destructive-shadow,var(--button-shadow,none))]",
|
|
564
|
+
"hover:bg-[var(--button-destructive-hover-bg,hsl(var(--destructive)/0.9))]",
|
|
565
|
+
"hover:text-[var(--button-destructive-hover-fg,var(--button-destructive-fg,white))]",
|
|
566
|
+
"hover:border-[color:var(--button-destructive-hover-border,var(--button-destructive-border,transparent))]",
|
|
567
|
+
"hover:[box-shadow:var(--button-destructive-shadow-hover,var(--button-shadow-hover,var(--button-destructive-shadow,var(--button-shadow,none))))]",
|
|
568
|
+
"focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
|
|
569
|
+
"dark:bg-destructive/60"
|
|
570
|
+
].join(" "),
|
|
571
|
+
// Outline variant - full customization with proper border handling
|
|
572
|
+
outline: [
|
|
573
|
+
"bg-[var(--button-outline-bg,hsl(var(--background)))]",
|
|
574
|
+
"text-[var(--button-outline-fg,inherit)]",
|
|
575
|
+
"border-[length:var(--button-outline-border-width,1px)]",
|
|
576
|
+
"border-[color:var(--button-outline-border,hsl(var(--border)))]",
|
|
577
|
+
"[box-shadow:var(--button-outline-shadow,var(--button-shadow,0_1px_2px_0_rgb(0_0_0/0.05)))]",
|
|
578
|
+
"hover:bg-[var(--button-outline-hover-bg,hsl(var(--accent)))]",
|
|
579
|
+
"hover:text-[var(--button-outline-hover-fg,hsl(var(--accent-foreground)))]",
|
|
580
|
+
"hover:border-[color:var(--button-outline-hover-border,var(--button-outline-border,hsl(var(--border))))]",
|
|
581
|
+
"hover:[box-shadow:var(--button-outline-shadow-hover,var(--button-shadow-hover,var(--button-outline-shadow,var(--button-shadow,none))))]",
|
|
582
|
+
"dark:bg-input/30 dark:border-input dark:hover:bg-input/50"
|
|
583
|
+
].join(" "),
|
|
584
|
+
// Secondary variant - full customization
|
|
585
|
+
secondary: [
|
|
586
|
+
"bg-[var(--button-secondary-bg,hsl(var(--secondary)))]",
|
|
587
|
+
"text-[var(--button-secondary-fg,hsl(var(--secondary-foreground)))]",
|
|
588
|
+
"border-[length:var(--button-secondary-border-width,0px)]",
|
|
589
|
+
"border-[color:var(--button-secondary-border,transparent)]",
|
|
590
|
+
"[box-shadow:var(--button-secondary-shadow,var(--button-shadow,none))]",
|
|
591
|
+
"hover:bg-[var(--button-secondary-hover-bg,hsl(var(--secondary)/0.8))]",
|
|
592
|
+
"hover:text-[var(--button-secondary-hover-fg,var(--button-secondary-fg,hsl(var(--secondary-foreground))))]",
|
|
593
|
+
"hover:border-[color:var(--button-secondary-hover-border,var(--button-secondary-border,transparent))]",
|
|
594
|
+
"hover:[box-shadow:var(--button-secondary-shadow-hover,var(--button-shadow-hover,var(--button-secondary-shadow,var(--button-shadow,none))))]"
|
|
595
|
+
].join(" "),
|
|
596
|
+
// Ghost variant - full customization
|
|
597
|
+
ghost: [
|
|
598
|
+
"bg-[var(--button-ghost-bg,transparent)]",
|
|
599
|
+
"text-[var(--button-ghost-fg,inherit)]",
|
|
600
|
+
"border-[length:var(--button-ghost-border-width,0px)]",
|
|
601
|
+
"border-[color:var(--button-ghost-border,transparent)]",
|
|
602
|
+
"[box-shadow:var(--button-ghost-shadow,var(--button-shadow,none))]",
|
|
603
|
+
"hover:bg-[var(--button-ghost-hover-bg,hsl(var(--accent)))]",
|
|
604
|
+
"hover:text-[var(--button-ghost-hover-fg,hsl(var(--accent-foreground)))]",
|
|
605
|
+
"hover:border-[color:var(--button-ghost-hover-border,var(--button-ghost-border,transparent))]",
|
|
606
|
+
"hover:[box-shadow:var(--button-ghost-shadow-hover,var(--button-shadow-hover,var(--button-ghost-shadow,var(--button-shadow,none))))]",
|
|
607
|
+
"dark:hover:bg-accent/50"
|
|
608
|
+
].join(" "),
|
|
609
|
+
// Link variant - full customization
|
|
610
|
+
link: [
|
|
611
|
+
"bg-[var(--button-link-bg,transparent)]",
|
|
612
|
+
"text-[var(--button-link-fg,hsl(var(--primary)))]",
|
|
613
|
+
"border-[length:var(--button-link-border-width,0px)]",
|
|
614
|
+
"border-[color:var(--button-link-border,transparent)]",
|
|
615
|
+
"[box-shadow:var(--button-link-shadow,none)]",
|
|
616
|
+
"hover:bg-[var(--button-link-hover-bg,transparent)]",
|
|
617
|
+
"hover:text-[var(--button-link-hover-fg,var(--button-link-fg,hsl(var(--primary))))]",
|
|
618
|
+
"hover:[box-shadow:var(--button-link-shadow-hover,none)]",
|
|
619
|
+
"underline-offset-4 hover:underline"
|
|
620
|
+
].join(" ")
|
|
621
|
+
},
|
|
622
|
+
size: {
|
|
623
|
+
default: [
|
|
624
|
+
"h-[var(--button-height-md,2.25rem)]",
|
|
625
|
+
"px-[var(--button-padding-x-md,1rem)]",
|
|
626
|
+
"py-[var(--button-padding-y-md,0.5rem)]",
|
|
627
|
+
"has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
|
|
628
|
+
].join(" "),
|
|
629
|
+
sm: [
|
|
630
|
+
"h-[var(--button-height-sm,2rem)]",
|
|
631
|
+
"px-[var(--button-padding-x-sm,0.75rem)]",
|
|
632
|
+
"py-[var(--button-padding-y-sm,0.25rem)]",
|
|
633
|
+
"gap-1.5",
|
|
634
|
+
"has-[>svg]:px-[calc(var(--button-padding-x-sm,0.75rem)*0.83)]"
|
|
635
|
+
].join(" "),
|
|
636
|
+
md: [
|
|
637
|
+
"h-[var(--button-height-md,2.25rem)]",
|
|
638
|
+
"px-[var(--button-padding-x-md,1rem)]",
|
|
639
|
+
"py-[var(--button-padding-y-md,0.5rem)]",
|
|
640
|
+
"has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
|
|
641
|
+
].join(" "),
|
|
642
|
+
lg: [
|
|
643
|
+
"h-[var(--button-height-lg,2.5rem)]",
|
|
644
|
+
"px-[var(--button-padding-x-lg,1.5rem)]",
|
|
645
|
+
"py-[var(--button-padding-y-lg,0.5rem)]",
|
|
646
|
+
"has-[>svg]:px-[calc(var(--button-padding-x-lg,1.5rem)*0.67)]"
|
|
647
|
+
].join(" "),
|
|
648
|
+
icon: "size-[var(--button-height-md,2.25rem)]",
|
|
649
|
+
"icon-sm": "size-[var(--button-height-sm,2rem)]",
|
|
650
|
+
"icon-lg": "size-[var(--button-height-lg,2.5rem)]"
|
|
651
|
+
}
|
|
652
|
+
},
|
|
653
|
+
defaultVariants: {
|
|
654
|
+
variant: "default",
|
|
655
|
+
size: "default"
|
|
656
|
+
}
|
|
657
|
+
});
|
|
658
|
+
function normalizePhoneNumber(input) {
|
|
659
|
+
const trimmed = input.trim();
|
|
660
|
+
if (trimmed.toLowerCase().startsWith("tel:")) {
|
|
661
|
+
return trimmed;
|
|
662
|
+
}
|
|
663
|
+
const match = trimmed.match(/^[\s\+\-\(\)]*(\d[\d\s\-\(\)\.]*\d)[\s\-]*(x|ext\.?|extension)?[\s\-]*(\d+)?$/i);
|
|
664
|
+
if (match) {
|
|
665
|
+
const mainNumber = match[1].replace(/[\s\-\(\)\.]/g, "");
|
|
666
|
+
const extension = match[3];
|
|
667
|
+
const normalized = mainNumber.length >= 10 && !trimmed.startsWith("+") ? `+${mainNumber}` : mainNumber;
|
|
668
|
+
const withExtension = extension ? `${normalized};ext=${extension}` : normalized;
|
|
669
|
+
return `tel:${withExtension}`;
|
|
670
|
+
}
|
|
671
|
+
const cleaned = trimmed.replace(/[\s\-\(\)\.]/g, "");
|
|
672
|
+
return `tel:${cleaned}`;
|
|
673
|
+
}
|
|
674
|
+
function normalizeEmail(input) {
|
|
675
|
+
const trimmed = input.trim();
|
|
676
|
+
if (trimmed.toLowerCase().startsWith("mailto:")) {
|
|
677
|
+
return trimmed;
|
|
678
|
+
}
|
|
679
|
+
return `mailto:${trimmed}`;
|
|
680
|
+
}
|
|
681
|
+
function isEmail(input) {
|
|
682
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
683
|
+
return emailRegex.test(input.trim());
|
|
684
|
+
}
|
|
685
|
+
function isPhoneNumber(input) {
|
|
686
|
+
const trimmed = input.trim();
|
|
687
|
+
if (trimmed.toLowerCase().startsWith("tel:")) {
|
|
688
|
+
return true;
|
|
689
|
+
}
|
|
690
|
+
const phoneRegex = /^[\s\+\-\(\)]*\d[\d\s\-\(\)\.]*\d[\s\-]*(x|ext\.?|extension)?[\s\-]*\d*$/i;
|
|
691
|
+
return phoneRegex.test(trimmed);
|
|
692
|
+
}
|
|
693
|
+
function isInternalUrl(href) {
|
|
694
|
+
if (typeof window === "undefined") {
|
|
695
|
+
return href.startsWith("/") && !href.startsWith("//");
|
|
696
|
+
}
|
|
697
|
+
const trimmed = href.trim();
|
|
698
|
+
if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
|
|
699
|
+
return true;
|
|
700
|
+
}
|
|
701
|
+
try {
|
|
702
|
+
const url = new URL(trimmed, window.location.href);
|
|
703
|
+
const currentOrigin = window.location.origin;
|
|
704
|
+
const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
|
|
705
|
+
return normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin);
|
|
706
|
+
} catch {
|
|
707
|
+
return false;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
function toRelativePath(href) {
|
|
711
|
+
if (typeof window === "undefined") {
|
|
712
|
+
return href;
|
|
713
|
+
}
|
|
714
|
+
const trimmed = href.trim();
|
|
715
|
+
if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
|
|
716
|
+
return trimmed;
|
|
717
|
+
}
|
|
718
|
+
try {
|
|
719
|
+
const url = new URL(trimmed, window.location.href);
|
|
720
|
+
const currentOrigin = window.location.origin;
|
|
721
|
+
const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
|
|
722
|
+
if (normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin)) {
|
|
723
|
+
return url.pathname + url.search + url.hash;
|
|
724
|
+
}
|
|
725
|
+
} catch {
|
|
726
|
+
}
|
|
727
|
+
return trimmed;
|
|
728
|
+
}
|
|
729
|
+
function useNavigation({
|
|
730
|
+
href,
|
|
731
|
+
onClick
|
|
732
|
+
} = {}) {
|
|
733
|
+
const linkType = React6__namespace.useMemo(() => {
|
|
734
|
+
if (!href || href.trim() === "") {
|
|
735
|
+
return onClick ? "none" : "none";
|
|
736
|
+
}
|
|
737
|
+
const trimmed = href.trim();
|
|
738
|
+
if (trimmed.toLowerCase().startsWith("mailto:") || isEmail(trimmed)) {
|
|
739
|
+
return "mailto";
|
|
740
|
+
}
|
|
741
|
+
if (trimmed.toLowerCase().startsWith("tel:") || isPhoneNumber(trimmed)) {
|
|
742
|
+
return "tel";
|
|
743
|
+
}
|
|
744
|
+
if (isInternalUrl(trimmed)) {
|
|
745
|
+
return "internal";
|
|
746
|
+
}
|
|
747
|
+
try {
|
|
748
|
+
new URL(trimmed, typeof window !== "undefined" ? window.location.href : "http://localhost");
|
|
749
|
+
return "external";
|
|
750
|
+
} catch {
|
|
751
|
+
return "internal";
|
|
752
|
+
}
|
|
753
|
+
}, [href, onClick]);
|
|
754
|
+
const normalizedHref = React6__namespace.useMemo(() => {
|
|
755
|
+
if (!href || href.trim() === "") {
|
|
756
|
+
return void 0;
|
|
757
|
+
}
|
|
758
|
+
const trimmed = href.trim();
|
|
759
|
+
switch (linkType) {
|
|
760
|
+
case "tel":
|
|
761
|
+
return normalizePhoneNumber(trimmed);
|
|
762
|
+
case "mailto":
|
|
763
|
+
return normalizeEmail(trimmed);
|
|
764
|
+
case "internal":
|
|
765
|
+
return toRelativePath(trimmed);
|
|
766
|
+
case "external":
|
|
767
|
+
return trimmed;
|
|
768
|
+
default:
|
|
769
|
+
return trimmed;
|
|
770
|
+
}
|
|
771
|
+
}, [href, linkType]);
|
|
772
|
+
const target = React6__namespace.useMemo(() => {
|
|
773
|
+
switch (linkType) {
|
|
774
|
+
case "external":
|
|
775
|
+
return "_blank";
|
|
776
|
+
case "internal":
|
|
777
|
+
return "_self";
|
|
778
|
+
case "mailto":
|
|
779
|
+
case "tel":
|
|
780
|
+
return void 0;
|
|
781
|
+
default:
|
|
782
|
+
return void 0;
|
|
783
|
+
}
|
|
784
|
+
}, [linkType]);
|
|
785
|
+
const rel = React6__namespace.useMemo(() => {
|
|
786
|
+
if (linkType === "external") {
|
|
787
|
+
return "noopener noreferrer";
|
|
788
|
+
}
|
|
789
|
+
return void 0;
|
|
790
|
+
}, [linkType]);
|
|
791
|
+
const isExternal = linkType === "external";
|
|
792
|
+
const isInternal = linkType === "internal";
|
|
793
|
+
const shouldUseRouter = isInternal && typeof normalizedHref === "string" && normalizedHref.startsWith("/");
|
|
794
|
+
const handleClick = React6__namespace.useCallback(
|
|
795
|
+
(event) => {
|
|
796
|
+
if (onClick) {
|
|
797
|
+
try {
|
|
798
|
+
onClick(event);
|
|
799
|
+
} catch (error) {
|
|
800
|
+
console.error("Error in user onClick handler:", error);
|
|
801
|
+
}
|
|
560
802
|
}
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
803
|
+
if (event.defaultPrevented) {
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
if (shouldUseRouter && normalizedHref && event.button === 0 && // left-click only
|
|
807
|
+
!event.metaKey && !event.altKey && !event.ctrlKey && !event.shiftKey) {
|
|
808
|
+
if (typeof window !== "undefined") {
|
|
809
|
+
const handler = window.__opensiteNavigationHandler;
|
|
810
|
+
if (typeof handler === "function") {
|
|
811
|
+
try {
|
|
812
|
+
const handled = handler(normalizedHref, event.nativeEvent || event);
|
|
813
|
+
if (handled !== false) {
|
|
814
|
+
event.preventDefault();
|
|
815
|
+
}
|
|
816
|
+
} catch (error) {
|
|
817
|
+
console.error("Error in navigation handler:", error);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
}
|
|
570
821
|
}
|
|
571
|
-
)
|
|
572
|
-
] });
|
|
573
|
-
});
|
|
574
|
-
var FeatureCard = React4__namespace.memo(({ feature, isActive, onClick }) => {
|
|
575
|
-
const variants = React4.useMemo(() => ({
|
|
576
|
-
initial: {
|
|
577
|
-
opacity: 0
|
|
578
|
-
},
|
|
579
|
-
animate: {
|
|
580
|
-
opacity: 1
|
|
581
822
|
},
|
|
582
|
-
|
|
583
|
-
|
|
823
|
+
[onClick, shouldUseRouter, normalizedHref]
|
|
824
|
+
);
|
|
825
|
+
return {
|
|
826
|
+
linkType,
|
|
827
|
+
normalizedHref,
|
|
828
|
+
target,
|
|
829
|
+
rel,
|
|
830
|
+
isExternal,
|
|
831
|
+
isInternal,
|
|
832
|
+
shouldUseRouter,
|
|
833
|
+
handleClick
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
var Pressable = React6__namespace.forwardRef(
|
|
837
|
+
({
|
|
838
|
+
children,
|
|
839
|
+
className,
|
|
840
|
+
href,
|
|
841
|
+
onClick,
|
|
842
|
+
variant,
|
|
843
|
+
size,
|
|
844
|
+
asButton = false,
|
|
845
|
+
fallbackComponentType = "span",
|
|
846
|
+
componentType,
|
|
847
|
+
"aria-label": ariaLabel,
|
|
848
|
+
"aria-describedby": ariaDescribedby,
|
|
849
|
+
id,
|
|
850
|
+
...props
|
|
851
|
+
}, ref) => {
|
|
852
|
+
const navigation = useNavigation({ href, onClick });
|
|
853
|
+
const {
|
|
854
|
+
normalizedHref,
|
|
855
|
+
target,
|
|
856
|
+
rel,
|
|
857
|
+
linkType,
|
|
858
|
+
isInternal,
|
|
859
|
+
handleClick
|
|
860
|
+
} = navigation;
|
|
861
|
+
const shouldRenderLink = normalizedHref && linkType !== "none";
|
|
862
|
+
const shouldRenderButton = !shouldRenderLink && onClick;
|
|
863
|
+
const effectiveComponentType = componentType || (shouldRenderLink ? "a" : shouldRenderButton ? "button" : fallbackComponentType);
|
|
864
|
+
const finalComponentType = isInternal && shouldRenderLink ? "a" : effectiveComponentType;
|
|
865
|
+
const shouldApplyButtonStyles = asButton || variant || size;
|
|
866
|
+
const combinedClassName = cn(
|
|
867
|
+
shouldApplyButtonStyles && buttonVariants({ variant, size }),
|
|
868
|
+
className
|
|
869
|
+
);
|
|
870
|
+
const dataProps = Object.fromEntries(
|
|
871
|
+
Object.entries(props).filter(([key]) => key.startsWith("data-"))
|
|
872
|
+
);
|
|
873
|
+
const buttonDataAttributes = shouldApplyButtonStyles ? {
|
|
874
|
+
"data-slot": "button",
|
|
875
|
+
"data-variant": variant ?? "default",
|
|
876
|
+
"data-size": size ?? "default"
|
|
877
|
+
} : {};
|
|
878
|
+
const commonProps = {
|
|
879
|
+
className: combinedClassName,
|
|
880
|
+
onClick: handleClick,
|
|
881
|
+
"aria-label": ariaLabel,
|
|
882
|
+
"aria-describedby": ariaDescribedby,
|
|
883
|
+
id,
|
|
884
|
+
...dataProps,
|
|
885
|
+
...buttonDataAttributes
|
|
886
|
+
};
|
|
887
|
+
if (finalComponentType === "a" && shouldRenderLink) {
|
|
888
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
889
|
+
"a",
|
|
890
|
+
{
|
|
891
|
+
ref,
|
|
892
|
+
href: normalizedHref,
|
|
893
|
+
target,
|
|
894
|
+
rel,
|
|
895
|
+
...commonProps,
|
|
896
|
+
...props,
|
|
897
|
+
children
|
|
898
|
+
}
|
|
899
|
+
);
|
|
584
900
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
901
|
+
if (finalComponentType === "button") {
|
|
902
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
903
|
+
"button",
|
|
904
|
+
{
|
|
905
|
+
ref,
|
|
906
|
+
type: props.type || "button",
|
|
907
|
+
...commonProps,
|
|
908
|
+
...props,
|
|
909
|
+
children
|
|
594
910
|
}
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
onClick,
|
|
601
|
-
children: isActive ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
602
|
-
framerMotion.motion.div,
|
|
911
|
+
);
|
|
912
|
+
}
|
|
913
|
+
if (finalComponentType === "div") {
|
|
914
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
915
|
+
"div",
|
|
603
916
|
{
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
917
|
+
ref,
|
|
918
|
+
...commonProps,
|
|
919
|
+
children
|
|
920
|
+
}
|
|
921
|
+
);
|
|
922
|
+
}
|
|
923
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
924
|
+
"span",
|
|
925
|
+
{
|
|
926
|
+
ref,
|
|
927
|
+
...commonProps,
|
|
928
|
+
children
|
|
929
|
+
}
|
|
930
|
+
);
|
|
931
|
+
}
|
|
932
|
+
);
|
|
933
|
+
Pressable.displayName = "Pressable";
|
|
934
|
+
var Controls = React6__namespace.memo(
|
|
935
|
+
({
|
|
936
|
+
handleNext,
|
|
937
|
+
handlePrevious,
|
|
938
|
+
isPreviousDisabled,
|
|
939
|
+
isNextDisabled
|
|
940
|
+
}) => {
|
|
941
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "hidden flex-col items-start gap-8 lg:flex", children: [
|
|
942
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
943
|
+
"button",
|
|
944
|
+
{
|
|
945
|
+
className: "rounded-full border p-2 flex items-center justify-center disabled:opacity-50 h-fit w-fit bg-card text-card-foreground",
|
|
946
|
+
onClick: handlePrevious,
|
|
947
|
+
disabled: isPreviousDisabled,
|
|
948
|
+
type: "button",
|
|
949
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/chevron-up", size: 24 })
|
|
950
|
+
}
|
|
951
|
+
),
|
|
952
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
953
|
+
"button",
|
|
954
|
+
{
|
|
955
|
+
className: "rounded-full border p-2 flex items-center justify-center disabled:opacity-50 h-fit w-fit bg-card text-card-foreground",
|
|
956
|
+
onClick: handleNext,
|
|
957
|
+
disabled: isNextDisabled,
|
|
958
|
+
type: "button",
|
|
959
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/chevron-down", size: 24 })
|
|
960
|
+
}
|
|
961
|
+
)
|
|
962
|
+
] });
|
|
963
|
+
}
|
|
964
|
+
);
|
|
965
|
+
var FeatureCard = React6__namespace.memo(
|
|
966
|
+
({ feature, isActive, onClick }) => {
|
|
967
|
+
const variants = React6.useMemo(
|
|
968
|
+
() => ({
|
|
969
|
+
initial: {
|
|
970
|
+
opacity: 0
|
|
971
|
+
},
|
|
972
|
+
animate: {
|
|
973
|
+
opacity: 1
|
|
974
|
+
},
|
|
975
|
+
exit: {
|
|
976
|
+
opacity: 0
|
|
977
|
+
}
|
|
978
|
+
}),
|
|
979
|
+
[]
|
|
980
|
+
);
|
|
981
|
+
return /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { mode: "popLayout", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
982
|
+
framerMotion.motion.div,
|
|
983
|
+
{
|
|
984
|
+
layout: true,
|
|
985
|
+
transition: {
|
|
986
|
+
layout: {
|
|
610
987
|
duration: 0.4,
|
|
611
|
-
delay: 0.3,
|
|
612
988
|
ease: "easeOut"
|
|
989
|
+
}
|
|
990
|
+
},
|
|
991
|
+
style: {
|
|
992
|
+
borderRadius: "24px"
|
|
993
|
+
},
|
|
994
|
+
className: cn(
|
|
995
|
+
"relative flex items-start gap-4 bg-background text-foreground md:w-fit md:max-w-sm",
|
|
996
|
+
isActive ? "shadow-xl overflow-visible" : "cursor-pointer shadow-none hover:shadow-xl transition-shadow duration-500 overflow-hidden"
|
|
997
|
+
),
|
|
998
|
+
onClick,
|
|
999
|
+
children: [
|
|
1000
|
+
isActive && feature.href && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute right-0 top-1/2 -translate-y-1/2 translate-x-1/2 bg-background rounded-full h-fit w-fit p-2 flex items-center justify-center z-10", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1001
|
+
Pressable,
|
|
1002
|
+
{
|
|
1003
|
+
href: feature.href,
|
|
1004
|
+
size: "icon-lg",
|
|
1005
|
+
className: "bg-primary text-primary-foreground",
|
|
1006
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/arrow-up-right" })
|
|
1007
|
+
}
|
|
1008
|
+
) }),
|
|
1009
|
+
isActive ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1010
|
+
framerMotion.motion.div,
|
|
1011
|
+
{
|
|
1012
|
+
layout: true,
|
|
1013
|
+
variants,
|
|
1014
|
+
initial: "initial",
|
|
1015
|
+
animate: "animate",
|
|
1016
|
+
exit: "exit",
|
|
1017
|
+
transition: {
|
|
1018
|
+
duration: 0.4,
|
|
1019
|
+
delay: 0.3,
|
|
1020
|
+
ease: "easeOut"
|
|
1021
|
+
},
|
|
1022
|
+
className: "p-6 text-sm md:p-8 md:text-base",
|
|
1023
|
+
children: (feature.title || feature.description) && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
|
|
1024
|
+
feature.title && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold", children: [
|
|
1025
|
+
feature.title,
|
|
1026
|
+
"."
|
|
1027
|
+
] }),
|
|
1028
|
+
feature.title && feature.description && " ",
|
|
1029
|
+
feature.description && /* @__PURE__ */ jsxRuntime.jsx("span", { children: feature.description })
|
|
1030
|
+
] })
|
|
1031
|
+
},
|
|
1032
|
+
`feature-description-active-${feature.title}`
|
|
1033
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1034
|
+
framerMotion.motion.div,
|
|
1035
|
+
{
|
|
1036
|
+
layout: true,
|
|
1037
|
+
variants,
|
|
1038
|
+
initial: "initial",
|
|
1039
|
+
animate: "animate",
|
|
1040
|
+
exit: "exit",
|
|
1041
|
+
transition: {
|
|
1042
|
+
duration: 0.4,
|
|
1043
|
+
delay: 0.2,
|
|
1044
|
+
ease: "easeOut"
|
|
1045
|
+
},
|
|
1046
|
+
className: cn(
|
|
1047
|
+
"flex h-fit shrink-0 items-center gap-4 text-sm md:py-3.5 md:pr-6 md:pl-3 md:text-base",
|
|
1048
|
+
!isActive && "h-0 w-0 md:h-auto md:w-auto"
|
|
1049
|
+
),
|
|
1050
|
+
style: {
|
|
1051
|
+
height: "auto",
|
|
1052
|
+
lineHeight: "normal"
|
|
1053
|
+
},
|
|
1054
|
+
children: [
|
|
1055
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1056
|
+
DynamicIcon,
|
|
1057
|
+
{
|
|
1058
|
+
name: "lucide/plus-circle",
|
|
1059
|
+
size: 24,
|
|
1060
|
+
className: "shrink-0"
|
|
1061
|
+
}
|
|
1062
|
+
),
|
|
1063
|
+
feature.title && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "shrink-0 font-semibold", children: feature.title })
|
|
1064
|
+
]
|
|
1065
|
+
},
|
|
1066
|
+
`feature-description-inactive-${feature.title}`
|
|
1067
|
+
)
|
|
1068
|
+
]
|
|
1069
|
+
}
|
|
1070
|
+
) });
|
|
1071
|
+
}
|
|
1072
|
+
);
|
|
1073
|
+
var FeaturesDesktop = React6__namespace.memo(
|
|
1074
|
+
({
|
|
1075
|
+
features,
|
|
1076
|
+
handleNext,
|
|
1077
|
+
handlePrevious,
|
|
1078
|
+
activeIndex,
|
|
1079
|
+
handleFeatureClick,
|
|
1080
|
+
isPreviousDisabled,
|
|
1081
|
+
isNextDisabled
|
|
1082
|
+
}) => {
|
|
1083
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative z-10 hidden items-center gap-8 md:flex", children: [
|
|
1084
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1085
|
+
Controls,
|
|
1086
|
+
{
|
|
1087
|
+
handleNext,
|
|
1088
|
+
handlePrevious,
|
|
1089
|
+
isPreviousDisabled,
|
|
1090
|
+
isNextDisabled
|
|
1091
|
+
}
|
|
1092
|
+
),
|
|
1093
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-4", children: features.map((feature, index) => {
|
|
1094
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1095
|
+
FeatureCard,
|
|
1096
|
+
{
|
|
1097
|
+
feature,
|
|
1098
|
+
isActive: index === activeIndex,
|
|
1099
|
+
onClick: () => handleFeatureClick(index)
|
|
613
1100
|
},
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
1101
|
+
`feature-card-${index}`
|
|
1102
|
+
);
|
|
1103
|
+
}) })
|
|
1104
|
+
] });
|
|
1105
|
+
}
|
|
1106
|
+
);
|
|
1107
|
+
var FeaturesMobile = React6__namespace.memo(
|
|
1108
|
+
({
|
|
1109
|
+
features,
|
|
1110
|
+
handleNext,
|
|
1111
|
+
handlePrevious,
|
|
1112
|
+
activeIndex,
|
|
1113
|
+
direction,
|
|
1114
|
+
isPreviousDisabled,
|
|
1115
|
+
isNextDisabled
|
|
1116
|
+
}) => {
|
|
1117
|
+
const variants = React6.useMemo(
|
|
1118
|
+
() => ({
|
|
1119
|
+
enter: (direction2) => ({
|
|
1120
|
+
x: direction2 > 0 ? 100 : -100,
|
|
1121
|
+
opacity: 0
|
|
1122
|
+
}),
|
|
1123
|
+
center: {
|
|
1124
|
+
x: 0,
|
|
1125
|
+
opacity: 1
|
|
623
1126
|
},
|
|
624
|
-
|
|
625
|
-
|
|
1127
|
+
exit: (direction2) => ({
|
|
1128
|
+
x: direction2 < 0 ? 100 : -100,
|
|
1129
|
+
opacity: 0
|
|
1130
|
+
})
|
|
1131
|
+
}),
|
|
1132
|
+
[]
|
|
1133
|
+
);
|
|
1134
|
+
const currentFeature = features[activeIndex];
|
|
1135
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative z-10 flex flex-col gap-4 md:hidden", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-stretch gap-4", children: [
|
|
1136
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { mode: "wait", custom: direction, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
626
1137
|
framerMotion.motion.div,
|
|
627
1138
|
{
|
|
628
|
-
|
|
1139
|
+
custom: direction,
|
|
629
1140
|
variants,
|
|
630
|
-
initial: "
|
|
631
|
-
animate: "
|
|
1141
|
+
initial: "enter",
|
|
1142
|
+
animate: "center",
|
|
632
1143
|
exit: "exit",
|
|
633
1144
|
transition: {
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
ease: "easeOut"
|
|
637
|
-
},
|
|
638
|
-
className: cn(
|
|
639
|
-
"flex h-fit shrink-0 items-center gap-4 text-sm md:py-3.5 md:pr-6 md:pl-3 md:text-base",
|
|
640
|
-
!isActive && "h-0 w-0 md:h-auto md:w-auto"
|
|
641
|
-
),
|
|
642
|
-
style: {
|
|
643
|
-
height: "auto",
|
|
644
|
-
lineHeight: "normal"
|
|
1145
|
+
x: { type: "spring", stiffness: 300, damping: 30 },
|
|
1146
|
+
opacity: { duration: 0.2 }
|
|
645
1147
|
},
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
size: 24,
|
|
652
|
-
className: "shrink-0"
|
|
653
|
-
}
|
|
654
|
-
),
|
|
655
|
-
feature.title && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "shrink-0 font-semibold", children: feature.title })
|
|
656
|
-
]
|
|
657
|
-
},
|
|
658
|
-
`feature-description-inactive-${feature.title}`
|
|
659
|
-
)
|
|
660
|
-
}
|
|
661
|
-
) });
|
|
662
|
-
});
|
|
663
|
-
var FeaturesDesktop = React4__namespace.memo(({
|
|
664
|
-
features,
|
|
665
|
-
handleNext,
|
|
666
|
-
handlePrevious,
|
|
667
|
-
activeIndex,
|
|
668
|
-
handleFeatureClick,
|
|
669
|
-
isPreviousDisabled,
|
|
670
|
-
isNextDisabled
|
|
671
|
-
}) => {
|
|
672
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative z-10 hidden items-center gap-8 md:flex", children: [
|
|
673
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
674
|
-
Controls,
|
|
675
|
-
{
|
|
676
|
-
handleNext,
|
|
677
|
-
handlePrevious,
|
|
678
|
-
isPreviousDisabled,
|
|
679
|
-
isNextDisabled
|
|
680
|
-
}
|
|
681
|
-
),
|
|
682
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-4", children: features.map((feature, index) => {
|
|
683
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
684
|
-
FeatureCard,
|
|
685
|
-
{
|
|
686
|
-
feature,
|
|
687
|
-
isActive: index === activeIndex,
|
|
688
|
-
onClick: () => handleFeatureClick(index)
|
|
689
|
-
},
|
|
690
|
-
`feature-card-${index}`
|
|
691
|
-
);
|
|
692
|
-
}) })
|
|
693
|
-
] });
|
|
694
|
-
});
|
|
695
|
-
var FeaturesMobile = React4__namespace.memo(({
|
|
696
|
-
features,
|
|
697
|
-
handleNext,
|
|
698
|
-
handlePrevious,
|
|
699
|
-
activeIndex,
|
|
700
|
-
direction,
|
|
701
|
-
isPreviousDisabled,
|
|
702
|
-
isNextDisabled
|
|
703
|
-
}) => {
|
|
704
|
-
const variants = React4.useMemo(() => ({
|
|
705
|
-
enter: (direction2) => ({
|
|
706
|
-
x: direction2 > 0 ? 100 : -100,
|
|
707
|
-
opacity: 0
|
|
708
|
-
}),
|
|
709
|
-
center: {
|
|
710
|
-
x: 0,
|
|
711
|
-
opacity: 1
|
|
712
|
-
},
|
|
713
|
-
exit: (direction2) => ({
|
|
714
|
-
x: direction2 < 0 ? 100 : -100,
|
|
715
|
-
opacity: 0
|
|
716
|
-
})
|
|
717
|
-
}), []);
|
|
718
|
-
const currentFeature = features[activeIndex];
|
|
719
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative z-10 flex flex-col items-center gap-6 md:hidden", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center justify-between gap-4", children: [
|
|
720
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
721
|
-
"button",
|
|
722
|
-
{
|
|
723
|
-
className: "rounded-full border bg-background/50 p-2 hover:bg-background disabled:opacity-50",
|
|
724
|
-
onClick: handlePrevious,
|
|
725
|
-
disabled: isPreviousDisabled,
|
|
726
|
-
type: "button",
|
|
727
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/chevron-left", size: 24 })
|
|
728
|
-
}
|
|
729
|
-
),
|
|
730
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative h-24 w-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { mode: "wait", custom: direction, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
731
|
-
framerMotion.motion.div,
|
|
732
|
-
{
|
|
733
|
-
custom: direction,
|
|
734
|
-
variants,
|
|
735
|
-
initial: "enter",
|
|
736
|
-
animate: "center",
|
|
737
|
-
exit: "exit",
|
|
738
|
-
transition: {
|
|
739
|
-
x: { type: "spring", stiffness: 300, damping: 30 },
|
|
740
|
-
opacity: { duration: 0.2 }
|
|
1148
|
+
className: "rounded-3xl bg-background p-4 text-left",
|
|
1149
|
+
children: (currentFeature?.title || currentFeature?.description) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm", children: [
|
|
1150
|
+
currentFeature.title && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold", children: currentFeature.title }),
|
|
1151
|
+
currentFeature.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1", children: currentFeature.description })
|
|
1152
|
+
] })
|
|
741
1153
|
},
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
})
|
|
1154
|
+
activeIndex
|
|
1155
|
+
) }) }),
|
|
1156
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col justify-center gap-2", children: [
|
|
1157
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1158
|
+
"button",
|
|
1159
|
+
{
|
|
1160
|
+
className: "rounded-full border p-2 flex items-center justify-center disabled:opacity-50 h-fit w-fit bg-card text-card-foreground",
|
|
1161
|
+
onClick: handlePrevious,
|
|
1162
|
+
disabled: isPreviousDisabled,
|
|
1163
|
+
type: "button",
|
|
1164
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/chevron-up", size: 20 })
|
|
1165
|
+
}
|
|
1166
|
+
),
|
|
1167
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1168
|
+
"button",
|
|
1169
|
+
{
|
|
1170
|
+
className: "rounded-full border p-2 flex items-center justify-center disabled:opacity-50 h-fit w-fit bg-card text-card-foreground",
|
|
1171
|
+
onClick: handleNext,
|
|
1172
|
+
disabled: isNextDisabled,
|
|
1173
|
+
type: "button",
|
|
1174
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/chevron-down", size: 20 })
|
|
1175
|
+
}
|
|
1176
|
+
)
|
|
1177
|
+
] })
|
|
1178
|
+
] }) });
|
|
1179
|
+
}
|
|
1180
|
+
);
|
|
766
1181
|
function FeatureAnimatedCarousel({
|
|
1182
|
+
title,
|
|
1183
|
+
description,
|
|
1184
|
+
titleClassName,
|
|
1185
|
+
descriptionClassName,
|
|
767
1186
|
features,
|
|
768
1187
|
className,
|
|
769
1188
|
optixFlowConfig,
|
|
770
1189
|
background,
|
|
771
|
-
spacing,
|
|
772
1190
|
pattern,
|
|
773
1191
|
patternOpacity,
|
|
774
|
-
patternClassName
|
|
1192
|
+
patternClassName,
|
|
1193
|
+
headerClassName,
|
|
1194
|
+
blockCardClassName,
|
|
1195
|
+
spacing = "py-12 md:py-32",
|
|
1196
|
+
containerClassName = "px-6 sm:px-6 md:px-8 lg:px-8"
|
|
775
1197
|
}) {
|
|
776
|
-
const [activeIndex, setActiveIndex] =
|
|
777
|
-
const [direction, setDirection] =
|
|
778
|
-
const handleNext =
|
|
1198
|
+
const [activeIndex, setActiveIndex] = React6__namespace.useState(0);
|
|
1199
|
+
const [direction, setDirection] = React6__namespace.useState(1);
|
|
1200
|
+
const handleNext = React6.useCallback(() => {
|
|
779
1201
|
if (features && activeIndex < features.length - 1) {
|
|
780
1202
|
setDirection(1);
|
|
781
1203
|
setActiveIndex(activeIndex + 1);
|
|
782
1204
|
}
|
|
783
1205
|
}, [activeIndex, features]);
|
|
784
|
-
const handlePrevious =
|
|
1206
|
+
const handlePrevious = React6.useCallback(() => {
|
|
785
1207
|
if (activeIndex > 0) {
|
|
786
1208
|
setDirection(-1);
|
|
787
1209
|
setActiveIndex(activeIndex - 1);
|
|
788
1210
|
}
|
|
789
1211
|
}, [activeIndex]);
|
|
790
|
-
const handleFeatureClick =
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
1212
|
+
const handleFeatureClick = React6.useCallback(
|
|
1213
|
+
(index) => {
|
|
1214
|
+
setDirection(index > activeIndex ? 1 : -1);
|
|
1215
|
+
setActiveIndex(index);
|
|
1216
|
+
},
|
|
1217
|
+
[activeIndex]
|
|
1218
|
+
);
|
|
794
1219
|
const isPreviousDisabled = activeIndex === 0;
|
|
795
1220
|
const isNextDisabled = !features || activeIndex === features.length - 1;
|
|
796
|
-
const imageVariants =
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
1221
|
+
const imageVariants = React6.useMemo(
|
|
1222
|
+
() => ({
|
|
1223
|
+
enter: (direction2) => ({
|
|
1224
|
+
x: direction2 > 0 ? 300 : -300,
|
|
1225
|
+
opacity: 0
|
|
1226
|
+
}),
|
|
1227
|
+
center: {
|
|
1228
|
+
x: 0,
|
|
1229
|
+
opacity: 1
|
|
1230
|
+
},
|
|
1231
|
+
exit: (direction2) => ({
|
|
1232
|
+
x: direction2 < 0 ? 300 : -300,
|
|
1233
|
+
opacity: 0
|
|
1234
|
+
})
|
|
800
1235
|
}),
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
opacity: 1
|
|
804
|
-
},
|
|
805
|
-
exit: (direction2) => ({
|
|
806
|
-
x: direction2 < 0 ? 300 : -300,
|
|
807
|
-
opacity: 0
|
|
808
|
-
})
|
|
809
|
-
}), []);
|
|
1236
|
+
[]
|
|
1237
|
+
);
|
|
810
1238
|
if (!features || features.length === 0) {
|
|
811
1239
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
812
1240
|
Section,
|
|
@@ -817,11 +1245,15 @@ function FeatureAnimatedCarousel({
|
|
|
817
1245
|
patternOpacity,
|
|
818
1246
|
patternClassName,
|
|
819
1247
|
className,
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
1248
|
+
containerClassName,
|
|
1249
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1250
|
+
"div",
|
|
1251
|
+
{
|
|
1252
|
+
className: cn(
|
|
1253
|
+
"relative flex min-h-[500px] flex-col-reverse gap-8 overflow-hidden rounded-3xl bg-muted p-6 md:flex-row md:items-center md:p-12 lg:min-h-[600px]"
|
|
1254
|
+
)
|
|
1255
|
+
}
|
|
1256
|
+
)
|
|
825
1257
|
}
|
|
826
1258
|
);
|
|
827
1259
|
}
|
|
@@ -835,60 +1267,116 @@ function FeatureAnimatedCarousel({
|
|
|
835
1267
|
patternOpacity,
|
|
836
1268
|
patternClassName,
|
|
837
1269
|
className,
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
), children: [
|
|
843
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
844
|
-
FeaturesDesktop,
|
|
1270
|
+
containerClassName,
|
|
1271
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col space-y-6 md:space-y-16", children: [
|
|
1272
|
+
title || description ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1273
|
+
"div",
|
|
845
1274
|
{
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
1275
|
+
className: cn(
|
|
1276
|
+
"flex flex-col gap-4 md:gap-6 text-left",
|
|
1277
|
+
headerClassName
|
|
1278
|
+
),
|
|
1279
|
+
children: [
|
|
1280
|
+
title && (typeof title === "string" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1281
|
+
"h2",
|
|
1282
|
+
{
|
|
1283
|
+
className: cn(
|
|
1284
|
+
"text-xl font-semibold text-balance md:text-2xl lg:text-3xl max-w-lg md:max-w-md",
|
|
1285
|
+
titleClassName
|
|
1286
|
+
),
|
|
1287
|
+
children: title
|
|
1288
|
+
}
|
|
1289
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1290
|
+
"div",
|
|
1291
|
+
{
|
|
1292
|
+
className: cn(
|
|
1293
|
+
"text-xl font-semibold text-balance md:text-2xl lg:text-3xl max-w-lg md:max-w-md",
|
|
1294
|
+
titleClassName
|
|
1295
|
+
),
|
|
1296
|
+
children: title
|
|
1297
|
+
}
|
|
1298
|
+
)),
|
|
1299
|
+
description && (typeof description === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("max-w-lg md:max-w-md", descriptionClassName), children: description }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1300
|
+
"div",
|
|
1301
|
+
{
|
|
1302
|
+
className: cn("max-w-lg md:max-w-md", descriptionClassName),
|
|
1303
|
+
children: description
|
|
1304
|
+
}
|
|
1305
|
+
))
|
|
1306
|
+
]
|
|
853
1307
|
}
|
|
854
|
-
),
|
|
855
|
-
/* @__PURE__ */ jsxRuntime.
|
|
856
|
-
|
|
1308
|
+
) : null,
|
|
1309
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1310
|
+
"div",
|
|
857
1311
|
{
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
1312
|
+
className: cn(
|
|
1313
|
+
"relative flex min-h-full md:min-h-[500px] flex-col-reverse gap-5 md:gap-8 bg-muted overflow-hidden rounded-3xl p-4 md:p-6 md:flex-row md:items-center lg:p-12 lg:min-h-[600px]",
|
|
1314
|
+
blockCardClassName
|
|
1315
|
+
),
|
|
1316
|
+
children: [
|
|
1317
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1318
|
+
FeaturesDesktop,
|
|
1319
|
+
{
|
|
1320
|
+
features,
|
|
1321
|
+
handleNext,
|
|
1322
|
+
handlePrevious,
|
|
1323
|
+
activeIndex,
|
|
1324
|
+
handleFeatureClick,
|
|
1325
|
+
isPreviousDisabled,
|
|
1326
|
+
isNextDisabled
|
|
1327
|
+
}
|
|
1328
|
+
),
|
|
1329
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1330
|
+
FeaturesMobile,
|
|
1331
|
+
{
|
|
1332
|
+
features,
|
|
1333
|
+
handleNext,
|
|
1334
|
+
handlePrevious,
|
|
1335
|
+
activeIndex,
|
|
1336
|
+
direction,
|
|
1337
|
+
isPreviousDisabled,
|
|
1338
|
+
isNextDisabled
|
|
1339
|
+
}
|
|
1340
|
+
),
|
|
1341
|
+
currentFeature?.image && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full h-[250px] md:h-auto md:absolute md:right-8 md:top-8 md:bottom-8 md:w-1/2", children: [
|
|
1342
|
+
currentFeature.href && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-4 right-4 z-10 rounded-full h-fit w-fit shadow-md hover:shadow-2xl flex items-center justify-center md:hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1343
|
+
Pressable,
|
|
1344
|
+
{
|
|
1345
|
+
href: currentFeature.href,
|
|
1346
|
+
size: "icon-lg",
|
|
1347
|
+
className: "bg-primary text-primary-foreground",
|
|
1348
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/arrow-up-right" })
|
|
1349
|
+
}
|
|
1350
|
+
) }),
|
|
1351
|
+
/* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { mode: "wait", custom: direction, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1352
|
+
framerMotion.motion.div,
|
|
1353
|
+
{
|
|
1354
|
+
custom: direction,
|
|
1355
|
+
variants: imageVariants,
|
|
1356
|
+
initial: "enter",
|
|
1357
|
+
animate: "center",
|
|
1358
|
+
exit: "exit",
|
|
1359
|
+
transition: {
|
|
1360
|
+
x: { type: "spring", stiffness: 300, damping: 30 },
|
|
1361
|
+
opacity: { duration: 0.3 }
|
|
1362
|
+
},
|
|
1363
|
+
className: "h-full w-full shadow-xl overflow-hidden rounded-2xl",
|
|
1364
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1365
|
+
img.Img,
|
|
1366
|
+
{
|
|
1367
|
+
src: currentFeature.image,
|
|
1368
|
+
alt: currentFeature.imageAlt || (typeof currentFeature.title === "string" ? currentFeature.title : "Feature image"),
|
|
1369
|
+
className: "h-full w-full object-cover",
|
|
1370
|
+
optixFlowConfig
|
|
1371
|
+
}
|
|
1372
|
+
)
|
|
1373
|
+
},
|
|
1374
|
+
activeIndex
|
|
1375
|
+
) })
|
|
1376
|
+
] })
|
|
1377
|
+
]
|
|
865
1378
|
}
|
|
866
|
-
)
|
|
867
|
-
currentFeature?.image && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex-1 overflow-hidden rounded-2xl md:absolute md:right-8 md:top-8 md:bottom-8 md:w-1/2", children: /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { mode: "wait", custom: direction, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
868
|
-
framerMotion.motion.div,
|
|
869
|
-
{
|
|
870
|
-
custom: direction,
|
|
871
|
-
variants: imageVariants,
|
|
872
|
-
initial: "enter",
|
|
873
|
-
animate: "center",
|
|
874
|
-
exit: "exit",
|
|
875
|
-
transition: {
|
|
876
|
-
x: { type: "spring", stiffness: 300, damping: 30 },
|
|
877
|
-
opacity: { duration: 0.2 }
|
|
878
|
-
},
|
|
879
|
-
className: "h-full w-full",
|
|
880
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
881
|
-
img.Img,
|
|
882
|
-
{
|
|
883
|
-
src: currentFeature.image,
|
|
884
|
-
alt: currentFeature.imageAlt || (typeof currentFeature.title === "string" ? currentFeature.title : "Feature image"),
|
|
885
|
-
className: "h-full w-full object-cover",
|
|
886
|
-
optixFlowConfig
|
|
887
|
-
}
|
|
888
|
-
)
|
|
889
|
-
},
|
|
890
|
-
activeIndex
|
|
891
|
-
) }) })
|
|
1379
|
+
)
|
|
892
1380
|
] })
|
|
893
1381
|
}
|
|
894
1382
|
);
|