spb/company-atlas
Public
Python 66.3%
TypeScript 22.7%
JavaScript 8.6%
HTML 1.4%
CSS 0.7%
1import { SignificanceBadge } from '@/components/ui/badges';2import { Note } from '@/components/ui/section';3import { cn } from '@/lib/cn';4import { fmtPct } from '@/lib/format';5import type { BlockDelta, DiffPayload } from '@/lib/types';67/** Block-level diff (added / removed / modified with before → after text), significance meter and reasons. */8export function DiffViewer({ diff, significance, className }: { diff: DiffPayload; significance?: number | null; className?: string }) {9 const total = diff.added.length + diff.removed.length + diff.modified.length;10 return (11 <div className={cn('space-y-5', className)} data-diff-viewer>12 <div className="grid gap-4 md:grid-cols-[minmax(0,1fr)_minmax(0,1.4fr)]">13 <div>14 <p className="eyebrow">Significance</p>15 <div className="mt-1 flex items-center gap-3">16 <div className="meter flex-1">17 <span style={{ width: `${Math.round((significance ?? 0) * 100)}%`, background: (significance ?? 0) >= 0.65 ? 'var(--warning)' : (significance ?? 0) >= 0.4 ? 'var(--accent)' : 'var(--ink-3)' }} />18 </div>19 <SignificanceBadge value={significance} />20 </div>21 <p className="tnum mt-2 text-xs text-ink-3">22 text delta {fmtPct(diff.text_delta_ratio, 1, true)} · similarity {fmtPct(diff.similarity, 1, true)} · {diff.counts.unchanged !== undefined ? `${diff.counts.unchanged} unchanged blocks` : `${total} changed blocks`}23 </p>24 <div className="mt-2 flex flex-wrap gap-3 text-xs">25 <span className="text-positive">+{diff.added.length} added</span>26 <span className="text-danger">−{diff.removed.length} removed</span>27 <span className="text-warning">~{diff.modified.length} modified</span>28 {diff.moved.length > 0 && <span className="text-ink-3">↕ {diff.moved.length} moved</span>}29 </div>30 </div>31 <div>32 <p className="eyebrow">Why it scored this way</p>33 {diff.reasons.length ? (34 <ul className="mt-1 space-y-0.5 text-sm text-ink-2">35 {diff.reasons.map((r) => (36 <li key={r}>· {r}</li>37 ))}38 </ul>39 ) : (40 <Note className="mt-1">No reasons recorded for this diff.</Note>41 )}42 </div>43 </div>4445 {total === 0 ? (46 <Note>No block-level differences above the noise floor between these versions.</Note>47 ) : (48 <div className="space-y-4">49 {diff.added.length > 0 && <Group label="Added" items={diff.added} kind="added" />}50 {diff.removed.length > 0 && <Group label="Removed" items={diff.removed} kind="removed" />}51 {diff.modified.length > 0 && <Group label="Modified" items={diff.modified} kind="modified" />}52 </div>53 )}54 </div>55 );56}5758function Group({ label, items, kind }: { label: string; items: BlockDelta[]; kind: 'added' | 'removed' | 'modified' }) {59 return (60 <section>61 <p className="eyebrow mb-1.5">62 {label} <span className="tnum normal-case tracking-normal text-ink-3">({items.length})</span>63 </p>64 <ul className="space-y-2">65 {items.map((b) => (66 <li key={`${kind}-${b.key}`} className={cn('diff-block', kind)}>67 <p className="mono mb-1 flex flex-wrap items-center gap-2 text-[10px] text-ink-3">68 <span className="uppercase tracking-wider">{b.kind}</span>69 <span className="truncate">{b.path}</span>70 <span className="ml-auto tnum">w {b.weight.toFixed(2)}{b.similarity !== null ? ` · sim ${b.similarity.toFixed(2)}` : ''}</span>71 </p>72 {kind === 'modified' ? (73 <>74 <p className="diff-before">{b.before}</p>75 <p className="diff-after mt-1">{b.after}</p>76 </>77 ) : (78 <p className={kind === 'removed' ? 'diff-before' : 'diff-after'}>{kind === 'removed' ? b.before : b.after}</p>79 )}80 </li>81 ))}82 </ul>83 </section>84 );85}86