Menu

Change language

GitHub repo

Feature Comparison Slider

blockmarketing

Interactive architecture comparison slider workbench contrasting Monolithic npm packages against UIPKGE unbundled code ownership.

Installation

$npx uipkge-ng@latest add feature-comparison-slider
Manifest:https://uipkge.dev/r/angular/feature-comparison-slider.jsonInstalls to:src/app/components/blocks/feature-comparison-slider/

Variants

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

Raw manifest:https://uipkge.dev/r/angular/feature-comparison-slider.json