@mlw-packages/react-components 1.9.10 → 1.9.11
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/index.css +12 -0
- package/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +415 -8
- package/dist/index.mjs +416 -9
- package/package.json +1 -1
package/dist/index.css
CHANGED
|
@@ -585,6 +585,9 @@ body {
|
|
|
585
585
|
.z-\[1\] {
|
|
586
586
|
z-index: 1;
|
|
587
587
|
}
|
|
588
|
+
.z-\[60\] {
|
|
589
|
+
z-index: 60;
|
|
590
|
+
}
|
|
588
591
|
.z-\[9998\] {
|
|
589
592
|
z-index: 9998;
|
|
590
593
|
}
|
|
@@ -1583,6 +1586,9 @@ body {
|
|
|
1583
1586
|
.cursor-move {
|
|
1584
1587
|
cursor: move;
|
|
1585
1588
|
}
|
|
1589
|
+
.cursor-none {
|
|
1590
|
+
cursor: none;
|
|
1591
|
+
}
|
|
1586
1592
|
.cursor-not-allowed {
|
|
1587
1593
|
cursor: not-allowed;
|
|
1588
1594
|
}
|
|
@@ -2201,6 +2207,9 @@ body {
|
|
|
2201
2207
|
--tw-border-opacity: 1;
|
|
2202
2208
|
border-color: rgb(255 255 255 / var(--tw-border-opacity, 1));
|
|
2203
2209
|
}
|
|
2210
|
+
.border-white\/10 {
|
|
2211
|
+
border-color: rgb(255 255 255 / 0.1);
|
|
2212
|
+
}
|
|
2204
2213
|
.border-white\/20 {
|
|
2205
2214
|
border-color: rgb(255 255 255 / 0.2);
|
|
2206
2215
|
}
|
|
@@ -4450,6 +4459,9 @@ body {
|
|
|
4450
4459
|
.hover\:bg-background\/20:hover {
|
|
4451
4460
|
background-color: hsl(var(--background) / 0.2);
|
|
4452
4461
|
}
|
|
4462
|
+
.hover\:bg-black\/70:hover {
|
|
4463
|
+
background-color: rgb(0 0 0 / 0.7);
|
|
4464
|
+
}
|
|
4453
4465
|
.hover\:bg-blue-600:hover {
|
|
4454
4466
|
--tw-bg-opacity: 1;
|
|
4455
4467
|
background-color: rgb(37 99 235 / var(--tw-bg-opacity, 1));
|
package/dist/index.d.mts
CHANGED
|
@@ -2323,8 +2323,10 @@ interface CarouselBaseProps {
|
|
|
2323
2323
|
stiffness?: number;
|
|
2324
2324
|
damping?: number;
|
|
2325
2325
|
};
|
|
2326
|
+
zoomEffect?: "lens" | "scale" | null;
|
|
2327
|
+
download?: boolean;
|
|
2326
2328
|
}
|
|
2327
|
-
declare function CarouselBase({ items, className, containerClassName, imageClassName, width, height, showControls, showIndicators, autoPlay, autoPlayInterval, springConfig, }: CarouselBaseProps): react_jsx_runtime.JSX.Element;
|
|
2329
|
+
declare function CarouselBase({ items, className, containerClassName, imageClassName, width, height, showControls, showIndicators, autoPlay, autoPlayInterval, springConfig, zoomEffect, download, }: CarouselBaseProps): react_jsx_runtime.JSX.Element;
|
|
2328
2330
|
|
|
2329
2331
|
declare function useIsMobile(): boolean;
|
|
2330
2332
|
|
package/dist/index.d.ts
CHANGED
|
@@ -2323,8 +2323,10 @@ interface CarouselBaseProps {
|
|
|
2323
2323
|
stiffness?: number;
|
|
2324
2324
|
damping?: number;
|
|
2325
2325
|
};
|
|
2326
|
+
zoomEffect?: "lens" | "scale" | null;
|
|
2327
|
+
download?: boolean;
|
|
2326
2328
|
}
|
|
2327
|
-
declare function CarouselBase({ items, className, containerClassName, imageClassName, width, height, showControls, showIndicators, autoPlay, autoPlayInterval, springConfig, }: CarouselBaseProps): react_jsx_runtime.JSX.Element;
|
|
2329
|
+
declare function CarouselBase({ items, className, containerClassName, imageClassName, width, height, showControls, showIndicators, autoPlay, autoPlayInterval, springConfig, zoomEffect, download, }: CarouselBaseProps): react_jsx_runtime.JSX.Element;
|
|
2328
2330
|
|
|
2329
2331
|
declare function useIsMobile(): boolean;
|
|
2330
2332
|
|
package/dist/index.js
CHANGED
|
@@ -18647,13 +18647,290 @@ function Leaderboard({
|
|
|
18647
18647
|
}
|
|
18648
18648
|
);
|
|
18649
18649
|
}
|
|
18650
|
+
var Lens = ({
|
|
18651
|
+
children,
|
|
18652
|
+
initialZoom = 1.5,
|
|
18653
|
+
maxZoom = 4,
|
|
18654
|
+
lensSize = 150,
|
|
18655
|
+
isStatic = false,
|
|
18656
|
+
position = { x: 200, y: 150 },
|
|
18657
|
+
hovering,
|
|
18658
|
+
setHovering
|
|
18659
|
+
}) => {
|
|
18660
|
+
const containerRef = React32.useRef(null);
|
|
18661
|
+
const [localIsHovering, setLocalIsHovering] = React32.useState(false);
|
|
18662
|
+
const isHovering = hovering !== void 0 ? hovering : localIsHovering;
|
|
18663
|
+
const setIsHovering = setHovering || setLocalIsHovering;
|
|
18664
|
+
const [mousePosition, setMousePosition] = React32.useState({ x: 100, y: 100 });
|
|
18665
|
+
const [zoomFactor, setZoomFactor] = React32.useState(initialZoom);
|
|
18666
|
+
const [isActivated, setIsActivated] = React32.useState(false);
|
|
18667
|
+
const handleMouseMove = (e) => {
|
|
18668
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
18669
|
+
const x = e.clientX - rect.left;
|
|
18670
|
+
const y = e.clientY - rect.top;
|
|
18671
|
+
setMousePosition({ x, y });
|
|
18672
|
+
};
|
|
18673
|
+
const handleWheel = (e) => {
|
|
18674
|
+
if (!isActivated) return;
|
|
18675
|
+
const delta = -e.deltaY * 5e-3;
|
|
18676
|
+
setZoomFactor((prev) => Math.min(Math.max(1.1, prev + delta), maxZoom));
|
|
18677
|
+
};
|
|
18678
|
+
const resetZoom = () => {
|
|
18679
|
+
setZoomFactor(initialZoom);
|
|
18680
|
+
setIsActivated(false);
|
|
18681
|
+
};
|
|
18682
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
18683
|
+
"div",
|
|
18684
|
+
{
|
|
18685
|
+
ref: containerRef,
|
|
18686
|
+
className: cn(
|
|
18687
|
+
"relative overflow-hidden rounded-lg z-20 h-full",
|
|
18688
|
+
isActivated ? "cursor-none" : "cursor-pointer"
|
|
18689
|
+
),
|
|
18690
|
+
onClick: () => setIsActivated(!isActivated),
|
|
18691
|
+
onMouseEnter: () => {
|
|
18692
|
+
setIsHovering(true);
|
|
18693
|
+
},
|
|
18694
|
+
onMouseLeave: () => {
|
|
18695
|
+
setIsHovering(false);
|
|
18696
|
+
resetZoom();
|
|
18697
|
+
},
|
|
18698
|
+
onMouseMove: handleMouseMove,
|
|
18699
|
+
onWheel: handleWheel,
|
|
18700
|
+
children: [
|
|
18701
|
+
children,
|
|
18702
|
+
isStatic ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
18703
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18704
|
+
framerMotion.motion.div,
|
|
18705
|
+
{
|
|
18706
|
+
initial: { opacity: 0, scale: 0.58 },
|
|
18707
|
+
animate: { opacity: 1, scale: 1 },
|
|
18708
|
+
exit: { opacity: 0, scale: 0.8 },
|
|
18709
|
+
transition: { duration: 0.3, ease: "easeOut" },
|
|
18710
|
+
className: "absolute inset-0 overflow-hidden",
|
|
18711
|
+
style: {
|
|
18712
|
+
maskImage: `radial-gradient(circle ${lensSize / 2}px at ${position.x}px ${position.y}px, black 100%, transparent 100%)`,
|
|
18713
|
+
WebkitMaskImage: `radial-gradient(circle ${lensSize / 2}px at ${position.x}px ${position.y}px, black 100%, transparent 100%)`,
|
|
18714
|
+
transformOrigin: `${position.x}px ${position.y}px`
|
|
18715
|
+
},
|
|
18716
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
18717
|
+
"div",
|
|
18718
|
+
{
|
|
18719
|
+
className: "absolute inset-0",
|
|
18720
|
+
style: {
|
|
18721
|
+
transform: `scale(${zoomFactor})`,
|
|
18722
|
+
transformOrigin: `${position.x}px ${position.y}px`
|
|
18723
|
+
},
|
|
18724
|
+
children
|
|
18725
|
+
}
|
|
18726
|
+
)
|
|
18727
|
+
}
|
|
18728
|
+
),
|
|
18729
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18730
|
+
"div",
|
|
18731
|
+
{
|
|
18732
|
+
className: "absolute pointer-events-none",
|
|
18733
|
+
style: {
|
|
18734
|
+
left: position.x - lensSize / 2,
|
|
18735
|
+
top: position.y - lensSize / 2,
|
|
18736
|
+
width: lensSize,
|
|
18737
|
+
height: lensSize,
|
|
18738
|
+
borderRadius: "50%",
|
|
18739
|
+
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4), 0 4px 16px rgba(0, 0, 0, 0.2)",
|
|
18740
|
+
background: "radial-gradient(circle at center, transparent 60%, rgba(255, 255, 255, 0.1) 70%, rgba(255, 255, 255, 0.2) 80%, transparent 100%)"
|
|
18741
|
+
}
|
|
18742
|
+
}
|
|
18743
|
+
)
|
|
18744
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: isHovering && isActivated && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
18745
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18746
|
+
framerMotion.motion.div,
|
|
18747
|
+
{
|
|
18748
|
+
initial: { opacity: 0, scale: 0.58 },
|
|
18749
|
+
animate: { opacity: 1, scale: 1 },
|
|
18750
|
+
exit: { opacity: 0, scale: 0.8 },
|
|
18751
|
+
transition: { duration: 0.3, ease: "easeOut" },
|
|
18752
|
+
className: "absolute inset-0 overflow-hidden",
|
|
18753
|
+
style: {
|
|
18754
|
+
maskImage: `radial-gradient(circle ${lensSize / 2}px at ${mousePosition.x}px ${mousePosition.y}px, black 100%, transparent 100%)`,
|
|
18755
|
+
WebkitMaskImage: `radial-gradient(circle ${lensSize / 2}px at ${mousePosition.x}px ${mousePosition.y}px, black 100%, transparent 100%)`,
|
|
18756
|
+
transformOrigin: `${mousePosition.x}px ${mousePosition.y}px`,
|
|
18757
|
+
zIndex: 50
|
|
18758
|
+
},
|
|
18759
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
18760
|
+
"div",
|
|
18761
|
+
{
|
|
18762
|
+
className: "absolute inset-0",
|
|
18763
|
+
style: {
|
|
18764
|
+
transform: `scale(${zoomFactor})`,
|
|
18765
|
+
transformOrigin: `${mousePosition.x}px ${mousePosition.y}px`
|
|
18766
|
+
},
|
|
18767
|
+
children
|
|
18768
|
+
}
|
|
18769
|
+
)
|
|
18770
|
+
}
|
|
18771
|
+
),
|
|
18772
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18773
|
+
framerMotion.motion.div,
|
|
18774
|
+
{
|
|
18775
|
+
initial: { opacity: 0, scale: 0.58 },
|
|
18776
|
+
animate: { opacity: 1, scale: 1 },
|
|
18777
|
+
exit: { opacity: 0, scale: 0.8 },
|
|
18778
|
+
transition: { duration: 0.3, ease: "easeOut" },
|
|
18779
|
+
className: "absolute pointer-events-none z-[60]",
|
|
18780
|
+
style: {
|
|
18781
|
+
left: mousePosition.x - lensSize / 2,
|
|
18782
|
+
top: mousePosition.y - lensSize / 2,
|
|
18783
|
+
width: lensSize,
|
|
18784
|
+
height: lensSize,
|
|
18785
|
+
borderRadius: "50%",
|
|
18786
|
+
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4), 0 4px 16px rgba(0, 0, 0, 0.2)",
|
|
18787
|
+
background: "radial-gradient(circle at center, transparent 60%, rgba(255, 255, 255, 0.1) 70%, rgba(255, 255, 255, 0.2) 80%, transparent 100%)"
|
|
18788
|
+
}
|
|
18789
|
+
}
|
|
18790
|
+
)
|
|
18791
|
+
] }) })
|
|
18792
|
+
]
|
|
18793
|
+
}
|
|
18794
|
+
);
|
|
18795
|
+
};
|
|
18796
|
+
var ZoomImage = React32__namespace.forwardRef(
|
|
18797
|
+
({
|
|
18798
|
+
className,
|
|
18799
|
+
src,
|
|
18800
|
+
alt,
|
|
18801
|
+
maxZoom = 2,
|
|
18802
|
+
transitionDuration = 0.3,
|
|
18803
|
+
borderRadius = 12,
|
|
18804
|
+
imageClassName,
|
|
18805
|
+
...props
|
|
18806
|
+
}, ref) => {
|
|
18807
|
+
const mouseX = framerMotion.useMotionValue(50);
|
|
18808
|
+
const mouseY = framerMotion.useMotionValue(50);
|
|
18809
|
+
const zoomLevel = framerMotion.useMotionValue(1);
|
|
18810
|
+
const springConfig = { damping: 20, stiffness: 150, mass: 0.5 };
|
|
18811
|
+
const smoothMouseX = framerMotion.useSpring(mouseX, springConfig);
|
|
18812
|
+
const smoothMouseY = framerMotion.useSpring(mouseY, springConfig);
|
|
18813
|
+
const smoothZoomLevel = framerMotion.useSpring(zoomLevel, springConfig);
|
|
18814
|
+
const transformOrigin = framerMotion.useTransform(
|
|
18815
|
+
[smoothMouseX, smoothMouseY],
|
|
18816
|
+
([latestX, latestY]) => `${latestX}% ${latestY}%`
|
|
18817
|
+
);
|
|
18818
|
+
const touchStartDist = React32__namespace.useRef(0);
|
|
18819
|
+
const touchStartZoom = React32__namespace.useRef(1);
|
|
18820
|
+
const isPinching = React32__namespace.useRef(false);
|
|
18821
|
+
const handleMouseMove = (e) => {
|
|
18822
|
+
if (isPinching.current) return;
|
|
18823
|
+
const { left, top, width, height } = e.currentTarget.getBoundingClientRect();
|
|
18824
|
+
const x = (e.clientX - left) / width * 100;
|
|
18825
|
+
const y = (e.clientY - top) / height * 100;
|
|
18826
|
+
mouseX.set(x);
|
|
18827
|
+
mouseY.set(y);
|
|
18828
|
+
};
|
|
18829
|
+
const handleWheel = (e) => {
|
|
18830
|
+
const delta = -e.deltaY * 5e-3;
|
|
18831
|
+
const newZoom = Math.min(Math.max(1, zoomLevel.get() + delta), maxZoom);
|
|
18832
|
+
zoomLevel.set(newZoom);
|
|
18833
|
+
};
|
|
18834
|
+
const handleMouseLeave = () => {
|
|
18835
|
+
if (!isPinching.current) {
|
|
18836
|
+
mouseX.set(50);
|
|
18837
|
+
mouseY.set(50);
|
|
18838
|
+
zoomLevel.set(1);
|
|
18839
|
+
}
|
|
18840
|
+
};
|
|
18841
|
+
const getDistance = (touches) => {
|
|
18842
|
+
const dx = touches[0].clientX - touches[1].clientX;
|
|
18843
|
+
const dy = touches[0].clientY - touches[1].clientY;
|
|
18844
|
+
return Math.sqrt(dx * dx + dy * dy);
|
|
18845
|
+
};
|
|
18846
|
+
const getCenter = (touches, rect) => {
|
|
18847
|
+
const x = (touches[0].clientX + touches[1].clientX) / 2;
|
|
18848
|
+
const y = (touches[0].clientY + touches[1].clientY) / 2;
|
|
18849
|
+
return {
|
|
18850
|
+
x: (x - rect.left) / rect.width * 100,
|
|
18851
|
+
y: (y - rect.top) / rect.height * 100
|
|
18852
|
+
};
|
|
18853
|
+
};
|
|
18854
|
+
const handleTouchStart = (e) => {
|
|
18855
|
+
if (e.touches.length === 2) {
|
|
18856
|
+
isPinching.current = true;
|
|
18857
|
+
touchStartDist.current = getDistance(e.touches);
|
|
18858
|
+
touchStartZoom.current = zoomLevel.get();
|
|
18859
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
18860
|
+
const center = getCenter(e.touches, rect);
|
|
18861
|
+
mouseX.set(center.x);
|
|
18862
|
+
mouseY.set(center.y);
|
|
18863
|
+
}
|
|
18864
|
+
};
|
|
18865
|
+
const handleTouchMove = (e) => {
|
|
18866
|
+
if (e.touches.length === 2 && isPinching.current) {
|
|
18867
|
+
e.preventDefault();
|
|
18868
|
+
const dist = getDistance(e.touches);
|
|
18869
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
18870
|
+
const scaleChange = dist / touchStartDist.current;
|
|
18871
|
+
const newZoom = Math.min(
|
|
18872
|
+
Math.max(1, touchStartZoom.current * scaleChange),
|
|
18873
|
+
maxZoom
|
|
18874
|
+
);
|
|
18875
|
+
zoomLevel.set(newZoom);
|
|
18876
|
+
const center = getCenter(e.touches, rect);
|
|
18877
|
+
mouseX.set(center.x);
|
|
18878
|
+
mouseY.set(center.y);
|
|
18879
|
+
}
|
|
18880
|
+
};
|
|
18881
|
+
const handleTouchEnd = (e) => {
|
|
18882
|
+
if (e.touches.length < 2) {
|
|
18883
|
+
if (isPinching.current) {
|
|
18884
|
+
isPinching.current = false;
|
|
18885
|
+
}
|
|
18886
|
+
}
|
|
18887
|
+
};
|
|
18888
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
18889
|
+
framerMotion.motion.div,
|
|
18890
|
+
{
|
|
18891
|
+
ref,
|
|
18892
|
+
className: cn(
|
|
18893
|
+
"relative w-full h-full overflow-hidden touch-none",
|
|
18894
|
+
className
|
|
18895
|
+
),
|
|
18896
|
+
style: { borderRadius: `${borderRadius}px` },
|
|
18897
|
+
onMouseMove: handleMouseMove,
|
|
18898
|
+
onMouseLeave: handleMouseLeave,
|
|
18899
|
+
onWheel: handleWheel,
|
|
18900
|
+
onTouchStart: handleTouchStart,
|
|
18901
|
+
onTouchMove: handleTouchMove,
|
|
18902
|
+
onTouchEnd: handleTouchEnd,
|
|
18903
|
+
...props,
|
|
18904
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
18905
|
+
framerMotion.motion.img,
|
|
18906
|
+
{
|
|
18907
|
+
src,
|
|
18908
|
+
alt,
|
|
18909
|
+
className: cn("w-full h-full object-cover", imageClassName),
|
|
18910
|
+
style: {
|
|
18911
|
+
borderRadius: `${borderRadius}px`,
|
|
18912
|
+
transformOrigin,
|
|
18913
|
+
scale: smoothZoomLevel
|
|
18914
|
+
},
|
|
18915
|
+
transition: {
|
|
18916
|
+
type: "spring",
|
|
18917
|
+
duration: transitionDuration,
|
|
18918
|
+
bounce: 0
|
|
18919
|
+
}
|
|
18920
|
+
}
|
|
18921
|
+
)
|
|
18922
|
+
}
|
|
18923
|
+
);
|
|
18924
|
+
}
|
|
18925
|
+
);
|
|
18926
|
+
ZoomImage.displayName = "ZoomImage";
|
|
18650
18927
|
function CarouselBase({
|
|
18651
18928
|
items,
|
|
18652
18929
|
className,
|
|
18653
18930
|
containerClassName,
|
|
18654
18931
|
imageClassName,
|
|
18655
18932
|
width,
|
|
18656
|
-
height
|
|
18933
|
+
height,
|
|
18657
18934
|
showControls = true,
|
|
18658
18935
|
showIndicators = true,
|
|
18659
18936
|
autoPlay = false,
|
|
@@ -18661,11 +18938,16 @@ function CarouselBase({
|
|
|
18661
18938
|
springConfig = {
|
|
18662
18939
|
stiffness: 300,
|
|
18663
18940
|
damping: 30
|
|
18664
|
-
}
|
|
18941
|
+
},
|
|
18942
|
+
zoomEffect = null,
|
|
18943
|
+
download = false
|
|
18665
18944
|
}) {
|
|
18945
|
+
const isMobile = useIsMobile();
|
|
18666
18946
|
const [index, setIndex] = React32.useState(0);
|
|
18667
18947
|
const containerRef = React32.useRef(null);
|
|
18668
18948
|
const x = framerMotion.useMotionValue(0);
|
|
18949
|
+
const [isDownloading, setIsDownloading] = React32.useState(false);
|
|
18950
|
+
const [downloadSuccess, setDownloadSuccess] = React32.useState(false);
|
|
18669
18951
|
React32.useEffect(() => {
|
|
18670
18952
|
if (containerRef.current) {
|
|
18671
18953
|
const containerWidth = containerRef.current.offsetWidth || 1;
|
|
@@ -18684,21 +18966,66 @@ function CarouselBase({
|
|
|
18684
18966
|
}, autoPlayInterval);
|
|
18685
18967
|
return () => clearInterval(interval);
|
|
18686
18968
|
}, [autoPlay, autoPlayInterval, items.length]);
|
|
18969
|
+
const handleDownload = async () => {
|
|
18970
|
+
if (isDownloading) return;
|
|
18971
|
+
setIsDownloading(true);
|
|
18972
|
+
setDownloadSuccess(false);
|
|
18973
|
+
const currentItem = items[index];
|
|
18974
|
+
try {
|
|
18975
|
+
const response = await fetch(currentItem.url);
|
|
18976
|
+
const blob = await response.blob();
|
|
18977
|
+
const url = window.URL.createObjectURL(blob);
|
|
18978
|
+
const link = document.createElement("a");
|
|
18979
|
+
link.href = url;
|
|
18980
|
+
link.download = currentItem.title || "image";
|
|
18981
|
+
document.body.appendChild(link);
|
|
18982
|
+
link.click();
|
|
18983
|
+
document.body.removeChild(link);
|
|
18984
|
+
window.URL.revokeObjectURL(url);
|
|
18985
|
+
setIsDownloading(false);
|
|
18986
|
+
setDownloadSuccess(true);
|
|
18987
|
+
setTimeout(() => setDownloadSuccess(false), 2e3);
|
|
18988
|
+
} catch (error) {
|
|
18989
|
+
console.error("Error downloading image:", error);
|
|
18990
|
+
setIsDownloading(false);
|
|
18991
|
+
}
|
|
18992
|
+
};
|
|
18687
18993
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
18688
18994
|
"div",
|
|
18689
18995
|
{
|
|
18690
18996
|
className: cn("w-full lg:p-10 sm:p-4 p-2", className),
|
|
18691
|
-
style: { width },
|
|
18692
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-3", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
18997
|
+
style: { width, height },
|
|
18998
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-3 h-full", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
18693
18999
|
"div",
|
|
18694
19000
|
{
|
|
18695
19001
|
className: cn(
|
|
18696
|
-
"relative overflow-hidden rounded-lg",
|
|
19002
|
+
"relative overflow-hidden rounded-lg h-full",
|
|
18697
19003
|
containerClassName
|
|
18698
19004
|
),
|
|
18699
19005
|
ref: containerRef,
|
|
18700
19006
|
children: [
|
|
18701
|
-
/* @__PURE__ */ jsxRuntime.jsx(framerMotion.motion.div, { className: "flex", style: { x }, children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 w-full",
|
|
19007
|
+
/* @__PURE__ */ jsxRuntime.jsx(framerMotion.motion.div, { className: "flex h-full", style: { x }, children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 w-full h-full", children: isMobile || zoomEffect === "scale" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
19008
|
+
ZoomImage,
|
|
19009
|
+
{
|
|
19010
|
+
src: item.url,
|
|
19011
|
+
alt: item.title,
|
|
19012
|
+
className: cn("w-full h-full select-none"),
|
|
19013
|
+
imageClassName,
|
|
19014
|
+
borderRadius: 8,
|
|
19015
|
+
maxZoom: 3
|
|
19016
|
+
}
|
|
19017
|
+
) : zoomEffect === "lens" ? /* @__PURE__ */ jsxRuntime.jsx(Lens, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
19018
|
+
"img",
|
|
19019
|
+
{
|
|
19020
|
+
src: item.url,
|
|
19021
|
+
alt: item.title,
|
|
19022
|
+
className: cn(
|
|
19023
|
+
"w-full h-full object-cover rounded-lg select-none pointer-events-none",
|
|
19024
|
+
imageClassName
|
|
19025
|
+
),
|
|
19026
|
+
draggable: false
|
|
19027
|
+
}
|
|
19028
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
18702
19029
|
"img",
|
|
18703
19030
|
{
|
|
18704
19031
|
src: item.url,
|
|
@@ -18710,13 +19037,93 @@ function CarouselBase({
|
|
|
18710
19037
|
draggable: false
|
|
18711
19038
|
}
|
|
18712
19039
|
) }, item.id)) }),
|
|
19040
|
+
download && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19041
|
+
framerMotion.motion.button,
|
|
19042
|
+
{
|
|
19043
|
+
onClick: handleDownload,
|
|
19044
|
+
className: cn(
|
|
19045
|
+
"absolute top-4 right-4 z-30 p-2 rounded-full text-white transition-colors border border-white/10",
|
|
19046
|
+
downloadSuccess ? "bg-green-500 hover:bg-green-600" : "bg-black/50 hover:bg-black/70"
|
|
19047
|
+
),
|
|
19048
|
+
title: "Download image",
|
|
19049
|
+
initial: false,
|
|
19050
|
+
animate: {
|
|
19051
|
+
scale: isDownloading ? 0.9 : 1,
|
|
19052
|
+
backgroundColor: downloadSuccess ? "rgb(34, 197, 94)" : "rgba(0, 0, 0, 0.5)"
|
|
19053
|
+
},
|
|
19054
|
+
whileHover: { scale: 1.05 },
|
|
19055
|
+
whileTap: { scale: 0.95 },
|
|
19056
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { mode: "wait", initial: false, children: isDownloading ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
19057
|
+
framerMotion.motion.svg,
|
|
19058
|
+
{
|
|
19059
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
19060
|
+
width: "20",
|
|
19061
|
+
height: "20",
|
|
19062
|
+
viewBox: "0 0 24 24",
|
|
19063
|
+
fill: "none",
|
|
19064
|
+
stroke: "currentColor",
|
|
19065
|
+
strokeWidth: "2",
|
|
19066
|
+
strokeLinecap: "round",
|
|
19067
|
+
strokeLinejoin: "round",
|
|
19068
|
+
animate: { rotate: 360 },
|
|
19069
|
+
transition: {
|
|
19070
|
+
repeat: Infinity,
|
|
19071
|
+
ease: "linear",
|
|
19072
|
+
duration: 1
|
|
19073
|
+
},
|
|
19074
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
|
|
19075
|
+
},
|
|
19076
|
+
"loading"
|
|
19077
|
+
) : downloadSuccess ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
19078
|
+
framerMotion.motion.svg,
|
|
19079
|
+
{
|
|
19080
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
19081
|
+
width: "20",
|
|
19082
|
+
height: "20",
|
|
19083
|
+
viewBox: "0 0 24 24",
|
|
19084
|
+
fill: "none",
|
|
19085
|
+
stroke: "currentColor",
|
|
19086
|
+
strokeWidth: "2",
|
|
19087
|
+
strokeLinecap: "round",
|
|
19088
|
+
strokeLinejoin: "round",
|
|
19089
|
+
initial: { scale: 0.5, opacity: 0 },
|
|
19090
|
+
animate: { scale: 1, opacity: 1 },
|
|
19091
|
+
exit: { scale: 0.5, opacity: 0 },
|
|
19092
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "20 6 9 17 4 12" })
|
|
19093
|
+
},
|
|
19094
|
+
"success"
|
|
19095
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
19096
|
+
framerMotion.motion.svg,
|
|
19097
|
+
{
|
|
19098
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
19099
|
+
width: "20",
|
|
19100
|
+
height: "20",
|
|
19101
|
+
viewBox: "0 0 24 24",
|
|
19102
|
+
fill: "none",
|
|
19103
|
+
stroke: "currentColor",
|
|
19104
|
+
strokeWidth: "2",
|
|
19105
|
+
strokeLinecap: "round",
|
|
19106
|
+
strokeLinejoin: "round",
|
|
19107
|
+
initial: { scale: 0.5, opacity: 0 },
|
|
19108
|
+
animate: { scale: 1, opacity: 1 },
|
|
19109
|
+
exit: { scale: 0.5, opacity: 0 },
|
|
19110
|
+
children: [
|
|
19111
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
|
|
19112
|
+
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "7 10 12 15 17 10" }),
|
|
19113
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", x2: "12", y1: "15", y2: "3" })
|
|
19114
|
+
]
|
|
19115
|
+
},
|
|
19116
|
+
"download"
|
|
19117
|
+
) })
|
|
19118
|
+
}
|
|
19119
|
+
),
|
|
18713
19120
|
showControls && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
18714
19121
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18715
19122
|
framerMotion.motion.button,
|
|
18716
19123
|
{
|
|
18717
19124
|
disabled: index === 0,
|
|
18718
19125
|
onClick: () => setIndex((i) => Math.max(0, i - 1)),
|
|
18719
|
-
className: `absolute left-4 top-1/2 -translate-y-1/2 w-10 h-10 rounded-full flex items-center justify-center shadow-lg transition-transform z-
|
|
19126
|
+
className: `absolute left-4 top-1/2 -translate-y-1/2 w-10 h-10 rounded-full flex items-center justify-center shadow-lg transition-transform z-30
|
|
18720
19127
|
${index === 0 ? "opacity-40 cursor-not-allowed" : "bg-secondary hover:scale-110 hover:opacity-100 opacity-70"}`,
|
|
18721
19128
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
18722
19129
|
"svg",
|
|
@@ -18743,7 +19150,7 @@ function CarouselBase({
|
|
|
18743
19150
|
{
|
|
18744
19151
|
disabled: index === items.length - 1,
|
|
18745
19152
|
onClick: () => setIndex((i) => Math.min(items.length - 1, i + 1)),
|
|
18746
|
-
className: `absolute right-4 top-1/2 -translate-y-1/2 w-10 h-10 rounded-full flex items-center justify-center shadow-lg transition-transform z-
|
|
19153
|
+
className: `absolute right-4 top-1/2 -translate-y-1/2 w-10 h-10 rounded-full flex items-center justify-center shadow-lg transition-transform z-30
|
|
18747
19154
|
${index === items.length - 1 ? "opacity-40 cursor-not-allowed" : "bg-secondary hover:scale-110 hover:opacity-100 opacity-70"}`,
|
|
18748
19155
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
18749
19156
|
"svg",
|
package/dist/index.mjs
CHANGED
|
@@ -15,7 +15,7 @@ import { toast as toast$1, Toaster as Toaster$1 } from 'sonner';
|
|
|
15
15
|
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
16
16
|
import 'react-router-dom';
|
|
17
17
|
import { Command } from 'cmdk';
|
|
18
|
-
import { AnimatePresence, motion, useMotionValue, animate } from 'framer-motion';
|
|
18
|
+
import { AnimatePresence, motion, useMotionValue, useSpring, useTransform, animate } from 'framer-motion';
|
|
19
19
|
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
|
20
20
|
import { XIcon as XIcon$1, CalendarDotIcon, DotsThreeIcon as DotsThreeIcon$1, Check, CheckIcon as CheckIcon$1 } from '@phosphor-icons/react/dist/ssr';
|
|
21
21
|
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
@@ -18605,13 +18605,290 @@ function Leaderboard({
|
|
|
18605
18605
|
}
|
|
18606
18606
|
);
|
|
18607
18607
|
}
|
|
18608
|
+
var Lens = ({
|
|
18609
|
+
children,
|
|
18610
|
+
initialZoom = 1.5,
|
|
18611
|
+
maxZoom = 4,
|
|
18612
|
+
lensSize = 150,
|
|
18613
|
+
isStatic = false,
|
|
18614
|
+
position = { x: 200, y: 150 },
|
|
18615
|
+
hovering,
|
|
18616
|
+
setHovering
|
|
18617
|
+
}) => {
|
|
18618
|
+
const containerRef = useRef(null);
|
|
18619
|
+
const [localIsHovering, setLocalIsHovering] = useState(false);
|
|
18620
|
+
const isHovering = hovering !== void 0 ? hovering : localIsHovering;
|
|
18621
|
+
const setIsHovering = setHovering || setLocalIsHovering;
|
|
18622
|
+
const [mousePosition, setMousePosition] = useState({ x: 100, y: 100 });
|
|
18623
|
+
const [zoomFactor, setZoomFactor] = useState(initialZoom);
|
|
18624
|
+
const [isActivated, setIsActivated] = useState(false);
|
|
18625
|
+
const handleMouseMove = (e) => {
|
|
18626
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
18627
|
+
const x = e.clientX - rect.left;
|
|
18628
|
+
const y = e.clientY - rect.top;
|
|
18629
|
+
setMousePosition({ x, y });
|
|
18630
|
+
};
|
|
18631
|
+
const handleWheel = (e) => {
|
|
18632
|
+
if (!isActivated) return;
|
|
18633
|
+
const delta = -e.deltaY * 5e-3;
|
|
18634
|
+
setZoomFactor((prev) => Math.min(Math.max(1.1, prev + delta), maxZoom));
|
|
18635
|
+
};
|
|
18636
|
+
const resetZoom = () => {
|
|
18637
|
+
setZoomFactor(initialZoom);
|
|
18638
|
+
setIsActivated(false);
|
|
18639
|
+
};
|
|
18640
|
+
return /* @__PURE__ */ jsxs(
|
|
18641
|
+
"div",
|
|
18642
|
+
{
|
|
18643
|
+
ref: containerRef,
|
|
18644
|
+
className: cn(
|
|
18645
|
+
"relative overflow-hidden rounded-lg z-20 h-full",
|
|
18646
|
+
isActivated ? "cursor-none" : "cursor-pointer"
|
|
18647
|
+
),
|
|
18648
|
+
onClick: () => setIsActivated(!isActivated),
|
|
18649
|
+
onMouseEnter: () => {
|
|
18650
|
+
setIsHovering(true);
|
|
18651
|
+
},
|
|
18652
|
+
onMouseLeave: () => {
|
|
18653
|
+
setIsHovering(false);
|
|
18654
|
+
resetZoom();
|
|
18655
|
+
},
|
|
18656
|
+
onMouseMove: handleMouseMove,
|
|
18657
|
+
onWheel: handleWheel,
|
|
18658
|
+
children: [
|
|
18659
|
+
children,
|
|
18660
|
+
isStatic ? /* @__PURE__ */ jsxs("div", { children: [
|
|
18661
|
+
/* @__PURE__ */ jsx(
|
|
18662
|
+
motion.div,
|
|
18663
|
+
{
|
|
18664
|
+
initial: { opacity: 0, scale: 0.58 },
|
|
18665
|
+
animate: { opacity: 1, scale: 1 },
|
|
18666
|
+
exit: { opacity: 0, scale: 0.8 },
|
|
18667
|
+
transition: { duration: 0.3, ease: "easeOut" },
|
|
18668
|
+
className: "absolute inset-0 overflow-hidden",
|
|
18669
|
+
style: {
|
|
18670
|
+
maskImage: `radial-gradient(circle ${lensSize / 2}px at ${position.x}px ${position.y}px, black 100%, transparent 100%)`,
|
|
18671
|
+
WebkitMaskImage: `radial-gradient(circle ${lensSize / 2}px at ${position.x}px ${position.y}px, black 100%, transparent 100%)`,
|
|
18672
|
+
transformOrigin: `${position.x}px ${position.y}px`
|
|
18673
|
+
},
|
|
18674
|
+
children: /* @__PURE__ */ jsx(
|
|
18675
|
+
"div",
|
|
18676
|
+
{
|
|
18677
|
+
className: "absolute inset-0",
|
|
18678
|
+
style: {
|
|
18679
|
+
transform: `scale(${zoomFactor})`,
|
|
18680
|
+
transformOrigin: `${position.x}px ${position.y}px`
|
|
18681
|
+
},
|
|
18682
|
+
children
|
|
18683
|
+
}
|
|
18684
|
+
)
|
|
18685
|
+
}
|
|
18686
|
+
),
|
|
18687
|
+
/* @__PURE__ */ jsx(
|
|
18688
|
+
"div",
|
|
18689
|
+
{
|
|
18690
|
+
className: "absolute pointer-events-none",
|
|
18691
|
+
style: {
|
|
18692
|
+
left: position.x - lensSize / 2,
|
|
18693
|
+
top: position.y - lensSize / 2,
|
|
18694
|
+
width: lensSize,
|
|
18695
|
+
height: lensSize,
|
|
18696
|
+
borderRadius: "50%",
|
|
18697
|
+
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4), 0 4px 16px rgba(0, 0, 0, 0.2)",
|
|
18698
|
+
background: "radial-gradient(circle at center, transparent 60%, rgba(255, 255, 255, 0.1) 70%, rgba(255, 255, 255, 0.2) 80%, transparent 100%)"
|
|
18699
|
+
}
|
|
18700
|
+
}
|
|
18701
|
+
)
|
|
18702
|
+
] }) : /* @__PURE__ */ jsx(AnimatePresence, { children: isHovering && isActivated && /* @__PURE__ */ jsxs("div", { children: [
|
|
18703
|
+
/* @__PURE__ */ jsx(
|
|
18704
|
+
motion.div,
|
|
18705
|
+
{
|
|
18706
|
+
initial: { opacity: 0, scale: 0.58 },
|
|
18707
|
+
animate: { opacity: 1, scale: 1 },
|
|
18708
|
+
exit: { opacity: 0, scale: 0.8 },
|
|
18709
|
+
transition: { duration: 0.3, ease: "easeOut" },
|
|
18710
|
+
className: "absolute inset-0 overflow-hidden",
|
|
18711
|
+
style: {
|
|
18712
|
+
maskImage: `radial-gradient(circle ${lensSize / 2}px at ${mousePosition.x}px ${mousePosition.y}px, black 100%, transparent 100%)`,
|
|
18713
|
+
WebkitMaskImage: `radial-gradient(circle ${lensSize / 2}px at ${mousePosition.x}px ${mousePosition.y}px, black 100%, transparent 100%)`,
|
|
18714
|
+
transformOrigin: `${mousePosition.x}px ${mousePosition.y}px`,
|
|
18715
|
+
zIndex: 50
|
|
18716
|
+
},
|
|
18717
|
+
children: /* @__PURE__ */ jsx(
|
|
18718
|
+
"div",
|
|
18719
|
+
{
|
|
18720
|
+
className: "absolute inset-0",
|
|
18721
|
+
style: {
|
|
18722
|
+
transform: `scale(${zoomFactor})`,
|
|
18723
|
+
transformOrigin: `${mousePosition.x}px ${mousePosition.y}px`
|
|
18724
|
+
},
|
|
18725
|
+
children
|
|
18726
|
+
}
|
|
18727
|
+
)
|
|
18728
|
+
}
|
|
18729
|
+
),
|
|
18730
|
+
/* @__PURE__ */ jsx(
|
|
18731
|
+
motion.div,
|
|
18732
|
+
{
|
|
18733
|
+
initial: { opacity: 0, scale: 0.58 },
|
|
18734
|
+
animate: { opacity: 1, scale: 1 },
|
|
18735
|
+
exit: { opacity: 0, scale: 0.8 },
|
|
18736
|
+
transition: { duration: 0.3, ease: "easeOut" },
|
|
18737
|
+
className: "absolute pointer-events-none z-[60]",
|
|
18738
|
+
style: {
|
|
18739
|
+
left: mousePosition.x - lensSize / 2,
|
|
18740
|
+
top: mousePosition.y - lensSize / 2,
|
|
18741
|
+
width: lensSize,
|
|
18742
|
+
height: lensSize,
|
|
18743
|
+
borderRadius: "50%",
|
|
18744
|
+
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4), 0 4px 16px rgba(0, 0, 0, 0.2)",
|
|
18745
|
+
background: "radial-gradient(circle at center, transparent 60%, rgba(255, 255, 255, 0.1) 70%, rgba(255, 255, 255, 0.2) 80%, transparent 100%)"
|
|
18746
|
+
}
|
|
18747
|
+
}
|
|
18748
|
+
)
|
|
18749
|
+
] }) })
|
|
18750
|
+
]
|
|
18751
|
+
}
|
|
18752
|
+
);
|
|
18753
|
+
};
|
|
18754
|
+
var ZoomImage = React32.forwardRef(
|
|
18755
|
+
({
|
|
18756
|
+
className,
|
|
18757
|
+
src,
|
|
18758
|
+
alt,
|
|
18759
|
+
maxZoom = 2,
|
|
18760
|
+
transitionDuration = 0.3,
|
|
18761
|
+
borderRadius = 12,
|
|
18762
|
+
imageClassName,
|
|
18763
|
+
...props
|
|
18764
|
+
}, ref) => {
|
|
18765
|
+
const mouseX = useMotionValue(50);
|
|
18766
|
+
const mouseY = useMotionValue(50);
|
|
18767
|
+
const zoomLevel = useMotionValue(1);
|
|
18768
|
+
const springConfig = { damping: 20, stiffness: 150, mass: 0.5 };
|
|
18769
|
+
const smoothMouseX = useSpring(mouseX, springConfig);
|
|
18770
|
+
const smoothMouseY = useSpring(mouseY, springConfig);
|
|
18771
|
+
const smoothZoomLevel = useSpring(zoomLevel, springConfig);
|
|
18772
|
+
const transformOrigin = useTransform(
|
|
18773
|
+
[smoothMouseX, smoothMouseY],
|
|
18774
|
+
([latestX, latestY]) => `${latestX}% ${latestY}%`
|
|
18775
|
+
);
|
|
18776
|
+
const touchStartDist = React32.useRef(0);
|
|
18777
|
+
const touchStartZoom = React32.useRef(1);
|
|
18778
|
+
const isPinching = React32.useRef(false);
|
|
18779
|
+
const handleMouseMove = (e) => {
|
|
18780
|
+
if (isPinching.current) return;
|
|
18781
|
+
const { left, top, width, height } = e.currentTarget.getBoundingClientRect();
|
|
18782
|
+
const x = (e.clientX - left) / width * 100;
|
|
18783
|
+
const y = (e.clientY - top) / height * 100;
|
|
18784
|
+
mouseX.set(x);
|
|
18785
|
+
mouseY.set(y);
|
|
18786
|
+
};
|
|
18787
|
+
const handleWheel = (e) => {
|
|
18788
|
+
const delta = -e.deltaY * 5e-3;
|
|
18789
|
+
const newZoom = Math.min(Math.max(1, zoomLevel.get() + delta), maxZoom);
|
|
18790
|
+
zoomLevel.set(newZoom);
|
|
18791
|
+
};
|
|
18792
|
+
const handleMouseLeave = () => {
|
|
18793
|
+
if (!isPinching.current) {
|
|
18794
|
+
mouseX.set(50);
|
|
18795
|
+
mouseY.set(50);
|
|
18796
|
+
zoomLevel.set(1);
|
|
18797
|
+
}
|
|
18798
|
+
};
|
|
18799
|
+
const getDistance = (touches) => {
|
|
18800
|
+
const dx = touches[0].clientX - touches[1].clientX;
|
|
18801
|
+
const dy = touches[0].clientY - touches[1].clientY;
|
|
18802
|
+
return Math.sqrt(dx * dx + dy * dy);
|
|
18803
|
+
};
|
|
18804
|
+
const getCenter = (touches, rect) => {
|
|
18805
|
+
const x = (touches[0].clientX + touches[1].clientX) / 2;
|
|
18806
|
+
const y = (touches[0].clientY + touches[1].clientY) / 2;
|
|
18807
|
+
return {
|
|
18808
|
+
x: (x - rect.left) / rect.width * 100,
|
|
18809
|
+
y: (y - rect.top) / rect.height * 100
|
|
18810
|
+
};
|
|
18811
|
+
};
|
|
18812
|
+
const handleTouchStart = (e) => {
|
|
18813
|
+
if (e.touches.length === 2) {
|
|
18814
|
+
isPinching.current = true;
|
|
18815
|
+
touchStartDist.current = getDistance(e.touches);
|
|
18816
|
+
touchStartZoom.current = zoomLevel.get();
|
|
18817
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
18818
|
+
const center = getCenter(e.touches, rect);
|
|
18819
|
+
mouseX.set(center.x);
|
|
18820
|
+
mouseY.set(center.y);
|
|
18821
|
+
}
|
|
18822
|
+
};
|
|
18823
|
+
const handleTouchMove = (e) => {
|
|
18824
|
+
if (e.touches.length === 2 && isPinching.current) {
|
|
18825
|
+
e.preventDefault();
|
|
18826
|
+
const dist = getDistance(e.touches);
|
|
18827
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
18828
|
+
const scaleChange = dist / touchStartDist.current;
|
|
18829
|
+
const newZoom = Math.min(
|
|
18830
|
+
Math.max(1, touchStartZoom.current * scaleChange),
|
|
18831
|
+
maxZoom
|
|
18832
|
+
);
|
|
18833
|
+
zoomLevel.set(newZoom);
|
|
18834
|
+
const center = getCenter(e.touches, rect);
|
|
18835
|
+
mouseX.set(center.x);
|
|
18836
|
+
mouseY.set(center.y);
|
|
18837
|
+
}
|
|
18838
|
+
};
|
|
18839
|
+
const handleTouchEnd = (e) => {
|
|
18840
|
+
if (e.touches.length < 2) {
|
|
18841
|
+
if (isPinching.current) {
|
|
18842
|
+
isPinching.current = false;
|
|
18843
|
+
}
|
|
18844
|
+
}
|
|
18845
|
+
};
|
|
18846
|
+
return /* @__PURE__ */ jsx(
|
|
18847
|
+
motion.div,
|
|
18848
|
+
{
|
|
18849
|
+
ref,
|
|
18850
|
+
className: cn(
|
|
18851
|
+
"relative w-full h-full overflow-hidden touch-none",
|
|
18852
|
+
className
|
|
18853
|
+
),
|
|
18854
|
+
style: { borderRadius: `${borderRadius}px` },
|
|
18855
|
+
onMouseMove: handleMouseMove,
|
|
18856
|
+
onMouseLeave: handleMouseLeave,
|
|
18857
|
+
onWheel: handleWheel,
|
|
18858
|
+
onTouchStart: handleTouchStart,
|
|
18859
|
+
onTouchMove: handleTouchMove,
|
|
18860
|
+
onTouchEnd: handleTouchEnd,
|
|
18861
|
+
...props,
|
|
18862
|
+
children: /* @__PURE__ */ jsx(
|
|
18863
|
+
motion.img,
|
|
18864
|
+
{
|
|
18865
|
+
src,
|
|
18866
|
+
alt,
|
|
18867
|
+
className: cn("w-full h-full object-cover", imageClassName),
|
|
18868
|
+
style: {
|
|
18869
|
+
borderRadius: `${borderRadius}px`,
|
|
18870
|
+
transformOrigin,
|
|
18871
|
+
scale: smoothZoomLevel
|
|
18872
|
+
},
|
|
18873
|
+
transition: {
|
|
18874
|
+
type: "spring",
|
|
18875
|
+
duration: transitionDuration,
|
|
18876
|
+
bounce: 0
|
|
18877
|
+
}
|
|
18878
|
+
}
|
|
18879
|
+
)
|
|
18880
|
+
}
|
|
18881
|
+
);
|
|
18882
|
+
}
|
|
18883
|
+
);
|
|
18884
|
+
ZoomImage.displayName = "ZoomImage";
|
|
18608
18885
|
function CarouselBase({
|
|
18609
18886
|
items,
|
|
18610
18887
|
className,
|
|
18611
18888
|
containerClassName,
|
|
18612
18889
|
imageClassName,
|
|
18613
18890
|
width,
|
|
18614
|
-
height
|
|
18891
|
+
height,
|
|
18615
18892
|
showControls = true,
|
|
18616
18893
|
showIndicators = true,
|
|
18617
18894
|
autoPlay = false,
|
|
@@ -18619,11 +18896,16 @@ function CarouselBase({
|
|
|
18619
18896
|
springConfig = {
|
|
18620
18897
|
stiffness: 300,
|
|
18621
18898
|
damping: 30
|
|
18622
|
-
}
|
|
18899
|
+
},
|
|
18900
|
+
zoomEffect = null,
|
|
18901
|
+
download = false
|
|
18623
18902
|
}) {
|
|
18903
|
+
const isMobile = useIsMobile();
|
|
18624
18904
|
const [index, setIndex] = useState(0);
|
|
18625
18905
|
const containerRef = useRef(null);
|
|
18626
18906
|
const x = useMotionValue(0);
|
|
18907
|
+
const [isDownloading, setIsDownloading] = useState(false);
|
|
18908
|
+
const [downloadSuccess, setDownloadSuccess] = useState(false);
|
|
18627
18909
|
useEffect(() => {
|
|
18628
18910
|
if (containerRef.current) {
|
|
18629
18911
|
const containerWidth = containerRef.current.offsetWidth || 1;
|
|
@@ -18642,21 +18924,66 @@ function CarouselBase({
|
|
|
18642
18924
|
}, autoPlayInterval);
|
|
18643
18925
|
return () => clearInterval(interval);
|
|
18644
18926
|
}, [autoPlay, autoPlayInterval, items.length]);
|
|
18927
|
+
const handleDownload = async () => {
|
|
18928
|
+
if (isDownloading) return;
|
|
18929
|
+
setIsDownloading(true);
|
|
18930
|
+
setDownloadSuccess(false);
|
|
18931
|
+
const currentItem = items[index];
|
|
18932
|
+
try {
|
|
18933
|
+
const response = await fetch(currentItem.url);
|
|
18934
|
+
const blob = await response.blob();
|
|
18935
|
+
const url = window.URL.createObjectURL(blob);
|
|
18936
|
+
const link = document.createElement("a");
|
|
18937
|
+
link.href = url;
|
|
18938
|
+
link.download = currentItem.title || "image";
|
|
18939
|
+
document.body.appendChild(link);
|
|
18940
|
+
link.click();
|
|
18941
|
+
document.body.removeChild(link);
|
|
18942
|
+
window.URL.revokeObjectURL(url);
|
|
18943
|
+
setIsDownloading(false);
|
|
18944
|
+
setDownloadSuccess(true);
|
|
18945
|
+
setTimeout(() => setDownloadSuccess(false), 2e3);
|
|
18946
|
+
} catch (error) {
|
|
18947
|
+
console.error("Error downloading image:", error);
|
|
18948
|
+
setIsDownloading(false);
|
|
18949
|
+
}
|
|
18950
|
+
};
|
|
18645
18951
|
return /* @__PURE__ */ jsx(
|
|
18646
18952
|
"div",
|
|
18647
18953
|
{
|
|
18648
18954
|
className: cn("w-full lg:p-10 sm:p-4 p-2", className),
|
|
18649
|
-
style: { width },
|
|
18650
|
-
children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-3", children: /* @__PURE__ */ jsxs(
|
|
18955
|
+
style: { width, height },
|
|
18956
|
+
children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-3 h-full", children: /* @__PURE__ */ jsxs(
|
|
18651
18957
|
"div",
|
|
18652
18958
|
{
|
|
18653
18959
|
className: cn(
|
|
18654
|
-
"relative overflow-hidden rounded-lg",
|
|
18960
|
+
"relative overflow-hidden rounded-lg h-full",
|
|
18655
18961
|
containerClassName
|
|
18656
18962
|
),
|
|
18657
18963
|
ref: containerRef,
|
|
18658
18964
|
children: [
|
|
18659
|
-
/* @__PURE__ */ jsx(motion.div, { className: "flex", style: { x }, children: items.map((item) => /* @__PURE__ */ jsx("div", { className: "shrink-0 w-full",
|
|
18965
|
+
/* @__PURE__ */ jsx(motion.div, { className: "flex h-full", style: { x }, children: items.map((item) => /* @__PURE__ */ jsx("div", { className: "shrink-0 w-full h-full", children: isMobile || zoomEffect === "scale" ? /* @__PURE__ */ jsx(
|
|
18966
|
+
ZoomImage,
|
|
18967
|
+
{
|
|
18968
|
+
src: item.url,
|
|
18969
|
+
alt: item.title,
|
|
18970
|
+
className: cn("w-full h-full select-none"),
|
|
18971
|
+
imageClassName,
|
|
18972
|
+
borderRadius: 8,
|
|
18973
|
+
maxZoom: 3
|
|
18974
|
+
}
|
|
18975
|
+
) : zoomEffect === "lens" ? /* @__PURE__ */ jsx(Lens, { children: /* @__PURE__ */ jsx(
|
|
18976
|
+
"img",
|
|
18977
|
+
{
|
|
18978
|
+
src: item.url,
|
|
18979
|
+
alt: item.title,
|
|
18980
|
+
className: cn(
|
|
18981
|
+
"w-full h-full object-cover rounded-lg select-none pointer-events-none",
|
|
18982
|
+
imageClassName
|
|
18983
|
+
),
|
|
18984
|
+
draggable: false
|
|
18985
|
+
}
|
|
18986
|
+
) }) : /* @__PURE__ */ jsx(
|
|
18660
18987
|
"img",
|
|
18661
18988
|
{
|
|
18662
18989
|
src: item.url,
|
|
@@ -18668,13 +18995,93 @@ function CarouselBase({
|
|
|
18668
18995
|
draggable: false
|
|
18669
18996
|
}
|
|
18670
18997
|
) }, item.id)) }),
|
|
18998
|
+
download && /* @__PURE__ */ jsx(
|
|
18999
|
+
motion.button,
|
|
19000
|
+
{
|
|
19001
|
+
onClick: handleDownload,
|
|
19002
|
+
className: cn(
|
|
19003
|
+
"absolute top-4 right-4 z-30 p-2 rounded-full text-white transition-colors border border-white/10",
|
|
19004
|
+
downloadSuccess ? "bg-green-500 hover:bg-green-600" : "bg-black/50 hover:bg-black/70"
|
|
19005
|
+
),
|
|
19006
|
+
title: "Download image",
|
|
19007
|
+
initial: false,
|
|
19008
|
+
animate: {
|
|
19009
|
+
scale: isDownloading ? 0.9 : 1,
|
|
19010
|
+
backgroundColor: downloadSuccess ? "rgb(34, 197, 94)" : "rgba(0, 0, 0, 0.5)"
|
|
19011
|
+
},
|
|
19012
|
+
whileHover: { scale: 1.05 },
|
|
19013
|
+
whileTap: { scale: 0.95 },
|
|
19014
|
+
children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", initial: false, children: isDownloading ? /* @__PURE__ */ jsx(
|
|
19015
|
+
motion.svg,
|
|
19016
|
+
{
|
|
19017
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
19018
|
+
width: "20",
|
|
19019
|
+
height: "20",
|
|
19020
|
+
viewBox: "0 0 24 24",
|
|
19021
|
+
fill: "none",
|
|
19022
|
+
stroke: "currentColor",
|
|
19023
|
+
strokeWidth: "2",
|
|
19024
|
+
strokeLinecap: "round",
|
|
19025
|
+
strokeLinejoin: "round",
|
|
19026
|
+
animate: { rotate: 360 },
|
|
19027
|
+
transition: {
|
|
19028
|
+
repeat: Infinity,
|
|
19029
|
+
ease: "linear",
|
|
19030
|
+
duration: 1
|
|
19031
|
+
},
|
|
19032
|
+
children: /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
|
|
19033
|
+
},
|
|
19034
|
+
"loading"
|
|
19035
|
+
) : downloadSuccess ? /* @__PURE__ */ jsx(
|
|
19036
|
+
motion.svg,
|
|
19037
|
+
{
|
|
19038
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
19039
|
+
width: "20",
|
|
19040
|
+
height: "20",
|
|
19041
|
+
viewBox: "0 0 24 24",
|
|
19042
|
+
fill: "none",
|
|
19043
|
+
stroke: "currentColor",
|
|
19044
|
+
strokeWidth: "2",
|
|
19045
|
+
strokeLinecap: "round",
|
|
19046
|
+
strokeLinejoin: "round",
|
|
19047
|
+
initial: { scale: 0.5, opacity: 0 },
|
|
19048
|
+
animate: { scale: 1, opacity: 1 },
|
|
19049
|
+
exit: { scale: 0.5, opacity: 0 },
|
|
19050
|
+
children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" })
|
|
19051
|
+
},
|
|
19052
|
+
"success"
|
|
19053
|
+
) : /* @__PURE__ */ jsxs(
|
|
19054
|
+
motion.svg,
|
|
19055
|
+
{
|
|
19056
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
19057
|
+
width: "20",
|
|
19058
|
+
height: "20",
|
|
19059
|
+
viewBox: "0 0 24 24",
|
|
19060
|
+
fill: "none",
|
|
19061
|
+
stroke: "currentColor",
|
|
19062
|
+
strokeWidth: "2",
|
|
19063
|
+
strokeLinecap: "round",
|
|
19064
|
+
strokeLinejoin: "round",
|
|
19065
|
+
initial: { scale: 0.5, opacity: 0 },
|
|
19066
|
+
animate: { scale: 1, opacity: 1 },
|
|
19067
|
+
exit: { scale: 0.5, opacity: 0 },
|
|
19068
|
+
children: [
|
|
19069
|
+
/* @__PURE__ */ jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
|
|
19070
|
+
/* @__PURE__ */ jsx("polyline", { points: "7 10 12 15 17 10" }),
|
|
19071
|
+
/* @__PURE__ */ jsx("line", { x1: "12", x2: "12", y1: "15", y2: "3" })
|
|
19072
|
+
]
|
|
19073
|
+
},
|
|
19074
|
+
"download"
|
|
19075
|
+
) })
|
|
19076
|
+
}
|
|
19077
|
+
),
|
|
18671
19078
|
showControls && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
18672
19079
|
/* @__PURE__ */ jsx(
|
|
18673
19080
|
motion.button,
|
|
18674
19081
|
{
|
|
18675
19082
|
disabled: index === 0,
|
|
18676
19083
|
onClick: () => setIndex((i) => Math.max(0, i - 1)),
|
|
18677
|
-
className: `absolute left-4 top-1/2 -translate-y-1/2 w-10 h-10 rounded-full flex items-center justify-center shadow-lg transition-transform z-
|
|
19084
|
+
className: `absolute left-4 top-1/2 -translate-y-1/2 w-10 h-10 rounded-full flex items-center justify-center shadow-lg transition-transform z-30
|
|
18678
19085
|
${index === 0 ? "opacity-40 cursor-not-allowed" : "bg-secondary hover:scale-110 hover:opacity-100 opacity-70"}`,
|
|
18679
19086
|
children: /* @__PURE__ */ jsx(
|
|
18680
19087
|
"svg",
|
|
@@ -18701,7 +19108,7 @@ function CarouselBase({
|
|
|
18701
19108
|
{
|
|
18702
19109
|
disabled: index === items.length - 1,
|
|
18703
19110
|
onClick: () => setIndex((i) => Math.min(items.length - 1, i + 1)),
|
|
18704
|
-
className: `absolute right-4 top-1/2 -translate-y-1/2 w-10 h-10 rounded-full flex items-center justify-center shadow-lg transition-transform z-
|
|
19111
|
+
className: `absolute right-4 top-1/2 -translate-y-1/2 w-10 h-10 rounded-full flex items-center justify-center shadow-lg transition-transform z-30
|
|
18705
19112
|
${index === items.length - 1 ? "opacity-40 cursor-not-allowed" : "bg-secondary hover:scale-110 hover:opacity-100 opacity-70"}`,
|
|
18706
19113
|
children: /* @__PURE__ */ jsx(
|
|
18707
19114
|
"svg",
|