{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "feature-carousel", "title": "Feature Carousel", "description": "A smooth carousel for showcasing product features.", "dependencies": [ "motion", "@hugeicons/core-free-icons", "@hugeicons/react", "clsx", "tailwind-merge" ], "files": [ { "path": "registry/default/example/feature-carousel.tsx", "content": "\"use client\";\r\n\r\nimport React, { useState, useEffect, useCallback } from \"react\";\r\nimport { motion, AnimatePresence } from \"motion/react\";\r\nimport {\r\n Pizza04Icon,\r\n CommandFreeIcons,\r\n GlobalSearchIcon,\r\n AiCloudIcon,\r\n SmartPhone01Icon,\r\n CheckmarkCircle01Icon,\r\n DashboardSquare01Icon,\r\n MagicWandIcon,\r\n} from \"@hugeicons/core-free-icons\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { HugeiconsIcon } from \"@hugeicons/react\";\r\n\r\n// Change Here\r\nconst FEATURES = [\r\n {\r\n id: \"sustainable\",\r\n label: \"Sustainable Sourcing\",\r\n icon: Pizza04Icon,\r\n image:\r\n \"https://images.unsplash.com/photo-1542601906990-b4d3fb778b09?q=80&w=1200\",\r\n description: \"Ethically sourced ingredients from local farmers.\",\r\n },\r\n {\r\n id: \"community\",\r\n label: \"Community Focused\",\r\n icon: CommandFreeIcons,\r\n image:\r\n \"https://images.unsplash.com/photo-1517048676732-d65bc937f952?q=80&w=1200\",\r\n description: \"Building stronger bonds through shared experiences.\",\r\n },\r\n {\r\n id: \"global\",\r\n label: \"Global Reach\",\r\n icon: GlobalSearchIcon,\r\n image:\r\n \"https://images.unsplash.com/photo-1521737711867-e3b97375f902?q=80&w=1200\",\r\n description: \"Connecting visionaries across all continents.\",\r\n },\r\n {\r\n id: \"award\",\r\n label: \"Award Winning\",\r\n icon: CheckmarkCircle01Icon,\r\n image:\r\n \"https://images.unsplash.com/photo-1578574577315-3fbeb0cecdc2?q=80&w=1200\",\r\n description: \"Recognized excellence in design and innovation.\",\r\n },\r\n {\r\n id: \"cloud\",\r\n label: \"Cloud Ready\",\r\n icon: AiCloudIcon,\r\n image:\r\n \"https://images.unsplash.com/photo-1451187580459-43490279c0fa?q=80&w=1200\",\r\n description: \"Scale your infrastructure with seamless ease.\",\r\n },\r\n {\r\n id: \"mobile\",\r\n label: \"Mobile First\",\r\n icon: SmartPhone01Icon,\r\n image:\r\n \"https://images.unsplash.com/photo-1512941937669-90a1b58e7e9c?q=80&w=1200\",\r\n description: \"A world-class experience on every single device.\",\r\n },\r\n {\r\n id: \"analytics\",\r\n label: \"Real-time Analytics\",\r\n icon: DashboardSquare01Icon,\r\n image:\r\n \"https://images.unsplash.com/photo-1551288049-bbda38a10ad5?q=80&w=1200\",\r\n description: \"Insights at your fingertips, updated in real-time.\",\r\n },\r\n {\r\n id: \"security\",\r\n label: \"Enterprise Security\",\r\n icon: CheckmarkCircle01Icon,\r\n image:\r\n \"https://images.unsplash.com/photo-1550751827-4bd374c3f58b?q=80&w=1200\",\r\n description: \"Bank-grade security protocols for your data.\",\r\n },\r\n {\r\n id: \"magic\",\r\n label: \"Magic Automations\",\r\n icon: MagicWandIcon,\r\n image:\r\n \"https://images.unsplash.com/photo-1485827404703-89b55fcc595e?q=80&w=1200\",\r\n description: \"Let AI handle the repetitive tasks for you.\",\r\n },\r\n {\r\n id: \"local\",\r\n label: \"Locally Owned\",\r\n icon: CheckmarkCircle01Icon,\r\n image:\r\n \"https://images.unsplash.com/photo-1556761175-b413da4baf72?q=80&w=1200\",\r\n description: \"Supporting local businesses and creators.\",\r\n },\r\n];\r\n\r\nconst AUTO_PLAY_INTERVAL = 3000;\r\nconst ITEM_HEIGHT = 65;\r\n\r\nconst wrap = (min: number, max: number, v: number) => {\r\n const rangeSize = max - min;\r\n return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min;\r\n};\r\n\r\nexport default function FeatureCarousel() {\r\n const [step, setStep] = useState(0);\r\n const [isPaused, setIsPaused] = useState(false);\r\n\r\n const currentIndex =\r\n ((step % FEATURES.length) + FEATURES.length) % FEATURES.length;\r\n\r\n const nextStep = useCallback(() => {\r\n setStep((prev) => prev + 1);\r\n }, []);\r\n\r\n const handleChipClick = (index: number) => {\r\n const diff = (index - currentIndex + FEATURES.length) % FEATURES.length;\r\n if (diff > 0) setStep((s) => s + diff);\r\n };\r\n\r\n useEffect(() => {\r\n if (isPaused) return;\r\n const interval = setInterval(nextStep, AUTO_PLAY_INTERVAL);\r\n return () => clearInterval(interval);\r\n }, [nextStep, isPaused]);\r\n\r\n const getCardStatus = (index: number) => {\r\n const diff = index - currentIndex;\r\n const len = FEATURES.length;\r\n\r\n let normalizedDiff = diff;\r\n if (diff > len / 2) normalizedDiff -= len;\r\n if (diff < -len / 2) normalizedDiff += len;\r\n\r\n if (normalizedDiff === 0) return \"active\";\r\n if (normalizedDiff === -1) return \"prev\";\r\n if (normalizedDiff === 1) return \"next\";\r\n return \"hidden\";\r\n };\r\n\r\n return (\r\n
\r\n {feature.description}\r\n
\r\n