{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "blog-3",
  "title": "Filterable Blog Index",
  "description": "Blog index with a featured post, category filter pills, and a three-column grid of post cards that filters on selection.",
  "dependencies": [
    "@base-ui/react"
  ],
  "registryDependencies": [
    "avatar",
    "badge",
    "button",
    "card"
  ],
  "files": [
    {
      "path": "registry/blocks/blog/3/blog-block.tsx",
      "content": "\"use client\"\n\nimport { useState } from \"react\"\nimport { Avatar, AvatarFallback, AvatarImage } from \"@/components/ui/avatar\"\nimport { Badge } from \"@/components/ui/badge\"\nimport { Button } from \"@/components/ui/button\"\nimport {\n  Card,\n  CardContent,\n  CardFooter,\n  CardHeader,\n  CardTitle,\n} from \"@/components/ui/card\"\nimport { cn } from \"@/lib/utils\"\nimport { IconPlaceholder } from \"@/components/icons/icon-placeholder\"\n\nconst featured = {\n  category: \"Engineering\",\n  title: \"How we cut API latency by 60% with edge caching\",\n  image:\n    \"https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=1200&q=80\",\n  excerpt:\n    \"Our monolith was fast enough, until it wasn't. We traced the bottleneck to cold database reads on every request and rearchitected the caching layer in three weeks.\",\n  author: { name: \"Lena Park\", initials: \"LP\", img: 47 },\n  date: \"Jun 9, 2026\",\n  readTime: \"7 Min Read\",\n}\n\nconst categories = [\n  \"All\",\n  \"Engineering\",\n  \"Design\",\n  \"Product\",\n  \"Company\",\n] as const\n\nconst posts = [\n  {\n    category: \"Design\",\n    title: \"Building a token system that survives a rebrand\",\n    image:\n      \"https://images.unsplash.com/photo-1561070791-2526d30994b5?w=800&q=80\",\n    excerpt:\n      \"Semantic tokens feel abstract until your brand color changes overnight.\",\n    author: { name: \"Marcus Webb\", initials: \"MW\", img: 12 },\n    date: \"May 28, 2026\",\n    readTime: \"5 Min Read\",\n  },\n  {\n    category: \"Product\",\n    title: \"What 1,200 user interviews taught us about onboarding\",\n    image:\n      \"https://images.unsplash.com/photo-1522071820081-009f0129c71c?w=800&q=80\",\n    excerpt:\n      \"Drop-off at step two had nothing to do with the UI, it was a mental model gap.\",\n    author: { name: \"Sofia Andrade\", initials: \"SA\", img: 45 },\n    date: \"May 14, 2026\",\n    readTime: \"9 Min Read\",\n  },\n  {\n    category: \"Engineering\",\n    title: \"Shipping a type-safe API layer without a build step\",\n    image:\n      \"https://images.unsplash.com/photo-1667372393119-3d4c48d07fc9?w=800&q=80\",\n    excerpt:\n      \"We replaced our codegen pipeline with inferred types and never looked back.\",\n    author: { name: \"Devon Ross\", initials: \"DR\", img: 13 },\n    date: \"May 2, 2026\",\n    readTime: \"6 Min Read\",\n  },\n  {\n    category: \"Company\",\n    title: \"Why Acme is going remote-first in 2026\",\n    image:\n      \"https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=800&q=80\",\n    excerpt:\n      \"Three years of hybrid taught us where collaboration actually happens.\",\n    author: { name: \"Priya Nair\", initials: \"PN\", img: 44 },\n    date: \"Apr 19, 2026\",\n    readTime: \"4 Min Read\",\n  },\n  {\n    category: \"Design\",\n    title: \"A practical guide to accessible color contrast\",\n    image:\n      \"https://images.unsplash.com/photo-1555949963-ff9fe0c870eb?w=800&q=80\",\n    excerpt:\n      \"Pass WCAG without sacrificing the palette your brand team fought for.\",\n    author: { name: \"Theo Lambert\", initials: \"TL\", img: 15 },\n    date: \"Apr 5, 2026\",\n    readTime: \"8 Min Read\",\n  },\n  {\n    category: \"Product\",\n    title: \"Pricing experiments that doubled our trial conversion\",\n    image:\n      \"https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?w=800&q=80\",\n    excerpt:\n      \"Small framing changes on the pricing page moved the needle more than discounts.\",\n    author: { name: \"Hana Kim\", initials: \"HK\", img: 41 },\n    date: \"Mar 22, 2026\",\n    readTime: \"5 Min Read\",\n  },\n]\n\nexport default function BlogBlock() {\n  const [active, setActive] = useState<(typeof categories)[number]>(\"All\")\n\n  const visible =\n    active === \"All\" ? posts : posts.filter((p) => p.category === active)\n\n  return (\n    <section className=\"flex min-h-svh w-full justify-center bg-background px-6 py-16 text-foreground\">\n      <div className=\"mx-auto w-full max-w-6xl\">\n        <div className=\"mb-10 flex flex-col gap-3\">\n          <Badge variant=\"secondary\" className=\"w-fit\">\n            <IconPlaceholder\n              lucide=\"Bookmark\"\n              tabler=\"IconBookmark\"\n              hugeicons=\"BookmarkIcon\"\n              phosphor=\"Bookmark\"\n              remixicon=\"RiBookmarkLine\"\n              data-icon=\"inline-start\"\n            />\n            The Acme Blog\n          </Badge>\n          <h1 className=\"font-heading text-3xl font-semibold tracking-tight sm:text-4xl\">\n            Stories from the team building Acme\n          </h1>\n          <p className=\"max-w-2xl text-muted-foreground\">\n            Engineering deep dives, design notes, and the product decisions\n            behind the work we ship.\n          </p>\n        </div>\n\n        <Card className=\"group mb-12 overflow-hidden p-0 md:grid md:grid-cols-2\">\n          <div className=\"relative aspect-video overflow-hidden bg-muted md:aspect-auto md:h-full\">\n            <img\n              src={featured.image}\n              alt={featured.title}\n              className=\"size-full object-cover grayscale transition-all duration-300 group-hover:grayscale-0\"\n            />\n            <span className=\"absolute top-4 right-4 flex items-center gap-1 rounded-4xl bg-background/85 px-2 py-0.5 text-xs font-medium text-foreground backdrop-blur-sm\">\n              <IconPlaceholder\n                lucide=\"Clock\"\n                tabler=\"IconClock\"\n                hugeicons=\"TimeIcon\"\n                phosphor=\"Clock\"\n                remixicon=\"RiTimeLine\"\n                className=\"size-3\"\n              />\n              {featured.readTime}\n            </span>\n          </div>\n          <div className=\"flex flex-col justify-center gap-4 p-6 sm:p-8\">\n            <Badge className=\"w-fit\">{featured.category}</Badge>\n            <h2 className=\"font-heading text-2xl font-semibold tracking-tight sm:text-3xl\">\n              {featured.title}\n            </h2>\n            <p className=\"text-muted-foreground\">{featured.excerpt}</p>\n            <div className=\"flex items-center gap-3\">\n              <Avatar className=\"size-9 border border-border\">\n                <AvatarImage\n                  src={`https://i.pravatar.cc/150?img=${featured.author.img}`}\n                  alt={featured.author.name}\n                  className=\"grayscale\"\n                />\n                <AvatarFallback>{featured.author.initials}</AvatarFallback>\n              </Avatar>\n              <div className=\"text-sm\">\n                <p className=\"font-medium\">{featured.author.name}</p>\n                <p className=\"text-muted-foreground\">{featured.date}</p>\n              </div>\n            </div>\n            <div>\n              <Button render={<a href=\"#\" />} nativeButton={false}>\n                Read Article\n                <IconPlaceholder\n                  lucide=\"ArrowRight\"\n                  tabler=\"IconArrowRight\"\n                  hugeicons=\"ArrowRightIcon\"\n                  phosphor=\"ArrowRight\"\n                  remixicon=\"RiArrowRightLine\"\n                  data-icon=\"inline-end\"\n                />\n              </Button>\n            </div>\n          </div>\n        </Card>\n\n        <div className=\"mb-8 flex flex-wrap gap-2\">\n          {categories.map((category) => {\n            const isActive = active === category\n            return (\n              <button\n                key={category}\n                type=\"button\"\n                onClick={() => setActive(category)}\n                aria-pressed={isActive}\n                className={cn(\n                  \"rounded-md border px-4 py-1.5 text-sm font-medium transition-colors\",\n                  isActive\n                    ? \"border-primary bg-primary text-primary-foreground\"\n                    : \"border-border bg-background text-muted-foreground hover:bg-muted hover:text-foreground\"\n                )}\n              >\n                {category}\n              </button>\n            )\n          })}\n        </div>\n\n        <div className=\"grid grid-cols-1 gap-6 sm:grid-cols-2 md:grid-cols-3\">\n          {visible.map((post) => (\n            <Card\n              key={post.title}\n              className=\"group flex h-full flex-col overflow-hidden p-0 transition-shadow hover:shadow-md\"\n            >\n              <div className=\"relative aspect-video overflow-hidden bg-muted\">\n                <img\n                  src={post.image}\n                  alt={post.title}\n                  className=\"size-full object-cover grayscale transition-all duration-300 group-hover:grayscale-0\"\n                />\n                <span className=\"absolute top-3 right-3 flex items-center gap-1 rounded-4xl bg-background/85 px-2 py-0.5 text-[11px] font-medium text-foreground backdrop-blur-sm\">\n                  <IconPlaceholder\n                    lucide=\"Clock\"\n                    tabler=\"IconClock\"\n                    hugeicons=\"TimeIcon\"\n                    phosphor=\"Clock\"\n                    remixicon=\"RiTimeLine\"\n                    className=\"size-3\"\n                  />\n                  {post.readTime}\n                </span>\n              </div>\n              <CardHeader className=\"gap-2 px-5 pt-5\">\n                <Badge variant=\"secondary\" className=\"w-fit\">\n                  {post.category}\n                </Badge>\n                <CardTitle className=\"text-lg leading-snug\">\n                  <a\n                    href=\"#\"\n                    className=\"transition-colors group-hover:text-primary\"\n                  >\n                    {post.title}\n                  </a>\n                </CardTitle>\n              </CardHeader>\n              <CardContent className=\"flex-1 px-5\">\n                <p className=\"text-sm text-muted-foreground\">{post.excerpt}</p>\n              </CardContent>\n              <CardFooter className=\"items-center gap-3 px-5 pb-5\">\n                <Avatar className=\"size-8 border border-border\">\n                  <AvatarImage\n                    src={`https://i.pravatar.cc/150?img=${post.author.img}`}\n                    alt={post.author.name}\n                    className=\"grayscale\"\n                  />\n                  <AvatarFallback className=\"text-xs\">\n                    {post.author.initials}\n                  </AvatarFallback>\n                </Avatar>\n                <div className=\"min-w-0 text-xs\">\n                  <p className=\"truncate font-medium text-foreground\">\n                    {post.author.name}\n                  </p>\n                  <p className=\"text-muted-foreground\">{post.date}</p>\n                </div>\n              </CardFooter>\n            </Card>\n          ))}\n        </div>\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "meta": {
    "height": "1660px",
    "tier": "free"
  },
  "docs": "Requires a `base-*` style in components.json (the `shadcn init` default). Legacy `new-york`/`radix-*` styles install Radix primitives, which reject the `render` prop this block uses.",
  "categories": [
    "blog"
  ],
  "type": "registry:block"
}