Logos Carousel
ncdai/logos-carouselUnverifiedComponent
Cycle through logos column by column in a staggered wave.
Install it
npx shadcn@latest add https://raw.githubusercontent.com/exekartik/exeKartik/main/logos-carousel.jsonSource
1"use client"23import { Children, memo, useEffect, useMemo, useRef, useState } from "react"4import type { ReactNode } from "react"5import {6 AnimatePresence,7 motion,8 useInView,9 usePageInView,10 useReducedMotion,11} from "motion/react"12import type { Transition } from "motion/react"1314import { cn } from "@/lib/utils"1516const DEFAULT_COLUMN_COUNT = 41718/** How long each logo stays visible before cycling to the next one (ms). */19const CYCLE_INTERVAL = 24002021/**22 * Delay between adjacent columns within a single wave (ms). Kept smaller than23 * the enter/exit duration so neighbouring transitions overlap into a ripple.24 */25const STAGGER_DELAY = 1252627/** Duration of a single enter or exit transition (s). */28const TRANSITION_DURATION = 0.52930const EASE_OUT_QUAD = [0.25, 0.46, 0.45, 0.94] as const3132/** Direction the wave sweeps across the columns. */33type WaveDirection = "ltr" | "rtl"3435export type LogosCarouselProps = {36 /** Logo elements to cycle through. Each child is rendered as a single logo. */37 children: ReactNode38 /**39 * Number of columns to spread the logos across. Capped at the number of logos.40 * @defaultValue 441 */42 columnCount?: number43 /**44 * Direction the ripple travels: left-to-right or right-to-left.45 * @defaultValue "ltr"46 */47 direction?: WaveDirection48 className?: string49}5051export function LogosCarousel({52 children,53 columnCount = DEFAULT_COLUMN_COUNT,54 direction = "ltr",55 className,56}: LogosCarouselProps) {57 const columns = useMemo(58 () => distributeLogos(Children.toArray(children), columnCount),59 [children, columnCount]60 )6162 const reduceMotion = useReducedMotion() ?? false6364 const containerRef = useRef<HTMLDivElement>(null)65 const isPageInView = usePageInView()66 const isInView = useInView(containerRef, { margin: "100px" })6768 const [step, setStep] = useState(0)69 const shouldPlay = isPageInView && isInView7071 useEffect(() => {72 if (!shouldPlay) return7374 const beatId = setInterval(75 () => setStep((prev) => prev + 1),76 CYCLE_INTERVAL77 )7879 return () => clearInterval(beatId)80 }, [shouldPlay])8182 return (83 <div84 ref={containerRef}85 data-slot="logos-carousel"86 className={cn("grid", className)}87 style={{88 gridTemplateColumns: `repeat(var(--column-count,${columns.length}), minmax(0, 1fr))`,89 }}90 >91 {columns.map((columnLogos, columnIndex) => {92 const waveIndex =93 direction === "rtl" ? columns.length - 1 - columnIndex : columnIndex9495// … truncated
What it pulls in
npm packages
Files it writes
More from ncdai
All 17 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Apple Hello Effectapple-hello-effect | ncdai | Components | Unverified | 1 dep | |
| Apple Hello Effect - Hindiapple-hello-effect-hindi | ncdai | Components | Unverified | 1 dep | |
| Apple Hello Effect - Spanishapple-hello-effect-spanish | ncdai | Components | Unverified | 1 dep | |
| Apple Hello Effect - Vietnameseapple-hello-effect-vietnamese | ncdai | Components | Unverified | 1 dep | |
| Brand Assets Menubrand-assets-menu | ncdai | Components | Unverified | 1 dep | |
| chevrons-up-down-iconchevrons-up-down-icon | ncdai | Components | Unverified | 1 dep | |
| Code Block Commandcode-block-command | ncdai | Components | Unverified | 4 deps · 3 files | |
| Consent Managerconsent-manager | ncdai | Components | Unverified | 1 dep · 2 files |
