Cta Split Demo Request Modal
blockmarketingSplit-pane enterprise demo request workbench with benefit highlights, team size selectors, framework focus filters, and interactive submission feedback.
Installation
$pnpm dlx uipkge-ng@latest add cta-split-demo-request-modal$npx uipkge-ng@latest add cta-split-demo-request-modal$yarn dlx uipkge-ng@latest add cta-split-demo-request-modal$bunx uipkge-ng@latest add cta-split-demo-request-modalManifest:
https://uipkge.dev/r/angular/cta-split-demo-request-modal.jsonInstalls to:src/app/components/blocks/cta-split-demo-request-modal/Variants
Loading interactive previews…
Loading interactive previews…
npm dependencies
Files installed (2)
src/app/components/blocks/cta-split-demo-request-modal/cta-split-demo-request-modal.component.ts10.4 kB
// Split-pane enterprise demo request workbench with benefit highlights, team size // selectors, framework focus filters, and interactive submission feedback. // Port of the React block 1:1. import { ChangeDetectionStrategy, Component, Input, signal } from '@angular/core' import { ArrowRight, Calendar, CheckCircle2, Lock, LucideAngularModule, Mail, Palette, 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' import { UiInputComponent } from '@/ui/input/input.component' const teamSizes = ['1-10', '11-50', '50-200', '200+'] const frameworkOptions = ['Vue / Nuxt', 'React / Next', 'Dual-Framework'] @Component({ changeDetection: ChangeDetectionStrategy.Eager, selector: 'ui-cta-split-demo-request-modal, [ui-cta-split-demo-request-modal]', 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, UiInputComponent], template: ` <section data-slot="cta-split-demo-request-modal" [class]="rootClass"> <div class="mx-auto max-w-6xl space-y-12"> <!-- Section Header --> <div class="mx-auto max-w-3xl space-y-4 text-center"> <span ui-badge variant="secondary" class="gap-1.5 px-3 py-1 font-mono text-xs shadow-xs"> <lucide-icon [img]="Calendar" class="text-primary size-3.5" /> Enterprise Design System Strategy </span> <h2 class="text-foreground text-3xl font-bold tracking-tight sm:text-4xl"> Schedule an architectural walkthrough. </h2> <p class="text-muted-foreground text-base"> See how unbundled registries and dual-framework tokens accelerate enterprise frontend velocity. </p> </div> <!-- Split Workbench Container --> <div class="grid grid-cols-1 items-stretch gap-8 lg:grid-cols-12"> <!-- Left Column: Enterprise Benefits (6 Cols) --> <div ui-card class="border-border bg-card/95 flex flex-col justify-between space-y-6 rounded-2xl p-6 text-left shadow-xl sm:p-8 lg:col-span-6" > <div class="space-y-6"> <h3 class="text-foreground font-mono text-xl font-bold">What you'll discover on the call:</h3> <div class="space-y-4"> <div class="flex items-start gap-3"> <div class="bg-primary/10 border-primary/20 text-primary shrink-0 rounded-lg border p-2"> <lucide-icon [img]="Zap" class="size-4" /> </div> <div> <h4 class="text-foreground font-mono text-xs font-bold">Eliminating NPM Semver Bottlenecks</h4> <p class="text-muted-foreground mt-0.5 text-xs"> How code ownership prevents breaking upgrades and unblocks feature teams. </p> </div> </div> <div class="flex items-start gap-3"> <div class="bg-primary/10 border-primary/20 text-primary shrink-0 rounded-lg border p-2"> <lucide-icon [img]="ShieldCheck" class="size-4" /> </div> <div> <h4 class="text-foreground font-mono text-xs font-bold"> Private Registry Mirroring & Air-Gapping </h4> <p class="text-muted-foreground mt-0.5 text-xs"> Host internal organizational registries behind your enterprise firewall with custom security audits. </p> </div> </div> <div class="flex items-start gap-3"> <div class="bg-primary/10 border-primary/20 text-primary shrink-0 rounded-lg border p-2"> <lucide-icon [img]="Palette" class="size-4" /> </div> <div> <h4 class="text-foreground font-mono text-xs font-bold">Tailwind CSS v4 Token Architecture</h4> <p class="text-muted-foreground mt-0.5 text-xs"> 100% mathematical token sync across Vue 3.5 SFCs and React 19 TSX islands. </p> </div> </div> </div> </div> <!-- Trust footer --> <div class="border-border text-muted-foreground flex items-center justify-between border-t pt-4 font-mono text-xs" > <span class="flex items-center gap-1.5"> <lucide-icon [img]="Lock" class="text-primary size-3.5" /> NDA Protected • No Obligation </span> <span class="text-success font-semibold">✓ 30-Min Fast Track</span> </div> </div> <!-- Right Column: Interactive Scheduling Form (6 Cols) --> <div ui-card class="border-border bg-card/95 flex flex-col justify-between space-y-6 rounded-2xl p-6 text-left shadow-sm sm:p-8 lg:col-span-6" > @if (!isSubmitted()) { <div class="space-y-5"> <div class="space-y-1"> <h3 class="text-foreground font-mono text-lg font-bold">Request Your Custom Demo</h3> <p class="text-muted-foreground text-xs"> Fill in your team details to receive an instant calendar invite. </p> </div> <!-- Email Field --> <div class="space-y-1.5"> <label class="text-muted-foreground font-mono text-xs">Work Email Address</label> <div class="relative"> <lucide-icon [img]="Mail" class="text-muted-foreground absolute top-1/2 left-3.5 size-4 -translate-y-1/2" /> <ui-input type="email" [value]="email()" (valueChange)="email.set($event)" placeholder="[email protected]" class="bg-card border-border h-10 rounded-xl pl-10 font-mono text-xs shadow-xs" /> </div> </div> <!-- Team Size Picker --> <div class="space-y-1.5"> <label class="text-muted-foreground font-mono text-xs">Engineering Team Size</label> <div class="grid grid-cols-4 gap-1.5"> @for (size of teamSizes; track size) { <button type="button" [class]="optionClass(teamSize() === size)" (click)="teamSize.set(size)"> {{ size }} </button> } </div> </div> <!-- Framework Focus --> <div class="space-y-1.5"> <label class="text-muted-foreground font-mono text-xs">Primary Architecture Focus</label> <div class="grid grid-cols-3 gap-1.5"> @for (fw of frameworkOptions; track fw) { <button type="button" [class]="optionClass(frameworkFocus() === fw)" (click)="frameworkFocus.set(fw)" > {{ fw }} </button> } </div> </div> <button ui-button class="mt-2 h-10 w-full gap-1.5 font-mono text-xs shadow-md" (click)="submitDemoRequest()" > <span>Confirm & Pick Time Slot</span> <lucide-icon [img]="ArrowRight" class="size-3.5" /> </button> </div> } @else { <div class="space-y-4 py-12 text-center"> <div class="border-success/20 bg-success/10 text-success mx-auto flex size-12 items-center justify-center rounded-full border" > <lucide-icon [img]="CheckCircle2" class="size-6" /> </div> <div class="space-y-1"> <h4 class="text-foreground font-mono text-base font-bold">Demo Request Received</h4> <p class="text-muted-foreground mx-auto max-w-xs text-xs"> We've sent calendar access to <span class="text-foreground font-mono font-semibold">{{ email() }}</span >. Check your inbox to select a time. </p> </div> <button ui-button size="sm" variant="outline" class="font-mono text-xs" (click)="isSubmitted.set(false)" > Submit Another Request </button> </div> } </div> </div> </div> </section> `, }) export class UiCtaSplitDemoRequestModalComponent { protected readonly ArrowRight = ArrowRight protected readonly Calendar = Calendar protected readonly CheckCircle2 = CheckCircle2 protected readonly Lock = Lock protected readonly Mail = Mail protected readonly Palette = Palette protected readonly ShieldCheck = ShieldCheck protected readonly Zap = Zap protected readonly teamSizes = teamSizes protected readonly frameworkOptions = frameworkOptions @Input('class') className?: string readonly email = signal('') readonly teamSize = signal('11-50') readonly frameworkFocus = signal('Dual-Framework Monorepo') readonly isSubmitted = signal(false) get rootClass(): string { return cn('bg-background relative overflow-hidden px-4 py-16 sm:px-6 sm:py-24 lg:px-8', this.className) } optionClass(selected: boolean): string { return cn( 'rounded-lg border py-1.5 text-center font-mono text-xs transition-colors', selected ? 'border-primary bg-primary text-primary-foreground font-semibold shadow-xs' : 'border-border bg-card text-muted-foreground hover:text-foreground', ) } submitDemoRequest(): void { if (!this.email()) return this.isSubmitted.set(true) } }src/app/components/blocks/cta-split-demo-request-modal/index.ts0.1 kB
export { UiCtaSplitDemoRequestModalComponent } from './cta-split-demo-request-modal.component'
Raw manifest:https://uipkge.dev/r/angular/cta-split-demo-request-modal.json