{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "newsletter-signup",
  "title": "Newsletter Signup",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/newsletter-signup/newsletter-signup.component.ts",
      "content": "// Engineering dispatch signup: channel track selector, live dispatch form with\n// success state, archive sampler, and RSS note. Port of the Vue/React block 1:1.\nimport { ChangeDetectionStrategy, Component, Input, signal } from '@angular/core'\nimport { ArrowRight, BellRing, BookOpen, Check, LucideAngularModule, Mail, Send } from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport {\n  UiCardComponent,\n  UiCardContentComponent,\n  UiCardDescriptionComponent,\n  UiCardHeaderComponent,\n  UiCardTitleComponent,\n} from '@/ui/card/card.component'\nimport { UiInputComponent } from '@/ui/input/input.component'\nimport { UiSeparatorComponent } from '@/ui/separator/separator.component'\n\nexport type NewsletterSignupVariant = 'centered' | 'split'\n\ninterface ChannelOption {\n  id: string\n  title: string\n  frequency: string\n  description: string\n  badge: string\n}\n\nexport const newsletterChannels: ChannelOption[] = [\n  {\n    id: 'architecture',\n    title: 'Architecture & Token Deep Dives',\n    frequency: 'Bi-Weekly',\n    description: 'Technical breakdowns on OKLCH color science, headless AST transformers, and zero-lockin paradigms.',\n    badge: 'Flagship',\n  },\n  {\n    id: 'releases',\n    title: 'Registry Ship Notes & RFCs',\n    frequency: 'Monthly',\n    description: 'Direct changelogs, new workbench releases, breaking primitive refactors, and roadmap discussions.',\n    badge: 'Changelog',\n  },\n  {\n    id: 'security',\n    title: 'Security & Dependency Bulletins',\n    frequency: 'As-Needed',\n    description: 'Zero-day vulnerability alerts, upstream headless primitive fixes, and patch notifications.',\n    badge: 'Critical',\n  },\n]\n\nexport const recentIssues = [\n  {\n    id: 48,\n    date: 'Aug 2026',\n    title: 'The Death of Monolithic npm UI Packages',\n    reads: '4 min read',\n    tags: ['Architecture', 'Registry', 'AST'],\n    snippet:\n      'Why the next decade of frontend engineering belongs to unbundled registries where the consumer owns the source code.',\n  },\n  {\n    id: 47,\n    date: 'Jul 2026',\n    title: 'OKLCH Theming in Tailwind CSS v4',\n    reads: '6 min read',\n    tags: ['Tailwind v4', 'Color Science', 'Tokens'],\n    snippet:\n      'Mastering perceptual lightness, chroma gamut mapping, and dynamic theme switching without runtime CSS bloat.',\n  },\n]\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-newsletter-signup, [ui-newsletter-signup]',\n  standalone: true,\n  // The block renders its own root <section>: keep the host out of layout.\n  host: { '[attr.class]': '\"contents\"' },\n  imports: [\n    LucideAngularModule,\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiCardComponent,\n    UiCardContentComponent,\n    UiCardDescriptionComponent,\n    UiCardHeaderComponent,\n    UiCardTitleComponent,\n    UiInputComponent,\n    UiSeparatorComponent,\n  ],\n  template: `\n    <section data-slot=\"newsletter-signup\" [class]=\"rootClass\">\n      <div class=\"mx-auto max-w-6xl space-y-10\">\n        <!-- Section Header -->\n        <div class=\"max-w-3xl space-y-3\">\n          <span ui-badge variant=\"secondary\" class=\"gap-1.5 px-3 py-1 font-mono text-xs shadow-xs\">\n            <lucide-icon [img]=\"Mail\" class=\"text-primary size-3.5\" />\n            Engineering Dispatch & Architecture Radar\n          </span>\n          <h2 class=\"text-foreground text-3xl font-bold tracking-tight sm:text-4xl\">\n            Ship notes, not marketing fluff.\n          </h2>\n          <p class=\"text-muted-foreground text-sm leading-relaxed sm:text-base\">\n            Join 18,400+ frontend architects, design engineers, and systems builders. Plain-text insights into component\n            architecture, token systems, and dual-framework engineering.\n          </p>\n        </div>\n\n        <!-- Main Layout -->\n        <div class=\"grid grid-cols-1 items-start gap-8 lg:grid-cols-12\">\n          <!-- Left Column: Channel Selector & Live Dispatch Form (7 Cols) -->\n          <div class=\"space-y-6 lg:col-span-7\">\n            <div ui-card class=\"border-border bg-card overflow-hidden shadow-sm\">\n              <div ui-card-header class=\"bg-muted/20 border-border/60 border-b pb-4\">\n                <div class=\"flex items-center justify-between\">\n                  <h3 ui-card-title class=\"flex items-center gap-2 text-base font-semibold\">\n                    <lucide-icon [img]=\"BellRing\" class=\"text-primary size-4\" />\n                    Select Dispatch Track\n                  </h3>\n                  <span class=\"text-muted-foreground font-mono text-xs\">Zero Spam Guarantee</span>\n                </div>\n                <p ui-card-description class=\"text-xs\">\n                  Choose the telemetry streams you want delivered to your inbox.\n                </p>\n              </div>\n\n              <div ui-card-content class=\"space-y-5 p-6\">\n                <!-- Channel Radio Cards -->\n                <div class=\"space-y-2.5\">\n                  @for (ch of channels; track ch.id) {\n                    <div\n                      class=\"group cursor-pointer rounded-xl border p-3.5 transition-colors\"\n                      [class]=\"channelCardClass(ch.id)\"\n                      (click)=\"selectedChannel.set(ch.id)\"\n                      (keydown.enter)=\"selectedChannel.set(ch.id)\"\n                      tabindex=\"0\"\n                      role=\"radio\"\n                      [attr.aria-checked]=\"selectedChannel() === ch.id\"\n                    >\n                      <div class=\"flex items-center justify-between gap-2\">\n                        <div class=\"flex items-center gap-2\">\n                          <div\n                            class=\"flex size-3.5 items-center justify-center rounded-full border transition-colors\"\n                            [class]=\"channelDotClass(ch.id)\"\n                          >\n                            @if (selectedChannel() === ch.id) {\n                              <div class=\"bg-primary-foreground size-1.5 rounded-full\"></div>\n                            }\n                          </div>\n                          <span class=\"text-foreground text-xs font-semibold\">{{ ch.title }}</span>\n                        </div>\n                        <span ui-badge variant=\"outline\" class=\"font-mono text-xs\">{{ ch.frequency }}</span>\n                      </div>\n                      <p class=\"text-muted-foreground mt-1.5 pl-5.5 text-xs leading-relaxed\">{{ ch.description }}</p>\n                    </div>\n                  }\n                </div>\n\n                <ui-separator />\n\n                <!-- Dispatch Subscription Input -->\n                @if (!submitted()) {\n                  <form class=\"space-y-3\" (submit)=\"handleSubmit($event)\">\n                    <div class=\"flex flex-col gap-2 sm:flex-row\">\n                      <ui-input\n                        [value]=\"email()\"\n                        (valueChange)=\"email.set($event)\"\n                        type=\"email\"\n                        placeholder=\"architect@company.com\"\n                        required\n                        class=\"h-10 flex-1 font-mono text-xs\"\n                        aria-label=\"Email address for dispatch\"\n                      />\n                      <button\n                        ui-button\n                        type=\"submit\"\n                        [disabled]=\"isSubmitting()\"\n                        class=\"h-10 gap-1.5 px-5 text-xs font-semibold\"\n                      >\n                        <span>Subscribe to Stream</span>\n                        <lucide-icon [img]=\"Send\" class=\"size-3.5\" />\n                      </button>\n                    </div>\n                    <div class=\"text-muted-foreground flex items-center justify-between pt-1 font-mono text-xs\">\n                      <span>Plain text &bull; 1-click unsubscribe</span>\n                      <span class=\"text-success font-semibold\">18,412 Active Subscribers</span>\n                    </div>\n                  </form>\n                } @else {\n                  <div class=\"border-success/20 bg-success/10 space-y-2 rounded-xl border p-5 text-center\">\n                    <div\n                      class=\"bg-success/20 text-success mx-auto flex size-9 items-center justify-center rounded-full\"\n                    >\n                      <lucide-icon [img]=\"Check\" class=\"size-5\" />\n                    </div>\n                    <p class=\"text-foreground text-sm font-semibold\">Dispatches Activated!</p>\n                    <p class=\"text-muted-foreground text-xs\">\n                      Verification sent to <strong class=\"text-foreground font-mono\">{{ email() }}</strong\n                      >. Check your inbox to confirm delivery.\n                    </p>\n                  </div>\n                }\n              </div>\n            </div>\n          </div>\n\n          <!-- Right Column: Recent Issue Sampler & Archives (5 Cols) -->\n          <div class=\"space-y-4 lg:col-span-5\">\n            <div class=\"flex items-center justify-between\">\n              <p class=\"text-muted-foreground flex items-center gap-1.5 font-mono text-xs tracking-wider uppercase\">\n                <lucide-icon [img]=\"BookOpen\" class=\"text-primary size-3.5\" /> Archive Sampler\n              </p>\n              <span class=\"text-muted-foreground font-mono text-xs\">Issue #{{ issues[activePreviewIssue()].id }}</span>\n            </div>\n\n            <!-- Interactive Issue Cards -->\n            <div class=\"space-y-3\">\n              @for (issue of issues; track issue.id; let idx = $index) {\n                <div\n                  class=\"bg-card cursor-pointer rounded-xl border p-4 transition-colors\"\n                  [class]=\"previewCardClass(idx)\"\n                  (click)=\"activePreviewIssue.set(idx)\"\n                  (keydown.enter)=\"activePreviewIssue.set(idx)\"\n                  tabindex=\"0\"\n                  role=\"button\"\n                  [attr.aria-pressed]=\"activePreviewIssue() === idx\"\n                >\n                  <div class=\"text-muted-foreground mb-1.5 flex items-center justify-between font-mono text-xs\">\n                    <span>{{ issue.date }} &bull; Issue #{{ issue.id }}</span>\n                    <span class=\"text-foreground font-medium\">{{ issue.reads }}</span>\n                  </div>\n                  <h3 class=\"text-foreground mb-1.5 text-sm leading-snug font-bold\">{{ issue.title }}</h3>\n                  <p class=\"text-muted-foreground text-xs leading-relaxed\">{{ issue.snippet }}</p>\n\n                  <div class=\"mt-3 flex flex-wrap gap-1.5\">\n                    @for (tag of issue.tags; track tag) {\n                      <span ui-badge variant=\"secondary\" class=\"px-1.5 py-0 font-mono text-xs\">#{{ tag }}</span>\n                    }\n                  </div>\n                </div>\n              }\n            </div>\n\n            <!-- RSS / Mastodon / CLI note -->\n            <div\n              class=\"border-border bg-muted/20 text-muted-foreground flex items-center justify-between rounded-lg border p-3.5 text-xs\"\n            >\n              <span class=\"font-mono\">Prefer RSS feeds?</span>\n              <a\n                href=\"https://uipkge.dev/rss.xml\"\n                target=\"_blank\"\n                rel=\"noreferrer\"\n                class=\"text-primary inline-flex items-center gap-1 font-mono hover:underline\"\n              >\n                uipkge.dev/rss.xml <lucide-icon [img]=\"ArrowRight\" class=\"size-3\" />\n              </a>\n            </div>\n          </div>\n        </div>\n      </div>\n    </section>\n  `,\n})\nexport class UiNewsletterSignupComponent {\n  protected readonly ArrowRight = ArrowRight\n  protected readonly BellRing = BellRing\n  protected readonly BookOpen = BookOpen\n  protected readonly Check = Check\n  protected readonly Mail = Mail\n  protected readonly Send = Send\n\n  protected readonly channels = newsletterChannels\n  protected readonly issues = recentIssues\n\n  @Input() variant: NewsletterSignupVariant = 'split'\n  @Input('class') className?: string\n\n  readonly email = signal('')\n  readonly selectedChannel = signal('architecture')\n  readonly submitted = signal(false)\n  readonly activePreviewIssue = signal(0)\n  readonly isSubmitting = signal(false)\n\n  get rootClass(): string {\n    return cn('bg-background relative overflow-hidden px-4 py-16 sm:px-6 lg:px-8', this.className)\n  }\n\n  channelCardClass(id: string): string {\n    return cn(\n      this.selectedChannel() === id\n        ? 'border-primary bg-primary/5 ring-primary/20 shadow-xs ring-1'\n        : 'border-border bg-background hover:bg-muted/40',\n    )\n  }\n\n  channelDotClass(id: string): string {\n    return cn(this.selectedChannel() === id ? 'border-primary bg-primary' : 'border-muted-foreground/40')\n  }\n\n  previewCardClass(idx: number): string {\n    return cn(\n      this.activePreviewIssue() === idx ? 'border-primary/50 shadow-xs' : 'border-border hover:border-border/80',\n    )\n  }\n\n  handleSubmit(event?: Event): void {\n    event?.preventDefault()\n    if (!this.email() || !this.email().includes('@')) return\n    this.isSubmitting.set(true)\n    setTimeout(() => {\n      this.isSubmitting.set(false)\n      this.submitted.set(true)\n    }, 400)\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/newsletter-signup/newsletter-signup.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/newsletter-signup/index.ts",
      "content": "export {\n  UiNewsletterSignupComponent,\n  type NewsletterSignupVariant,\n  newsletterChannels,\n  recentIssues,\n} from './newsletter-signup.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/newsletter-signup/index.ts"
    }
  ],
  "dependencies": [
    "lucide-angular"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/badge.json",
    "https://uipkge.dev/r/angular/button.json",
    "https://uipkge.dev/r/angular/card.json",
    "https://uipkge.dev/r/angular/input.json",
    "https://uipkge.dev/r/angular/separator.json"
  ],
  "description": "Engineering dispatch and release radar workbench with channel tracks (Architecture, Releases, Security), live archive previews, and subscriber metrics.",
  "categories": [
    "marketing"
  ],
  "deprecated": true,
  "replacedBy": "newsletter"
}