Code — Diff Review
blockmarketingUnified diff panel with added and removed lines, a file path header, a reviewer note anchored to a line, and a summary bar counting the changes.
Installation
$pnpm dlx uipkge-ng@latest add code-diff-review$npx uipkge-ng@latest add code-diff-review$yarn dlx uipkge-ng@latest add code-diff-review$bunx uipkge-ng@latest add code-diff-reviewManifest:
https://uipkge.dev/r/angular/code-diff-review.jsonInstalls to:src/app/components/blocks/code-diff-review/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.
DiffLineinterface DiffLine {
old: number | null
new: number | null
tone: DiffTone
text: string
}Files installed (2)
src/app/components/blocks/code-diff-review/code-diff-review.component.ts6.4 kB
// Unified diff panel with added and removed lines, a file path header, a reviewer note // anchored to a line, and a summary bar counting the changes. Port of the React block 1:1. import { ChangeDetectionStrategy, Component, Input, computed } from '@angular/core' import { Check, FileDiff, LucideAngularModule, MessageSquare } from 'lucide-angular' import { cn } from '@/lib/utils' import { UiAvatarComponent, UiAvatarFallbackComponent } from '@/ui/avatar/avatar.component' import { UiBadgeComponent } from '@/ui/badge/badge.component' import { UiButtonComponent } from '@/ui/button/button.component' import { UiCardComponent, UiCardContentComponent } from '@/ui/card/card.component' import { UiSeparatorComponent } from '@/ui/separator/separator.component' type DiffTone = 'same' | 'add' | 'remove' interface DiffLine { old: number | null new: number | null tone: DiffTone text: string } // tone drives the row treatment, so individual lines carry no styling of their own. const hunk: DiffLine[] = [ { old: 12, new: 12, tone: 'same', text: 'metric revenue_net {' }, { old: 13, new: 13, tone: 'same', text: ' owner: finance-analytics' }, { old: 14, new: null, tone: 'remove', text: ' window: trailing_30d' }, { old: null, new: 14, tone: 'add', text: ' window: trailing_28d' }, { old: null, new: 15, tone: 'add', text: ' restated_from: 2026-01-01' }, { old: 15, new: 16, tone: 'same', text: ' source: warehouse.orders' }, { old: 16, new: 17, tone: 'same', text: '}' }, ] @Component({ changeDetection: ChangeDetectionStrategy.Eager, selector: 'ui-code-diff-review, [ui-code-diff-review]', 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, UiAvatarComponent, UiAvatarFallbackComponent, UiBadgeComponent, UiButtonComponent, UiCardComponent, UiCardContentComponent, UiSeparatorComponent, ], template: ` <section data-slot="code-diff-review" class="bg-background"> <div class="mx-auto max-w-3xl px-6 py-20"> <span ui-badge variant="secondary" class="gap-1.5"> <lucide-icon [img]="FileDiff" class="size-3" aria-hidden="true" /> Change review </span> <h2 class="mt-4 text-2xl font-semibold tracking-tight">Every metric change is a reviewable diff</h2> <p class="text-muted-foreground mt-2"> Definitions live in the repo, so changing one opens a pull request with an owner and a revert path. </p> <div ui-card class="mt-8"> <div ui-card-content class="p-0"> <div class="border-border flex items-center gap-3 border-b px-4 py-2.5"> <code class="min-w-0 truncate font-mono text-xs">metrics/revenue_net.yml</code> <div class="ml-auto flex shrink-0 items-center gap-2 font-mono text-xs"> <span class="text-success">+{{ added() }}</span> <span class="text-destructive">−{{ removed() }}</span> </div> </div> <div class="overflow-x-auto"> <table class="w-full border-collapse font-mono text-xs"> <caption class="sr-only"> Unified diff for metrics/revenue_net.yml </caption> <tbody> @for (line of lines; track line.text; let i = $index) { <tr [class]="rowClass(line.tone)"> <td class="text-muted-foreground/60 w-10 px-2 py-1 text-right select-none"> {{ line.old ?? '' }} </td> <td class="text-muted-foreground/60 w-10 px-2 py-1 text-right select-none"> {{ line.new ?? '' }} </td> <td class="w-4 py-1 pl-2 select-none">{{ marker(line.tone) }}</td> <td class="py-1 pr-4 whitespace-pre">{{ line.text }}</td> </tr> } </tbody> </table> </div> <ui-separator /> <div class="flex items-start gap-3 px-4 py-3"> <ui-avatar class="size-7"> <ui-avatar-fallback class="text-xs">EW</ui-avatar-fallback> </ui-avatar> <div class="min-w-0"> <p class="text-xs"> <span class="font-medium">Erin Walsh</span> <span class="text-muted-foreground"> on line 14</span> </p> <p class="text-muted-foreground mt-1 text-xs leading-relaxed"> Restating from January means Q1 reports change. Flag it in the release note before this merges. </p> </div> <button ui-button variant="ghost" size="sm" class="ml-auto h-7 shrink-0 gap-1.5 text-xs"> <lucide-icon [img]="MessageSquare" class="size-3" aria-hidden="true" /> Reply </button> </div> </div> </div> <div class="text-muted-foreground mt-4 flex flex-wrap items-center gap-x-5 gap-y-2 text-xs"> <span class="flex items-center gap-1.5"> <lucide-icon [img]="Check" class="text-success size-3.5" aria-hidden="true" /> Reconciliation passed against the prior four quarters </span> <span class="flex items-center gap-1.5"> <lucide-icon [img]="Check" class="text-success size-3.5" aria-hidden="true" /> 41 downstream consumers identified </span> </div> </div> </section> `, }) export class UiCodeDiffReviewComponent { protected readonly Check = Check protected readonly FileDiff = FileDiff protected readonly MessageSquare = MessageSquare protected readonly lines = hunk @Input('class') className?: string readonly added = computed(() => hunk.filter((line) => line.tone === 'add').length) readonly removed = computed(() => hunk.filter((line) => line.tone === 'remove').length) get rootClass(): string { return cn('w-full', this.className) } rowClass(tone: DiffTone): string { if (tone === 'add') return 'bg-success/10 text-foreground' if (tone === 'remove') return 'bg-destructive/10 text-muted-foreground' return 'text-muted-foreground' } marker(tone: DiffTone): string { return tone === 'add' ? '+' : tone === 'remove' ? '-' : ' ' } }src/app/components/blocks/code-diff-review/index.ts0.1 kB
export { UiCodeDiffReviewComponent } from './code-diff-review.component'
Raw manifest:https://uipkge.dev/r/angular/code-diff-review.json