UNPKG

lightswind

Version:

A professionally designed animate react component library & templates market that brings together functionality, accessibility, and beautiful aesthetics for modern applications.

71 lines (70 loc) 7.04 kB
// components/Carousel3D.tsx "use client"; import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { useRef, useEffect, useState, } from "react"; import { ChevronLeft, ChevronRight, ArrowRight } from "lucide-react"; import { Card, CardContent } from "@/app/component2/ui/card"; import { useIsMobile } from "../hooks/use-mobile"; import Link from "next/link"; const Carousel3D = ({ items, autoRotate = true, rotateInterval = 4000, cardHeight = 500, title = "From Textile to Intelligence", subtitle = "Customer Cases", tagline = "Explore how our textile sensor technology is revolutionizing multiple industries with intelligent fabric solutions tailored to specific needs.", isMobileSwipe = true, }) => { const [active, setActive] = useState(0); const carouselRef = useRef(null); const [isInView, setIsInView] = useState(false); const [isHovering, setIsHovering] = useState(false); const [touchStart, setTouchStart] = useState(null); const [touchEnd, setTouchEnd] = useState(null); const isMobile = useIsMobile(); const minSwipeDistance = 50; useEffect(() => { if (autoRotate && isInView && !isHovering) { const interval = setInterval(() => { setActive((prev) => (prev + 1) % items.length); }, rotateInterval); return () => clearInterval(interval); } }, [isInView, isHovering, autoRotate, rotateInterval, items.length]); useEffect(() => { const observer = new IntersectionObserver(([entry]) => setIsInView(entry.isIntersecting), { threshold: 0.2 }); return () => observer.disconnect(); }, []); const onTouchStart = (e) => { setTouchStart(e.targetTouches[0].clientX); setTouchEnd(null); }; const onTouchMove = (e) => { setTouchEnd(e.targetTouches[0].clientX); }; const onTouchEnd = () => { if (!touchStart || !touchEnd) return; const distance = touchStart - touchEnd; if (distance > minSwipeDistance) { setActive((prev) => (prev + 1) % items.length); } else if (distance < -minSwipeDistance) { setActive((prev) => (prev - 1 + items.length) % items.length); } }; const getCardAnimationClass = (index) => { if (index === active) return "scale-100 opacity-100 z-20"; if (index === (active + 1) % items.length) return "translate-x-[40%] scale-95 opacity-60 z-10"; if (index === (active - 1 + items.length) % items.length) return "translate-x-[-40%] scale-95 opacity-60 z-10"; return "scale-90 opacity-0"; }; return (_jsx("section", { id: "carousel3d", className: "bg-transparent min-w-full mx-aut \r\n flex items-center justify-center", children: _jsx("div", { className: "w-full px-4 sm:px-6 lg:px-8 \r\n min-w-[350px] md:min-w-[1000px] max-w-7xl ", children: _jsxs("div", { className: "relative overflow-hidden h-[550px] ", onMouseEnter: () => setIsHovering(true), onMouseLeave: () => setIsHovering(false), onTouchStart: onTouchStart, onTouchMove: onTouchMove, onTouchEnd: onTouchEnd, ref: carouselRef, children: [_jsx("div", { className: "absolute top-0 left-0 w-full h-full flex items-center justify-center ", children: items.map((item, index) => (_jsx("div", { className: `absolute top-0 w-full max-w-md transform transition-all duration-500 ${getCardAnimationClass(index)}`, children: _jsxs(Card, { className: `overflow-hidden bg-background h-[${cardHeight}px] border shadow-sm hover:shadow-md flex flex-col`, children: [_jsxs("div", { className: "relative bg-black p-6 flex items-center justify-center h-48 overflow-hidden", style: { backgroundImage: `url(${item.imageUrl})`, backgroundSize: "cover", backgroundPosition: "center", }, children: [_jsx("div", { className: "absolute inset-0 bg-black/50" }), _jsxs("div", { className: "relative z-10 text-center text-white", children: [_jsx("h3", { className: "text-2xl font-bold mb-2", children: item.brand.toUpperCase() }), _jsx("div", { className: "w-12 h-1 bg-white mx-auto mb-2" }), _jsx("p", { className: "text-sm ", children: item.title })] })] }), _jsxs(CardContent, { className: "p-6 flex flex-col flex-grow", children: [_jsx("h3", { className: "text-xl font-bold mb-1 text-foreground", children: item.title }), _jsx("p", { className: "text-gray-500 text-sm font-medium mb-2", children: item.brand }), _jsx("p", { className: "text-gray-600 text-sm flex-grow", children: item.description }), _jsxs("div", { className: "mt-4", children: [_jsx("div", { className: "flex flex-wrap gap-2 mb-4", children: item.tags.map((tag, idx) => (_jsx("span", { className: "px-2 py-1 bg-gray-50 text-gray-600 rounded-full text-xs animate-pulse-slow", children: tag }, idx))) }), _jsxs(Link, { href: item.link, className: "text-gray-500 flex items-center hover:underline relative group", onClick: () => { if (item.link.startsWith("/")) { window.scrollTo(0, 0); } }, children: [_jsx("span", { className: "relative z-10", children: "Learn more" }), _jsx(ArrowRight, { className: "ml-2 w-4 h-4 relative z-10 transition-transform group-hover:translate-x-1" }), _jsx("span", { className: "absolute left-0 bottom-0 w-0 h-0.5 bg-gray-500 transition-all duration-300 group-hover:w-full" })] })] })] })] }) }, item.id))) }), !isMobile && (_jsxs(_Fragment, { children: [_jsx("button", { className: "absolute left-4 top-1/2 -translate-y-1/2 w-10 h-10 bg-white/80 rounded-full flex items-center justify-center text-gray-500 hover:bg-white z-30 shadow-md transition-all hover:scale-110", onClick: () => setActive((prev) => (prev - 1 + items.length) % items.length), "aria-label": "Previous", children: _jsx(ChevronLeft, { className: "w-5 h-5" }) }), _jsx("button", { className: "absolute right-4 top-1/2 -translate-y-1/2 w-10 h-10 bg-white/80 rounded-full flex items-center justify-center text-gray-500 hover:bg-white z-30 shadow-md transition-all hover:scale-110", onClick: () => setActive((prev) => (prev + 1) % items.length), "aria-label": "Next", children: _jsx(ChevronRight, { className: "w-5 h-5" }) })] })), _jsx("div", { className: "absolute bottom-6 left-0 right-0 flex justify-center items-center space-x-3 z-30", children: items.map((_, idx) => (_jsx("button", { className: `w-2 h-2 rounded-full transition-all duration-300 ${active === idx ? "bg-gray-500 w-5" : "bg-gray-200 hover:bg-gray-300"}`, onClick: () => setActive(idx), "aria-label": `Go to item ${idx + 1}` }, idx))) })] }) }) })); }; export default Carousel3D;