diff options
| author | Adam <[email protected]> | 2025-10-30 12:02:44 -0500 |
|---|---|---|
| committer | Adam <[email protected]> | 2025-10-30 12:02:51 -0500 |
| commit | ee7612a31c02ea442d8bf3e5d3b75ff572fac26a (patch) | |
| tree | 26c720bf7d08b2a7b2475acd5598ffc23c39b953 /packages/ui/src/components/diff-changes.tsx | |
| parent | 582ed7c363fec4faa8cf393e023024ac90e65b82 (diff) | |
| download | opencode-ee7612a31c02ea442d8bf3e5d3b75ff572fac26a.tar.gz opencode-ee7612a31c02ea442d8bf3e5d3b75ff572fac26a.zip | |
wip: desktop work
Diffstat (limited to 'packages/ui/src/components/diff-changes.tsx')
| -rw-r--r-- | packages/ui/src/components/diff-changes.tsx | 110 |
1 files changed, 104 insertions, 6 deletions
diff --git a/packages/ui/src/components/diff-changes.tsx b/packages/ui/src/components/diff-changes.tsx index 7661a9741..433c47f39 100644 --- a/packages/ui/src/components/diff-changes.tsx +++ b/packages/ui/src/components/diff-changes.tsx @@ -1,7 +1,9 @@ import type { FileDiff } from "@opencode-ai/sdk" -import { createMemo, Show } from "solid-js" +import { createMemo, For, Match, Show, Switch } from "solid-js" + +export function DiffChanges(props: { diff: FileDiff | FileDiff[]; variant?: "default" | "bars" }) { + const variant = () => props.variant ?? "default" -export function DiffChanges(props: { diff: FileDiff | FileDiff[] }) { const additions = createMemo(() => Array.isArray(props.diff) ? props.diff.reduce((acc, diff) => acc + (diff.additions ?? 0), 0) @@ -13,11 +15,107 @@ export function DiffChanges(props: { diff: FileDiff | FileDiff[] }) { : props.diff.deletions, ) const total = createMemo(() => (additions() ?? 0) + (deletions() ?? 0)) + + const countLines = (text: string) => { + if (!text) return 0 + return text.split("\n").length + } + + const totalBeforeLines = createMemo(() => { + if (!Array.isArray(props.diff)) return countLines(props.diff.before || "") + return props.diff.reduce((acc, diff) => acc + countLines(diff.before || ""), 0) + }) + + const blockCounts = createMemo(() => { + const TOTAL_BLOCKS = 5 + + const adds = additions() ?? 0 + const dels = deletions() ?? 0 + + if (adds === 0 && dels === 0) { + return { added: 0, deleted: 0, neutral: TOTAL_BLOCKS } + } + + const total = adds + dels + + if (total < 5) { + const added = adds > 0 ? 1 : 0 + const deleted = dels > 0 ? 1 : 0 + const neutral = TOTAL_BLOCKS - added - deleted + return { added, deleted, neutral } + } + + const ratio = adds > dels ? adds / dels : dels / adds + let BLOCKS_FOR_COLORS = TOTAL_BLOCKS + + if (total < 20) { + BLOCKS_FOR_COLORS = TOTAL_BLOCKS - 1 + } else if (ratio < 4) { + BLOCKS_FOR_COLORS = TOTAL_BLOCKS - 1 + } + + const percentAdded = adds / total + const percentDeleted = dels / total + + const added_raw = percentAdded * BLOCKS_FOR_COLORS + const deleted_raw = percentDeleted * BLOCKS_FOR_COLORS + + let added = adds > 0 ? Math.max(1, Math.round(added_raw)) : 0 + let deleted = dels > 0 ? Math.max(1, Math.round(deleted_raw)) : 0 + + // Cap bars based on actual change magnitude + if (adds > 0 && adds <= 5) added = Math.min(added, 1) + if (adds > 5 && adds <= 10) added = Math.min(added, 2) + if (dels > 0 && dels <= 5) deleted = Math.min(deleted, 1) + if (dels > 5 && dels <= 10) deleted = Math.min(deleted, 2) + + let total_allocated = added + deleted + if (total_allocated > BLOCKS_FOR_COLORS) { + if (added_raw > deleted_raw) { + added = BLOCKS_FOR_COLORS - deleted + } else { + deleted = BLOCKS_FOR_COLORS - added + } + total_allocated = added + deleted + } + + const neutral = Math.max(0, TOTAL_BLOCKS - total_allocated) + + return { added, deleted, neutral } + }) + + const ADD_COLOR = "var(--icon-diff-add-base)" + const DELETE_COLOR = "var(--icon-diff-delete-base)" + const NEUTRAL_COLOR = "var(--icon-weak-base)" + + const visibleBlocks = createMemo(() => { + const counts = blockCounts() + const blocks = [ + ...Array(counts.added).fill(ADD_COLOR), + ...Array(counts.deleted).fill(DELETE_COLOR), + ...Array(counts.neutral).fill(NEUTRAL_COLOR), + ] + return blocks.slice(0, 5) + }) + return ( - <Show when={total() > 0}> - <div data-component="diff-changes"> - <span data-slot="additions">{`+${additions()}`}</span> - <span data-slot="deletions">{`-${deletions()}`}</span> + <Show when={variant() === "default" ? total() > 0 : true}> + <div data-component="diff-changes" data-variant={variant()}> + <Switch> + <Match when={variant() === "bars"}> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 12" fill="none"> + <g> + <For each={visibleBlocks()}> + {(color, i) => <rect x={i() * 4} width="2" height="12" rx="1" fill={color} />} + </For> + </g> + </svg> + </Match> + <Match when={variant() === "default"}> + <span data-slot="additions">{`+${additions()}`}</span> + <span data-slot="deletions">{`-${deletions()}`}</span> + </Match> + </Switch> </div> </Show> ) |
