Menu

Change language

GitHub repo

Hero Ascii Terminal Stream

blockhero

Retro-futuristic ASCII terminal stream hero section with command runner and AST telemetry logs.

Installation

$npx uipkge-ng@latest add hero-ascii-terminal-stream
Manifest:https://uipkge.dev/r/angular/hero-ascii-terminal-stream.jsonInstalls to:src/app/components/blocks/hero-ascii-terminal-stream/

Variants

Loading interactive previews…

npm dependencies

Includes

Files installed (2)

  • src/app/components/blocks/hero-ascii-terminal-stream/hero-ascii-terminal-stream.component.ts8.6 kB
    // Retro-futuristic ASCII terminal stream hero with an interactive command
    // executor (bench / parity / tree / clear) and live telemetry logs.
    // Port of the React block 1:1.
    import { ChangeDetectionStrategy, Component, DestroyRef, Input, inject, signal } from '@angular/core'
    import { FormsModule } from '@angular/forms'
    import { ArrowRight, LucideAngularModule, Terminal } from 'lucide-angular'
    import { cn } from '@/lib/utils'
    import { UiButtonComponent } from '@/ui/button/button.component'
    import { UiCardComponent, UiCardContentComponent } from '@/ui/card/card.component'
    
    export interface HeroAsciiTerminalStreamProps {
      title?: string
      description?: string
    }
    
    const ASCII_BANNER = `
      _   _ ___ ____  _  ______ _____
     | | | |_ _|  _ \\| |/ / ___| ____|
     | | | || || |_) | ' / |  _|  _|
     | |_| || ||  __/| . \\ |_| | |___
      \\___/|___|_|   |_|\\_\\____|_____|
      ================================
      DUAL-FRAMEWORK UNBUNDLED REGISTRY
    `
    
    const initialLogs: string[] = [
      'INIT: Initializing UIPKGE dual-framework AST registry...',
      'RESOLVE: Synchronizing @uipkge/button -> Vue 3.5 & React 19',
      'OKLCH: Loaded 48 semantic color variables from packages/shared',
      'BENCHMARK: Cold compilation completed in 1.42ms (zero dead code)',
      'READY: Terminal listening on edge:8080',
    ]
    
    const quickCommands = ['bench', 'parity', 'tree', 'clear'] as const
    
    @Component({
      changeDetection: ChangeDetectionStrategy.Eager,
      selector: 'ui-hero-ascii-terminal-stream, [ui-hero-ascii-terminal-stream]',
      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: [FormsModule, LucideAngularModule, UiButtonComponent, UiCardComponent, UiCardContentComponent],
      template: `
        <section data-slot="hero-ascii-terminal-stream" [class]="rootClass">
          <div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
            <!-- Section Header -->
            <div class="mx-auto max-w-3xl space-y-4 text-center">
              <a
                href="#ascii-terminal"
                class="group border-border/80 bg-secondary/60 hover:bg-secondary text-foreground inline-flex items-center gap-2 rounded-full border px-3.5 py-1 text-xs font-medium shadow-2xs transition-colors"
              >
                <lucide-icon [img]="Terminal" class="text-primary size-3.5" />
                <span>Real-time ASCII Telemetry Stream</span>
                <lucide-icon
                  [img]="ArrowRight"
                  class="text-muted-foreground size-3 transition-transform group-hover:translate-x-0.5"
                />
              </a>
    
              <h1 class="text-foreground text-4xl font-bold tracking-tight sm:text-5xl lg:text-6xl">
                {{ title }}
              </h1>
    
              <p class="text-muted-foreground text-base sm:text-lg">
                {{ description }}
              </p>
    
              <!-- Command Chips -->
              <div class="flex flex-wrap items-center justify-center gap-2 pt-2">
                <span class="text-muted-foreground text-xs">Quick commands:</span>
                @for (chip of commandChips; track chip) {
                  <button
                    type="button"
                    class="border-border bg-muted/40 hover:bg-muted text-foreground rounded border px-2 py-0.5 font-mono text-xs transition-colors"
                    (click)="runCommand(chip)"
                  >
                    {{ '$' + chip }}
                  </button>
                }
              </div>
            </div>
    
            <!-- Main ASCII Terminal Card -->
            <div class="mx-auto mt-12 max-w-4xl">
              <div ui-card class="border-border bg-card overflow-hidden font-mono text-xs shadow-lg">
                <!-- Terminal Title Bar -->
                <div class="border-border bg-muted/40 flex items-center justify-between border-b px-4 py-2.5">
                  <div class="flex items-center gap-2">
                    <div class="flex gap-1.5">
                      <span class="bg-destructive/80 size-2.5 rounded-full"></span>
                      <span class="bg-warning/80 size-2.5 rounded-full"></span>
                      <span class="bg-success/80 size-2.5 rounded-full"></span>
                    </div>
                    <span class="text-foreground pl-2 text-xs font-bold">uipkge-telemetry-cli &bull; zsh</span>
                  </div>
                  <div class="text-muted-foreground flex items-center gap-3 text-xs">
                    <span class="flex items-center gap-1">
                      <span class="bg-success size-1.5 rounded-full"></span>
                      <span>60 FPS</span>
                    </span>
                    <span>1.2MB RSS</span>
                  </div>
                </div>
    
                <!-- Terminal Content Viewport -->
                <div ui-card-content class="bg-background/95 space-y-4 p-6">
                  <!-- ASCII Art Banner -->
                  <pre class="text-primary overflow-x-auto text-xs leading-tight font-bold select-none"><code>{{
                    asciiBanner
                  }}</code></pre>
    
                  <!-- Logs Stream Output -->
                  <div class="border-border/80 max-h-56 space-y-1.5 overflow-y-auto border-t pt-2 text-xs">
                    @for (log of terminalLogs(); track $index) {
                      <div [class]="logClass(log)">
                        {{ log }}
                      </div>
                    }
                  </div>
    
                  <!-- Terminal Interactive Input Prompt -->
                  <form class="border-border flex items-center gap-2 border-t pt-3" (submit)="onSubmit($event)">
                    <span class="text-primary font-bold">&gt;</span>
                    <input
                      type="text"
                      placeholder="Type command (e.g. bench, parity, clear)..."
                      [(ngModel)]="inputCommand"
                      name="terminal-command"
                      class="text-foreground placeholder:text-muted-foreground flex-1 bg-transparent text-xs focus-visible:outline-none"
                    />
                    <button ui-button size="sm" type="submit" class="h-7 gap-1 px-2.5 text-xs">
                      <span>Run</span>
                      <lucide-icon [img]="ArrowRight" class="size-3" />
                    </button>
                  </form>
                </div>
              </div>
            </div>
          </div>
        </section>
      `,
    })
    export class UiHeroAsciiTerminalStreamComponent {
      protected readonly ArrowRight = ArrowRight
      protected readonly Terminal = Terminal
    
      protected readonly asciiBanner = ASCII_BANNER
      protected readonly commandChips = quickCommands
    
      @Input() title = 'Deterministic UI engineering stream for technical operators.'
      @Input() description =
        'Inspect build outputs, verify zero-dependency bundle telemetry, and stream component ASTs in real time with hardware precision.'
      @Input('class') className?: string
    
      readonly terminalLogs = signal<string[]>([...initialLogs])
      readonly isRunning = signal(false)
      protected inputCommand = ''
    
      private runTimer: ReturnType<typeof setTimeout> | undefined
    
      constructor() {
        inject(DestroyRef).onDestroy(() => clearTimeout(this.runTimer))
      }
    
      get rootClass(): string {
        return cn('bg-background relative overflow-hidden py-16 sm:py-24', this.className)
      }
    
      logClass(log: string): string {
        return cn(
          'leading-relaxed',
          log.startsWith('$')
            ? 'text-primary font-bold'
            : log.includes('PASS') || log.includes('OKLCH')
              ? 'text-success'
              : 'text-muted-foreground',
        )
      }
    
      onSubmit(event: SubmitEvent): void {
        event.preventDefault()
        this.runCommand(this.inputCommand)
      }
    
      runCommand(cmd: string): void {
        const cleanCmd = cmd.trim().toLowerCase()
        if (!cleanCmd) return
    
        this.terminalLogs.update((prev) => [...prev, `$ ${cleanCmd}`])
        this.isRunning.set(true)
    
        clearTimeout(this.runTimer)
        this.runTimer = setTimeout(() => {
          if (cleanCmd === 'clear') {
            this.terminalLogs.set(['TERMINAL: Buffer cleared.'])
          } else if (cleanCmd === 'bench') {
            this.terminalLogs.update((prev) => [
              ...prev,
              'BENCHMARK: Button (1.1kb) | Modal (2.8kb) | DataGrid (4.2kb)',
              'RESULT: 100% Tree-shaken bundle efficiency.',
            ])
          } else if (cleanCmd === 'parity') {
            this.terminalLogs.update((prev) => [
              ...prev,
              'PARITY: 31 variant tokens evaluated across Vue & React.',
              'STATUS: [PASS] Zero framework divergence detected.',
            ])
          } else if (cleanCmd === 'tree') {
            this.terminalLogs.update((prev) => [
              ...prev,
              'TREE: packages/registry-vue (471) <-> packages/registry-react (471)',
            ])
          } else {
            this.terminalLogs.update((prev) => [...prev, `EXEC: Command '${cleanCmd}' executed with exit code 0.`])
          }
          this.isRunning.set(false)
        }, 400)
    
        this.inputCommand = ''
      }
    }
    
  • src/app/components/blocks/hero-ascii-terminal-stream/index.ts0.1 kB

Raw manifest:https://uipkge.dev/r/angular/hero-ascii-terminal-stream.json