{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "testimonials-grid",
  "title": "Testimonial grid",
  "description": "Masonry wall of social posts and quote cards, led by a wide case-study quote with a headline metric.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils",
    "avatar",
    "button",
    "https://velora.colorlib.com/r/blur-fade.json",
    "https://velora.colorlib.com/r/text-highlighter.json",
    "https://velora.colorlib.com/r/tweet-card.json"
  ],
  "files": [
    {
      "path": "src/components/blocks/testimonials-grid.tsx",
      "content": "import { ArrowRightIcon } from \"lucide-react\";\n\nimport { Avatar, AvatarFallback, AvatarImage } from \"@/components/ui/avatar\";\nimport { Button } from \"@/components/ui/button\";\nimport { BlurFade } from \"@/components/velora/blur-fade\";\nimport { TextHighlighter } from \"@/components/velora/text-highlighter\";\nimport { TweetCard } from \"@/components/velora/tweet-card\";\n\nconst photo = (id: string) =>\n  `https://images.unsplash.com/photo-${id}?w=160&h=160&q=70&auto=format&fit=crop`;\n\nconst FEATURED = {\n  before:\n    \"We moved 40 teams onto Acme in a fortnight. Six months later, specs reach production\",\n  highlight: \"three times faster\",\n  after: \"and nobody has to chase a status update again.\",\n  name: \"Grace Whitfield\",\n  role: \"Engineering Director, Pinewood\",\n  avatar: photo(\"1580489944761-15a19d654956\"),\n  metric: \"3.2×\",\n  metricLabel: \"faster from spec to release\",\n  secondary: \"40 teams migrated in 14 days\",\n};\n\ntype Post =\n  | {\n      kind: \"tweet\";\n      name: string;\n      handle: string;\n      time: string;\n      verified?: boolean;\n      avatar?: string;\n      text: string;\n    }\n  | {\n      kind: \"quote\";\n      name: string;\n      role: string;\n      avatar?: string;\n      text: string;\n    };\n\nconst POSTS: Post[] = [\n  {\n    kind: \"tweet\",\n    name: \"Tomás Herrera\",\n    handle: \"tomasbuilds\",\n    time: \"Mar 14\",\n    verified: true,\n    avatar: photo(\"1500648767791-00dcc994a43e\"),\n    text: \"Switched our whole org to @acmehq this quarter. The GitHub sync is the first one I've never had to babysit.\",\n  },\n  {\n    kind: \"quote\",\n    name: \"Hannah Weiss\",\n    role: \"Design Lead, Kestrel\",\n    avatar: photo(\"1438761681033-6461ffad8d80\"),\n    text: \"It's calm software. Nothing pings unless it matters, specs sit right next to the tickets they describe, and design reviews finally happen in one place instead of four.\",\n  },\n  {\n    kind: \"tweet\",\n    name: \"Aiko Tanaka\",\n    handle: \"aiko_ops\",\n    time: \"Feb 2\",\n    text: \"Quarterly planning for 12 teams, done before lunch. @acmehq I owe you a coffee.\",\n  },\n  {\n    kind: \"quote\",\n    name: \"Samuel Achebe\",\n    role: \"COO, Meridian\",\n    text: \"Acme scaled from our first ten people to four hundred without turning into a spreadsheet.\",\n  },\n  {\n    kind: \"tweet\",\n    name: \"Lena Fischer\",\n    handle: \"lenadesigns\",\n    time: \"Jan 28\",\n    verified: true,\n    avatar: photo(\"1534528741775-53994a69daeb\"),\n    text: \"Hot take: the best feature of @acmehq is what it leaves out. No clutter, no noise, just the work. Keyboard shortcuts for everything too.\",\n  },\n  {\n    kind: \"quote\",\n    name: \"Daniel Okafor\",\n    role: \"Engineering Manager, Lumen Labs\",\n    avatar: photo(\"1507003211169-0a1dd7228f2d\"),\n    text: \"The release notes write themselves from merged work. Our support queue dropped by a third the month we switched.\",\n  },\n  {\n    kind: \"tweet\",\n    name: \"Rafael Costa\",\n    handle: \"rafacodes\",\n    time: \"Dec 9\",\n    text: \"Imported five years of issues into @acmehq in one afternoon. Labels, links, history — all of it came across.\",\n  },\n  {\n    kind: \"tweet\",\n    name: \"Priya Raman\",\n    handle: \"priyaships\",\n    time: \"Nov 21\",\n    verified: true,\n    avatar: photo(\"1544005313-94ddf0286df2\"),\n    text: \"Our public roadmap on @acmehq gets more traffic than our pricing page. Customers love seeing what's next.\",\n  },\n  {\n    kind: \"quote\",\n    name: \"Marcus Bell\",\n    role: \"CTO, Tidewater\",\n    avatar: photo(\"1506794778202-cad84cf45f1d\"),\n    text: \"Fast, quiet and opinionated in the right places. My team stopped complaining about process tooling.\",\n  },\n];\n\nconst initials = (name: string) =>\n  name\n    .split(\" \")\n    .map((part) => part[0])\n    .slice(0, 2)\n    .join(\"\");\n\n/** Colours @mentions so they read like a real post. */\nfunction withMentions(text: string) {\n  return text.split(/(@\\w+)/g).map((part, i) =>\n    part.startsWith(\"@\") ? (\n      <span key={i} className=\"text-brand\">\n        {part}\n      </span>\n    ) : (\n      part\n    )\n  );\n}\n\nfunction Person({\n  name,\n  detail,\n  avatar,\n  size = \"default\",\n}: {\n  name: string;\n  detail: string;\n  avatar?: string;\n  size?: \"default\" | \"lg\";\n}) {\n  return (\n    <figcaption className=\"flex items-center gap-3\">\n      <Avatar size=\"lg\" className={size === \"lg\" ? \"size-12\" : undefined}>\n        {avatar && <AvatarImage src={avatar} alt=\"\" />}\n        <AvatarFallback className=\"bg-gradient-to-br from-brand-from to-brand-to text-xs font-semibold text-brand-foreground\">\n          {initials(name)}\n        </AvatarFallback>\n      </Avatar>\n      <div className=\"min-w-0 text-sm\">\n        <div className=\"font-medium\">{name}</div>\n        <div className=\"text-muted-foreground\">{detail}</div>\n      </div>\n    </figcaption>\n  );\n}\n\n/**\n * Review wall: a wide case-study quote with its headline metric, then a\n * masonry of social posts and quote cards laid out with CSS columns — no\n * JavaScript measuring, and cards never split across columns.\n */\nexport function TestimonialsGrid() {\n  return (\n    <section className=\"px-6 py-24 sm:py-32 lg:px-8\">\n      <div className=\"mx-auto max-w-7xl\">\n        <BlurFade className=\"flex flex-col gap-6 lg:flex-row lg:items-end lg:justify-between\">\n          <div className=\"max-w-2xl\">\n            <p className=\"text-sm font-semibold text-brand\">Wall of love</p>\n            <h2 className=\"mt-3 text-3xl font-semibold tracking-tight text-balance sm:text-5xl\">\n              Don&apos;t take our word for it\n            </h2>\n            <p className=\"mt-5 text-lg text-pretty text-muted-foreground\">\n              Engineers, designers and operators on what changed after they\n              moved their team to Acme.\n            </p>\n          </div>\n          <Button variant=\"outline\" asChild className=\"self-start lg:self-auto\">\n            <a href=\"#\">\n              Read all reviews <ArrowRightIcon />\n            </a>\n          </Button>\n        </BlurFade>\n\n        <div className=\"relative mt-14 grid overflow-hidden rounded-3xl border bg-card lg:grid-cols-[1fr_20rem]\">\n          <div\n            aria-hidden\n            className=\"pointer-events-none absolute -top-24 -left-24 size-72 rounded-full bg-brand/15 blur-3xl\"\n          />\n          <figure className=\"relative flex flex-col justify-between gap-10 p-6 sm:p-10\">\n            <blockquote className=\"text-xl font-medium tracking-tight text-pretty sm:text-2xl lg:text-3xl\">\n              <p>\n                &ldquo;{FEATURED.before}{\" \"}\n                <TextHighlighter>{FEATURED.highlight}</TextHighlighter>{\" \"}\n                {FEATURED.after}&rdquo;\n              </p>\n            </blockquote>\n            <Person\n              name={FEATURED.name}\n              detail={FEATURED.role}\n              avatar={FEATURED.avatar}\n              size=\"lg\"\n            />\n          </figure>\n          <div className=\"relative flex flex-col justify-center gap-2 border-t bg-muted/40 p-6 sm:p-10 lg:border-t-0 lg:border-l\">\n            <p className=\"bg-gradient-to-br from-brand-from via-brand-via to-brand-to bg-clip-text text-6xl font-semibold tracking-tight text-transparent sm:text-7xl\">\n              {FEATURED.metric}\n            </p>\n            <p className=\"text-base font-medium\">{FEATURED.metricLabel}</p>\n            <p className=\"text-sm text-muted-foreground\">{FEATURED.secondary}</p>\n          </div>\n        </div>\n\n        <div className=\"mt-4 columns-1 gap-4 sm:columns-2 lg:columns-3\">\n          {POSTS.map((post) =>\n            post.kind === \"tweet\" ? (\n              <TweetCard\n                key={post.handle}\n                name={post.name}\n                handle={post.handle}\n                time={post.time}\n                verified={post.verified}\n                avatar={post.avatar}\n                content={withMentions(post.text)}\n                className=\"mb-4 max-w-none break-inside-avoid p-5\"\n              />\n            ) : (\n              <figure\n                key={post.name}\n                className=\"mb-4 flex break-inside-avoid flex-col gap-5 rounded-2xl border bg-card p-6 text-card-foreground\"\n              >\n                <blockquote className=\"text-sm leading-relaxed text-pretty sm:text-base\">\n                  <p>&ldquo;{post.text}&rdquo;</p>\n                </blockquote>\n                <Person name={post.name} detail={post.role} avatar={post.avatar} />\n              </figure>\n            )\n          )}\n        </div>\n      </div>\n    </section>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/blocks/testimonials-grid.tsx"
    }
  ],
  "categories": [
    "testimonial-sections"
  ],
  "type": "registry:block"
}