Menu

Change language

GitHub repo

Cta Split Demo Request Modal

blockmarketing

Split-pane enterprise demo request workbench with benefit highlights, team size selectors, framework focus filters, and interactive submission feedback.

Installation

$npx uipkge-ng@latest add cta-split-demo-request-modal
Manifest: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…

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 &amp; 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 &bull; No Obligation
                  </span>
                  <span class="text-success font-semibold">&check; 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 &amp; 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

Raw manifest:https://uipkge.dev/r/angular/cta-split-demo-request-modal.json