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
JavaScript
"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" }) })] })] })] }) }));
};