Menu

Change language

GitHub repo

Security — Trust Centre Grid

blockmarketing

Trust centre surface pairing compliance programmes with their audit date, scope, and report link, over a row of operational controls stated as facts rather than claims.

Installation

$npx uipkge-ng@latest add security-trust-center-grid
Manifest:https://uipkge.dev/r/angular/security-trust-center-grid.jsonInstalls to:src/app/components/blocks/security-trust-center-grid/

Variants

Loading interactive previews…

Schema

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

TrustProgramme
interface TrustProgramme {
  name: string
  scope: string
  audited: string
  body: string
}
TrustControl
interface TrustControl {
  icon: typeof Lock
  label: string
  detail: string
}

Files installed (2)

  • src/app/components/blocks/security-trust-center-grid/security-trust-center-grid.component.ts5.8 kB
    // Trust centre surface pairing compliance programmes with their audit date,
    // scope, and report link, over operational controls stated as verifiable facts.
    // Port of the React block 1:1.
    import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
    import {
      ArrowUpRight,
      FileText,
      KeyRound,
      Lock,
      LucideAngularModule,
      ScrollText,
      ServerCog,
      Users,
    } from 'lucide-angular'
    import { cn } from '@/lib/utils'
    import { UiBadgeComponent } from '@/ui/badge/badge.component'
    import { UiButtonComponent } from '@/ui/button/button.component'
    import { UiCardComponent, UiCardContentComponent } from '@/ui/card/card.component'
    import { UiSeparatorComponent } from '@/ui/separator/separator.component'
    
    interface TrustProgramme {
      name: string
      scope: string
      audited: string
      body: string
    }
    
    const programmes: TrustProgramme[] = [
      {
        name: 'SOC 2 Type II',
        scope: 'Security, availability, confidentiality',
        audited: 'Mar 2026',
        body: 'Prescient Assurance',
      },
      { name: 'ISO 27001', scope: 'Information security management', audited: 'Jan 2026', body: 'BSI Group' },
      { name: 'HIPAA', scope: 'PHI handling, BAA available', audited: 'Nov 2025', body: 'Third-party assessed' },
      { name: 'GDPR', scope: 'EU data protection, DPA available', audited: 'Ongoing', body: 'Self-attested' },
    ]
    
    interface TrustControl {
      icon: typeof Lock
      label: string
      detail: string
    }
    
    // Stated as mechanisms, not reassurance: each line is something a reviewer can
    // verify rather than a claim about intent.
    const controls: TrustControl[] = [
      { icon: Lock, label: 'Read-only warehouse access', detail: 'No write grant is ever requested.' },
      { icon: KeyRound, label: 'Customer-managed keys', detail: 'Rotation handled through your KMS.' },
      { icon: Users, label: 'SCIM deprovisioning', detail: 'Access ends with the directory record.' },
      { icon: ScrollText, label: 'Immutable audit log', detail: 'Append-only, exportable, 7-year retention.' },
      { icon: ServerCog, label: 'Regional isolation', detail: 'EU, US, and AU estates do not share planes.' },
      { icon: FileText, label: 'Published subprocessors', detail: 'Change notice 30 days before it takes effect.' },
    ]
    
    @Component({
      changeDetection: ChangeDetectionStrategy.Eager,
      selector: 'ui-security-trust-center-grid, [ui-security-trust-center-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,
        UiButtonComponent,
        UiCardComponent,
        UiCardContentComponent,
        UiSeparatorComponent,
      ],
      template: `
        <section data-slot="security-trust-center-grid" [class]="rootClass">
          <div class="mx-auto max-w-6xl px-6 py-20 lg:py-28">
            <div class="flex flex-wrap items-end justify-between gap-6">
              <div class="max-w-2xl">
                <span ui-badge variant="secondary">Trust</span>
                <h2 class="mt-4 text-3xl font-semibold tracking-tight sm:text-4xl">What we can show you, with dates</h2>
                <p class="text-muted-foreground mt-3 text-lg">
                  Reports are available under NDA. Everything below names who audited it and when.
                </p>
              </div>
              <button ui-button variant="outline">Open the trust centre</button>
            </div>
    
            <div class="mt-10 grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
              @for (programme of programmes; track programme.name) {
                <div ui-card class="group">
                  <div ui-card-content class="flex h-full flex-col p-5">
                    <p class="text-sm font-semibold">{{ programme.name }}</p>
                    <p class="text-muted-foreground mt-2 text-xs leading-relaxed">{{ programme.scope }}</p>
                    <ui-separator class="my-4" />
                    <dl class="space-y-1.5 text-xs">
                      <div class="flex items-center justify-between gap-3">
                        <dt class="text-muted-foreground">Audited</dt>
                        <dd class="font-medium">{{ programme.audited }}</dd>
                      </div>
                      <div class="flex items-center justify-between gap-3">
                        <dt class="text-muted-foreground">By</dt>
                        <dd class="truncate font-medium">{{ programme.body }}</dd>
                      </div>
                    </dl>
                    <button ui-button variant="ghost" size="sm" class="mt-auto justify-start px-0 pt-4 text-xs">
                      Request report
                      <lucide-icon
                        [img]="ArrowUpRight"
                        class="ml-1 size-3 transition-transform group-hover:translate-x-0.5 group-hover:-translate-y-0.5"
                        aria-hidden="true"
                      />
                    </button>
                  </div>
                </div>
              }
            </div>
    
            <ui-separator class="my-10" />
    
            <ul class="grid gap-x-10 gap-y-6 sm:grid-cols-2 lg:grid-cols-3">
              @for (control of controls; track control.label) {
                <li class="flex gap-3">
                  <lucide-icon
                    [img]="control.icon"
                    class="text-muted-foreground mt-0.5 size-4 shrink-0"
                    aria-hidden="true"
                  />
                  <div class="min-w-0">
                    <p class="text-sm font-medium">{{ control.label }}</p>
                    <p class="text-muted-foreground mt-0.5 text-xs leading-relaxed">{{ control.detail }}</p>
                  </div>
                </li>
              }
            </ul>
          </div>
        </section>
      `,
    })
    export class UiSecurityTrustCenterGridComponent {
      protected readonly ArrowUpRight = ArrowUpRight
      protected readonly programmes = programmes
      protected readonly controls = controls
    
      @Input('class') className?: string
    
      get rootClass(): string {
        return cn('bg-background', this.className)
      }
    }
    
  • src/app/components/blocks/security-trust-center-grid/index.ts0.1 kB

Raw manifest:https://uipkge.dev/r/angular/security-trust-center-grid.json