Menu

Change language

GitHub repo

Changelog Release Notes Timeline

blockmarketing

Developer changelog timeline with interactive version filters, categorical changes (features, improvements, fixes), and commit hash links.

Installation

$npx uipkge-ng@latest add changelog-release-notes-timeline
Manifest:https://uipkge.dev/r/angular/changelog-release-notes-timeline.jsonInstalls to:src/app/components/blocks/changelog-release-notes-timeline/

Variants

Loading interactive previews…

Schema

Type aliases exported from this item's source. Use these to shape the data you pass in.

ChangelogTimelineEntry
interface ChangelogTimelineEntry {
  version: string
  date: string
  title: string
  description: string
  commitHash: string
  isLatest?: boolean
  features: string[]
  improvements: string[]
  fixes: string[]
}

npm dependencies

Includes

Files installed (2)

  • src/app/components/blocks/changelog-release-notes-timeline/changelog-release-notes-timeline.component.ts11.3 kB
    // Developer changelog timeline with interactive version filters, categorical changes
    // (features, improvements, fixes), and commit hash links. Port of the React block 1:1.
    import { ChangeDetectionStrategy, Component, Input, computed, signal } from '@angular/core'
    import { Calendar, CheckCircle2, GitCommit, History, Layers, LucideAngularModule, Wrench, Zap } from 'lucide-angular'
    import { cn } from '@/lib/utils'
    import { UiBadgeComponent } from '@/ui/badge/badge.component'
    import { UiCardComponent } from '@/ui/card/card.component'
    
    export interface ChangelogTimelineEntry {
      version: string
      date: string
      title: string
      description: string
      commitHash: string
      isLatest?: boolean
      features: string[]
      improvements: string[]
      fixes: string[]
    }
    
    const entries: ChangelogTimelineEntry[] = [
      {
        version: 'v2.4.0',
        date: 'August 2026',
        title: 'Marketing Blocks Expansion & Tailwind CSS v4 OKLCH Engine',
        description:
          'Massive expansion introducing 75+ unbundled marketing blocks with zero sub-12px microtext, dual-framework AST parity, and interactive functional workbenches.',
        commitHash: '926c404',
        isLatest: true,
        features: [
          'Interactive Hero Sandboxes with live framework and theme preview tabs.',
          'Split Developer Workbenches for live AST code preview and schema compilation.',
          'ROI & Usage Cost Calculators with reactive slider models and dynamic tier calculation.',
          'Infinite CSS-driven Logo Tickers and Verified Engineer Endorsement Masonry.',
        ],
        improvements: [
          'Strict adherence to Pioneer Craft standards (Linear, Raycast, Stripe typography scale).',
          'Refactored token definitions into single canonical shared `@theme inline` stylesheet.',
          'Optimized Astro SSG islands hydration for instant sub-20ms INP responsiveness.',
        ],
        fixes: [
          'Resolved circular imports in CVA variant definitions by extracting dedicated variant files.',
          'Fixed React JSX expression single curly braces syntax parity.',
        ],
      },
      {
        version: 'v2.3.0',
        date: 'July 2026',
        title: 'Dual-Framework Parity Engine & AST Synchronization',
        description:
          'Automated cross-framework parity check tool ensuring 100% token and CVA variant synchronization between Vue 3.5 and React 19.',
        commitHash: 'a8b3f12',
        features: [
          'Cross-framework parity checking CLI (`npm run check:parity`).',
          'Direct shadcn-vue and shadcn CLI HTTP unbundled distribution.',
        ],
        improvements: [
          'Removed all monolithic npm package bindings in favor of pure unbundled distribution.',
          'Enhanced Lucide icon alignment across polymorphic Reka UI primitives.',
        ],
        fixes: ['Fixed SSR hydration mismatch on theme color scheme initial render.'],
      },
      {
        version: 'v2.2.0',
        date: 'June 2026',
        title: 'Ecosystem Reference Templates Launch',
        description:
          'Introduced reference architectures for Nuxt 3 HRMS, Hospital Clinical Intelligence, and Global Shipment Tracking.',
        commitHash: 'e47c991',
        features: [
          'Shipment Tracking Template with live GPS telemetry cards.',
          'HRMS Nuxt Template with interactive payroll matrices and attendance timecards.',
        ],
        improvements: ['Streamlined bootstrap items (`init`, `tailwind`, `utils`, `use-theme`).'],
        fixes: ['Addressed upstream `shadcn-vue` resolver circular warning.'],
      },
    ]
    
    @Component({
      changeDetection: ChangeDetectionStrategy.Eager,
      selector: 'ui-changelog-release-notes-timeline, [ui-changelog-release-notes-timeline]',
      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="changelog-release-notes-timeline" [class]="rootClass">
          <div class="mx-auto max-w-4xl space-y-12">
            <!-- Header -->
            <div class="mx-auto max-w-2xl 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]="History" class="text-primary size-3.5" />
                Changelog &amp; Release History
              </span>
              <h2 class="text-foreground text-3xl font-bold tracking-tight sm:text-4xl">Continuous craft updates.</h2>
              <p class="text-muted-foreground text-base">
                Explore every version release, architectural improvement, and new block added to the registry.
              </p>
    
              <!-- Version Filters -->
              <div class="flex flex-wrap items-center justify-center gap-2 pt-2">
                <button type="button" [class]="filterClass('all')" (click)="selectedVersion.set('all')">
                  All Releases
                </button>
                @for (e of allEntries; track e.version) {
                  <button type="button" [class]="filterClass(e.version)" (click)="selectedVersion.set(e.version)">
                    {{ e.version }}
                  </button>
                }
              </div>
            </div>
    
            <!-- Timeline Feed -->
            <div class="border-border/80 relative ml-2 space-y-12 border-l pl-6 text-left sm:ml-4 sm:pl-8">
              @for (entry of filteredEntries(); track entry.version) {
                <div class="group relative">
                  <!-- Timeline Node Circle -->
                  <div [class]="nodeClass(entry.isLatest ?? false)">
                    @if (entry.isLatest) {
                      <div class="bg-primary size-1.5 animate-pulse rounded-full"></div>
                    }
                  </div>
    
                  <!-- Entry Card -->
                  <div ui-card class="border-border bg-card/95 space-y-6 rounded-2xl p-6 shadow-xl sm:p-8">
                    <!-- Header Row: Version pill, Date, Commit Diff -->
                    <div class="border-border/60 flex flex-wrap items-center justify-between gap-4 border-b pb-4">
                      <div class="flex items-center gap-2.5">
                        <span
                          ui-badge
                          [variant]="entry.isLatest ? 'default' : 'secondary'"
                          class="px-2.5 py-0.5 font-mono text-xs"
                        >
                          {{ entry.version }}
                        </span>
                        @if (entry.isLatest) {
                          <span class="text-success font-mono text-xs font-bold uppercase">Latest Release</span>
                        }
                      </div>
    
                      <div class="text-muted-foreground flex items-center gap-4 font-mono text-xs">
                        <span class="flex items-center gap-1">
                          <lucide-icon [img]="Calendar" class="size-3.5" />
                          {{ entry.date }}
                        </span>
                        <span class="text-foreground/80 hover:text-foreground flex items-center gap-1">
                          <lucide-icon [img]="GitCommit" class="text-primary size-3.5" />
                          <code>{{ entry.commitHash }}</code>
                        </span>
                      </div>
                    </div>
    
                    <!-- Title & Summary -->
                    <div class="space-y-2">
                      <h3 class="text-foreground font-mono text-xl font-bold tracking-tight">{{ entry.title }}</h3>
                      <p class="text-muted-foreground text-xs leading-relaxed sm:text-sm">{{ entry.description }}</p>
                    </div>
    
                    <!-- Category Section 1: Features -->
                    @if (entry.features.length) {
                      <div class="space-y-2">
                        <h4 class="text-success flex items-center gap-1.5 font-mono text-xs font-bold">
                          <lucide-icon [img]="Layers" class="size-3.5" />
                          New Capabilities &amp; Blocks
                        </h4>
                        <ul class="text-foreground/90 space-y-1.5 pl-1 font-mono text-xs">
                          @for (f of entry.features; track f) {
                            <li class="flex items-start gap-2">
                              <lucide-icon [img]="CheckCircle2" class="text-success mt-0.5 size-3.5 shrink-0" />
                              <span>{{ f }}</span>
                            </li>
                          }
                        </ul>
                      </div>
                    }
    
                    <!-- Category Section 2: Improvements -->
                    @if (entry.improvements.length) {
                      <div class="space-y-2">
                        <h4 class="text-primary flex items-center gap-1.5 font-mono text-xs font-bold">
                          <lucide-icon [img]="Zap" class="size-3.5" />
                          Craft &amp; Architecture Enhancements
                        </h4>
                        <ul class="text-foreground/90 space-y-1.5 pl-1 font-mono text-xs">
                          @for (imp of entry.improvements; track imp) {
                            <li class="flex items-start gap-2">
                              <span class="text-primary font-bold">&bull;</span>
                              <span>{{ imp }}</span>
                            </li>
                          }
                        </ul>
                      </div>
                    }
    
                    <!-- Category Section 3: Fixes -->
                    @if (entry.fixes.length) {
                      <div class="space-y-2">
                        <h4 class="text-warning flex items-center gap-1.5 font-mono text-xs font-bold">
                          <lucide-icon [img]="Wrench" class="size-3.5" />
                          Fixes &amp; Parity Patches
                        </h4>
                        <ul class="text-muted-foreground space-y-1.5 pl-1 font-mono text-xs">
                          @for (fix of entry.fixes; track fix) {
                            <li class="flex items-start gap-2">
                              <span class="text-warning font-bold">&bull;</span>
                              <span>{{ fix }}</span>
                            </li>
                          }
                        </ul>
                      </div>
                    }
                  </div>
                </div>
              }
            </div>
          </div>
        </section>
      `,
    })
    export class UiChangelogReleaseNotesTimelineComponent {
      protected readonly Calendar = Calendar
      protected readonly CheckCircle2 = CheckCircle2
      protected readonly GitCommit = GitCommit
      protected readonly History = History
      protected readonly Layers = Layers
      protected readonly Wrench = Wrench
      protected readonly Zap = Zap
    
      protected readonly allEntries = entries
    
      @Input('class') className?: string
    
      readonly selectedVersion = signal('all')
    
      readonly filteredEntries = computed(() => {
        const v = this.selectedVersion()
        if (v === 'all') return entries
        return entries.filter((e) => e.version === v)
      })
    
      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)
      }
    
      nodeClass(isLatest: boolean): string {
        return cn(
          'bg-background absolute top-1.5 -left-[31px] flex size-4 items-center justify-center rounded-full border-2 transition-colors sm:-left-[39px]',
          isLatest ? 'border-primary bg-primary/20' : 'border-muted-foreground/40',
        )
      }
    
      filterClass(version: string): string {
        return cn(
          'rounded-lg border px-3 py-1 font-mono text-xs transition-colors',
          this.selectedVersion() === version
            ? 'border-primary bg-primary text-primary-foreground font-semibold shadow-xs'
            : 'border-border bg-card text-muted-foreground hover:text-foreground',
        )
      }
    
      selectVersion(version: string): void {
        this.selectedVersion.set(version)
      }
    }
    
  • src/app/components/blocks/changelog-release-notes-timeline/index.ts0.1 kB

Raw manifest:https://uipkge.dev/r/angular/changelog-release-notes-timeline.json