{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "newsletter-issue-archive",
  "title": "Newsletter Issue Archive",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-react/blocks/newsletter-issue-archive/NewsletterIssueArchive.tsx",
      "content": "'use client'\n\nimport { useMemo, useState, type FormEvent } from 'react'\nimport {\n  ArrowRight,\n  Bookmark,\n  Calendar,\n  Check,\n  Clock,\n  Heart,\n  MessageSquare,\n  Newspaper,\n  Rss,\n  Search,\n  Users,\n  X,\n  Zap,\n} from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Input } from '@/components/ui/input'\n\nexport interface NewsletterIssue {\n  id: string\n  issueNumber: number\n  volumeDate: string\n  title: string\n  excerpt: string\n  category: 'Architecture' | 'Design Tokens' | 'Performance' | 'Interviews'\n  tags: string[]\n  readTime: string\n  date: string\n  commentsCount: number\n  likesCount: number\n  featured?: boolean\n}\n\nexport interface NewsletterIssueArchiveProps {\n  publicationName?: string\n  subtitle?: string\n  subscriberCount?: string\n  className?: string\n}\n\nconst categories = ['All Issues', 'Architecture', 'Design Tokens', 'Performance', 'Interviews'] as const\n\nconst featuredIssue: NewsletterIssue = {\n  id: 'issue-43',\n  issueNumber: 43,\n  volumeDate: 'Aug 2026',\n  title: 'The Death of npm Component Libraries: Why Copy-Paste Architecture Won',\n  excerpt:\n    'How unbundled UI registries replaced monolithic node_modules packages, eliminated dependency hell, and gave full code ownership back to frontend engineering teams across the industry.',\n  category: 'Architecture',\n  tags: ['#architecture', '#registries', '#future-of-web', '#tooling'],\n  readTime: '9 min read',\n  date: 'Aug 25, 2026',\n  commentsCount: 128,\n  likesCount: 1420,\n  featured: true,\n}\n\nconst archiveIssues: NewsletterIssue[] = [\n  {\n    id: 'issue-42',\n    issueNumber: 42,\n    volumeDate: 'Aug 2026',\n    title: 'Why Zero-Dependency Registries Are Winning',\n    excerpt:\n      'A deep dive into why enterprise engineering teams are abandoning monolithic UI packages in favor of composable own-your-code registry models that eliminate breaking upgrade cascades.',\n    category: 'Architecture',\n    tags: ['#architecture', '#web-performance', '#dx'],\n    readTime: '6 min read',\n    date: 'Aug 18, 2026',\n    commentsCount: 84,\n    likesCount: 642,\n  },\n  {\n    id: 'issue-41',\n    issueNumber: 41,\n    volumeDate: 'Aug 2026',\n    title: 'Mastering Tailwind v4: OKLCH Colors & Dynamic Themes',\n    excerpt:\n      'How modern CSS color spaces and inline theme definitions unlock mathematically perceptually uniform light/dark transitions without CSS variables explosion.',\n    category: 'Design Tokens',\n    tags: ['#design-tokens', '#css', '#theming'],\n    readTime: '8 min read',\n    date: 'Aug 11, 2026',\n    commentsCount: 56,\n    likesCount: 519,\n  },\n  {\n    id: 'issue-40',\n    issueNumber: 40,\n    volumeDate: 'Aug 2026',\n    title: 'Zero-CLS Island Hydration in Modern Web Frameworks',\n    excerpt:\n      'Eliminating Cumulative Layout Shift when server-rendered islands hydrate in Astro and Nuxt. Practical patterns distilled from serving 1M+ monthly pageviews.',\n    category: 'Performance',\n    tags: ['#performance', '#core-web-vitals', '#astro'],\n    readTime: '5 min read',\n    date: 'Aug 04, 2026',\n    commentsCount: 92,\n    likesCount: 730,\n  },\n  {\n    id: 'issue-39',\n    issueNumber: 39,\n    volumeDate: 'Jul 2026',\n    title: 'Interview: Building High-Craft Interfaces with Paco Coursey',\n    excerpt:\n      'The creator of cmdk and sonner breaks down spring physics, popover placement math, and why 60fps micro-interactions define software brand trust.',\n    category: 'Interviews',\n    tags: ['#interviews', '#craft', '#animation'],\n    readTime: '11 min read',\n    date: 'Jul 28, 2026',\n    commentsCount: 147,\n    likesCount: 1205,\n  },\n  {\n    id: 'issue-38',\n    issueNumber: 38,\n    volumeDate: 'Jul 2026',\n    title: 'Building Resilient Component APIs with Polymorphic Slots',\n    excerpt:\n      'Why the asChild composition pattern beat standard prop drilling for accessible primitives, and how Reka UI implements headless polymorphism without DOM overhead.',\n    category: 'Architecture',\n    tags: ['#architecture', '#vue', '#reka-ui'],\n    readTime: '7 min read',\n    date: 'Jul 21, 2026',\n    commentsCount: 63,\n    likesCount: 488,\n  },\n  {\n    id: 'issue-37',\n    issueNumber: 37,\n    volumeDate: 'Jul 2026',\n    title: 'Designing for Multi-Tenant White-Labeling at Scale',\n    excerpt:\n      'Architecting a headless token graph that dynamically maps corporate brand identities and custom color palettes across 500+ enterprise subdomains in real time.',\n    category: 'Design Tokens',\n    tags: ['#design-tokens', '#architecture', '#enterprise'],\n    readTime: '9 min read',\n    date: 'Jul 14, 2026',\n    commentsCount: 71,\n    likesCount: 610,\n  },\n]\n\nexport function NewsletterIssueArchive({\n  publicationName = 'The Unbundled Engineer',\n  subtitle = 'Weekly architectural teardowns of modern design systems, web performance, and component registries.',\n  subscriberCount = '42,500+ Subscribers · Top 1% on Substack',\n  className,\n}: NewsletterIssueArchiveProps) {\n  const [email, setEmail] = useState('')\n  const [isSubscribed, setIsSubscribed] = useState(false)\n  const [searchQuery, setSearchQuery] = useState('')\n  const [selectedCategory, setSelectedCategory] = useState<string>('All Issues')\n\n  function handleSubscribe(e: FormEvent<HTMLFormElement>) {\n    e.preventDefault()\n    if (!email || !email.includes('@')) return\n    setIsSubscribed(true)\n  }\n\n  const filteredIssues = useMemo(() => {\n    const query = searchQuery.trim().toLowerCase()\n    return archiveIssues.filter((issue) => {\n      const matchesCategory = selectedCategory === 'All Issues' || issue.category === selectedCategory\n\n      const matchesSearch =\n        !query ||\n        issue.title.toLowerCase().includes(query) ||\n        issue.excerpt.toLowerCase().includes(query) ||\n        issue.tags.some((tag) => tag.toLowerCase().includes(query)) ||\n        `issue #${issue.issueNumber}`.toLowerCase().includes(query)\n\n      return matchesCategory && matchesSearch\n    })\n  }, [searchQuery, selectedCategory])\n\n  function getCategoryCount(cat: string) {\n    if (cat === 'All Issues') return archiveIssues.length\n    return archiveIssues.filter((issue) => issue.category === cat).length\n  }\n\n  function clearFilters() {\n    setSearchQuery('')\n    setSelectedCategory('All Issues')\n  }\n\n  return (\n    <div\n      data-slot=\"newsletter-issue-archive\"\n      className={cn('mx-auto w-full max-w-5xl space-y-12 px-4 py-8 sm:px-6 sm:py-12', className)}\n    >\n      {/* Newsletter Header Hero */}\n      <header className=\"mx-auto max-w-3xl space-y-4 text-center\">\n        <div className=\"border-primary/20 bg-primary/5 text-primary inline-flex items-center gap-1.5 rounded-full border px-3.5 py-1 text-xs font-medium shadow-xs\">\n          <Users className=\"size-3.5 shrink-0\" aria-hidden=\"true\" />\n          <span>{subscriberCount}</span>\n        </div>\n\n        <h1 className=\"text-foreground text-3xl font-bold tracking-tight sm:text-4xl lg:text-5xl\">{publicationName}</h1>\n\n        <p className=\"text-muted-foreground mx-auto max-w-2xl text-base leading-relaxed sm:text-lg\">{subtitle}</p>\n\n        {/* Subscribe Form */}\n        <div className=\"mx-auto w-full max-w-md pt-2\">\n          {!isSubscribed ? (\n            <div>\n              <form className=\"flex flex-col gap-2 sm:flex-row sm:gap-0\" onSubmit={handleSubscribe}>\n                <Input\n                  id=\"newsletter-archive-email-react\"\n                  value={email}\n                  onChange={(e) => setEmail(e.target.value)}\n                  type=\"email\"\n                  placeholder=\"Enter your work email...\"\n                  required\n                  className=\"bg-card h-11 text-sm shadow-xs sm:rounded-r-none\"\n                  aria-label=\"Work email address\"\n                />\n                <Button type=\"submit\" className=\"h-11 shrink-0 px-6 font-medium sm:rounded-l-none\">\n                  Subscribe for Free\n                </Button>\n              </form>\n              <p className=\"text-muted-foreground mt-2.5 flex flex-wrap items-center justify-center gap-x-2 gap-y-1 text-xs\">\n                <span>Free weekly issues</span>\n                <span>Zero spam</span>\n                <span>1-click unsubscribe</span>\n              </p>\n            </div>\n          ) : (\n            <div className=\"border-success/30 bg-success/10 text-success inline-flex items-center gap-2.5 rounded-lg border px-4 py-3 text-sm font-medium shadow-xs\">\n              <Check className=\"size-4 shrink-0\" aria-hidden=\"true\" />\n              <span>You&rsquo;re subscribed! Check your inbox for confirmation.</span>\n            </div>\n          )}\n        </div>\n      </header>\n\n      {/* Featured Issue Spotlight Card */}\n      <section aria-labelledby=\"featured-issue-heading-react\" className=\"space-y-3\">\n        <div className=\"flex items-center justify-between px-1\">\n          <h2\n            id=\"featured-issue-heading-react\"\n            className=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\"\n          >\n            Pinned Spotlight Edition\n          </h2>\n          <Badge variant=\"outline\" className=\"text-primary border-primary/30 gap-1 text-xs\">\n            <Zap className=\"size-3\" aria-hidden=\"true\" /> Latest Release\n          </Badge>\n        </div>\n\n        <Card className=\"border-border/80 bg-card hover:border-primary/40 overflow-hidden shadow-xs transition-colors\">\n          <div className=\"grid grid-cols-1 gap-6 p-6 sm:p-8 lg:grid-cols-12\">\n            {/* Text Content */}\n            <div className=\"flex flex-col justify-between space-y-4 lg:col-span-7\">\n              <div className=\"space-y-3\">\n                <div className=\"flex flex-wrap items-center gap-2\">\n                  <Badge variant=\"default\" className=\"font-mono text-xs\">\n                    Issue #{featuredIssue.issueNumber} · {featuredIssue.volumeDate}\n                  </Badge>\n                  <Badge variant=\"secondary\" className=\"text-xs\">\n                    {featuredIssue.category}\n                  </Badge>\n                  <span className=\"text-muted-foreground ml-auto inline-flex items-center gap-1 text-xs\">\n                    <Clock className=\"size-3\" aria-hidden=\"true\" />\n                    {featuredIssue.readTime}\n                  </span>\n                </div>\n\n                <h3 className=\"text-foreground hover:text-primary cursor-pointer text-xl font-bold tracking-tight transition-colors sm:text-2xl\">\n                  {featuredIssue.title}\n                </h3>\n\n                <p className=\"text-muted-foreground text-sm leading-relaxed sm:text-base\">{featuredIssue.excerpt}</p>\n              </div>\n\n              <div className=\"space-y-4 pt-2\">\n                <div className=\"flex flex-wrap gap-1.5\">\n                  {featuredIssue.tags.map((tag) => (\n                    <Badge key={tag} variant=\"outline\" className=\"text-muted-foreground font-mono text-xs font-normal\">\n                      {tag}\n                    </Badge>\n                  ))}\n                </div>\n\n                <div className=\"border-border/60 flex flex-wrap items-center justify-between gap-4 border-t pt-3\">\n                  <div className=\"text-muted-foreground flex items-center gap-4 text-xs\">\n                    <span className=\"inline-flex items-center gap-1.5\">\n                      <Calendar className=\"size-3.5\" aria-hidden=\"true\" />\n                      {featuredIssue.date}\n                    </span>\n                    <span className=\"inline-flex items-center gap-1.5\">\n                      <MessageSquare className=\"size-3.5\" aria-hidden=\"true\" />\n                      {featuredIssue.commentsCount} comments\n                    </span>\n                    <span className=\"inline-flex items-center gap-1.5\">\n                      <Heart className=\"size-3.5\" aria-hidden=\"true\" />\n                      {featuredIssue.likesCount}\n                    </span>\n                  </div>\n\n                  <Button variant=\"default\" size=\"sm\" className=\"group gap-1.5 font-medium\">\n                    Read Issue\n                    <ArrowRight\n                      className=\"size-3.5 transition-transform group-hover:translate-x-0.5\"\n                      aria-hidden=\"true\"\n                    />\n                  </Button>\n                </div>\n              </div>\n            </div>\n\n            {/* Schematic Cover Illustration */}\n            <div className=\"flex items-center lg:col-span-5\">\n              <div className=\"border-border/80 bg-muted/40 w-full rounded-lg border p-4 font-mono text-xs sm:p-5\">\n                <div className=\"border-border/60 mb-3 flex items-center justify-between border-b pb-2.5\">\n                  <div className=\"flex items-center gap-1.5\">\n                    <span className=\"bg-destructive/60 inline-block size-2.5 rounded-full\" />\n                    <span className=\"bg-warning/60 inline-block size-2.5 rounded-full\" />\n                    <span className=\"bg-success/60 inline-block size-2.5 rounded-full\" />\n                  </div>\n                  <span className=\"text-muted-foreground text-xs\">registry-teardown.ts</span>\n                </div>\n                <div className=\"text-muted-foreground space-y-2\">\n                  <div className=\"text-primary text-xs font-medium\">// Own your component code</div>\n                  <div>\n                    <span className=\"text-foreground\">$</span> npx shadcn@latest add @uipkge/card\n                  </div>\n                  <div className=\"text-success\">✔ Fetched raw TypeScript TSX</div>\n                  <div className=\"text-success\">✔ Merged local Tailwind v4 tokens</div>\n                  <div className=\"text-muted-foreground/80 pt-1\">// Zero runtime package lock-in</div>\n                </div>\n                <div className=\"border-border/40 mt-4 flex flex-wrap gap-1.5 border-t pt-3\">\n                  <span className=\"bg-background text-foreground border-border rounded border px-2 py-0.5 text-xs\">\n                    Zero npm deps\n                  </span>\n                  <span className=\"bg-background text-foreground border-border rounded border px-2 py-0.5 text-xs\">\n                    Tailwind v4\n                  </span>\n                  <span className=\"bg-background text-foreground border-border rounded border px-2 py-0.5 text-xs\">\n                    OKLCH\n                  </span>\n                </div>\n              </div>\n            </div>\n          </div>\n        </Card>\n      </section>\n\n      {/* Search and Filter Bar */}\n      <section aria-label=\"Search and filter archive\" className=\"space-y-4\">\n        <div className=\"flex flex-col items-stretch justify-between gap-4 md:flex-row md:items-center\">\n          {/* Search Input */}\n          <div className=\"w-full md:max-w-md\">\n            <Input\n              value={searchQuery}\n              onChange={(e) => setSearchQuery(e.target.value)}\n              type=\"search\"\n              placeholder=\"Search issues by title, topic, or tag...\"\n              prefixIcon={<Search className=\"size-4\" aria-hidden=\"true\" />}\n              allowClear\n              className=\"bg-card shadow-xs\"\n              aria-label=\"Search archive issues\"\n            />\n          </div>\n\n          {/* Result Counter */}\n          <div className=\"text-muted-foreground flex items-center justify-between gap-3 text-xs md:justify-end\">\n            <span>\n              Showing {filteredIssues.length} {filteredIssues.length === 1 ? 'edition' : 'editions'}\n            </span>\n            {(searchQuery || selectedCategory !== 'All Issues') && (\n              <button\n                type=\"button\"\n                className=\"text-primary focus-visible:ring-ring inline-flex items-center gap-1 rounded font-medium hover:underline focus-visible:ring-1 focus-visible:outline-none\"\n                onClick={clearFilters}\n              >\n                Reset filters\n                <X className=\"size-3\" aria-hidden=\"true\" />\n              </button>\n            )}\n          </div>\n        </div>\n\n        {/* Category Filter Pills */}\n        <div className=\"flex flex-wrap items-center gap-1.5\" role=\"tablist\" aria-label=\"Filter by category\">\n          {categories.map((cat) => {\n            const isSelected = selectedCategory === cat\n            return (\n              <button\n                key={cat}\n                type=\"button\"\n                role=\"tab\"\n                aria-selected={isSelected}\n                className={cn(\n                  'focus-visible:ring-ring inline-flex items-center gap-1.5 rounded-full px-3.5 py-1.5 text-xs transition-colors focus-visible:ring-2 focus-visible:outline-none',\n                  isSelected\n                    ? 'bg-primary text-primary-foreground font-medium shadow-xs'\n                    : 'bg-muted/70 text-muted-foreground hover:bg-muted hover:text-foreground',\n                )}\n                onClick={() => setSelectedCategory(cat)}\n              >\n                <span>{cat}</span>\n                <span\n                  className={cn(\n                    'py-0.2 rounded-full px-1.5 text-xs',\n                    isSelected\n                      ? 'bg-primary-foreground/20 text-primary-foreground'\n                      : 'bg-background/80 text-muted-foreground',\n                  )}\n                >\n                  {getCategoryCount(cat)}\n                </span>\n              </button>\n            )\n          })}\n        </div>\n      </section>\n\n      {/* Issue Archive List */}\n      <section aria-label=\"Archive issue list\">\n        {filteredIssues.length > 0 ? (\n          <div className=\"grid grid-cols-1 gap-5 md:grid-cols-2\">\n            {filteredIssues.map((issue) => (\n              <Card\n                key={issue.id}\n                className=\"group border-border/70 bg-card hover:border-primary/40 flex flex-col justify-between transition-colors hover:shadow-xs\"\n              >\n                <CardHeader className=\"pb-3\">\n                  <div className=\"flex items-center justify-between gap-2\">\n                    <Badge variant=\"outline\" className=\"font-mono text-xs\">\n                      Issue #{issue.issueNumber} · {issue.volumeDate}\n                    </Badge>\n                    <span className=\"text-muted-foreground inline-flex items-center gap-1 text-xs\">\n                      <Clock className=\"size-3\" aria-hidden=\"true\" />\n                      {issue.readTime}\n                    </span>\n                  </div>\n\n                  <CardTitle className=\"group-hover:text-primary cursor-pointer pt-2 text-base leading-snug font-semibold tracking-tight transition-colors sm:text-lg\">\n                    {issue.title}\n                  </CardTitle>\n\n                  <CardDescription className=\"text-muted-foreground mt-1.5 line-clamp-3 text-sm leading-relaxed\">\n                    {issue.excerpt}\n                  </CardDescription>\n                </CardHeader>\n\n                <CardContent className=\"py-0\">\n                  <div className=\"flex flex-wrap gap-1.5 pt-1\">\n                    {issue.tags.map((tag) => (\n                      <Badge key={tag} variant=\"secondary\" className=\"font-mono text-xs font-normal\">\n                        {tag}\n                      </Badge>\n                    ))}\n                  </div>\n                </CardContent>\n\n                <CardFooter className=\"border-border/60 text-muted-foreground mt-4 flex items-center justify-between border-t pt-4 text-xs\">\n                  <div className=\"flex items-center gap-3\">\n                    <span className=\"inline-flex items-center gap-1\">\n                      <Calendar className=\"size-3.5\" aria-hidden=\"true\" />\n                      {issue.date}\n                    </span>\n                    <span className=\"inline-flex items-center gap-1\">\n                      <MessageSquare className=\"size-3.5\" aria-hidden=\"true\" />\n                      {issue.commentsCount}\n                    </span>\n                    <span className=\"inline-flex items-center gap-1\">\n                      <Heart className=\"size-3.5\" aria-hidden=\"true\" />\n                      {issue.likesCount}\n                    </span>\n                  </div>\n\n                  <a\n                    href=\"#read\"\n                    className=\"text-foreground group-hover:text-primary inline-flex items-center gap-1 font-medium transition-colors focus-visible:underline focus-visible:outline-none\"\n                  >\n                    <span>Read Issue</span>\n                    <ArrowRight\n                      className=\"size-3.5 transition-transform group-hover:translate-x-0.5\"\n                      aria-hidden=\"true\"\n                    />\n                  </a>\n                </CardFooter>\n              </Card>\n            ))}\n          </div>\n        ) : (\n          /* Empty State */\n          <div className=\"border-border bg-card/50 space-y-3 rounded-xl border border-dashed p-10 text-center\">\n            <Newspaper className=\"text-muted-foreground/60 mx-auto size-8\" aria-hidden=\"true\" />\n            <h3 className=\"text-foreground text-base font-semibold\">No issues found</h3>\n            <p className=\"text-muted-foreground mx-auto max-w-sm text-sm\">\n              No newsletter issues matched &ldquo;{searchQuery}&rdquo; in {selectedCategory}.\n            </p>\n            <div className=\"pt-2\">\n              <Button variant=\"outline\" size=\"sm\" onClick={clearFilters}>\n                Clear search &amp; filters\n              </Button>\n            </div>\n          </div>\n        )}\n      </section>\n\n      {/* Publication Cadence & RSS Bar */}\n      <footer className=\"border-border/80 bg-muted/30 flex flex-col items-center justify-between gap-4 rounded-xl border p-6 text-center shadow-xs sm:flex-row sm:text-left\">\n        <div>\n          <h3 className=\"text-foreground text-sm font-semibold\">Never miss a teardown</h3>\n          <p className=\"text-muted-foreground mt-0.5 text-xs\">\n            Published every Tuesday morning. Zero sponsor promotions, purely deep technical architecture.\n          </p>\n        </div>\n\n        <div className=\"flex shrink-0 items-center gap-2.5\">\n          <Button variant=\"outline\" size=\"sm\" className=\"gap-1.5 text-xs\">\n            <Rss className=\"size-3.5\" aria-hidden=\"true\" />\n            RSS Feed\n          </Button>\n          <Button\n            variant=\"default\"\n            size=\"sm\"\n            className=\"gap-1.5 text-xs\"\n            onClick={() => {\n              const el = document.getElementById('newsletter-archive-email-react')\n              el?.focus()\n            }}\n          >\n            <Bookmark className=\"size-3.5\" aria-hidden=\"true\" />\n            Join Newsletter\n          </Button>\n        </div>\n      </footer>\n    </div>\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/NewsletterIssueArchive.tsx"
    }
  ],
  "dependencies": [
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/badge.json",
    "https://uipkge.dev/r/react/button.json",
    "https://uipkge.dev/r/react/card.json",
    "https://uipkge.dev/r/react/input.json"
  ],
  "description": "Substack and Beehiiv style publication archive with issue numbers, read times, subscriber counts, category filtering, search, featured issue spotlight, and subscribe flow.",
  "categories": [
    "media",
    "marketing",
    "app"
  ],
  "deprecated": true,
  "replacedBy": "newsletter"
}