Menu

Change language

GitHub repo

Sprint Timeline

blockproductivity

Agile sprint tracking timeline block: 2-week deliverable Gantt schedule with story point burndown indicators, milestone demos, dependency handoffs, and assignee tags.

Installation

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

Variants

Loading interactive previews…

npm dependencies

Includes

Files installed (2)

  • src/app/components/blocks/sprint-timeline/sprint-timeline.component.ts4.7 kB
    // Agile sprint tracking timeline block: 2-week deliverable Gantt schedule with story
    // point burndown indicators, milestone demos, dependency handoffs, and assignee tags.
    // Port of the Vue block 1:1.
    import { ChangeDetectionStrategy, Component, Input, computed } from '@angular/core'
    import { Clock, LucideAngularModule, Target, Zap } from 'lucide-angular'
    import { cn } from '@/lib/utils'
    import { UiBadgeComponent } from '@/ui/badge/badge.component'
    import { UiGanttComponent, UiGanttTimelineComponent, UiGanttTreeComponent } from '@/ui/gantt/gantt.component'
    import type { GanttTask } from '@/ui/gantt/types'
    
    const defaultTasks: GanttTask[] = [
      {
        id: 'sp-1',
        name: 'Gantt Component Specs & Tokens',
        startDate: '2026-08-10',
        endDate: '2026-08-13',
        progress: 100,
        status: 'done',
        priority: 'high',
        assignee: { name: 'Sarah Connor', initials: 'SC' },
      },
      {
        id: 'sp-2',
        name: 'Vue 3.5 SFC Implementation',
        startDate: '2026-08-12',
        endDate: '2026-08-18',
        progress: 90,
        status: 'in-progress',
        priority: 'urgent',
        dependencies: ['sp-1'],
        assignee: { name: 'Marcus Rivera', initials: 'MR' },
      },
      {
        id: 'sp-3',
        name: 'React 19 Parity Mirror',
        startDate: '2026-08-14',
        endDate: '2026-08-19',
        progress: 80,
        status: 'in-progress',
        priority: 'high',
        dependencies: ['sp-1'],
        assignee: { name: 'Priya Nair', initials: 'PN' },
      },
      {
        id: 'sp-4',
        name: 'Mid-Sprint Review & Demo',
        startDate: '2026-08-17',
        endDate: '2026-08-17',
        isMilestone: true,
        status: 'done',
      },
      {
        id: 'sp-5',
        name: 'Composed Roadmap & Sprint Blocks',
        startDate: '2026-08-18',
        endDate: '2026-08-22',
        progress: 40,
        status: 'in-progress',
        priority: 'medium',
        dependencies: ['sp-2', 'sp-3'],
        assignee: { name: 'Sundar Krishnan', initials: 'SK' },
      },
      {
        id: 'sp-6',
        name: 'Sprint Retrospective & Release',
        startDate: '2026-08-24',
        endDate: '2026-08-24',
        isMilestone: true,
        status: 'todo',
        dependencies: ['sp-5'],
      },
    ]
    
    @Component({
      changeDetection: ChangeDetectionStrategy.Eager,
      selector: 'ui-sprint-timeline, [ui-sprint-timeline]',
      standalone: true,
      // Vue renders the root <div> itself: the host stays out of layout and `class` goes to the root.
      host: { '[attr.class]': '"contents"' },
      imports: [LucideAngularModule, UiBadgeComponent, UiGanttComponent, UiGanttTimelineComponent, UiGanttTreeComponent],
      template: `
        <div data-uipkge data-slot="sprint-timeline" [class]="rootClass">
          <!-- Sprint Header Info -->
          <div class="border-border/60 flex flex-col gap-4 border-b pb-4 sm:flex-row sm:items-center sm:justify-between">
            <div class="space-y-1">
              <div class="flex items-center gap-2">
                <span ui-badge variant="outline" class="text-primary border-primary/30">
                  <lucide-icon [img]="Zap" class="mr-1 size-3" />
                  Active Sprint
                </span>
                <span class="text-muted-foreground font-mono text-xs">{{ startDate }} &rarr; {{ endDate }}</span>
              </div>
              <h3 class="text-foreground text-lg font-bold">{{ sprintName }}</h3>
            </div>
    
            <div class="flex items-center gap-4 font-mono text-xs">
              <div class="flex items-center gap-1.5">
                <lucide-icon [img]="Target" class="text-muted-foreground size-4" />
                <span>{{ completedPoints }} / {{ totalPoints }} Story Points</span>
              </div>
              <div class="text-warning flex items-center gap-1.5 font-semibold">
                <lucide-icon [img]="Clock" class="size-4" />
                <span>{{ daysRemaining }} Days Left</span>
              </div>
            </div>
          </div>
    
          <!-- Sprint Gantt Grid -->
          <ui-gantt [tasks]="tasks()" scale="day" [rowHeight]="38" [treeWidth]="260" class="h-72 border-none shadow-none">
            <div class="flex min-h-0 flex-1 overflow-hidden">
              <ui-gantt-tree [showPriority]="true" />
              <ui-gantt-timeline [showTodayLine]="true" [showDependencies]="true" />
            </div>
          </ui-gantt>
        </div>
      `,
    })
    export class UiSprintTimelineComponent {
      protected readonly Clock = Clock
      protected readonly Target = Target
      protected readonly Zap = Zap
    
      @Input() sprintName = 'Sprint 42: UI Registry 2.3'
      @Input() startDate = '2026-08-10'
      @Input() endDate = '2026-08-24'
      @Input() initialTasks?: GanttTask[]
      @Input('class') className?: string
    
      readonly completedPoints = 28
      readonly totalPoints = 35
      readonly daysRemaining = 6
    
      readonly tasks = computed<GanttTask[]>(() => this.initialTasks ?? defaultTasks)
    
      get rootClass(): string {
        return cn('border-border bg-card space-y-5 rounded-xl border p-5 shadow-xs', this.className)
      }
    }
    
  • src/app/components/blocks/sprint-timeline/index.ts0.1 kB

Raw manifest:https://uipkge.dev/r/angular/sprint-timeline.json