UNPKG

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
"use strict"; "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