Menu

Change language

GitHub repo

Stats Band

blockmarketing

Interactive live telemetry and performance matrix band with multi-timeframe switching, real-time SLA verification, regional cluster drilldown, and JSON export.

Installation

$npx uipkge-ng@latest add stats-band
Manifest:https://uipkge.dev/r/angular/stats-band.jsonInstalls to:src/app/components/blocks/stats-band/

Variants

Loading interactive previews…

Schema

Type aliases exported from this item's source. Use these to shape the data you pass in.

TimeframeValue
interface TimeframeValue {
  main: string
  change: string
  isPositive: boolean
  note: string
}
MetricData
interface MetricData {
  id: string
  label: string
  subtitle: string
  values: Record<StatsTimeframe, TimeframeValue>
  icon: unknown
  breakdown: { region: string; val: string; status: string }[]
}

npm dependencies

Includes

Files installed (2)

  • src/app/components/blocks/stats-band/stats-band.component.ts12 kB
    // Interactive live telemetry and performance matrix band with multi-timeframe
    // switching, real-time SLA verification, regional cluster drilldown, and JSON export.
    // Port of the Vue block 1:1.
    import { ChangeDetectionStrategy, Component, computed, Input, signal } from '@angular/core'
    import { Check, Clock, Copy, Globe, LucideAngularModule, ShieldCheck, TrendingUp, Users, Zap } from 'lucide-angular'
    import { cn } from '@/lib/utils'
    import { UiBadgeComponent } from '@/ui/badge/badge.component'
    import { UiButtonComponent } from '@/ui/button/button.component'
    
    export type StatsTimeframe = 'realtime' | '24h' | '7d' | '30d'
    export type StatsVariant = 'plain' | 'bordered'
    
    interface TimeframeValue {
      main: string
      change: string
      isPositive: boolean
      note: string
    }
    
    interface MetricData {
      id: string
      label: string
      subtitle: string
      values: Record<StatsTimeframe, TimeframeValue>
      icon: unknown
      breakdown: { region: string; val: string; status: string }[]
    }
    
    const stats: MetricData[] = [
      {
        id: 'uptime',
        label: 'Platform Availability',
        subtitle: 'Multi-region Active-Active SLA',
        icon: ShieldCheck,
        values: {
          realtime: { main: '100.00%', change: '0 incident in 90d', isPositive: true, note: 'Zero degradation' },
          '24h': { main: '99.95%', change: '+0.001%', isPositive: true, note: '100% healthy' },
          '7d': { main: '99.995%', change: '+0.005%', isPositive: true, note: 'Target > 99.99%' },
          '30d': { main: '99.988%', change: '+0.02%', isPositive: true, note: 'Statutory SLA met' },
        },
        breakdown: [
          { region: 'us-east-1 (N. Virginia)', val: '100.0%', status: 'Operational' },
          { region: 'eu-west-1 (Frankfurt)', val: '100.0%', status: 'Operational' },
          { region: 'ap-southeast-1 (Singapore)', val: '100.0%', status: 'Operational' },
          { region: 'sa-east-1 (São Paulo)', val: '99.99%', status: 'Operational' },
        ],
      },
      {
        id: 'throughput',
        label: 'Component Installs & Pulls',
        subtitle: 'Daily registry resolutions',
        icon: Zap,
        values: {
          realtime: { main: '1.42M', change: '+34.2k / hr', isPositive: true, note: 'Peak throughput' },
          '24h': { main: '3.89M', change: '+22.4% vs prev', isPositive: true, note: '320k unique repos' },
          '7d': { main: '26.4M', change: '+18.8%', isPositive: true, note: '1.4k new teams' },
          '30d': { main: '104.2M', change: '+41.0%', isPositive: true, note: 'Global scale' },
        },
        breakdown: [
          { region: 'Vue 3.5 / Nuxt 4 Core', val: '58.2%', status: 'Dominant' },
          { region: 'React 19 / Next.js Mirror', val: '41.8%', status: 'Growing' },
          { region: 'Direct CLI Installations', val: '88.4%', status: 'Automated' },
          { region: 'Manual Source Downloads', val: '11.6%', status: 'Direct' },
        ],
      },
      {
        id: 'latency',
        label: 'Global Edge P99 Latency',
        subtitle: 'Cloudflare Workers cache hits',
        icon: Clock,
        values: {
          realtime: { main: '12ms', change: '-4ms reduction', isPositive: true, note: 'Global median: 8ms' },
          '24h': { main: '14ms', change: '-2ms vs baseline', isPositive: true, note: '99.9% cache hit' },
          '7d': { main: '16ms', change: '-12ms optimization', isPositive: true, note: 'Zero edge cold-starts' },
          '30d': { main: '18ms', change: '-24ms', isPositive: true, note: 'V4 pipeline rollout' },
        },
        breakdown: [
          { region: 'North America (Edge)', val: '9ms', status: 'Fastest' },
          { region: 'Europe (Edge)', val: '11ms', status: 'Optimal' },
          { region: 'Asia-Pacific (Edge)', val: '14ms', status: 'Optimal' },
          { region: 'Latin America (Edge)', val: '18ms', status: 'Optimal' },
        ],
      },
      {
        id: 'satisfaction',
        label: 'Enterprise Developer NPS',
        subtitle: 'Surveyed across 450+ companies',
        icon: Users,
        values: {
          realtime: { main: '+78', change: 'Top 1% dev tools', isPositive: true, note: 'Verified feedback' },
          '24h': { main: '4.94 / 5', change: '99.2% positive', isPositive: true, note: 'From 1,240 ratings' },
          '7d': { main: '+76', change: '+4 pts vs qtr', isPositive: true, note: '98% retention' },
          '30d': { main: '+74', change: '+12 pts YoY', isPositive: true, note: 'Industry benchmark' },
        },
        breakdown: [
          { region: 'Code Quality & Typing', val: '99.6%', status: '5 Stars' },
          { region: 'Zero-Lockin Ownership', val: '98.8%', status: '5 Stars' },
          { region: 'Visual Design Aesthetics', val: '99.2%', status: '5 Stars' },
          { region: 'Documentation & Demos', val: '97.4%', status: '4.9 Stars' },
        ],
      },
    ]
    
    const timeframeOptions: { id: StatsTimeframe; label: string }[] = [
      { id: 'realtime', label: 'Live P99' },
      { id: '24h', label: '24H' },
      { id: '7d', label: '7D' },
      { id: '30d', label: '30D' },
    ]
    
    @Component({
      changeDetection: ChangeDetectionStrategy.Eager,
      selector: 'ui-stats-band, [ui-stats-band]',
      standalone: true,
      // Vue 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],
      template: `
        <section data-slot="stats-band" [class]="rootClass">
          <!-- Top Telemetry Header Bar -->
          <div
            class="border-border bg-muted/20 flex flex-col justify-between gap-4 border-b px-6 py-4 sm:flex-row sm:items-center"
          >
            <div class="flex items-center gap-2.5">
              <div class="bg-success flex size-2.5 rounded-full"></div>
              <span class="text-foreground font-mono text-xs font-semibold tracking-wider uppercase">
                Real-time Telemetry & Performance Matrix
              </span>
              <span
                ui-badge
                variant="outline"
                class="border-success/20 bg-success/10 text-success hidden font-mono text-xs sm:inline-flex"
              >
                All Systems Operational
              </span>
            </div>
    
            <div class="flex items-center gap-2 self-end sm:self-auto">
              <!-- Timeframe Selectors -->
              <div class="bg-background border-border flex items-center rounded-lg border p-0.5">
                @for (tf of timeframeOptions; track tf.id) {
                  <button
                    type="button"
                    [class]="timeframeButtonClass(tf.id)"
                    (click)="selectedTimeframe.set(tf.id)"
                  >
                    {{ tf.label }}
                  </button>
                }
              </div>
    
              <button
                ui-button
                variant="outline"
                size="sm"
                class="h-7 gap-1.5 px-2 font-mono text-xs"
                (click)="copyStatsPayload()"
              >
                @if (copied()) {
                  <lucide-icon [img]="Check" class="text-success size-3" />
                } @else {
                  <lucide-icon [img]="Copy" class="size-3" />
                }
                <span>{{ copied() ? 'Copied' : 'JSON' }}</span>
              </button>
            </div>
          </div>
    
          <!-- 4-Column KPI Metric Cards -->
          <div class="divide-border grid grid-cols-1 divide-y sm:grid-cols-2 sm:divide-x sm:divide-y-0 lg:grid-cols-4">
            @for (item of allStats; track item.id; let idx = $index) {
              <div
                [class]="statTileClass(idx)"
                (click)="toggleStat(idx)"
                (keydown.enter)="toggleStat(idx)"
                tabindex="0"
                role="button"
                [attr.aria-expanded]="activeStatIndex() === idx"
                [attr.aria-label]="'Toggle breakdown for ' + item.label"
              >
                <div class="flex items-start justify-between">
                  <p class="text-muted-foreground font-mono text-xs tracking-wider uppercase">{{ item.label }}</p>
                  <lucide-icon
                    [img]="item.icon"
                    class="text-muted-foreground group-hover:text-primary size-4 transition-colors"
                  />
                </div>
    
                <div class="mt-3 flex items-baseline gap-2">
                  <span class="text-foreground font-mono text-3xl font-bold tracking-tight">
                    {{ item.values[selectedTimeframe()].main }}
                  </span>
                </div>
    
                <p class="text-muted-foreground mt-1 line-clamp-1 text-xs">
                  {{ item.subtitle }}
                </p>
    
                <div class="border-border/60 mt-4 flex items-center justify-between border-t pt-3">
                  <span class="text-success inline-flex items-center gap-1 font-mono text-xs font-medium">
                    <lucide-icon [img]="TrendingUp" class="size-3" />
                    {{ item.values[selectedTimeframe()].change }}
                  </span>
                  <span class="text-muted-foreground font-mono text-xs">
                    {{ item.values[selectedTimeframe()].note }}
                  </span>
                </div>
              </div>
            }
          </div>
    
          <!-- Telemetry Regional Drilldown Drawer when a card is selected -->
          @if (activeStat(); as active) {
            <div class="bg-muted/20 border-border space-y-4 border-t p-6">
              <div class="flex items-center justify-between">
                <div class="flex items-center gap-2">
                  <lucide-icon [img]="Globe" class="text-primary size-4" />
                  <span class="text-foreground text-xs font-semibold">
                    Regional Telemetry & Infrastructure Breakdown: {{ active.label }}
                  </span>
                </div>
                <button ui-button variant="ghost" size="sm" class="h-6 text-xs" (click)="activeStatIndex.set(null)">
                  Close Breakdown
                </button>
              </div>
    
              <div class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
                @for (sub of active.breakdown; track sub.region) {
                  <div
                    class="border-border bg-background flex items-center justify-between rounded-lg border p-3 shadow-xs"
                  >
                    <div>
                      <p class="text-foreground text-xs font-medium">{{ sub.region }}</p>
                      <p class="text-muted-foreground mt-0.5 font-mono text-xs">{{ sub.status }}</p>
                    </div>
                    <span class="text-success font-mono text-xs font-bold">{{ sub.val }}</span>
                  </div>
                }
              </div>
            </div>
          }
        </section>
      `,
    })
    export class UiStatsBandComponent {
      protected readonly Check = Check
      protected readonly Copy = Copy
      protected readonly Globe = Globe
      protected readonly TrendingUp = TrendingUp
      protected readonly timeframeOptions = timeframeOptions
      protected readonly allStats = stats
    
      @Input() variant: StatsVariant = 'bordered'
      @Input('class') className?: string
    
      readonly selectedTimeframe = signal<StatsTimeframe>('realtime')
      readonly activeStatIndex = signal<number | null>(null)
      readonly copied = signal(false)
      private copyTimer: ReturnType<typeof setTimeout> | undefined
    
      readonly activeStat = computed(() => {
        const idx = this.activeStatIndex()
        return idx == null ? null : (stats[idx] ?? null)
      })
    
      get rootClass(): string {
        return cn(
          'bg-card relative w-full overflow-hidden',
          this.variant === 'bordered' ? 'border-border rounded-2xl border shadow-xs' : '',
          this.className,
        )
      }
    
      timeframeButtonClass(id: StatsTimeframe): string {
        return cn(
          'focus-visible:ring-ring rounded px-2.5 py-1 font-mono text-xs transition-colors focus-visible:ring-2 focus-visible:outline-none',
          this.selectedTimeframe() === id
            ? 'bg-primary text-primary-foreground font-semibold shadow-xs'
            : 'text-muted-foreground hover:text-foreground',
        )
      }
    
      statTileClass(idx: number): string {
        return cn(
          'hover:bg-muted/30 focus-visible:ring-ring group relative cursor-pointer p-6 transition-colors focus-visible:ring-2 focus-visible:ring-inset focus-visible:outline-none',
          this.activeStatIndex() === idx ? 'bg-muted/40 ring-primary/30 ring-1 ring-inset' : '',
        )
      }
    
      toggleStat(idx: number): void {
        this.activeStatIndex.set(this.activeStatIndex() === idx ? null : idx)
      }
    
      async copyStatsPayload(): Promise<void> {
        try {
          await navigator.clipboard.writeText(JSON.stringify(stats, null, 2))
          this.copied.set(true)
          clearTimeout(this.copyTimer)
          this.copyTimer = setTimeout(() => this.copied.set(false), 2000)
        } catch {
          // Clipboard unavailable
        }
      }
    }
    
  • src/app/components/blocks/stats-band/index.ts0.1 kB

Raw manifest:https://uipkge.dev/r/angular/stats-band.json