lightswind
Version:
A collection of beautifully crafted React Components, Blocks & Templates for Modern Developers. Create stunning web applications effortlessly by using our 160+ professional and animated react components.
152 lines • 9.28 kB
JavaScript
;
"use client";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ScrollCarousel = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const gsap_1 = require("gsap");
const ScrollTrigger_1 = require("gsap/ScrollTrigger");
// Assuming these are external, import them
const utils_1 = require("@/components/lib/utils");
gsap_1.gsap.registerPlugin(ScrollTrigger_1.ScrollTrigger);
// --- Custom Hook for Animations ---
const useFeatureAnimations = (containerRef, scrollContainerRef, scrollContainerRef2, progressBarRef, cardRefs, cardRefs2, isDesktop, maxScrollHeight) => {
(0, react_1.useLayoutEffect)(() => {
let ctx = gsap_1.gsap.context(() => {
// Desktop horizontal scroll logic
if (isDesktop) {
const scrollWidth1 = scrollContainerRef.current?.scrollWidth || 0;
const scrollWidth2 = scrollContainerRef2.current?.scrollWidth || 0;
const containerWidth = containerRef.current?.offsetWidth || 0;
const cardWidth = cardRefs.current[0]?.offsetWidth || 0;
const viewportOffset = (containerWidth - cardWidth) / 2;
const finalOffset1 = scrollWidth1 - containerWidth + viewportOffset;
const finalOffset2 = scrollWidth2 - containerWidth + viewportOffset;
// Use the provided maxScrollHeight or the calculated offset as the scroll distance
const scrollDistance = maxScrollHeight || finalOffset1;
gsap_1.gsap.set(scrollContainerRef2.current, {
x: -finalOffset2 + viewportOffset * 2,
});
gsap_1.gsap
.timeline({
scrollTrigger: {
trigger: containerRef.current,
start: "top top",
end: () => `+=${scrollDistance}`,
scrub: 1,
pin: true,
},
})
.fromTo(scrollContainerRef.current, { x: viewportOffset }, { x: -finalOffset1 + viewportOffset, ease: "none" });
gsap_1.gsap
.timeline({
scrollTrigger: {
trigger: containerRef.current,
start: "top top",
end: () => `+=${scrollDistance}`,
scrub: 1,
},
})
.to(scrollContainerRef2.current, { x: viewportOffset, ease: "none" });
gsap_1.gsap.to(progressBarRef.current, {
width: "100%",
ease: "none",
scrollTrigger: {
trigger: containerRef.current,
start: "top top",
end: () => `+=${scrollDistance}`,
scrub: true,
},
});
}
else {
// Mobile vertical scroll logic
const allCards = [...cardRefs.current, ...cardRefs2.current];
allCards.forEach((card, index) => {
if (card) {
gsap_1.gsap.fromTo(card, {
opacity: 0,
x: index % 2 === 0 ? -200 : 200,
}, {
opacity: 1,
x: 0,
duration: 1,
ease: "power2.out",
scrollTrigger: {
trigger: card,
start: "top 0%",
toggleActions: "play none none none",
once: true,
},
});
}
});
}
}, containerRef);
return () => {
ctx.revert();
};
}, [isDesktop, maxScrollHeight]);
};
// --- Component Definition ---
exports.ScrollCarousel = (0, react_1.forwardRef)(({ features, className, maxScrollHeight }, ref) => {
const containerRef = (0, react_1.useRef)(null);
const scrollContainerRef = (0, react_1.useRef)(null);
const scrollContainerRef2 = (0, react_1.useRef)(null);
const progressBarRef = (0, react_1.useRef)(null);
const cardRefs = (0, react_1.useRef)([]);
const cardRefs2 = (0, react_1.useRef)([]);
const [isDesktop, setIsDesktop] = (0, react_1.useState)(false);
// Dynamic sorting for the second row of cards
const features2 = [...features].sort(() => Math.random() - 0.5);
(0, react_1.useEffect)(() => {
const checkDesktop = () => {
setIsDesktop(window.matchMedia("(min-width: 768px)").matches);
};
checkDesktop();
window.addEventListener("resize", checkDesktop);
return () => window.removeEventListener("resize", checkDesktop);
}, []);
useFeatureAnimations(containerRef, scrollContainerRef, scrollContainerRef2, progressBarRef, cardRefs, cardRefs2, isDesktop, maxScrollHeight);
const renderFeatureCards = (featureSet, refs) => featureSet.map((feature, index) => ((0, jsx_runtime_1.jsx)("div", { ref: (el) => {
if (el)
refs.current[index] = el;
}, className: "feature-card flex-shrink-0 w-full md:w-full h-full\r\n z-10 gap-4 group relative transition-all duration-300 ease-in-out", children: (0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)(`relative h-full p-4 lg:p-8 rounded-3xl backdrop-blur-sm
flex items-center justify-center z-10
transition-all duration-300 my-4`, `backdrop-blur-lg border text-black dark:text-white`, "group-hover:scale-105 centered:scale-105"), children: [(0, jsx_runtime_1.jsx)("img", { src: feature.image ||
"https://images.pexels.com/photos/9934462/pexels-photo-9934462.jpeg", alt: "", className: "absolute inset-0 w-full h-full \r\n object-cover z-[-1] rounded-3xl " }), (0, jsx_runtime_1.jsx)("div", { className: "absolute bottom-4 z-10 w-full px-4", children: (0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)(`flex flex-col justify-end h-full opacity-100 translate-y-4 transition-all duration-300 ease-out text-center`), children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-2xl mb-0 font-bold text-white transition-all duration-300", children: feature.title }), (0, jsx_runtime_1.jsx)("p", { className: "text-white text-xs mb-4 opacity-60", children: feature.description })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "pointer-events-none absolute inset-0 transition-all duration-300 group-hover:bg-black/5 dark:group-hover:bg-white/5 centered:bg-black/5 dark:centered:bg-white/5 rounded-2xl group-hover:blur-md" })] }) }, index)));
return ((0, jsx_runtime_1.jsxs)("section", { className: (0, utils_1.cn)("bg-transparent text-foreground relative overflow-hidden", className), ref: ref, children: [(0, jsx_runtime_1.jsxs)("div", { ref: containerRef, className: `relative overflow-hidden md:h-screen md:py-20
flex flex-col gap-0 z-10
lg:[mask-image:_linear-gradient(to_right,transparent_0,_black_5%,_black_95%,transparent_100%)]`, children: [(0, jsx_runtime_1.jsx)("div", { ref: scrollContainerRef, className: `flex flex-col md:flex-row gap-8
items-center h-full px-6 md:px-0`, children: renderFeatureCards(features, cardRefs) }), (0, jsx_runtime_1.jsx)("div", { ref: scrollContainerRef2, className: `flex flex-col md:flex-row gap-8 items-center h-full px-6 md:px-0 hidden xl:flex`, children: renderFeatureCards(features2, cardRefs2) }), isDesktop && ((0, jsx_runtime_1.jsx)("div", { className: "absolute bottom-10 left-1/2 -translate-x-1/2 w-64 h-2 bg-black/30 dark:bg-white/30 z-50 overflow-hidden rounded-full", children: (0, jsx_runtime_1.jsx)("div", { ref: progressBarRef, className: "h-full rounded-full relative overflow-hidden transition-all duration-100", style: { width: "0%" }, children: (0, jsx_runtime_1.jsx)("div", { className: "absolute inset-0 animated-water" }) }) }))] }), (0, jsx_runtime_1.jsx)("style", { dangerouslySetInnerHTML: { __html: `
.animated-water {
background: repeating-linear-gradient(
-45deg,
rgba(0, 0, 0, 0.7) 0%,
rgba(0, 0, 0, 0.5) 25%,
rgba(0, 0, 0, 0.7) 50%
);
background-size: 40px 40px;
animation: waveMove 2s linear infinite;
}
.dark .animated-water {
background: repeating-linear-gradient(
-45deg,
rgba(255, 255, 255, 0.9) 0%,
rgba(255, 255, 255, 0.6) 25%,
rgba(255, 255, 255, 0.9) 50%
);
}
@keyframes waveMove {
from {
background-position: 0 0;
}
to {
background-position: 40px 40px;
}
}
` } })] }));
});
exports.ScrollCarousel.displayName = "ScrollCarousel";
exports.default = exports.ScrollCarousel;
//# sourceMappingURL=scroll-carousel.js.map