How It Works — Arrow Flow
blockmarketingFour-stage horizontal flow joined by drawn SVG arrows, each stage carrying an icon tile, a short label, and the artefact it produces, wrapping to a vertical rail on narrow screens.
Installation
$pnpm dlx uipkge-ng@latest add how-it-works-arrow-flow$npx uipkge-ng@latest add how-it-works-arrow-flow$yarn dlx uipkge-ng@latest add how-it-works-arrow-flow$bunx uipkge-ng@latest add how-it-works-arrow-flowManifest:
https://uipkge.dev/r/angular/how-it-works-arrow-flow.jsonInstalls to:src/app/components/blocks/how-it-works-arrow-flow/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.
HowItWorksStageinterface HowItWorksStage {
icon: LucideIconData
label: string
body: string
artefact: string
}npm dependencies
Files installed (2)
src/app/components/blocks/how-it-works-arrow-flow/how-it-works-arrow-flow.component.ts4.1 kB
// Four-stage horizontal flow joined by arrows, each stage carrying an icon tile, // a label and the artefact it produces; wraps to a vertical rail on narrow // screens. Port of the React block 1:1. import { ChangeDetectionStrategy, Component, Input } from '@angular/core' import { ArrowRight, Boxes, FileCheck, GitPullRequest, LucideAngularModule, Send, type LucideIconData, } 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' interface HowItWorksStage { icon: LucideIconData label: string body: string artefact: string } const stages: HowItWorksStage[] = [ { icon: Boxes, label: 'Connect', body: 'Read-only credentials to the warehouse.', artefact: 'Schema mirror' }, { icon: GitPullRequest, label: 'Define', body: 'Metrics authored as reviewable files.', artefact: 'Merged PR' }, { icon: FileCheck, label: 'Certify', body: 'Reconciled against the prior quarters.', artefact: 'Sign-off' }, { icon: Send, label: 'Publish', body: 'Rolled out to every consumer at once.', artefact: 'Live metric' }, ] @Component({ changeDetection: ChangeDetectionStrategy.Eager, selector: 'ui-how-it-works-arrow-flow, [ui-how-it-works-arrow-flow]', 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], template: ` <section data-slot="how-it-works-arrow-flow" [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">The flow</span> <h2 class="mt-4 text-3xl font-semibold tracking-tight sm:text-4xl">Four stages, one artefact each</h2> <p class="text-muted-foreground mt-3 text-lg"> Every stage ends in something you can point at, so progress is never a status update. </p> </div> <!-- Arrows sit between cells rather than inside cards, so they stay put when a card's copy runs longer. Below md the row becomes a rail. --> <div class="mt-12 grid gap-4 md:grid-cols-[1fr_auto_1fr_auto_1fr_auto_1fr] md:items-stretch md:gap-0"> @for (stage of stageList; track stage.label; let index = $index) { <div class="flex items-center gap-4 md:contents"> <div ui-card class="flex-1 md:h-full"> <div ui-card-content class="p-5"> <span class="border-border text-muted-foreground flex size-9 items-center justify-center rounded-lg border" aria-hidden="true" > <lucide-icon [img]="stage.icon" class="size-4" /> </span> <p class="mt-4 text-sm font-semibold">{{ stage.label }}</p> <p class="text-muted-foreground mt-1.5 text-xs leading-relaxed">{{ stage.body }}</p> <p class="text-muted-foreground/80 mt-3 font-mono text-xs tracking-wide uppercase"> → {{ stage.artefact }} </p> </div> </div> </div> @if (index < stageList.length - 1) { <div class="text-muted-foreground/50 hidden items-center justify-center px-2 md:flex" aria-hidden="true"> <lucide-icon [img]="ArrowRight" class="size-4" /> </div> } } </div> <div class="mt-10"> <button ui-button variant="outline"> Walk through a real rollout <lucide-icon [img]="ArrowRight" class="ml-2 size-4" aria-hidden="true" /> </button> </div> </div> </section> `, }) export class UiHowItWorksArrowFlowComponent { protected readonly ArrowRight = ArrowRight protected readonly stageList = stages @Input('class') className?: string get rootClass(): string { return cn('bg-background', this.className) } }src/app/components/blocks/how-it-works-arrow-flow/index.ts0.1 kB
export { UiHowItWorksArrowFlowComponent } from './how-it-works-arrow-flow.component'
Raw manifest:https://uipkge.dev/r/angular/how-it-works-arrow-flow.json