{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "card-carousel-hero", "type": "registry:ui", "title": "Card Carousel Hero", "description": "An interactive hero section featuring a card carousel with smooth animations", "dependencies": [ "motion", "gsap" ], "registryDependencies": [ "button", "card" ], "files": [ { "path": "registry/ruixenui/card-carousel-hero.tsx", "content": "\"use client\";\n\nimport React, { useRef, useEffect, useState } from \"react\";\nimport { Card, CardContent } from \"@/components/ui/card\";\nimport Image from \"next/image\";\nimport gsap from \"gsap\";\nimport { Button } from \"@/components/ui/button\";\n\nexport interface CardItem {\n src?: string;\n alt?: string;\n}\n\nexport interface CardCarouselHeroProps {\n category?: string;\n title?: string;\n subtitle?: string;\n cards?: CardItem[];\n}\n\nexport default function CardCarouselHero({\n category = \"Innovation Meets Simplicity\",\n title = \"Build Exceptional Interfaces\",\n subtitle = \"Use our component library powered by Shadcn UI & Tailwind CSS to craft beautiful, fast, and accessible UIs.\",\n cards = [],\n}: CardCarouselHeroProps) {\n const totalCards = cards.length || 5;\n const placeholders = Array.from({ length: totalCards }).map(() => ({\n src: undefined,\n alt: \"\",\n }));\n const data = cards.length > 0 ? cards : placeholders;\n\n const cardRefs = useRef([]);\n const [activeIndex, setActiveIndex] = useState(0);\n\n const animateCards = () => {\n const middleIndex = Math.floor(data.length / 2);\n\n gsap.set(cardRefs.current, {\n x: 0,\n scale: 0.5,\n opacity: 0,\n transformOrigin: \"center bottom\",\n });\n\n const tl = gsap.timeline({\n defaults: { duration: 0.6, ease: \"power3.out\" },\n });\n\n tl.to(cardRefs.current[middleIndex], { x: 0, scale: 1, opacity: 1 });\n\n for (let offset = 1; offset <= middleIndex; offset++) {\n const leftIndex = middleIndex - offset;\n const rightIndex = middleIndex + offset;\n\n const animations: gsap.TweenTarget[] = [];\n if (leftIndex >= 0) animations.push(cardRefs.current[leftIndex]);\n if (rightIndex < data.length)\n animations.push(cardRefs.current[rightIndex]);\n\n tl.to(\n animations,\n {\n x: (i, target) => {\n const idx = cardRefs.current.indexOf(target as HTMLDivElement);\n return (idx - middleIndex) * 120;\n },\n scale: (i, target) => {\n const idx = cardRefs.current.indexOf(target as HTMLDivElement);\n return 1 - Math.abs(idx - middleIndex) * 0.1;\n },\n opacity: 1,\n },\n \"+=0.1\",\n );\n }\n };\n\n useEffect(() => {\n animateCards();\n }, [activeIndex]);\n\n return (\n
\n
\n {/* Category */}\n \n\n {/* Title */}\n

\n {title}\n

\n\n {/* Subtitle */}\n

\n {subtitle}\n

\n\n {/* Card Carousel */}\n
\n {data.map((card, idx) => {\n const middleIndex = Math.floor(data.length / 2);\n const distance = Math.abs(idx - middleIndex);\n\n return (\n {\n if (el) cardRefs.current[idx] = el;\n }}\n className=\"absolute\"\n style={{ zIndex: data.length - distance }}\n >\n \n \n {card.src && (\n \n )}\n \n \n
\n );\n })}\n
\n \n
\n );\n}\n", "type": "registry:ui", "target": "components/ruixen/card-carousel-hero.tsx" } ] }