Menu

Change language

GitHub repo

Logo Cloud Categorized Grid

blockmarketing

Categorized 4-industry logo & enterprise customer workbench with scale metrics, category filter tabs, and full testimonial modal inspect.

Installation

$npx uipkge-ng@latest add logo-cloud-categorized-grid
Manifest:https://uipkge.dev/r/angular/logo-cloud-categorized-grid.jsonInstalls to:src/app/components/blocks/logo-cloud-categorized-grid/

Variants

Loading interactive previews…

Schema

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

CategorizedCustomer
interface CategorizedCustomer {
  id: string
  name: string
  category: 'cloud' | 'devtools' | 'fintech' | 'ai'
  tier: string
  scale: string
  quote: string
  author: string
  title: string
}
CategoryOption
interface CategoryOption {
  key: LogoCloudCategory
  label: string
  icon: typeof Globe
}

npm dependencies

Includes

Files installed (2)

  • src/app/components/blocks/logo-cloud-categorized-grid/logo-cloud-categorized-grid.component.ts13.1 kB
    // Categorized 4-industry logo & enterprise customer workbench with scale metrics,
    // category filter tabs, and a full testimonial modal inspect. Port of the
    // Vue/React block 1:1 — click a card to open its quote, filter tabs narrow the grid.
    import { ChangeDetectionStrategy, Component, Input, computed, signal } from '@angular/core'
    import {
      ArrowRight,
      Brain,
      Building2,
      Cloud,
      Globe,
      LucideAngularModule,
      Quote,
      ShieldCheck,
      Terminal,
      X,
    } from 'lucide-angular'
    import { cn } from '@/lib/utils'
    import { UiBadgeComponent } from '@/ui/badge/badge.component'
    import { UiCardComponent } from '@/ui/card/card.component'
    
    export interface CategorizedCustomer {
      id: string
      name: string
      category: 'cloud' | 'devtools' | 'fintech' | 'ai'
      tier: string
      scale: string
      quote: string
      author: string
      title: string
    }
    
    export type LogoCloudCategory = 'all' | 'cloud' | 'devtools' | 'fintech' | 'ai'
    
    const customerList: CategorizedCustomer[] = [
      // Infrastructure & Cloud
      {
        id: 'cloudflare',
        name: 'Cloudflare',
        category: 'cloud',
        tier: 'Enterprise Scale',
        scale: '300+ Edge Data Centers',
        quote:
          'UIPKGE allowed us to standardize our internal console UI across 40+ engineering squads with zero bundle overhead.',
        author: 'Alex K.',
        title: 'Principal Architect, Cloudflare Workers',
      },
      {
        id: 'flyio',
        name: 'Fly.io',
        category: 'cloud',
        tier: 'Core Partner',
        scale: '50k+ Compute Machines',
        quote: 'We copy the raw SFC components and style them directly to match our brand — no package upgrades to fight.',
        author: 'Sam T.',
        title: 'Lead Frontend Engineer',
      },
      {
        id: 'railway',
        name: 'Railway',
        category: 'cloud',
        tier: 'Growth Tier',
        scale: '1.5M Deployed Services',
        quote:
          'AST-level source control gives our team complete confidence without ever fearing breaking upstream package releases.',
        author: 'Elena R.',
        title: 'VP of Product Experience',
      },
    
      // Developer Tooling
      {
        id: 'vercel',
        name: 'Vercel',
        category: 'devtools',
        tier: 'Design Pioneer',
        scale: '100M+ Monthly Visitors',
        quote:
          'The level of keyboard ergonomics, focus ring layering, and spring physics in UIPKGE meets the highest craft benchmarks.',
        author: 'Rauno F.',
        title: 'Design Engineering Advisor',
      },
      {
        id: 'supabase',
        name: 'Supabase',
        category: 'devtools',
        tier: 'Ecosystem Partner',
        scale: '1M+ Databases Provisioned',
        quote: 'Dual-framework parity means we can ship both Vue and React examples for our developer docs in minutes.',
        author: 'Ant W.',
        title: 'Co-Founder & CEO',
      },
      {
        id: 'biome',
        name: 'BiomeJS',
        category: 'devtools',
        tier: 'Open Source',
        scale: '20M+ Weekly Downloads',
        quote: 'The cleanest AST code patterns in any modern UI registry. 100% type-safe.',
        author: 'Nico M.',
        title: 'Core Maintainer',
      },
    
      // Fintech & Security
      {
        id: 'stripe',
        name: 'Stripe',
        category: 'fintech',
        tier: 'Global Infrastructure',
        scale: '$1T+ Payment Volume',
        quote:
          'Zero dependency bloat guarantees compliance with strict internal security and dependency auditing requirements.',
        author: 'Marcus H.',
        title: 'Staff Security Engineer',
      },
      {
        id: 'ramp',
        name: 'Ramp',
        category: 'fintech',
        tier: 'Scale Unicorn',
        scale: '$10B+ Managed Spend',
        quote: 'The dense KPI tiles and transaction workbenches are plug-and-play masterpieces.',
        author: 'David P.',
        title: 'Director of Frontend Engineering',
      },
      {
        id: 'snyk',
        name: 'Snyk Security',
        category: 'fintech',
        tier: 'Enterprise SecOps',
        scale: '2.5M+ Repos Scanned',
        quote: 'Owning the source code completely removes transitive dependency CVE vulnerabilities.',
        author: 'Sarah L.',
        title: 'Head of Developer Relations',
      },
    
      // AI & Machine Learning
      {
        id: 'replicate',
        name: 'Replicate',
        category: 'ai',
        tier: 'AI Infrastructure',
        scale: '500M+ Model Inferences',
        quote: 'We built our interactive prompt tester in an afternoon using UIPKGE terminal and slider primitives.',
        author: 'Ben F.',
        title: 'Co-Founder',
      },
      {
        id: 'modal',
        name: 'Modal Labs',
        category: 'ai',
        tier: 'GPU Cloud',
        scale: '10k+ GPU Clusters',
        quote: 'The tactile feel and speed of the UI blocks matches the lightning speed of our Python container runs.',
        author: 'Erik B.',
        title: 'Co-Founder & CTO',
      },
      {
        id: 'mistral',
        name: 'Mistral AI',
        category: 'ai',
        tier: 'Frontier AI',
        scale: 'Global Deployment',
        quote: 'Phenomenal attention to typographic hierarchy and clean Geist font metrics.',
        author: 'Arthur M.',
        title: 'Co-Founder',
      },
    ]
    
    interface CategoryOption {
      key: LogoCloudCategory
      label: string
      icon: typeof Globe
    }
    
    const categoryOptions: CategoryOption[] = [
      { key: 'all', label: 'All Industries', icon: Globe },
      { key: 'cloud', label: 'Cloud & Infra', icon: Cloud },
      { key: 'devtools', label: 'DevTools & DX', icon: Terminal },
      { key: 'fintech', label: 'Fintech & Security', icon: ShieldCheck },
      { key: 'ai', label: 'AI & GPU Compute', icon: Brain },
    ]
    
    @Component({
      changeDetection: ChangeDetectionStrategy.Eager,
      selector: 'ui-logo-cloud-categorized-grid, [ui-logo-cloud-categorized-grid]',
      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, UiCardComponent],
      template: `
        <section data-slot="logo-cloud-categorized-grid" [class]="rootClass">
          <div class="mx-auto max-w-7xl 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]="Building2" class="text-primary size-3.5" />
                Industry Benchmark Customers
              </span>
              <h2 class="text-foreground text-3xl font-bold tracking-tight sm:text-4xl">
                Powering the world's most rigorous engineering organizations.
              </h2>
              <p class="text-muted-foreground text-base">
                From frontier AI labs to global payment platforms, see how top tier engineering teams build on UIPKGE.
              </p>
    
              <!-- Vertical Category Filter Tabs -->
              <div class="flex flex-wrap items-center justify-center gap-1 pt-4">
                @for (option of categories; track option.key) {
                  <button type="button" [class]="filterButtonClass(option.key)" (click)="selectCategory(option.key)">
                    <lucide-icon [img]="option.icon" class="size-3.5" />
                    <span>{{ option.label }}</span>
                  </button>
                }
              </div>
            </div>
    
            <!-- Categorized Customer Grid -->
            <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 sm:gap-6 lg:grid-cols-3">
              @for (customer of filteredCustomers(); track customer.id) {
                <div
                  ui-card
                  class="border-border bg-card/90 hover:border-primary/40 group flex cursor-pointer flex-col justify-between space-y-4 rounded-2xl p-5 shadow-sm transition-colors hover:shadow-md"
                  (click)="openModal(customer)"
                  (keydown.enter)="openModal(customer)"
                  tabindex="0"
                  role="button"
                  [attr.aria-label]="'Read quote from ' + customer.name"
                >
                  <!-- Card Top: Name & Tier Pill -->
                  <div class="flex items-center justify-between">
                    <div class="flex items-center gap-2.5">
                      <div
                        class="bg-primary/10 text-primary flex size-8 items-center justify-center rounded-lg font-mono text-xs font-bold"
                      >
                        {{ customer.name.charAt(0) }}
                      </div>
                      <div>
                        <h3 class="text-foreground group-hover:text-primary font-mono text-sm font-bold transition-colors">
                          {{ customer.name }}
                        </h3>
                        <p class="text-muted-foreground text-xs">{{ customer.scale }}</p>
                      </div>
                    </div>
                    <span ui-badge variant="outline" class="font-mono text-xs capitalize">
                      {{ customer.tier }}
                    </span>
                  </div>
    
                  <!-- Quote Excerpt -->
                  <p class="text-muted-foreground line-clamp-2 text-xs leading-relaxed italic">
                    &ldquo;{{ customer.quote }}&rdquo;
                  </p>
    
                  <!-- Card Footer: Author & Read Case Study -->
                  <div class="border-border/60 flex items-center justify-between border-t pt-2 text-xs">
                    <span class="text-muted-foreground font-mono text-xs">{{ customer.author }}</span>
                    <span class="text-primary flex items-center gap-1 text-xs font-medium group-hover:underline">
                      <span>Read quote</span>
                      <lucide-icon [img]="ArrowRight" class="size-3" />
                    </span>
                  </div>
                </div>
              }
            </div>
    
            <!-- Testimonial Detail Dialog Modal -->
            @if (activeModalCustomer(); as active) {
              <div class="bg-background/80 fixed inset-0 z-50 flex items-center justify-center p-4 backdrop-blur-md sm:p-6">
                <div
                  class="bg-card border-border relative w-full max-w-xl space-y-6 rounded-2xl border p-6 text-left shadow-sm sm:p-8"
                  role="dialog"
                  aria-modal="true"
                  [attr.aria-label]="'Testimonial from ' + active.name"
                >
                  <div class="border-border flex items-center justify-between border-b pb-4">
                    <div class="flex items-center gap-3">
                      <div
                        class="bg-primary/10 text-primary flex size-10 items-center justify-center rounded-xl font-mono text-sm font-bold"
                      >
                        {{ active.name.charAt(0) }}
                      </div>
                      <div>
                        <h3 class="text-foreground font-mono text-base font-bold">{{ active.name }}</h3>
                        <p class="text-muted-foreground font-mono text-xs">{{ active.scale }}</p>
                      </div>
                    </div>
                    <button
                      type="button"
                      class="text-muted-foreground hover:text-foreground hover:bg-muted rounded-md p-1 transition-colors"
                      aria-label="Close testimonial"
                      (click)="closeModal()"
                    >
                      <lucide-icon [img]="X" class="size-4" />
                    </button>
                  </div>
    
                  <div class="space-y-4">
                    <lucide-icon [img]="Quote" class="text-primary/40 size-6" />
                    <p class="text-foreground text-sm leading-relaxed sm:text-base">&ldquo;{{ active.quote }}&rdquo;</p>
                  </div>
    
                  <div
                    class="border-border bg-muted/20 -mx-6 -mb-6 flex items-center justify-between rounded-b-2xl border-t p-4 px-6 pt-4 sm:-mx-8 sm:-mb-8 sm:px-8"
                  >
                    <div>
                      <p class="text-foreground text-xs font-bold">{{ active.author }}</p>
                      <p class="text-muted-foreground font-mono text-xs">{{ active.title }}</p>
                    </div>
                    <span ui-badge variant="outline" class="border-success/20 bg-success/10 text-success font-mono text-xs">
                      Verified Production Customer
                    </span>
                  </div>
                </div>
              </div>
            }
          </div>
        </section>
      `,
    })
    export class UiLogoCloudCategorizedGridComponent {
      protected readonly ArrowRight = ArrowRight
      protected readonly Building2 = Building2
      protected readonly Quote = Quote
      protected readonly X = X
    
      protected readonly categories = categoryOptions
    
      @Input('class') className?: string
      @Input() set initialCategory(v: LogoCloudCategory | undefined) {
        if (v) this.selectedCategory.set(v)
      }
    
      readonly selectedCategory = signal<LogoCloudCategory>('all')
      readonly activeModalCustomer = signal<CategorizedCustomer | null>(null)
    
      readonly filteredCustomers = computed(() => {
        const selected = this.selectedCategory()
        if (selected === 'all') return customerList
        return customerList.filter((c) => c.category === selected)
      })
    
      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)
      }
    
      filterButtonClass(key: LogoCloudCategory): string {
        return cn(
          'flex items-center gap-1.5 rounded-lg border px-3 py-1.5 font-mono text-xs transition-colors',
          this.selectedCategory() === key
            ? 'border-primary bg-primary text-primary-foreground font-semibold shadow-xs'
            : 'border-border bg-card/60 text-muted-foreground hover:text-foreground hover:bg-muted',
        )
      }
    
      selectCategory(key: LogoCloudCategory): void {
        this.selectedCategory.set(key)
      }
    
      openModal(customer: CategorizedCustomer): void {
        this.activeModalCustomer.set(customer)
      }
    
      closeModal(): void {
        this.activeModalCustomer.set(null)
      }
    }
    
  • src/app/components/blocks/logo-cloud-categorized-grid/index.ts0.1 kB

Raw manifest:https://uipkge.dev/r/angular/logo-cloud-categorized-grid.json