Integrations — Featured Pairs
blockmarketingThree promoted integrations, each a card pairing the service with what the connection actually does, the three setup steps it takes, and its live connection state.
Installation
$pnpm dlx uipkge-ng@latest add integrations-featured-pairs$npx uipkge-ng@latest add integrations-featured-pairs$yarn dlx uipkge-ng@latest add integrations-featured-pairs$bunx uipkge-ng@latest add integrations-featured-pairsManifest:
https://uipkge.dev/r/angular/integrations-featured-pairs.jsonInstalls to:src/app/components/blocks/integrations-featured-pairs/Variants
Loading interactive previews…
Loading interactive previews…
Schema
Type aliases exported from this item's source. Use these to shape the data you pass in.
FeaturedIntegrationinterface FeaturedIntegration {
mark: string
name: string
summary: string
steps: string[]
status: string
healthy: boolean
meta: string
}npm dependencies
Files installed (2)
src/app/components/blocks/integrations-featured-pairs/integrations-featured-pairs.component.ts5.5 kB
// Three promoted integrations, each a card pairing the service with what the // connection actually does, the three setup steps it takes, and its live // connection state. Port of the React block 1:1. import { ChangeDetectionStrategy, Component, Input } from '@angular/core' import { ArrowRight, Check, LucideAngularModule, Plug } 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 FeaturedIntegration { mark: string name: string summary: string steps: string[] status: string healthy: boolean meta: string } const featured: FeaturedIntegration[] = [ { mark: 'SF', name: 'Snowflake', summary: 'Query your warehouse directly. Metrics resolve against live tables instead of a nightly copy.', steps: ['Create a read-only role', 'Paste the account URL', 'Pick the databases to expose'], status: 'Connected', healthy: true, meta: 'Read-only · no data egress', }, { mark: 'OK', name: 'Okta', summary: 'Group membership drives row-level scope, so access changes the moment HR changes it.', steps: ['Add the SAML app', 'Enable SCIM provisioning', 'Map groups to scopes'], status: 'Connected', healthy: true, meta: 'SAML + SCIM', }, { mark: 'SL', name: 'Slack', summary: 'Drift and freshness alerts land in the channel that owns the metric, with the run attached.', steps: ['Install the app', 'Choose default channels', 'Route alerts per metric owner'], status: 'Needs re-auth', healthy: false, meta: 'Token expires every 90 days', }, ] @Component({ changeDetection: ChangeDetectionStrategy.Eager, selector: 'ui-integrations-featured-pairs, [ui-integrations-featured-pairs]', 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="integrations-featured-pairs" [class]="rootClass"> <div class="mx-auto max-w-6xl px-6 py-20 lg:py-28"> <div class="max-w-2xl"> <span ui-badge variant="secondary">Featured integrations</span> <h2 class="mt-4 text-3xl font-semibold tracking-tight sm:text-4xl">The three most teams connect first</h2> <p class="text-muted-foreground mt-3 text-lg"> Each one is three steps and read-only. What the connection actually does is written on the card. </p> </div> <div class="mt-10 grid gap-4 md:grid-cols-3"> @for (integration of featured; track integration.name) { <div ui-card> <div ui-card-content class="flex h-full flex-col p-6"> <div class="flex items-center gap-3"> <span class="border-border text-muted-foreground flex size-10 items-center justify-center rounded-lg border font-mono text-sm font-semibold" aria-hidden="true" > {{ integration.mark }} </span> <div class="min-w-0"> <p class="truncate text-sm font-semibold">{{ integration.name }}</p> <p class="text-muted-foreground truncate text-xs">{{ integration.meta }}</p> </div> </div> <p class="text-muted-foreground mt-4 text-sm leading-relaxed">{{ integration.summary }}</p> <ui-separator class="my-5" /> <p class="text-muted-foreground font-mono text-xs tracking-[0.14em] uppercase">Setup</p> <ol class="mt-3 space-y-2"> @for (step of integration.steps; track step; let i = $index) { <li class="text-foreground flex items-start gap-2.5 text-sm"> <span class="text-muted-foreground/70 mt-px font-mono text-xs">{{ i + 1 }}</span> <span>{{ step }}</span> </li> } </ol> <div class="mt-auto flex items-center justify-between gap-3 pt-6"> <span ui-badge [variant]="integration.healthy ? 'secondary' : 'outline'" class="gap-1.5"> @if (integration.healthy) { <lucide-icon [img]="Check" class="size-3" aria-hidden="true" /> } @else { <lucide-icon [img]="Plug" class="size-3" aria-hidden="true" /> } {{ integration.status }} </span> <button ui-button variant="ghost" size="sm" class="h-auto px-2 py-1"> Docs <lucide-icon [img]="ArrowRight" class="ml-1 size-3.5" aria-hidden="true" /> </button> </div> </div> </div> } </div> </div> </section> `, }) export class UiIntegrationsFeaturedPairsComponent { protected readonly ArrowRight = ArrowRight protected readonly Check = Check protected readonly Plug = Plug protected readonly featured = featured @Input('class') className?: string get rootClass(): string { return cn('bg-background', this.className) } }src/app/components/blocks/integrations-featured-pairs/index.ts0.1 kB
export { UiIntegrationsFeaturedPairsComponent } from './integrations-featured-pairs.component'
Raw manifest:https://uipkge.dev/r/angular/integrations-featured-pairs.json