Logos

Logos 01 — Marquee

Infinite logo marquee of styled text wordmarks with edge fade and a trust line — swap in image logos via props.

$ npx shadcn@latest add @ludusvibe/logos-01
Open in v0

Code

Installed to components/sections/logos-01.tsx — it's yours to edit.

"use client"

import * as React from "react"

import { Marquee } from "@/components/ludus/marquee"
import { Reveal } from "@/components/ludus/reveal"
import { cn } from "@/lib/utils"

export type Logo = {
  name: string
  /** Optional image logo — rendered instead of the text wordmark. */
  src?: string
}

export type Logos01Props = {
  label?: string
  logos?: Logo[]
  /** Seconds for one full marquee loop. */
  marqueeDuration?: number
  className?: string
}

const defaultLogos: Logo[] = [
  { name: "Meridian" },
  { name: "Arclight" },
  { name: "Fathom" },
  { name: "Nimbus" },
  { name: "Polaris" },
  { name: "Hexwork" },
  { name: "Solstice" },
  { name: "Vantage" },
]

/** Distinct type treatments so text wordmarks read as different brands. */
const wordmarkStyles = [
  "font-heading text-lg font-bold tracking-tighter",
  "text-sm font-light tracking-[0.3em] uppercase",
  "font-heading text-lg font-semibold italic tracking-tight",
  "text-sm font-semibold tracking-[0.2em] uppercase",
  "font-heading text-lg font-medium tracking-wide",
  "text-base font-extrabold tracking-tight uppercase",
]

export function Logos01({
  label = "Trusted by teams at the world's fastest-moving companies",
  logos = defaultLogos,
  marqueeDuration = 35,
  className,
}: Logos01Props) {
  return (
    <section className={cn("bg-background px-6 py-16 md:py-20", className)}>
      <div className="mx-auto max-w-5xl">
        <Reveal>
          <p className="text-center text-sm text-muted-foreground">{label}</p>
        </Reveal>
        <Reveal delay={0.1} className="mt-8">
          <Marquee duration={marqueeDuration}>
            {logos.map((logo, index) =>
              logo.src ? (
                <img
                  key={logo.name}
                  src={logo.src}
                  alt={logo.name}
                  className="h-7 w-auto opacity-60 transition-opacity hover:opacity-100"
                />
              ) : (
                <span
                  key={logo.name}
                  className={cn(
                    "whitespace-nowrap text-muted-foreground/70 transition-colors hover:text-foreground",
                    wordmarkStyles[index % wordmarkStyles.length]
                  )}
                >
                  {logo.name}
                </span>
              )
            )}
          </Marquee>
        </Reveal>
      </div>
    </section>
  )
}