| 1 | import { memo } from "react"; |
| 2 | import { cn } from "~/lib/utils"; |
| 3 | |
| 4 | export function hasNonZeroStat(stat: { additions: number; deletions: number }): boolean { |
| 5 | return stat.additions > 0 || stat.deletions > 0; |
| 6 | } |
| 7 | |
| 8 | function formatCompactDiffCount(value: number): string { |
| 9 | if (value < 1000) return String(value); |
| 10 | if (value < 1_000_000) { |
| 11 | const k = value / 1000; |
| 12 | return `${k < 10 ? k.toFixed(1).replace(/\.0$/, "") : Math.round(k)}k`; |
| 13 | } |
| 14 | if (value < 1_000_000_000) { |
| 15 | const m = value / 1_000_000; |
| 16 | return `${m < 10 ? m.toFixed(1).replace(/\.0$/, "") : Math.round(m)}m`; |
| 17 | } |
| 18 | const b = value / 1_000_000_000; |
| 19 | return `${b < 10 ? b.toFixed(1).replace(/\.0$/, "") : Math.round(b)}b`; |
| 20 | } |
| 21 | |
| 22 | export const DiffStatLabel = memo(function DiffStatLabel(props: { |
| 23 | additions: number; |
| 24 | deletions: number; |
| 25 | className?: string; |
| 26 | showParentheses?: boolean; |
| 27 | layout?: "aligned" | "inline"; |
| 28 | }) { |
| 29 | const { additions, deletions, className, showParentheses = false, layout = "aligned" } = props; |
| 30 | return ( |
| 31 | <> |
| 32 | {showParentheses && <span className="text-muted-foreground/70">(</span>} |
| 33 | <span |
| 34 | role="group" |
| 35 | aria-label={`${additions} additions, ${deletions} deletions`} |
| 36 | className={cn( |
| 37 | layout === "inline" |
| 38 | ? "inline-flex items-center gap-1 tabular-nums align-middle" |
| 39 | : "inline-grid grid-cols-[4ch_4ch] gap-2 text-right tabular-nums align-middle", |
| 40 | className, |
| 41 | )} |
| 42 | > |
| 43 | <span aria-hidden="true" className="font-mono text-diff-addition"> |
| 44 | +{formatCompactDiffCount(additions)} |
| 45 | </span> |
| 46 | <span aria-hidden="true" className="font-mono text-diff-deletion"> |
| 47 | -{formatCompactDiffCount(deletions)} |
| 48 | </span> |
| 49 | </span> |
| 50 | {showParentheses && <span className="text-muted-foreground/70">)</span>} |
| 51 | </> |
| 52 | ); |
| 53 | }); |