{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "logo-carousel", "title": "Logo Carousel", "description": "A beautiful, high-performance scrolling logo carousel component with pausing, custom directions, speed, and fade effects.", "dependencies": [], "registryDependencies": [], "files": [ { "path": "registry/spark-ui/logo-carousel.tsx", "content": "\"use client\";\n\nimport React from \"react\";\nimport { cn } from \"@/lib/utils\";\n\ninterface LogoCarouselProps extends React.HTMLAttributes {\n duration?: number;\n pauseOnHover?: boolean;\n direction?: \"left\" | \"right\" | \"up\" | \"down\";\n reverse?: boolean;\n fade?: boolean;\n fadeAmount?: number;\n repeat?: number;\n gap?: string;\n}\n\nexport function LogoCarousel({\n children,\n className,\n duration = 20,\n pauseOnHover = false,\n direction = \"left\",\n reverse = false,\n fade = true,\n fadeAmount = 10,\n repeat = 2,\n gap = \"1.5rem\",\n ...props\n}: LogoCarouselProps) {\n const isVertical = direction === \"up\" || direction === \"down\";\n const [isHovered, setIsHovered] = React.useState(false);\n\n // Determine resolved direction combining direction and reverse\n let resolvedDirection = direction;\n if (reverse) {\n if (direction === \"left\") resolvedDirection = \"right\";\n else if (direction === \"right\") resolvedDirection = \"left\";\n else if (direction === \"up\") resolvedDirection = \"down\";\n else if (direction === \"down\") resolvedDirection = \"up\";\n }\n\n // Determine standard CSS animation name defined in globals.css\n const animationName =\n resolvedDirection === \"left\" ? \"logo-carousel\" :\n resolvedDirection === \"right\" ? \"logo-carousel-reverse\" :\n resolvedDirection === \"up\" ? \"logo-carousel-y\" :\n \"logo-carousel-y-reverse\";\n\n return (\n {\n if (pauseOnHover) setIsHovered(true);\n }}\n onMouseLeave={() => {\n if (pauseOnHover) setIsHovered(false);\n }}\n style={{\n \"--duration\": `${duration}s`,\n \"--gap\": gap,\n ...(fade && {\n maskImage: isVertical\n ? `linear-gradient(to bottom, transparent 0%, black ${fadeAmount}%, black ${100 - fadeAmount}%, transparent 100%)`\n : `linear-gradient(to right, transparent 0%, black ${fadeAmount}%, black ${100 - fadeAmount}%, transparent 100%)`,\n WebkitMaskImage: isVertical\n ? `linear-gradient(to bottom, transparent 0%, black ${fadeAmount}%, black ${100 - fadeAmount}%, transparent 100%)`\n : `linear-gradient(to right, transparent 0%, black ${fadeAmount}%, black ${100 - fadeAmount}%, transparent 100%)`,\n }),\n } as React.CSSProperties}\n {...props}\n >\n \n {Array.from({ length: repeat }).map((_, i) => (\n \n {React.Children.map(children, (child, idx) => (\n
\n {child}\n
\n ))}\n
\n ))}\n \n \n );\n}\n", "type": "registry:component" }, { "path": "public/logos/cursor.svg", "content": "", "type": "registry:file", "target": "public/logos/cursor.svg" }, { "path": "public/logos/descript.svg", "content": "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n", "type": "registry:file", "target": "public/logos/descript.svg" }, { "path": "public/logos/discord.svg", "content": "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n", "type": "registry:file", "target": "public/logos/discord.svg" }, { "path": "public/logos/duolingo.svg", "content": "\n \n \n Duolingo_wordmark_white\n \n \n \n", "type": "registry:file", "target": "public/logos/duolingo.svg" }, { "path": "public/logos/framer.svg", "content": "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n", "type": "registry:file", "target": "public/logos/framer.svg" }, { "path": "public/logos/google.svg", "content": "", "type": "registry:file", "target": "public/logos/google.svg" }, { "path": "public/logos/linear.svg", "content": "\n \n\n", "type": "registry:file", "target": "public/logos/linear.svg" }, { "path": "public/logos/netflix.svg", "content": "\n \n \n \n \n \n \n \n \n \n \n \n \n \n", "type": "registry:file", "target": "public/logos/netflix.svg" }, { "path": "public/logos/notion.svg", "content": "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n", "type": "registry:file", "target": "public/logos/notion.svg" }, { "path": "public/logos/openai.svg", "content": "", "type": "registry:file", "target": "public/logos/openai.svg" }, { "path": "public/logos/opensea.svg", "content": "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n", "type": "registry:file", "target": "public/logos/opensea.svg" }, { "path": "public/logos/phantom.svg", "content": "Logo Phantom", "type": "registry:file", "target": "public/logos/phantom.svg" }, { "path": "public/logos/ramp.svg", "content": "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n", "type": "registry:file", "target": "public/logos/ramp.svg" }, { "path": "public/logos/shopify.svg", "content": "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n", "type": "registry:file", "target": "public/logos/shopify.svg" }, { "path": "public/logos/tesla.svg", "content": "\n \n \n", "type": "registry:file", "target": "public/logos/tesla.svg" }, { "path": "public/logos/vercel.svg", "content": "\n\n\n", "type": "registry:file", "target": "public/logos/vercel.svg" } ], "type": "registry:component" }