Conversion CTA
blockmarketingInteractive developer CTA section with live framework switcher, interactive CLI installation terminal, 1-click clipboard copy, and production guarantees.
Installation
$pnpm dlx uipkge-ng@latest add cta-01$npx uipkge-ng@latest add cta-01$yarn dlx uipkge-ng@latest add cta-01$bunx uipkge-ng@latest add cta-01Manifest:
https://uipkge.dev/r/angular/cta-01.jsonInstalls to:src/app/components/blocks/cta-01/Variants
Loading interactive previews…
Loading interactive previews…
npm dependencies
Files installed (2)
src/app/components/blocks/cta-01/cta-01.component.ts9.7 kB
// Interactive developer CTA: eyebrow pill with edge latency, headline narrative, // framework-switching install terminal with clipboard copy, primary actions, and // a guarantees grid. Port of the React block 1:1. import { ChangeDetectionStrategy, Component, DestroyRef, Input, inject, signal } from '@angular/core' import { ArrowRight, Check, CheckCircle2, Code2, Copy, Download, Globe, Layers, LucideAngularModule, ShieldCheck, Zap, } from 'lucide-angular' import { cn } from '@/lib/utils' import { UiBadgeComponent } from '@/ui/badge/badge.component' import { UiButtonComponent } from '@/ui/button/button.component' import { UiCardComponent } from '@/ui/card/card.component' export type CtaFramework = 'vue' | 'react' | 'nuxt' export const installCommands: Record<CtaFramework, { command: string; subtitle: string }> = { vue: { command: 'npx shadcn-vue@latest add https://uipkge.dev/r/vue/init.json -y', subtitle: 'Zero-config Vue 3.5 + Tailwind v4 + Reka UI primitives', }, react: { command: 'npx shadcn@latest add https://uipkge.dev/r/react/init.json -y', subtitle: 'Production-ready React 19 + Radix primitives + CVA variants', }, nuxt: { command: 'npx shadcn-vue@latest add https://uipkge.dev/r/vue/init.json -y', subtitle: 'Nuxt 4 auto-imports, SSR hydration-safe, unbundled ownership', }, } const frameworks: { id: CtaFramework; label: string }[] = [ { id: 'vue', label: 'Vue 3.5' }, { id: 'react', label: 'React 19' }, { id: 'nuxt', label: 'Nuxt 4' }, ] @Component({ changeDetection: ChangeDetectionStrategy.Eager, selector: 'ui-cta-01, [ui-cta-01]', standalone: true, // React renders the root <section> itself: the host stays out of layout and `class` goes to the root. host: { '[attr.class]': '"contents"' }, imports: [LucideAngularModule, UiBadgeComponent, UiButtonComponent, UiCardComponent], template: ` <section data-slot="cta-01" [class]="rootClass"> <div class="mx-auto max-w-5xl space-y-10 px-4 text-center sm:px-6 lg:px-8"> <!-- Eyebrow Pill --> <div class="inline-flex items-center gap-2"> <span ui-badge variant="outline" class="border-primary/30 text-primary bg-primary/5 gap-1.5 px-3 py-1 font-mono text-xs tracking-wide uppercase" > <lucide-icon [img]="Zap" class="size-3.5" /> Unbundled Registry Distribution </span> <div class="text-muted-foreground flex items-center gap-1.5 font-mono text-xs"> <span class="bg-success size-2 rounded-full"></span> <span>CDN Edge: {{ pingMs() }}ms P99</span> </div> </div> <!-- Main Headline & Narrative --> <div class="mx-auto max-w-3xl space-y-4"> <h2 class="text-foreground text-3xl leading-[1.15] font-bold tracking-tight sm:text-5xl"> Own Your UI. No Semver Lock-in. Zero Bloat. </h2> <p class="text-muted-foreground text-base leading-relaxed sm:text-lg"> The components are the product. Source files are copied directly into your workspace. Modify, compose, and refactor without fighting external package boundaries. </p> </div> <!-- Interactive Developer Terminal Box --> <div ui-card class="mx-auto max-w-2xl overflow-hidden border-zinc-800 bg-zinc-950 text-left text-zinc-100 shadow-sm" > <!-- Terminal Titlebar --> <div class="flex items-center justify-between border-b border-zinc-800 bg-zinc-900/70 px-4 py-3"> <div class="flex items-center gap-2"> <div class="flex gap-1.5"> <div class="bg-destructive/80 size-3 rounded-full"></div> <div class="bg-warning/80 size-3 rounded-full"></div> <div class="bg-success/80 size-3 rounded-full"></div> </div> <span class="text-muted-foreground ml-2 font-mono text-xs">terminal — bootstrap workspace</span> </div> <!-- Framework selector tabs --> <div class="flex items-center gap-1 rounded-md border border-zinc-800 bg-zinc-950 p-0.5"> @for (fw of frameworks; track fw.id) { <button type="button" [class]="frameworkTabClass(fw.id)" (click)="activeFramework.set(fw.id)"> {{ fw.label }} </button> } </div> </div> <!-- Terminal Command Runner Body --> <div class="space-y-3 p-4 font-mono text-xs sm:p-5"> <div class="flex items-center justify-between gap-3 rounded-lg border border-zinc-800 bg-zinc-900/90 p-3"> <div class="text-success flex items-center gap-2.5 overflow-x-auto select-all"> <span class="text-muted-foreground shrink-0">$</span> <span class="whitespace-nowrap">{{ installCommands[activeFramework()].command }}</span> </div> <button ui-button size="sm" variant="outline" class="h-7 shrink-0 gap-1.5 border-zinc-700 bg-zinc-800 px-2.5 font-mono text-xs text-zinc-200 hover:bg-zinc-700" (click)="copyCommand()" > @if (copied()) { <lucide-icon [img]="Check" class="text-success size-3.5" /> } @else { <lucide-icon [img]="Copy" class="size-3.5" /> } <span>{{ copied() ? 'Copied' : 'Copy' }}</span> </button> </div> <p class="text-muted-foreground flex items-center gap-1.5 text-xs"> <span>{{ installCommands[activeFramework()].subtitle }}</span> </p> </div> </div> <!-- Primary Action Buttons --> <div class="flex flex-wrap items-center justify-center gap-3.5 pt-2"> <button ui-button size="lg" class="h-11 gap-2 px-6 font-semibold shadow-sm" (click)="copyCommand()"> <lucide-icon [img]="Download" class="size-4" /> {{ copied() ? 'Command Copied to Clipboard' : 'Install Components' }} </button> <a ui-button size="lg" variant="outline" class="h-11 gap-2 px-6 font-semibold" href="https://github.com/uday-a/uipkge-registry" target="_blank" rel="noreferrer" > <lucide-icon [img]="Code2" class="size-4" /> Explore Source Registry <lucide-icon [img]="ArrowRight" class="size-4" /> </a> </div> <!-- Trust Badges & Guarantees Grid --> <div class="border-border grid grid-cols-2 gap-4 border-t pt-8 text-left sm:grid-cols-4"> <div class="flex items-start gap-2.5"> <lucide-icon [img]="CheckCircle2" class="text-success mt-0.5 size-4 shrink-0" /> <div> <p class="text-foreground text-xs font-semibold">100% Code Ownership</p> <p class="text-muted-foreground mt-0.5 text-xs">Files live in your repository</p> </div> </div> <div class="flex items-start gap-2.5"> <lucide-icon [img]="ShieldCheck" class="text-success mt-0.5 size-4 shrink-0" /> <div> <p class="text-foreground text-xs font-semibold">Zero Runtime Bloat</p> <p class="text-muted-foreground mt-0.5 text-xs">No opaque wrapper dependencies</p> </div> </div> <div class="flex items-start gap-2.5"> <lucide-icon [img]="Layers" class="text-success mt-0.5 size-4 shrink-0" /> <div> <p class="text-foreground text-xs font-semibold">Tailwind CSS v4</p> <p class="text-muted-foreground mt-0.5 text-xs">OKLCH color system & tokens</p> </div> </div> <div class="flex items-start gap-2.5"> <lucide-icon [img]="Globe" class="text-success mt-0.5 size-4 shrink-0" /> <div> <p class="text-foreground text-xs font-semibold">Dual Framework</p> <p class="text-muted-foreground mt-0.5 text-xs">Strict Vue 3.5 & React 19 parity</p> </div> </div> </div> </div> </section> `, }) export class UiCta01Component { protected readonly ArrowRight = ArrowRight protected readonly Check = Check protected readonly CheckCircle2 = CheckCircle2 protected readonly Code2 = Code2 protected readonly Copy = Copy protected readonly Download = Download protected readonly Globe = Globe protected readonly Layers = Layers protected readonly ShieldCheck = ShieldCheck protected readonly Zap = Zap protected readonly frameworks = frameworks protected readonly installCommands = installCommands @Input('class') className?: string readonly activeFramework = signal<CtaFramework>('vue') readonly copied = signal(false) readonly pingMs = signal(14) private copyTimer: ReturnType<typeof setTimeout> | undefined constructor() { inject(DestroyRef).onDestroy(() => clearTimeout(this.copyTimer)) } get rootClass(): string { return cn('bg-background border-border relative w-full overflow-hidden border-y py-16 lg:py-24', this.className) } frameworkTabClass(id: CtaFramework): string { return cn( 'rounded px-2 py-0.5 font-mono text-xs transition-colors', this.activeFramework() === id ? 'bg-zinc-800 font-semibold text-zinc-100 shadow-xs' : 'text-muted-foreground hover:text-zinc-200', ) } async copyCommand(): Promise<void> { try { await navigator.clipboard.writeText(installCommands[this.activeFramework()].command) } catch { // Clipboard fallback } this.copied.set(true) clearTimeout(this.copyTimer) this.copyTimer = setTimeout(() => this.copied.set(false), 2000) } }src/app/components/blocks/cta-01/index.ts0.1 kB
export { UiCta01Component, installCommands, type CtaFramework } from './cta-01.component'
Raw manifest:https://uipkge.dev/r/angular/cta-01.json