{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "testimonial-04",
  "title": "Testimonial 04",
  "description": "A testimonial gallery with a dominant featured landscape card and three narrow portrait brand cards",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "card"
  ],
  "files": [
    {
      "path": "src/registry/blocks/testimonial-04/testimonial.tsx",
      "content": "\"use client\";\n\nimport { useState } from \"react\";\nimport { ArrowRight } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport { Card } from \"@/components/ui/card\";\n\ninterface Testimonial04Card {\n  image?: string;\n  brand: string;\n  title?: string;\n  url?: string;\n}\n\ninterface Testimonial04Props {\n  title?: string;\n  description?: string;\n  readMore?: { text: string; url?: string };\n  cards?: Testimonial04Card[];\n  className?: string;\n}\n\nconst defaultCards: Testimonial04Card[] = [\n  {\n    image:\n      \"https://www.shadcnship.com/images/placeholders/hero-architecture-7.webp\",\n    brand: \"shadcnship\",\n    title: \"How teams ship landing pages faster with reusable components\",\n    url: \"#\",\n  },\n  {\n    image:\n      \"https://www.shadcnship.com/images/placeholders/hero-architecture-5.webp\",\n    brand: \"Acme Corp\",\n    title: \"How Acme scaled their design system with copy & paste blocks\",\n    url: \"#\",\n  },\n  {\n    image:\n      \"https://www.shadcnship.com/images/placeholders/hero-architecture-6.webp\",\n    brand: \"Globex\",\n    title: \"How Globex rebuilt their marketing site in a week\",\n    url: \"#\",\n  },\n  {\n    image:\n      \"https://www.shadcnship.com/images/placeholders/hero-architecture-8.webp\",\n    brand: \"Initech\",\n    title: \"How Initech kept brand consistency across every launch\",\n    url: \"#\",\n  },\n];\n\nconst Testimonial04 = ({\n  title = \"Loved by Developers\",\n  description = \"See what developers are saying about building faster with our components\",\n  readMore = { text: \"Read more\", url: \"#\" },\n  cards = defaultCards,\n  className,\n}: Testimonial04Props) => {\n  const [active, setActive] = useState(0);\n\n  return (\n    <section className={cn(\"container mx-auto px-8 py-12 md:py-24\", className)}>\n      {/* Header */}\n      <div className=\"mb-12 flex flex-col items-center gap-4 text-center\">\n        <h2 className=\"max-w-2xl text-4xl leading-tight font-medium tracking-tight md:text-5xl\">\n          {title}\n        </h2>\n        <p className=\"max-w-xl text-muted-foreground md:text-lg\">\n          {description}\n        </p>\n      </div>\n\n      {/* Cards row — the hovered card expands, the others shrink.\n          The last hovered card keeps the expanded width. */}\n      <div className=\"mx-auto flex max-w-5xl flex-col gap-4 md:h-80 md:flex-row\">\n        {cards.map((card, index) => {\n          const isActive = index === active;\n\n          return (\n            <Card\n              key={index}\n              onMouseEnter={() => setActive(index)}\n              className=\"group relative h-48 min-w-0 basis-0 overflow-hidden p-0 transition-all duration-500 ease-in-out md:h-full\"\n              style={{ flexGrow: isActive ? 3 : 1 }}\n            >\n              <a href={card.url} className=\"absolute inset-0\">\n                {card.image && (\n                  <img\n                    src={card.image}\n                    alt={card.title ?? card.brand}\n                    className=\"size-full object-cover\"\n                  />\n                )}\n                <div className=\"absolute inset-0 bg-linear-to-t from-black/60 via-transparent to-black/20\" />\n\n                {/* Expanded content, visible on the active card only */}\n                {readMore && (\n                  <span\n                    className={cn(\n                      \"absolute top-4 right-4 inline-flex items-center gap-1.5 text-sm font-medium whitespace-nowrap text-white transition-opacity duration-300\",\n                      isActive ? \"opacity-100\" : \"opacity-0\",\n                    )}\n                  >\n                    {readMore.text}\n                    <ArrowRight className=\"size-4\" />\n                  </span>\n                )}\n                {card.title && (\n                  <h3\n                    className={cn(\n                      \"absolute bottom-12 left-4 max-w-sm text-lg leading-snug font-medium text-white transition-opacity duration-300\",\n                      isActive ? \"opacity-100 delay-200\" : \"opacity-0\",\n                    )}\n                  >\n                    {card.title}\n                  </h3>\n                )}\n\n                {/* Brand: bottom-left when active, bottom-center otherwise */}\n                <span\n                  className={cn(\n                    \"absolute bottom-4 text-sm font-semibold tracking-wide whitespace-nowrap text-white/90 transition-all duration-500\",\n                    isActive ? \"left-4\" : \"left-1/2 -translate-x-1/2\",\n                  )}\n                >\n                  {card.brand}\n                </span>\n              </a>\n            </Card>\n          );\n        })}\n      </div>\n    </section>\n  );\n};\n\nexport default Testimonial04;\nexport type { Testimonial04Props, Testimonial04Card };\n",
      "type": "registry:component",
      "target": "components/testimonial-04.tsx"
    }
  ],
  "meta": {
    "image": "/r/previews/testimonial-04.webp",
    "imageDark": "/r/previews/testimonial-04-dark.webp"
  },
  "categories": [
    "social-proof"
  ],
  "type": "registry:block"
}