UNPKG

xlibs-components

Version:

Modern React component library with Aceternity, MagicUI, and ShadCN components for building beautiful web applications

80 lines (79 loc) 5.71 kB
"use client"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { IconArrowLeft, IconArrowRight } from "@tabler/icons-react"; import { motion, AnimatePresence } from "framer-motion"; import { useEffect, useState } from "react"; import { buildComponentClasses } from '../../lib/config.js'; import { animatedTestimonialsConfig, testimonialCardConfig, testimonialContentConfig, navigationButtonConfig } from '../../configs/aceternity/animated-testimonials.config.js'; export const AnimatedTestimonials = ({ testimonials, autoplay = false, variant = "default", size = "md", cardVariant = "default", contentVariant = "default", buttonVariant = "default", className, }) => { const [active, setActive] = useState(0); const handleNext = () => { setActive((prev) => (prev + 1) % testimonials.length); }; const handlePrev = () => { setActive((prev) => (prev - 1 + testimonials.length) % testimonials.length); }; const isActive = (index) => { return index === active; }; useEffect(() => { if (autoplay) { const interval = setInterval(handleNext, 5000); return () => clearInterval(interval); } }, [autoplay]); const randomRotateY = () => { return Math.floor(Math.random() * 21) - 10; }; const containerClasses = buildComponentClasses(animatedTestimonialsConfig, variant, size, className); const cardClasses = buildComponentClasses(testimonialCardConfig, cardVariant, "md"); const contentClasses = buildComponentClasses(testimonialContentConfig, contentVariant, "md"); const buttonClasses = buildComponentClasses(navigationButtonConfig, buttonVariant, "md"); return (_jsx("div", { className: containerClasses, children: _jsxs("div", { className: "relative grid grid-cols-1 gap-20 md:grid-cols-2", children: [_jsx("div", { children: _jsx("div", { className: "relative h-80 w-full", children: _jsx(AnimatePresence, { children: testimonials.map((testimonial, index) => (_jsx(motion.div, { initial: { opacity: 0, scale: 0.9, z: -100, rotate: randomRotateY(), }, animate: { opacity: isActive(index) ? 1 : 0.7, scale: isActive(index) ? 1 : 0.95, z: isActive(index) ? 0 : -100, rotate: isActive(index) ? 0 : randomRotateY(), zIndex: isActive(index) ? 40 : testimonials.length + 2 - index, y: isActive(index) ? [0, -80, 0] : 0, }, exit: { opacity: 0, scale: 0.9, z: 100, rotate: randomRotateY(), }, transition: { duration: 0.4, ease: "easeInOut", }, className: "absolute inset-0 origin-bottom", children: _jsx("img", { src: testimonial.src, alt: testimonial.name, width: 500, height: 500, draggable: false, className: cardClasses }) }, testimonial.src))) }) }) }), _jsxs("div", { className: contentClasses, children: [_jsxs(motion.div, { initial: { y: 20, opacity: 0, }, animate: { y: 0, opacity: 1, }, exit: { y: -20, opacity: 0, }, transition: { duration: 0.2, ease: "easeInOut", }, children: [_jsx("h3", { className: "text-2xl font-bold text-foreground", children: testimonials[active].name }), _jsx("p", { className: "text-sm text-muted-foreground", children: testimonials[active].designation }), _jsx(motion.p, { className: "mt-8 text-lg text-muted-foreground", children: testimonials[active].quote.split(" ").map((word, index) => (_jsxs(motion.span, { initial: { filter: "blur(10px)", opacity: 0, y: 5, }, animate: { filter: "blur(0px)", opacity: 1, y: 0, }, transition: { duration: 0.2, ease: "easeInOut", delay: 0.02 * index, }, className: "inline-block", children: [word, "\u00A0"] }, index))) })] }, active), _jsxs("div", { className: "flex gap-4 pt-12 md:pt-0", children: [_jsx("button", { onClick: handlePrev, className: buttonClasses, children: _jsx(IconArrowLeft, { className: "h-5 w-5 text-foreground transition-transform duration-300 group-hover/button:rotate-12" }) }), _jsx("button", { onClick: handleNext, className: buttonClasses, children: _jsx(IconArrowRight, { className: "h-5 w-5 text-foreground transition-transform duration-300 group-hover/button:-rotate-12" }) })] })] })] }) })); };