{"$schema":"https://ui.shadcn.com/schema/registry-item.json","author":"Eduardo Calvo <educlopez93@gmail.com>","css":{},"dependencies":["motion"],"description":"Carousel team section block with auto-play","devDependencies":[],"files":[{"content":"\"use client\";\n\nimport { getAllPeople, getAvatarUrl, type Person } from \"@/lib/smoothui-data\";\nimport { motion, useReducedMotion } from \"motion/react\";\nimport { useEffect, useState } from \"react\";\n\nconst CARDS_PER_VIEW = 3; // Number of cards visible at once\nconst CARD_WIDTH = 288;\nconst CARD_GAP = 16;\nconst AUTOPLAY_INTERVAL = 5000;\nconst TRANSITION_TIMEOUT = 1500;\nconst AVATAR_SIZE = 160;\nconst STAGGER_DELAY = 0.1;\n\ninterface TeamCarouselProps {\n  description?: string;\n  members?: Person[];\n  subtitle?: string;\n  title?: string;\n}\n\nexport function TeamCarousel({\n  title = \"Tech Pioneers\",\n  subtitle = \"building the future\",\n  description = \"We bring together brilliant developers, engineers, and tech innovators to create groundbreaking digital solutions.\",\n  members = getAllPeople(),\n}: TeamCarouselProps) {\n  const shouldReduceMotion = useReducedMotion();\n  const [currentIndex, setCurrentIndex] = useState(0);\n  const [isAutoPlaying, setIsAutoPlaying] = useState(true);\n  const [isTransitioning, setIsTransitioning] = useState(false);\n\n  useEffect(() => {\n    if (!isAutoPlaying || isTransitioning) {\n      return;\n    }\n\n    const interval = setInterval(() => {\n      setCurrentIndex(\n        (prev) => (prev + 1) % (members.length - CARDS_PER_VIEW + 1)\n      );\n    }, AUTOPLAY_INTERVAL);\n\n    return () => clearInterval(interval);\n  }, [members.length, isAutoPlaying, isTransitioning]);\n\n  const nextSlide = () => {\n    if (isTransitioning) {\n      return;\n    }\n    const maxIndex = members.length - CARDS_PER_VIEW;\n    if (currentIndex >= maxIndex) {\n      return;\n    }\n\n    setIsTransitioning(true);\n    setCurrentIndex((prev) => Math.min(prev + 1, maxIndex));\n    setIsAutoPlaying(false);\n\n    setTimeout(() => {\n      setIsTransitioning(false);\n      setIsAutoPlaying(true);\n    }, TRANSITION_TIMEOUT);\n  };\n\n  const prevSlide = () => {\n    if (isTransitioning) {\n      return;\n    }\n    if (currentIndex <= 0) {\n      return;\n    }\n\n    setIsTransitioning(true);\n    setCurrentIndex((prev) => Math.max(prev - 1, 0));\n    setIsAutoPlaying(false);\n\n    setTimeout(() => {\n      setIsTransitioning(false);\n      setIsAutoPlaying(true);\n    }, TRANSITION_TIMEOUT);\n  };\n\n  return (\n    <section className=\"overflow-hidden py-32\">\n      <div className=\"mx-auto max-w-5xl px-8 lg:px-0\">\n        <motion.div\n          initial={shouldReduceMotion ? { opacity: 1 } : { opacity: 0, y: 20 }}\n          transition={shouldReduceMotion ? { duration: 0 } : { duration: 0.6 }}\n          viewport={{ once: true }}\n          whileInView={\n            shouldReduceMotion ? { opacity: 1 } : { opacity: 1, y: 0 }\n          }\n        >\n          <h2 className=\"font-medium text-5xl md:text-6xl\">\n            {title} <br />\n            <span className=\"text-foreground/50\">{subtitle}</span>\n          </h2>\n          <p className=\"mt-6 max-w-md text-foreground/70\">{description}</p>\n        </motion.div>\n\n        <div className=\"relative\">\n          {/* Navigation Buttons */}\n          <div className=\"mt-4 hidden items-center justify-end gap-4 md:flex\">\n            <motion.button\n              className=\"static top-1/2 -left-12 inline-flex size-11 shrink-0 translate-x-0 translate-y-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-full border bg-background font-medium text-sm shadow-xs outline-none transition-all hover:bg-accent hover:text-accent-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:border-input dark:bg-input/30 dark:aria-invalid:ring-destructive/40 dark:hover:bg-input/50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0\"\n              disabled={currentIndex === 0 || isTransitioning}\n              onClick={prevSlide}\n              type=\"button\"\n              whileHover={shouldReduceMotion ? {} : { scale: 1.05 }}\n              whileTap={shouldReduceMotion ? {} : { scale: 0.95 }}\n            >\n              <svg\n                aria-hidden=\"true\"\n                className=\"lucide lucide-arrow-left\"\n                fill=\"none\"\n                height=\"24\"\n                stroke=\"currentColor\"\n                strokeLinecap=\"round\"\n                strokeLinejoin=\"round\"\n                strokeWidth=\"2\"\n                viewBox=\"0 0 24 24\"\n                width=\"24\"\n                xmlns=\"http://www.w3.org/2000/svg\"\n              >\n                <path d=\"m12 19-7-7 7-7\" />\n                <path d=\"M19 12H5\" />\n              </svg>\n              <span className=\"sr-only\">Previous slide</span>\n            </motion.button>\n            <motion.button\n              className=\"static top-1/2 -right-12 inline-flex size-11 shrink-0 translate-x-0 translate-y-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-full border bg-background font-medium text-sm shadow-xs outline-none transition-all hover:bg-accent hover:text-accent-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:border-input dark:bg-input/30 dark:aria-invalid:ring-destructive/40 dark:hover:bg-input/50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0\"\n              disabled={\n                currentIndex >= members.length - CARDS_PER_VIEW ||\n                isTransitioning\n              }\n              onClick={nextSlide}\n              type=\"button\"\n              whileHover={shouldReduceMotion ? {} : { scale: 1.05 }}\n              whileTap={shouldReduceMotion ? {} : { scale: 0.95 }}\n            >\n              <svg\n                aria-hidden=\"true\"\n                className=\"lucide lucide-arrow-right\"\n                fill=\"none\"\n                height=\"24\"\n                stroke=\"currentColor\"\n                strokeLinecap=\"round\"\n                strokeLinejoin=\"round\"\n                strokeWidth=\"2\"\n                viewBox=\"0 0 24 24\"\n                width=\"24\"\n                xmlns=\"http://www.w3.org/2000/svg\"\n              >\n                <path d=\"M5 12h14\" />\n                <path d=\"m12 5 7 7-7 7\" />\n              </svg>\n              <span className=\"sr-only\">Next slide</span>\n            </motion.button>\n          </div>\n\n          {/* Carousel Content */}\n          <div className=\"mt-16 [&>div[data-slot=carousel-content]]:overflow-visible\">\n            <div className=\"overflow-hidden\" data-slot=\"carousel-content\">\n              <motion.div\n                animate={{ x: `-${currentIndex * (CARD_WIDTH + CARD_GAP)}px` }}\n                className=\"-ml-4 flex max-w-[min(calc(100vw-4rem),24rem)] select-none\"\n                transition={\n                  shouldReduceMotion\n                    ? { duration: 0 }\n                    : { damping: 30, stiffness: 300, type: \"spring\" as const }\n                }\n              >\n                {members.map((member, index) => (\n                  <div\n                    className=\"min-w-0 max-w-72 shrink-0 grow-0 basis-full pl-4\"\n                    data-slot=\"carousel-item\"\n                    key={member.name}\n                  >\n                    <motion.div\n                      className=\"rounded-2xl border border-border bg-background p-7 text-center\"\n                      initial={\n                        shouldReduceMotion\n                          ? { opacity: 1 }\n                          : { opacity: 0, y: 20 }\n                      }\n                      transition={\n                        shouldReduceMotion\n                          ? { duration: 0 }\n                          : { delay: index * STAGGER_DELAY, duration: 0.5 }\n                      }\n                      viewport={{ once: true }}\n                      whileInView={\n                        shouldReduceMotion\n                          ? { opacity: 1 }\n                          : { opacity: 1, y: 0 }\n                      }\n                    >\n                      <img\n                        alt={member.name}\n                        className=\"mx-auto size-20 rounded-full border border-border\"\n                        draggable={false}\n                        height={80}\n                        src={getAvatarUrl(member.avatar, AVATAR_SIZE)}\n                        width={80}\n                      />\n                      <div className=\"mt-6 flex flex-col justify-center\">\n                        <p className=\"font-medium text-foreground text-lg\">\n                          {member.name}\n                        </p>\n                        <p className=\"text-muted-foreground text-sm\">\n                          {member.role}\n                        </p>\n                      </div>\n                      <div\n                        className=\"my-6 shrink-0 bg-border bg-linear-to-r from-background via-border to-background data-[orientation=horizontal]:h-px data-[orientation=vertical]:h-full data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-px\"\n                        data-orientation=\"horizontal\"\n                        data-slot=\"separator-root\"\n                        role=\"none\"\n                      />\n                      <p className=\"text-muted-foreground text-sm\">\n                        {member.experience}\n                      </p>\n                    </motion.div>\n                  </div>\n                ))}\n              </motion.div>\n            </div>\n          </div>\n        </div>\n      </div>\n    </section>\n  );\n}\n\nexport default TeamCarousel;\n","path":"index.tsx","target":"components/smoothui/team-2/index.tsx","type":"registry:block"}],"name":"team-2","registryDependencies":["https://smoothui.dev/r/data.json"],"title":"Team 2","type":"registry:block"}