{
  "name": "animated-testimonials",
  "type": "registry:ui",
  "dependencies": [
    "@tabler/icons-react",
    "motion"
  ],
  "files": [
    {
      "path": "components/ui/animated-testimonials.tsx",
      "content": "\"use client\";\n\nimport { IconArrowLeft, IconArrowRight } from \"@tabler/icons-react\";\nimport { motion, AnimatePresence } from \"motion/react\";\n\nimport { useEffect, useState } from \"react\";\n\ntype Testimonial = {\n  quote: string;\n  name: string;\n  designation: string;\n  src: string;\n};\nexport const AnimatedTestimonials = ({\n  testimonials,\n  autoplay = false,\n}: {\n  testimonials: Testimonial[];\n  autoplay?: boolean;\n}) => {\n  const [active, setActive] = useState(0);\n\n  const handleNext = () => {\n    setActive((prev) => (prev + 1) % testimonials.length);\n  };\n\n  const handlePrev = () => {\n    setActive((prev) => (prev - 1 + testimonials.length) % testimonials.length);\n  };\n\n  const isActive = (index: number) => {\n    return index === active;\n  };\n\n  useEffect(() => {\n    if (autoplay) {\n      const interval = setInterval(handleNext, 5000);\n      return () => clearInterval(interval);\n    }\n  }, [autoplay]);\n\n  const randomRotateY = () => {\n    return Math.floor(Math.random() * 21) - 10;\n  };\n  return (\n    <div className=\"mx-auto max-w-sm px-4 py-20 font-sans antialiased md:max-w-4xl md:px-8 lg:px-12\">\n      <div className=\"relative grid grid-cols-1 gap-20 md:grid-cols-2\">\n        <div>\n          <div className=\"relative h-80 w-full\">\n            <AnimatePresence>\n              {testimonials.map((testimonial, index) => (\n                <motion.div\n                  key={testimonial.src}\n                  initial={{\n                    opacity: 0,\n                    scale: 0.9,\n                    z: -100,\n                    rotate: randomRotateY(),\n                  }}\n                  animate={{\n                    opacity: isActive(index) ? 1 : 0.7,\n                    scale: isActive(index) ? 1 : 0.95,\n                    z: isActive(index) ? 0 : -100,\n                    rotate: isActive(index) ? 0 : randomRotateY(),\n                    zIndex: isActive(index)\n                      ? 40\n                      : testimonials.length + 2 - index,\n                    y: isActive(index) ? [0, -80, 0] : 0,\n                  }}\n                  exit={{\n                    opacity: 0,\n                    scale: 0.9,\n                    z: 100,\n                    rotate: randomRotateY(),\n                  }}\n                  transition={{\n                    duration: 0.4,\n                    ease: \"easeInOut\",\n                  }}\n                  className=\"absolute inset-0 origin-bottom\"\n                >\n                  <img\n                    src={testimonial.src}\n                    alt={testimonial.name}\n                    width={500}\n                    height={500}\n                    draggable={false}\n                    className=\"h-full w-full rounded-3xl object-cover object-center\"\n                  />\n                </motion.div>\n              ))}\n            </AnimatePresence>\n          </div>\n        </div>\n        <div className=\"flex flex-col justify-between py-4\">\n          <motion.div\n            key={active}\n            initial={{\n              y: 20,\n              opacity: 0,\n            }}\n            animate={{\n              y: 0,\n              opacity: 1,\n            }}\n            exit={{\n              y: -20,\n              opacity: 0,\n            }}\n            transition={{\n              duration: 0.2,\n              ease: \"easeInOut\",\n            }}\n          >\n            <h3 className=\"text-2xl font-bold text-black dark:text-white\">\n              {testimonials[active].name}\n            </h3>\n            <p className=\"text-sm text-gray-500 dark:text-neutral-500\">\n              {testimonials[active].designation}\n            </p>\n            <motion.p className=\"mt-8 text-lg text-gray-500 dark:text-neutral-300\">\n              {testimonials[active].quote.split(\" \").map((word, index) => (\n                <motion.span\n                  key={index}\n                  initial={{\n                    filter: \"blur(10px)\",\n                    opacity: 0,\n                    y: 5,\n                  }}\n                  animate={{\n                    filter: \"blur(0px)\",\n                    opacity: 1,\n                    y: 0,\n                  }}\n                  transition={{\n                    duration: 0.2,\n                    ease: \"easeInOut\",\n                    delay: 0.02 * index,\n                  }}\n                  className=\"inline-block\"\n                >\n                  {word}&nbsp;\n                </motion.span>\n              ))}\n            </motion.p>\n          </motion.div>\n          <div className=\"flex gap-4 pt-12 md:pt-0\">\n            <button\n              onClick={handlePrev}\n              className=\"group/button flex h-7 w-7 items-center justify-center rounded-full bg-gray-100 dark:bg-neutral-800\"\n            >\n              <IconArrowLeft className=\"h-5 w-5 text-black transition-transform duration-300 group-hover/button:rotate-12 dark:text-neutral-400\" />\n            </button>\n            <button\n              onClick={handleNext}\n              className=\"group/button flex h-7 w-7 items-center justify-center rounded-full bg-gray-100 dark:bg-neutral-800\"\n            >\n              <IconArrowRight className=\"h-5 w-5 text-black transition-transform duration-300 group-hover/button:-rotate-12 dark:text-neutral-400\" />\n            </button>\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n};\n",
      "type": "registry:ui",
      "target": "components/ui/animated-testimonials.tsx"
    }
  ],
  "author": "Manu Arora <hi@manuarora.in>",
  "title": "Animated Testimonials"
}