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