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