@opensite/ui 0.7.9 → 0.8.0
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/carousel-feature-badge.cjs +114 -214
- package/dist/carousel-feature-badge.js +114 -214
- package/dist/carousel-horizontal-cards.cjs +283 -211
- package/dist/carousel-horizontal-cards.d.cts +5 -1
- package/dist/carousel-horizontal-cards.d.ts +5 -1
- package/dist/carousel-horizontal-cards.js +283 -211
- package/dist/carousel-pagination.cjs +601 -0
- package/dist/carousel-pagination.d.cts +75 -0
- package/dist/carousel-pagination.d.ts +75 -0
- package/dist/carousel-pagination.js +579 -0
- package/dist/components.cjs +45 -0
- package/dist/components.d.cts +1 -0
- package/dist/components.d.ts +1 -0
- package/dist/components.js +45 -1
- package/dist/index.cjs +45 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +45 -1
- package/dist/registry.cjs +424 -309
- package/dist/registry.js +424 -309
- package/package.json +6 -1
|
@@ -4,14 +4,119 @@ import React__default from 'react';
|
|
|
4
4
|
import { motion } from 'framer-motion';
|
|
5
5
|
import { clsx } from 'clsx';
|
|
6
6
|
import { twMerge } from 'tailwind-merge';
|
|
7
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
7
8
|
import { cva } from 'class-variance-authority';
|
|
8
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
9
9
|
import { Img } from '@page-speed/img';
|
|
10
10
|
|
|
11
11
|
// components/blocks/carousel/carousel-horizontal-cards.tsx
|
|
12
12
|
function cn(...inputs) {
|
|
13
13
|
return twMerge(clsx(inputs));
|
|
14
14
|
}
|
|
15
|
+
var svgCache = /* @__PURE__ */ new Map();
|
|
16
|
+
function DynamicIcon({
|
|
17
|
+
name,
|
|
18
|
+
size = 28,
|
|
19
|
+
color,
|
|
20
|
+
className,
|
|
21
|
+
alt
|
|
22
|
+
}) {
|
|
23
|
+
const [svgContent, setSvgContent] = React.useState(null);
|
|
24
|
+
const [isLoading, setIsLoading] = React.useState(true);
|
|
25
|
+
const [error, setError] = React.useState(null);
|
|
26
|
+
const { url, iconName } = React.useMemo(() => {
|
|
27
|
+
const separator = name.includes("/") ? "/" : ":";
|
|
28
|
+
const [prefix, iconName2] = name.split(separator);
|
|
29
|
+
const baseUrl = `https://icons.opensite.ai/api/icon/${prefix}/${iconName2}?format=svg&width=${size}&height=${size}`;
|
|
30
|
+
return {
|
|
31
|
+
url: baseUrl,
|
|
32
|
+
iconName: iconName2
|
|
33
|
+
};
|
|
34
|
+
}, [name, size]);
|
|
35
|
+
React.useEffect(() => {
|
|
36
|
+
let isMounted = true;
|
|
37
|
+
const fetchSvg = async () => {
|
|
38
|
+
const cached = svgCache.get(url);
|
|
39
|
+
if (cached) {
|
|
40
|
+
if (isMounted) {
|
|
41
|
+
setSvgContent(cached);
|
|
42
|
+
setIsLoading(false);
|
|
43
|
+
}
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
setIsLoading(true);
|
|
48
|
+
setError(null);
|
|
49
|
+
const response = await fetch(url);
|
|
50
|
+
if (!response.ok) {
|
|
51
|
+
throw new Error(`Failed to fetch icon: ${response.status}`);
|
|
52
|
+
}
|
|
53
|
+
let svg = await response.text();
|
|
54
|
+
svg = processSvgForCurrentColor(svg);
|
|
55
|
+
svgCache.set(url, svg);
|
|
56
|
+
if (isMounted) {
|
|
57
|
+
setSvgContent(svg);
|
|
58
|
+
setIsLoading(false);
|
|
59
|
+
}
|
|
60
|
+
} catch (err) {
|
|
61
|
+
if (isMounted) {
|
|
62
|
+
setError(err instanceof Error ? err.message : "Failed to load icon");
|
|
63
|
+
setIsLoading(false);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
fetchSvg();
|
|
68
|
+
return () => {
|
|
69
|
+
isMounted = false;
|
|
70
|
+
};
|
|
71
|
+
}, [url]);
|
|
72
|
+
if (isLoading) {
|
|
73
|
+
return /* @__PURE__ */ jsx(
|
|
74
|
+
"span",
|
|
75
|
+
{
|
|
76
|
+
className: cn("inline-block", className),
|
|
77
|
+
style: { width: size, height: size },
|
|
78
|
+
"aria-hidden": "true"
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
if (error || !svgContent) {
|
|
83
|
+
return /* @__PURE__ */ jsx(
|
|
84
|
+
"span",
|
|
85
|
+
{
|
|
86
|
+
className: cn("inline-block", className),
|
|
87
|
+
style: { width: size, height: size },
|
|
88
|
+
role: "img",
|
|
89
|
+
"aria-label": alt || iconName
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
return /* @__PURE__ */ jsx(
|
|
94
|
+
"span",
|
|
95
|
+
{
|
|
96
|
+
className: cn("inline-flex items-center justify-center", className),
|
|
97
|
+
style: {
|
|
98
|
+
width: size,
|
|
99
|
+
height: size,
|
|
100
|
+
color: color || "inherit"
|
|
101
|
+
},
|
|
102
|
+
role: "img",
|
|
103
|
+
"aria-label": alt || iconName,
|
|
104
|
+
dangerouslySetInnerHTML: { __html: svgContent }
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
function processSvgForCurrentColor(svg) {
|
|
109
|
+
let processed = svg;
|
|
110
|
+
processed = processed.replace(
|
|
111
|
+
/stroke=["'](#000000|#000|black)["']/gi,
|
|
112
|
+
'stroke="currentColor"'
|
|
113
|
+
);
|
|
114
|
+
processed = processed.replace(
|
|
115
|
+
/fill=["'](#000000|#000|black)["']/gi,
|
|
116
|
+
'fill="currentColor"'
|
|
117
|
+
);
|
|
118
|
+
return processed;
|
|
119
|
+
}
|
|
15
120
|
function normalizePhoneNumber(input) {
|
|
16
121
|
const trimmed = input.trim();
|
|
17
122
|
if (trimmed.toLowerCase().startsWith("tel:")) {
|
|
@@ -430,110 +535,49 @@ var Pressable = React.forwardRef(
|
|
|
430
535
|
}
|
|
431
536
|
);
|
|
432
537
|
Pressable.displayName = "Pressable";
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
538
|
+
function CarouselPagination({
|
|
539
|
+
onPrevious,
|
|
540
|
+
onNext,
|
|
541
|
+
canScrollPrevious = true,
|
|
542
|
+
canScrollNext = true,
|
|
543
|
+
iconSize = 24,
|
|
438
544
|
className,
|
|
439
|
-
|
|
545
|
+
buttonClassName,
|
|
546
|
+
previousIcon = "lucide/arrow-left",
|
|
547
|
+
nextIcon = "lucide/arrow-right",
|
|
548
|
+
previousAriaLabel = "Previous",
|
|
549
|
+
nextAriaLabel = "Next"
|
|
440
550
|
}) {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
const { url, iconName } = React.useMemo(() => {
|
|
445
|
-
const separator = name.includes("/") ? "/" : ":";
|
|
446
|
-
const [prefix, iconName2] = name.split(separator);
|
|
447
|
-
const baseUrl = `https://icons.opensite.ai/api/icon/${prefix}/${iconName2}?format=svg&width=${size}&height=${size}`;
|
|
448
|
-
return {
|
|
449
|
-
url: baseUrl,
|
|
450
|
-
iconName: iconName2
|
|
451
|
-
};
|
|
452
|
-
}, [name, size]);
|
|
453
|
-
React.useEffect(() => {
|
|
454
|
-
let isMounted = true;
|
|
455
|
-
const fetchSvg = async () => {
|
|
456
|
-
const cached = svgCache.get(url);
|
|
457
|
-
if (cached) {
|
|
458
|
-
if (isMounted) {
|
|
459
|
-
setSvgContent(cached);
|
|
460
|
-
setIsLoading(false);
|
|
461
|
-
}
|
|
462
|
-
return;
|
|
463
|
-
}
|
|
464
|
-
try {
|
|
465
|
-
setIsLoading(true);
|
|
466
|
-
setError(null);
|
|
467
|
-
const response = await fetch(url);
|
|
468
|
-
if (!response.ok) {
|
|
469
|
-
throw new Error(`Failed to fetch icon: ${response.status}`);
|
|
470
|
-
}
|
|
471
|
-
let svg = await response.text();
|
|
472
|
-
svg = processSvgForCurrentColor(svg);
|
|
473
|
-
svgCache.set(url, svg);
|
|
474
|
-
if (isMounted) {
|
|
475
|
-
setSvgContent(svg);
|
|
476
|
-
setIsLoading(false);
|
|
477
|
-
}
|
|
478
|
-
} catch (err) {
|
|
479
|
-
if (isMounted) {
|
|
480
|
-
setError(err instanceof Error ? err.message : "Failed to load icon");
|
|
481
|
-
setIsLoading(false);
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
};
|
|
485
|
-
fetchSvg();
|
|
486
|
-
return () => {
|
|
487
|
-
isMounted = false;
|
|
488
|
-
};
|
|
489
|
-
}, [url]);
|
|
490
|
-
if (isLoading) {
|
|
491
|
-
return /* @__PURE__ */ jsx(
|
|
492
|
-
"span",
|
|
551
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex justify-end gap-2", className), children: [
|
|
552
|
+
/* @__PURE__ */ jsx(
|
|
553
|
+
Pressable,
|
|
493
554
|
{
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
"aria-
|
|
555
|
+
onClick: onPrevious,
|
|
556
|
+
disabled: !canScrollPrevious,
|
|
557
|
+
"aria-label": previousAriaLabel,
|
|
558
|
+
asButton: true,
|
|
559
|
+
className: cn(
|
|
560
|
+
"relative z-40 flex h-10 w-10 items-center justify-center rounded-full disabled:opacity-50",
|
|
561
|
+
buttonClassName
|
|
562
|
+
),
|
|
563
|
+
children: /* @__PURE__ */ jsx(DynamicIcon, { name: previousIcon, size: iconSize })
|
|
497
564
|
}
|
|
498
|
-
)
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
return /* @__PURE__ */ jsx(
|
|
502
|
-
"span",
|
|
565
|
+
),
|
|
566
|
+
/* @__PURE__ */ jsx(
|
|
567
|
+
Pressable,
|
|
503
568
|
{
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
569
|
+
onClick: onNext,
|
|
570
|
+
disabled: !canScrollNext,
|
|
571
|
+
"aria-label": nextAriaLabel,
|
|
572
|
+
asButton: true,
|
|
573
|
+
className: cn(
|
|
574
|
+
"relative z-40 flex h-10 w-10 items-center justify-center rounded-full disabled:opacity-50",
|
|
575
|
+
buttonClassName
|
|
576
|
+
),
|
|
577
|
+
children: /* @__PURE__ */ jsx(DynamicIcon, { name: nextIcon, size: iconSize })
|
|
508
578
|
}
|
|
509
|
-
)
|
|
510
|
-
}
|
|
511
|
-
return /* @__PURE__ */ jsx(
|
|
512
|
-
"span",
|
|
513
|
-
{
|
|
514
|
-
className: cn("inline-flex items-center justify-center", className),
|
|
515
|
-
style: {
|
|
516
|
-
width: size,
|
|
517
|
-
height: size,
|
|
518
|
-
color: color || "inherit"
|
|
519
|
-
},
|
|
520
|
-
role: "img",
|
|
521
|
-
"aria-label": alt || iconName,
|
|
522
|
-
dangerouslySetInnerHTML: { __html: svgContent }
|
|
523
|
-
}
|
|
524
|
-
);
|
|
525
|
-
}
|
|
526
|
-
function processSvgForCurrentColor(svg) {
|
|
527
|
-
let processed = svg;
|
|
528
|
-
processed = processed.replace(
|
|
529
|
-
/stroke=["'](#000000|#000|black)["']/gi,
|
|
530
|
-
'stroke="currentColor"'
|
|
531
|
-
);
|
|
532
|
-
processed = processed.replace(
|
|
533
|
-
/fill=["'](#000000|#000|black)["']/gi,
|
|
534
|
-
'fill="currentColor"'
|
|
535
|
-
);
|
|
536
|
-
return processed;
|
|
579
|
+
)
|
|
580
|
+
] });
|
|
537
581
|
}
|
|
538
582
|
var maxWidthStyles = {
|
|
539
583
|
sm: "max-w-screen-sm",
|
|
@@ -932,28 +976,22 @@ function CarouselHorizontalCards({
|
|
|
932
976
|
const carouselRef = React.useRef(null);
|
|
933
977
|
const [isAtStart, setIsAtStart] = React.useState(true);
|
|
934
978
|
const [isAtEnd, setIsAtEnd] = React.useState(false);
|
|
935
|
-
const
|
|
936
|
-
if (
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
const scroll = (direction) => {
|
|
979
|
+
const scrollLeft = () => {
|
|
980
|
+
if (carouselRef.current) {
|
|
981
|
+
carouselRef.current.scrollBy({ left: -300, behavior: "smooth" });
|
|
982
|
+
}
|
|
983
|
+
};
|
|
984
|
+
const scrollRight = () => {
|
|
942
985
|
if (carouselRef.current) {
|
|
943
|
-
|
|
944
|
-
const cardWidth = getCardWidth();
|
|
945
|
-
const gap = 16;
|
|
946
|
-
const scrollAmount = cardWidth + gap;
|
|
947
|
-
const newScrollLeft = direction === "left" ? scrollLeft - scrollAmount : scrollLeft + scrollAmount;
|
|
948
|
-
carouselRef.current.scrollTo({ left: newScrollLeft, behavior: "smooth" });
|
|
986
|
+
carouselRef.current.scrollBy({ left: 300, behavior: "smooth" });
|
|
949
987
|
}
|
|
950
988
|
};
|
|
951
989
|
React.useEffect(() => {
|
|
952
990
|
const checkScrollPosition = () => {
|
|
953
991
|
if (carouselRef.current) {
|
|
954
|
-
const { scrollLeft, scrollWidth, clientWidth } = carouselRef.current;
|
|
955
|
-
setIsAtStart(
|
|
956
|
-
setIsAtEnd(
|
|
992
|
+
const { scrollLeft: scrollLeft2, scrollWidth, clientWidth } = carouselRef.current;
|
|
993
|
+
setIsAtStart(scrollLeft2 < 10);
|
|
994
|
+
setIsAtEnd(scrollLeft2 + clientWidth >= scrollWidth - 10);
|
|
957
995
|
}
|
|
958
996
|
};
|
|
959
997
|
const currentRef = carouselRef.current;
|
|
@@ -969,41 +1007,6 @@ function CarouselHorizontalCards({
|
|
|
969
1007
|
window.removeEventListener("resize", checkScrollPosition);
|
|
970
1008
|
};
|
|
971
1009
|
}, [items]);
|
|
972
|
-
const renderItems = () => {
|
|
973
|
-
if (itemsSlot) return itemsSlot;
|
|
974
|
-
if (!items || items.length === 0) return null;
|
|
975
|
-
return items.map((item, index) => /* @__PURE__ */ jsx(
|
|
976
|
-
motion.div,
|
|
977
|
-
{
|
|
978
|
-
className: cn(
|
|
979
|
-
"group w-[320px] shrink-0 snap-start sm:w-[360px] lg:w-[400px]",
|
|
980
|
-
item.className
|
|
981
|
-
),
|
|
982
|
-
initial: { opacity: 0, y: 20 },
|
|
983
|
-
animate: { opacity: 1, y: 0 },
|
|
984
|
-
transition: { duration: 0.5, delay: index * 0.1 },
|
|
985
|
-
children: /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-lg border bg-card text-card-foreground shadow-sm transition-shadow hover:shadow-md", children: [
|
|
986
|
-
/* @__PURE__ */ jsx(
|
|
987
|
-
Img,
|
|
988
|
-
{
|
|
989
|
-
alt: typeof item.title === "string" ? item.title : `Card ${index + 1}`,
|
|
990
|
-
className: cn("aspect-video w-full object-cover transition-transform group-hover:scale-105", item.imageClassName),
|
|
991
|
-
src: item.imageSrc,
|
|
992
|
-
optixFlowConfig
|
|
993
|
-
}
|
|
994
|
-
),
|
|
995
|
-
/* @__PURE__ */ jsxs("div", { className: "p-4", children: [
|
|
996
|
-
item.title && (typeof item.title === "string" ? /* @__PURE__ */ jsx("h3", { className: "text-md font-semibold leading-tight text-card-foreground", children: item.title }) : /* @__PURE__ */ jsx("div", { children: item.title })),
|
|
997
|
-
(item.count !== void 0 || item.countLabel) && /* @__PURE__ */ jsxs("div", { className: "mt-4", children: [
|
|
998
|
-
item.count !== void 0 && /* @__PURE__ */ jsx("p", { className: "text-xl font-bold", children: item.count }),
|
|
999
|
-
item.countLabel && (typeof item.countLabel === "string" ? /* @__PURE__ */ jsx("p", { className: "text-xs font-medium uppercase tracking-wider text-muted-foreground", children: item.countLabel }) : /* @__PURE__ */ jsx("div", { children: item.countLabel }))
|
|
1000
|
-
] })
|
|
1001
|
-
] })
|
|
1002
|
-
] })
|
|
1003
|
-
},
|
|
1004
|
-
item.id
|
|
1005
|
-
));
|
|
1006
|
-
};
|
|
1007
1010
|
return /* @__PURE__ */ jsx(
|
|
1008
1011
|
Section,
|
|
1009
1012
|
{
|
|
@@ -1014,74 +1017,143 @@ function CarouselHorizontalCards({
|
|
|
1014
1017
|
patternOpacity,
|
|
1015
1018
|
"aria-labelledby": "carousel-title",
|
|
1016
1019
|
children: /* @__PURE__ */ jsxs("div", { className: cn("container mx-auto px-4 md:px-6", containerClassName), children: [
|
|
1017
|
-
/* @__PURE__ */ jsx(
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1020
|
+
/* @__PURE__ */ jsx(
|
|
1021
|
+
"div",
|
|
1022
|
+
{
|
|
1023
|
+
className: cn(
|
|
1024
|
+
"mb-8 flex items-center justify-between gap-4",
|
|
1025
|
+
headerClassName
|
|
1026
|
+
),
|
|
1027
|
+
children: /* @__PURE__ */ jsxs("div", { children: [
|
|
1028
|
+
heading && /* @__PURE__ */ jsxs("a", { href: headingHref, className: "group inline-flex items-center", children: [
|
|
1029
|
+
typeof heading === "string" ? /* @__PURE__ */ jsx(
|
|
1030
|
+
"h2",
|
|
1031
|
+
{
|
|
1032
|
+
id: "carousel-title",
|
|
1033
|
+
className: cn(
|
|
1034
|
+
"text-2xl font-bold tracking-tight text-card-foreground md:text-3xl",
|
|
1035
|
+
headingClassName
|
|
1036
|
+
),
|
|
1037
|
+
children: heading
|
|
1038
|
+
}
|
|
1039
|
+
) : /* @__PURE__ */ jsx("div", { className: headingClassName, children: heading }),
|
|
1040
|
+
/* @__PURE__ */ jsx(
|
|
1041
|
+
DynamicIcon,
|
|
1042
|
+
{
|
|
1043
|
+
name: "lucide/chevron-right",
|
|
1044
|
+
size: 24,
|
|
1045
|
+
className: "ml-2 shrink-0 self-center transition-transform group-hover:translate-x-1"
|
|
1046
|
+
}
|
|
1047
|
+
)
|
|
1048
|
+
] }),
|
|
1049
|
+
subtitle && (typeof subtitle === "string" ? /* @__PURE__ */ jsx(
|
|
1050
|
+
"p",
|
|
1051
|
+
{
|
|
1052
|
+
className: cn(
|
|
1053
|
+
"mt-1 text-muted-foreground",
|
|
1054
|
+
subtitleClassName
|
|
1055
|
+
),
|
|
1056
|
+
children: subtitle
|
|
1057
|
+
}
|
|
1058
|
+
) : /* @__PURE__ */ jsx("div", { className: subtitleClassName, children: subtitle }))
|
|
1059
|
+
] })
|
|
1060
|
+
}
|
|
1061
|
+
),
|
|
1062
|
+
/* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
|
|
1039
1063
|
/* @__PURE__ */ jsx(
|
|
1040
1064
|
"div",
|
|
1041
1065
|
{
|
|
1066
|
+
className: "flex w-full overflow-x-scroll overscroll-x-auto scroll-smooth py-4 [scrollbar-width:none] md:py-6",
|
|
1042
1067
|
ref: carouselRef,
|
|
1043
|
-
|
|
1044
|
-
"
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1068
|
+
children: /* @__PURE__ */ jsxs(
|
|
1069
|
+
"div",
|
|
1070
|
+
{
|
|
1071
|
+
className: cn(
|
|
1072
|
+
"flex flex-row justify-start gap-4 pl-4",
|
|
1073
|
+
carouselClassName
|
|
1074
|
+
),
|
|
1075
|
+
children: [
|
|
1076
|
+
items?.map((item, index) => /* @__PURE__ */ jsx(
|
|
1077
|
+
motion.div,
|
|
1078
|
+
{
|
|
1079
|
+
className: cn(
|
|
1080
|
+
"rounded-lg last:pr-[5%] md:last:pr-[33%]"
|
|
1081
|
+
),
|
|
1082
|
+
initial: { opacity: 0, y: 20 },
|
|
1083
|
+
animate: { opacity: 1, y: 0 },
|
|
1084
|
+
transition: { duration: 0.5, delay: 0.2 * index, ease: "easeOut" },
|
|
1085
|
+
children: /* @__PURE__ */ jsx(
|
|
1086
|
+
"div",
|
|
1087
|
+
{
|
|
1088
|
+
className: cn(
|
|
1089
|
+
"group w-56 shrink-0 md:w-96",
|
|
1090
|
+
item.className
|
|
1091
|
+
),
|
|
1092
|
+
children: /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-lg border bg-card text-card-foreground shadow-sm transition-shadow hover:shadow-md", children: [
|
|
1093
|
+
/* @__PURE__ */ jsx(
|
|
1094
|
+
Img,
|
|
1095
|
+
{
|
|
1096
|
+
alt: typeof item.title === "string" ? item.title : `Card ${index + 1}`,
|
|
1097
|
+
className: cn(
|
|
1098
|
+
"aspect-video w-full object-cover transition-transform group-hover:scale-105",
|
|
1099
|
+
item.imageClassName
|
|
1100
|
+
),
|
|
1101
|
+
src: item.imageSrc,
|
|
1102
|
+
optixFlowConfig
|
|
1103
|
+
}
|
|
1104
|
+
),
|
|
1105
|
+
/* @__PURE__ */ jsxs("div", { className: "p-4", children: [
|
|
1106
|
+
item.title && (typeof item.title === "string" ? /* @__PURE__ */ jsx("h3", { className: "text-md font-semibold leading-tight text-card-foreground", children: item.title }) : /* @__PURE__ */ jsx("div", { children: item.title })),
|
|
1107
|
+
(item.count !== void 0 || item.countLabel) && /* @__PURE__ */ jsxs("div", { className: "mt-4", children: [
|
|
1108
|
+
item.count !== void 0 && /* @__PURE__ */ jsx("p", { className: "text-xl font-bold", children: item.count }),
|
|
1109
|
+
item.countLabel && (typeof item.countLabel === "string" ? /* @__PURE__ */ jsx("p", { className: "text-xs font-medium uppercase tracking-wider text-muted-foreground", children: item.countLabel }) : /* @__PURE__ */ jsx("div", { children: item.countLabel }))
|
|
1110
|
+
] }),
|
|
1111
|
+
item.actions && item.actions.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-4 flex flex-wrap gap-2", children: item.actions.map((action, actionIndex) => {
|
|
1112
|
+
const {
|
|
1113
|
+
label,
|
|
1114
|
+
icon,
|
|
1115
|
+
iconAfter,
|
|
1116
|
+
children,
|
|
1117
|
+
className: actionClassName,
|
|
1118
|
+
asButton,
|
|
1119
|
+
...pressableProps
|
|
1120
|
+
} = action;
|
|
1121
|
+
return /* @__PURE__ */ jsx(
|
|
1122
|
+
Pressable,
|
|
1123
|
+
{
|
|
1124
|
+
asButton,
|
|
1125
|
+
className: actionClassName,
|
|
1126
|
+
...pressableProps,
|
|
1127
|
+
children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1128
|
+
icon,
|
|
1129
|
+
label,
|
|
1130
|
+
iconAfter
|
|
1131
|
+
] })
|
|
1132
|
+
},
|
|
1133
|
+
actionIndex
|
|
1134
|
+
);
|
|
1135
|
+
}) })
|
|
1136
|
+
] })
|
|
1137
|
+
] })
|
|
1138
|
+
}
|
|
1139
|
+
)
|
|
1140
|
+
},
|
|
1141
|
+
item.id
|
|
1142
|
+
)),
|
|
1143
|
+
itemsSlot
|
|
1144
|
+
]
|
|
1145
|
+
}
|
|
1146
|
+
)
|
|
1049
1147
|
}
|
|
1050
1148
|
),
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
{
|
|
1054
|
-
onClick: () => scroll("left"),
|
|
1055
|
-
className: cn(
|
|
1056
|
-
"absolute left-4 top-1/2 z-10 -translate-y-1/2",
|
|
1057
|
-
"flex h-12 w-12 items-center justify-center",
|
|
1058
|
-
"rounded-full border border-border/50 bg-background shadow-lg",
|
|
1059
|
-
"text-foreground transition-all duration-200",
|
|
1060
|
-
"hover:bg-accent hover:shadow-xl hover:scale-105",
|
|
1061
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
1062
|
-
navigationClassName
|
|
1063
|
-
),
|
|
1064
|
-
"aria-label": "Scroll left",
|
|
1065
|
-
asButton: true,
|
|
1066
|
-
children: /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/chevron-left", size: 24 })
|
|
1067
|
-
}
|
|
1068
|
-
),
|
|
1069
|
-
!isAtEnd && /* @__PURE__ */ jsx(
|
|
1070
|
-
Pressable,
|
|
1149
|
+
/* @__PURE__ */ jsx(
|
|
1150
|
+
CarouselPagination,
|
|
1071
1151
|
{
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
"text-foreground transition-all duration-200",
|
|
1078
|
-
"hover:bg-accent hover:shadow-xl hover:scale-105",
|
|
1079
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
1080
|
-
navigationClassName
|
|
1081
|
-
),
|
|
1082
|
-
"aria-label": "Scroll right",
|
|
1083
|
-
asButton: true,
|
|
1084
|
-
children: /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/chevron-right", size: 24 })
|
|
1152
|
+
onPrevious: scrollLeft,
|
|
1153
|
+
onNext: scrollRight,
|
|
1154
|
+
canScrollPrevious: !isAtStart,
|
|
1155
|
+
canScrollNext: !isAtEnd,
|
|
1156
|
+
className: cn("mr-0 md:mr-10", navigationClassName)
|
|
1085
1157
|
}
|
|
1086
1158
|
)
|
|
1087
1159
|
] })
|