Feature Comparison Slider
blockmarketingInteractive architecture comparison slider workbench contrasting Monolithic npm packages against UIPKGE unbundled code ownership.
Installation
$pnpm dlx uipkge-ng@latest add feature-comparison-slider$npx uipkge-ng@latest add feature-comparison-slider$yarn dlx uipkge-ng@latest add feature-comparison-slider$bunx uipkge-ng@latest add feature-comparison-sliderManifest:
https://uipkge.dev/r/angular/feature-comparison-slider.jsonInstalls to:src/app/components/blocks/feature-comparison-slider/Variants
Loading interactive previews…
Loading interactive previews…
npm dependencies
Files installed (2)
src/app/components/blocks/feature-comparison-slider/feature-comparison-slider.component.ts9.9 kB
// Interactive architecture comparison workbench contrasting monolithic npm packages against // UIPKGE unbundled code ownership: preset buttons jump the slider, the range input scrubs it, // and the dual split view renders both sides. Port of the React block 1:1. import { ChangeDetectionStrategy, Component, Input, signal } from '@angular/core' import { AlertTriangle, ArrowLeftRight, CheckCircle2, Layers, LucideAngularModule, PackageX } from 'lucide-angular' import { cn } from '@/lib/utils' import { UiBadgeComponent } from '@/ui/badge/badge.component' import { UiButtonComponent } from '@/ui/button/button.component' import { UiCardComponent } from '@/ui/card/card.component' @Component({ changeDetection: ChangeDetectionStrategy.Eager, selector: 'ui-feature-comparison-slider, [ui-feature-comparison-slider]', 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], template: ` <section data-slot="feature-comparison-slider" [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]="ArrowLeftRight" class="text-primary size-3.5" /> Side-by-Side architectural upgrade </span> <h2 class="text-foreground text-3xl font-bold tracking-tight sm:text-4xl"> Monolithic npm packages vs Unbundled code ownership. </h2> <p class="text-muted-foreground text-base"> Drag the slider to compare how UIPKGE eliminates dependency chains, bundle bloat, and breaking semver updates. </p> <!-- Slider Quick Presets --> <div class="flex items-center justify-center gap-2 pt-2"> <button ui-button size="sm" variant="outline" [class]="presetClass(0)" (click)="setPreset(0)"> 100% Monolith </button> <button ui-button size="sm" variant="outline" [class]="presetClass(50)" (click)="setPreset(50)"> 50 / 50 Comparison </button> <button ui-button size="sm" variant="outline" [class]="presetClass(100)" (click)="setPreset(100)"> 100% UIPKGE Registry </button> </div> </div> <!-- Interactive Comparison Container --> <div ui-card class="border-border bg-card relative overflow-hidden rounded-2xl shadow-sm select-none"> <!-- Dual Split View Canvas --> <div class="grid min-h-[460px] grid-cols-1 md:grid-cols-2"> <!-- Left Side: Monolithic Approach --> <div class="bg-destructive/5 border-border flex flex-col justify-between space-y-6 border-b p-6 text-left sm:p-8 md:border-r md:border-b-0" > <div class="space-y-4"> <div class="flex items-center justify-between"> <span ui-badge variant="outline" class="text-destructive bg-destructive/10 border-destructive/20 gap-1.5 font-mono text-xs" > <lucide-icon [img]="PackageX" class="size-3.5" /> Traditional NPM Package </span> <span class="text-muted-foreground font-mono text-xs">Locked in node_modules</span> </div> <h3 class="text-foreground font-mono text-xl font-bold">Black-Box Dependency Hell</h3> <p class="text-muted-foreground text-xs leading-relaxed sm:text-sm"> Monolithic component libraries ship compiled bundles with opaque internals, forcing you to fight CSS specificity and wait months for upstream bug fixes. </p> <!-- Pain Points List --> <ul class="space-y-2.5 pt-2"> <li class="text-muted-foreground flex items-start gap-2 text-xs"> <lucide-icon [img]="AlertTriangle" class="text-destructive mt-0.5 size-4 shrink-0" /> <span><strong>640 kB vendor chunk:</strong> Ships all 80+ unused components to production.</span> </li> <li class="text-muted-foreground flex items-start gap-2 text-xs"> <lucide-icon [img]="AlertTriangle" class="text-destructive mt-0.5 size-4 shrink-0" /> <span ><strong>Breaking semver upgrades:</strong> Upgrading minor versions breaks custom CSS overrides.</span > </li> <li class="text-muted-foreground flex items-start gap-2 text-xs"> <lucide-icon [img]="AlertTriangle" class="text-destructive mt-0.5 size-4 shrink-0" /> <span ><strong>CVE vulnerability surface:</strong> Deep transitive dependency chains trigger security flags.</span > </li> </ul> </div> <div class="border-destructive/20 bg-destructive/10 text-destructive flex items-center justify-between rounded-lg border p-3.5 font-mono text-xs" > <span>Maintenance Overhead</span> <span class="font-bold">High (24 hrs/mo)</span> </div> </div> <!-- Right Side: UIPKGE Unbundled Architecture --> <div class="bg-success/5 flex flex-col justify-between space-y-6 p-6 text-left sm:p-8"> <div class="space-y-4"> <div class="flex items-center justify-between"> <span ui-badge variant="outline" class="border-success/20 bg-success/10 text-success gap-1.5 font-mono text-xs" > <lucide-icon [img]="Layers" class="size-3.5" /> UIPKGE Component Registry </span> <span class="text-success font-mono text-xs font-semibold">100% Owned Source</span> </div> <h3 class="text-foreground font-mono text-xl font-bold">Direct Code Ownership</h3> <p class="text-muted-foreground text-xs leading-relaxed sm:text-sm"> Source files copied directly into your repository. You have absolute control over every token, prop, micro-interaction, and layout shape. </p> <!-- Superpowers List --> <ul class="space-y-2.5 pt-2"> <li class="text-foreground/90 flex items-start gap-2 text-xs"> <lucide-icon [img]="CheckCircle2" class="text-success mt-0.5 size-4 shrink-0" /> <span ><strong>Zero bundle bloat:</strong> Only the exact component files you install exist in your app.</span > </li> <li class="text-foreground/90 flex items-start gap-2 text-xs"> <lucide-icon [img]="CheckCircle2" class="text-success mt-0.5 size-4 shrink-0" /> <span ><strong>Zero breaking updates:</strong> No package updates ever modify your codebase without your consent.</span > </li> <li class="text-foreground/90 flex items-start gap-2 text-xs"> <lucide-icon [img]="CheckCircle2" class="text-success mt-0.5 size-4 shrink-0" /> <span ><strong>Zero CVE risk:</strong> No third-party runtime dependencies or obscure node_modules wrappers.</span > </li> </ul> </div> <div class="border-success/20 bg-success/10 text-success flex items-center justify-between rounded-lg border p-3.5 font-mono text-xs" > <span>Maintenance Overhead</span> <span class="font-bold">Zero (Permanent Stability)</span> </div> </div> </div> <!-- Slider Range Bar at Bottom --> <div class="bg-muted/40 border-border flex items-center gap-4 border-t p-4"> <span class="text-destructive shrink-0 font-mono text-xs">Monolith</span> <input type="range" min="0" max="100" [value]="sliderPosition()" (input)="onSliderInput($event)" aria-label="Comparison slider position" class="accent-primary bg-border h-2 w-full cursor-pointer rounded-lg" /> <span class="text-success shrink-0 font-mono text-xs font-semibold">UIPKGE</span> </div> </div> </div> </section> `, }) export class UiFeatureComparisonSliderComponent { protected readonly AlertTriangle = AlertTriangle protected readonly ArrowLeftRight = ArrowLeftRight protected readonly CheckCircle2 = CheckCircle2 protected readonly Layers = Layers protected readonly PackageX = PackageX @Input() set initialPosition(v: number | undefined) { this.sliderPosition.set(v ?? 50) } @Input('class') className?: string readonly sliderPosition = signal(50) 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) } setPreset(pos: number): void { this.sliderPosition.set(pos) } presetClass(pos: number): string { return cn('font-mono text-xs', this.sliderPosition() === pos && 'border-primary bg-primary/10 text-primary') } onSliderInput(event: Event): void { this.sliderPosition.set(Number((event.target as HTMLInputElement).value)) } }src/app/components/blocks/feature-comparison-slider/index.ts0.1 kB
export { UiFeatureComparisonSliderComponent } from './feature-comparison-slider.component'
Raw manifest:https://uipkge.dev/r/angular/feature-comparison-slider.json