Menu

Change language

GitHub repo

Hero Saas Metrics Dashboard

blockmarketing

High-impact SaaS hero section with interactive timeframe filtering, live revenue and workload KPIs, and dynamic telemetry area chart.

Installation

$npx uipkge-ng@latest add hero-saas-metrics-dashboard
Manifest:https://uipkge.dev/r/angular/hero-saas-metrics-dashboard.jsonInstalls to:src/app/components/blocks/hero-saas-metrics-dashboard/

Variants

Loading interactive previews…

Schema

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

SaasMetricData
interface SaasMetricData {
  mrr: string
  growth: string
  activeUsers: string
  requests: string
  chartPoints: number[]
}

npm dependencies

Theming

CSS custom properties referenced in this item. Override any of them in your :root or per-element to retheme.

--primary

Files installed (2)

  • src/app/components/blocks/hero-saas-metrics-dashboard/hero-saas-metrics-dashboard.component.ts11.2 kB
    // High-impact SaaS hero with interactive timeframe filtering, live revenue and
    // workload KPIs, and a dynamic telemetry area chart. Port of the React block 1:1.
    import { ChangeDetectionStrategy, Component, Input, computed, signal } from '@angular/core'
    import { ArrowRight, CheckCircle2, LucideAngularModule, Play, ShieldCheck, TrendingUp } 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 SaasMetricsTimeframe = 'live' | '24h' | '7d' | '30d'
    
    export interface SaasMetricData {
      mrr: string
      growth: string
      activeUsers: string
      requests: string
      chartPoints: number[]
    }
    
    const metricsByTimeframe: Record<SaasMetricsTimeframe, SaasMetricData> = {
      live: {
        mrr: '$148,920',
        growth: '+24.6%',
        activeUsers: '14,280',
        requests: '1.42M/min',
        chartPoints: [28, 42, 36, 54, 48, 62, 78, 70, 85, 92, 88, 98],
      },
      '24h': {
        mrr: '$146,800',
        growth: '+18.2%',
        activeUsers: '42,100',
        requests: '84.6M',
        chartPoints: [35, 38, 45, 52, 50, 68, 64, 75, 82, 80, 89, 94],
      },
      '7d': {
        mrr: '$139,400',
        growth: '+31.4%',
        activeUsers: '185,400',
        requests: '592M',
        chartPoints: [20, 28, 35, 42, 55, 60, 72, 68, 80, 85, 90, 100],
      },
      '30d': {
        mrr: '$124,100',
        growth: '+44.1%',
        activeUsers: '490,000',
        requests: '2.4B',
        chartPoints: [15, 22, 30, 38, 48, 58, 65, 74, 82, 88, 94, 105],
      },
    }
    
    const timeframes: SaasMetricsTimeframe[] = ['live', '24h', '7d', '30d']
    
    @Component({
      changeDetection: ChangeDetectionStrategy.Eager,
      selector: 'ui-hero-saas-metrics-dashboard, [ui-hero-saas-metrics-dashboard]',
      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="hero-saas-metrics-dashboard" [class]="rootClass">
          <!-- Radial Glow Background -->
          <div
            class="bg-primary/10 pointer-events-none absolute top-0 left-1/2 -z-10 h-80 w-full max-w-6xl -translate-x-1/2 rounded-full blur-xl"
          ></div>
    
          <div class="mx-auto max-w-6xl space-y-12 text-center">
            <!-- Header Copy -->
            <div class="mx-auto max-w-3xl space-y-5">
              <span ui-badge variant="secondary" class="gap-1.5 px-3 py-1 font-mono text-xs shadow-xs">
                <lucide-icon [img]="TrendingUp" class="text-primary size-3.5" />
                Enterprise Revenue & Event Intelligence
              </span>
    
              <h1 class="text-foreground text-4xl leading-[1.12] font-bold tracking-tight sm:text-5xl lg:text-6xl">
                Real-time telemetry for modern engineering teams.
              </h1>
    
              <p class="text-muted-foreground text-base leading-relaxed sm:text-lg">
                Monitor revenue acceleration, API transaction throughput, and compute workloads with sub-millisecond
                precision.
              </p>
    
              <!-- CTA Action Buttons -->
              <div class="flex flex-wrap items-center justify-center gap-3 pt-2">
                <a ui-button size="lg" href="#start" class="gap-2 font-semibold shadow-xs">
                  <span>Start Free Sandbox</span>
                  <lucide-icon [img]="ArrowRight" class="size-4" />
                </a>
    
                <a ui-button variant="outline" size="lg" href="#demo" class="gap-2 font-medium">
                  <lucide-icon [img]="Play" class="size-3.5 fill-current" />
                  <span>Interactive Demo</span>
                </a>
              </div>
    
              <div class="text-muted-foreground flex items-center justify-center gap-6 pt-2 font-mono text-xs">
                <span class="inline-flex items-center gap-1.5">
                  <lucide-icon [img]="ShieldCheck" class="text-success size-4" /> SOC2 Type II Certified
                </span>
                <span class="inline-flex items-center gap-1.5">
                  <lucide-icon [img]="CheckCircle2" class="text-primary size-4" /> 99.95% SLA Uptime
                </span>
              </div>
            </div>
    
            <!-- Interactive SaaS Dashboard Preview Card -->
            <div class="relative mx-auto max-w-5xl">
              <div ui-card class="border-border bg-card overflow-hidden rounded-2xl text-left shadow-sm">
                <!-- Mock Window Top Bar -->
                <div class="border-border bg-muted/40 flex items-center justify-between border-b px-4 py-3">
                  <div class="flex items-center gap-3">
                    <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-foreground font-mono text-xs font-medium">console.uipkge.dev/production</span>
                  </div>
    
                  <!-- Timeframe Filter Tabs -->
                  <div class="bg-background border-border flex items-center gap-1 rounded-lg border p-0.5">
                    @for (tf of timeframeList; track tf) {
                      <button type="button" [class]="timeframeTabClass(tf)" (click)="setTimeframe(tf)">
                        {{ tf }}
                      </button>
                    }
                  </div>
                </div>
    
                <!-- Dashboard Metric Cards Grid -->
                <div class="space-y-6 p-6 sm:p-8">
                  <div class="grid grid-cols-1 gap-4 sm:grid-cols-3">
                    <!-- MRR Card -->
                    <div class="border-border bg-background/50 space-y-1 rounded-xl border p-4">
                      <div class="text-muted-foreground flex items-center justify-between text-xs">
                        <span class="font-mono">Recurring Revenue</span>
                        <span
                          ui-badge
                          variant="outline"
                          class="border-success/20 bg-success/10 text-success font-mono text-xs"
                        >
                          {{ activeMetric().growth }}
                        </span>
                      </div>
                      <p class="text-foreground font-mono text-2xl font-bold">{{ activeMetric().mrr }}</p>
                      <p class="text-muted-foreground text-xs">Calculated across active subscriptions</p>
                    </div>
    
                    <!-- Active Workloads Card -->
                    <div class="border-border bg-background/50 space-y-1 rounded-xl border p-4">
                      <div class="text-muted-foreground flex items-center justify-between text-xs">
                        <span class="font-mono">Active Nodes & Pods</span>
                        <span class="bg-success size-2 rounded-full"></span>
                      </div>
                      <p class="text-foreground font-mono text-2xl font-bold">{{ activeMetric().activeUsers }}</p>
                      <p class="text-muted-foreground text-xs">Distributed across 8 global regions</p>
                    </div>
    
                    <!-- Request Throughput Card -->
                    <div class="border-border bg-background/50 space-y-1 rounded-xl border p-4">
                      <div class="text-muted-foreground flex items-center justify-between text-xs">
                        <span class="font-mono">Throughput</span>
                        <lucide-icon [img]="TrendingUp" class="text-primary size-3.5" />
                      </div>
                      <p class="text-foreground font-mono text-2xl font-bold">{{ activeMetric().requests }}</p>
                      <p class="text-muted-foreground text-xs">Edge cached queries & websocket streams</p>
                    </div>
                  </div>
    
                  <!-- Interactive Area Trend Chart -->
                  <div class="border-border bg-background/30 space-y-3 rounded-xl border p-5">
                    <div class="flex items-center justify-between">
                      <div>
                        <p class="text-muted-foreground font-mono text-xs uppercase">Transaction Velocity & Event Stream</p>
                        <p class="text-foreground text-sm font-semibold">Global Ingestion Rate</p>
                      </div>
                      <span class="text-success font-mono text-xs font-medium">99.998% Success</span>
                    </div>
    
                    <!-- SVG Area Chart -->
                    <div class="relative h-28 w-full overflow-hidden">
                      <svg
                        class="h-full w-full"
                        viewBox="0 0 500 120"
                        preserveAspectRatio="none"
                        role="img"
                        aria-label="Transaction velocity trend chart"
                      >
                        <defs>
                          <linearGradient id="chartGlow" x1="0" y1="0" x2="0" y2="1">
                            <stop offset="0%" stop-color="var(--primary)" stop-opacity="0.35" />
                            <stop offset="100%" stop-color="var(--primary)" stop-opacity="0.0" />
                          </linearGradient>
                        </defs>
                        <!-- Gradient Area -->
                        <path [attr.d]="chartAreaPath()" fill="url(#chartGlow)" />
                        <!-- Stroke Line -->
                        <path
                          [attr.d]="chartSvgPath()"
                          fill="none"
                          stroke="var(--primary)"
                          stroke-width="2.5"
                          stroke-linecap="round"
                        />
                      </svg>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </section>
      `,
    })
    export class UiHeroSaasMetricsDashboardComponent {
      protected readonly ArrowRight = ArrowRight
      protected readonly CheckCircle2 = CheckCircle2
      protected readonly Play = Play
      protected readonly ShieldCheck = ShieldCheck
      protected readonly TrendingUp = TrendingUp
    
      protected readonly timeframeList = timeframes
    
      @Input('class') className?: string
    
      readonly activeTimeframe = signal<SaasMetricsTimeframe>('live')
    
      readonly activeMetric = computed(() => metricsByTimeframe[this.activeTimeframe()])
    
      readonly chartSvgPath = computed(() => {
        const points = this.activeMetric().chartPoints
        const width = 500
        const height = 120
        const max = Math.max(...points)
        const min = Math.min(...points)
        const range = max - min || 1
    
        return points
          .map((val, idx) => {
            const x = (idx / (points.length - 1)) * width
            const y = height - ((val - min) / range) * (height - 20) - 10
            return `${idx === 0 ? 'M' : 'L'} ${x.toFixed(1)} ${y.toFixed(1)}`
          })
          .join(' ')
      })
    
      readonly chartAreaPath = computed(() => `${this.chartSvgPath()} L 500 120 L 0 120 Z`)
    
      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)
      }
    
      timeframeTabClass(tf: SaasMetricsTimeframe): string {
        return cn(
          'rounded-md px-2.5 py-1 font-mono text-xs uppercase transition-[color,background-color,transform] duration-150 active:scale-95 focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none',
          this.activeTimeframe() === tf
            ? 'bg-primary text-primary-foreground font-semibold shadow-xs'
            : 'text-muted-foreground hover:text-foreground',
        )
      }
    
      setTimeframe(tf: SaasMetricsTimeframe): void {
        this.activeTimeframe.set(tf)
      }
    }
    
  • src/app/components/blocks/hero-saas-metrics-dashboard/index.ts0.1 kB

Raw manifest:https://uipkge.dev/r/angular/hero-saas-metrics-dashboard.json