Feature Scroll Spy Walkthrough
blockmarketingStep-by-step 4-phase developer workflow progression with sticky live code terminal sandbox and instant stage inspector.
Installation
$pnpm dlx uipkge-ng@latest add feature-scroll-spy-walkthrough$npx uipkge-ng@latest add feature-scroll-spy-walkthrough$yarn dlx uipkge-ng@latest add feature-scroll-spy-walkthrough$bunx uipkge-ng@latest add feature-scroll-spy-walkthroughManifest:
https://uipkge.dev/r/angular/feature-scroll-spy-walkthrough.jsonInstalls to:src/app/components/blocks/feature-scroll-spy-walkthrough/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.
WalkthroughStepinterface WalkthroughStep {
id: string
stepNumber: string
title: string
subtitle: string
description: string
terminalOutput: string
badgeText: string
meta: string
}npm dependencies
Files installed (2)
src/app/components/blocks/feature-scroll-spy-walkthrough/feature-scroll-spy-walkthrough.component.ts9.1 kB
// 4-phase developer workflow walkthrough: clickable step cards on the left and a // sticky live terminal sandbox on the right with prev/next progression. Port of the // React block 1:1. import { ChangeDetectionStrategy, Component, Input, computed, signal } from '@angular/core' import { LucideAngularModule, Rocket } from 'lucide-angular' import { cn } from '@/lib/utils' import { UiBadgeComponent } from '@/ui/badge/badge.component' import { UiCardComponent } from '@/ui/card/card.component' export interface WalkthroughStep { id: string stepNumber: string title: string subtitle: string description: string terminalOutput: string badgeText: string meta: string } const steps: WalkthroughStep[] = [ { id: 'init', stepNumber: '01', title: 'Initialize Registry Foundation', subtitle: 'Zero configuration Tailwind tokens', description: 'Run the init command to pull OKLCH color palettes, calibrated shadow tokens, spring physics curves, and cn() utility functions into your project.', terminalOutput: `$ npx shadcn@latest add https://uipkge.dev/r/react/init.json -y\n✔ Downloaded styles/tailwind.css (OKLCH tokens)\n✔ Injected lib/utils.ts (cn helper)\n✔ Configured @/ alias path mapping`, badgeText: 'Instant Scaffolding', meta: 'Execution time: 1.4s', }, { id: 'primitives', stepNumber: '02', title: 'Pull Headless Primitives', subtitle: 'Radix UI powered primitives', description: 'Pull accessible, keyboard-friendly primitives like Button, Card, Badge, and Sparklines directly into components/ui/ with full TypeScript type safety.', terminalOutput: `$ npx shadcn@latest add @uipkge/button @uipkge/card -y\n✔ Created components/ui/button/Button.tsx\n✔ Created components/ui/button/button.variants.ts\n✔ Zero npm package dependencies added`, badgeText: 'AST Injection', meta: 'Unbundled & Tree-shaken', }, { id: 'compose', stepNumber: '03', title: 'Compose Rich Workbenches', subtitle: 'Visible markup with zero hidden templates', description: 'Compose tiles, headers, and interactive state directly in your pages. No hidden wrapper abstractions or rigid data prop constraints.', terminalOutput: `// In your React 19 JSX:\nimport { Button } from '@/components/ui/button'\nimport { Card } from '@/components/ui/card'\n\nexport function Workbench() {\n return <Card className="p-6">...</Card>\n}`, badgeText: 'Raw Composition', meta: '100% Code Ownership', }, { id: 'deploy', stepNumber: '04', title: 'Ship to Global Edge', subtitle: 'Zero runtime overhead', description: 'Deploy to Cloudflare, Vercel, or AWS with sub-millisecond cold starts and pristine 100/100 Core Web Vitals performance.', terminalOutput: `$ npm run build\n✔ Client build: 38.4 kB (Gzip: 11.2 kB)\n✔ Lighthouse Performance: 100 / 100\n✔ First Contentful Paint: 0.4s\n🚀 Deployed to Edge CDN`, badgeText: 'Production Ready', meta: 'Zero CSS-in-JS Runtime', }, ] @Component({ changeDetection: ChangeDetectionStrategy.Eager, selector: 'ui-feature-scroll-spy-walkthrough, [ui-feature-scroll-spy-walkthrough]', 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="feature-scroll-spy-walkthrough" [class]="rootClass"> <div class="mx-auto max-w-6xl 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]="Rocket" class="text-primary size-3.5" /> End-to-End Developer Journey </span> <h2 class="text-foreground text-3xl font-bold tracking-tight sm:text-4xl"> From first command to global production in minutes. </h2> <p class="text-muted-foreground text-base"> Follow the 4-stage unbundled workflow that gives your team total freedom and zero maintenance fatigue. </p> </div> <!-- Interactive 2-Column Split: Steps Rail on Left, Sticky Live Sandbox on Right --> <div class="grid grid-cols-1 items-start gap-8 lg:grid-cols-12"> <!-- Left: Step Navigation Cards (5 Cols) --> <div class="space-y-3 lg:col-span-5"> @for (st of allSteps; track st.id; let idx = $index) { <div [class]="stepCardClass(idx)" (click)="activeStepIndex.set(idx)"> <div class="flex items-start gap-4"> <div [class]="stepNumberClass(idx)"> {{ st.stepNumber }} </div> <div class="min-w-0 flex-1 space-y-1"> <div class="flex items-center justify-between"> <h3 class="text-foreground truncate font-mono text-sm font-bold">{{ st.title }}</h3> <span ui-badge variant="outline" class="ml-2 shrink-0 font-mono text-xs"> {{ st.badgeText }} </span> </div> <p class="text-muted-foreground text-xs leading-relaxed">{{ st.description }}</p> </div> </div> </div> } </div> <!-- Right: Sticky Live Sandbox Terminal Display (7 Cols) --> <div ui-card class="border-border bg-card/95 sticky top-24 space-y-6 rounded-2xl p-6 text-left shadow-sm sm:p-8 lg:col-span-7" > <!-- Terminal Header Bar --> <div class="border-border flex items-center justify-between border-b pb-4"> <div class="flex items-center gap-2"> <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> <span class="text-muted-foreground ml-2 font-mono text-xs"> stage_{{ currentStep().stepNumber }}_{{ currentStep().id }}.sh </span> </div> <span ui-badge variant="secondary" class="border-success/20 bg-success/10 text-success font-mono text-xs"> {{ currentStep().meta }} </span> </div> <!-- Code Sandbox Body --> <div class="space-y-2"> <pre class="border-border bg-muted/40 text-foreground overflow-x-auto rounded-xl border p-5 font-mono text-xs leading-relaxed whitespace-pre-wrap" ><code>{{ currentStep().terminalOutput }}</code></pre> </div> <!-- Step Progression Navigator --> <div class="border-border flex items-center justify-between border-t pt-2 font-mono text-xs"> <button type="button" class="text-muted-foreground hover:text-foreground disabled:pointer-events-none disabled:opacity-30" [disabled]="activeStepIndex() === 0" (click)="prevStep()" > ← Previous Step </button> <span class="text-muted-foreground">Step {{ activeStepIndex() + 1 }} of {{ allSteps.length }}</span> <button type="button" class="text-primary font-semibold hover:underline disabled:pointer-events-none disabled:opacity-30" [disabled]="activeStepIndex() === allSteps.length - 1" (click)="nextStep()" > Next Step → </button> </div> </div> </div> </div> </section> `, }) export class UiFeatureScrollSpyWalkthroughComponent { protected readonly Rocket = Rocket protected readonly allSteps = steps @Input() set initialStep(v: number) { if (Number.isInteger(v) && v >= 0 && v < steps.length) this.activeStepIndex.set(v) } @Input('class') className?: string readonly activeStepIndex = signal(0) readonly currentStep = computed(() => steps[this.activeStepIndex()] ?? steps[0]!) 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) } stepCardClass(idx: number): string { return cn( 'group relative cursor-pointer overflow-hidden rounded-2xl border p-5 text-left transition-colors', this.activeStepIndex() === idx ? 'border-primary/80 bg-card ring-primary/20 shadow-lg ring-1' : 'border-border/70 bg-card/40 hover:border-border hover:bg-card/70', ) } stepNumberClass(idx: number): string { return cn( 'flex size-8 shrink-0 items-center justify-center rounded-lg font-mono text-xs font-bold transition-colors', this.activeStepIndex() === idx ? 'bg-primary text-primary-foreground shadow-xs' : 'bg-muted text-muted-foreground', ) } prevStep(): void { this.activeStepIndex.update((i) => Math.max(0, i - 1)) } nextStep(): void { this.activeStepIndex.update((i) => Math.min(steps.length - 1, i + 1)) } }src/app/components/blocks/feature-scroll-spy-walkthrough/index.ts0.1 kB
export { UiFeatureScrollSpyWalkthroughComponent, type WalkthroughStep, } from './feature-scroll-spy-walkthrough.component'
Raw manifest:https://uipkge.dev/r/angular/feature-scroll-spy-walkthrough.json