Skip to content

Commit 813de55

Browse files
committed
feat(cli): center-align +/- bars in proposal file stats view
1 parent 16f9d04 commit 813de55

File tree

1 file changed

+26
-49
lines changed

1 file changed

+26
-49
lines changed

cli/src/components/implementor-row.tsx

Lines changed: 26 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -288,14 +288,10 @@ interface CompactFileStatsProps {
288288
}
289289

290290
/**
291-
* Compact view showing file changes with center-aligned addition/deletion bars
292-
* Click a file name to view its diff inline below that row
293-
*
294-
* Layout:
295-
* M handler.ts ██████████ +30 -5 ░░░ 2 hunks
296-
* A utils.ts ████ +15 1 hunk
297-
* [diff content shown here when selected]
298-
* M config.ts ██ +2 -1 ░ 1 hunk
291+
* Compact view showing file changes with full-width, center-aligned addition/deletion bars.
292+
* The left side is a green bar (additions) and the right side is a red bar (deletions),
293+
* both extending to the center with their +N / -N counts rendered in white inside the bars.
294+
* Click a file name to view its diff inline below that row.
299295
*/
300296
const CompactFileStats = memo(({
301297
fileStats,
@@ -314,11 +310,6 @@ const CompactFileStats = memo(({
314310
)
315311
}
316312

317-
// Calculate max values for proportional bar sizing
318-
const maxAdded = Math.max(...fileStats.map(f => f.stats.linesAdded), 1)
319-
const maxRemoved = Math.max(...fileStats.map(f => f.stats.linesRemoved), 1)
320-
const maxLines = Math.max(maxAdded, maxRemoved)
321-
322313
// Fixed bar width - keeps layout simple and predictable
323314
const maxBarWidth = 5
324315

@@ -341,7 +332,6 @@ const CompactFileStats = memo(({
341332
file={file}
342333
availableWidth={availableWidth}
343334
maxBarWidth={maxBarWidth}
344-
maxLines={maxLines}
345335
maxAddedStrWidth={maxAddedStrWidth}
346336
maxRemovedStrWidth={maxRemovedStrWidth}
347337
isSelected={selectedFile === file.path}
@@ -357,7 +347,6 @@ interface CompactFileRowProps {
357347
file: FileStats
358348
availableWidth: number
359349
maxBarWidth: number
360-
maxLines: number
361350
maxAddedStrWidth: number
362351
maxRemovedStrWidth: number
363352
isSelected: boolean
@@ -366,17 +355,13 @@ interface CompactFileRowProps {
366355
}
367356

368357
/**
369-
* Single file row with center-aligned bars
370-
* Layout: M filename ████+4 -2░░ 2 hunks
371-
* Bar visualization is fixed, file path flexes/truncates to fit
372-
* Bars meet at a center axis with proper padding for alignment across all rows
373-
* File name is underlined on hover, clickable to show diff inline below
358+
* Single file row with full-width colored bars meeting at center.
359+
* File name is underlined on hover, clickable to show diff inline below.
374360
*/
375361
const CompactFileRow = memo(({
376362
file,
377363
availableWidth,
378364
maxBarWidth,
379-
maxLines,
380365
maxAddedStrWidth,
381366
maxRemovedStrWidth,
382367
isSelected,
@@ -385,36 +370,27 @@ const CompactFileRow = memo(({
385370
}: CompactFileRowProps) => {
386371
const theme = useTheme()
387372
const [isHovered, setIsHovered] = useState(false)
388-
const { linesAdded, linesRemoved } = file.stats
389373

390-
// Calculate bar widths proportional to line counts
391-
const addedBarWidth = linesAdded > 0
392-
? Math.max(1, Math.round((linesAdded / maxLines) * maxBarWidth))
393-
: 0
394-
const removedBarWidth = linesRemoved > 0
395-
? Math.max(1, Math.round((linesRemoved / maxLines) * maxBarWidth))
396-
: 0
374+
// Format numbers - always show counts, including +0 and -0
375+
const addedStr = `+${file.stats.linesAdded}`
376+
const removedStr = `-${file.stats.linesRemoved}`
397377

398-
// Build bar strings - use spaces since we're using background colors
399-
const addedBarSpaces = ' '.repeat(addedBarWidth)
400-
const removedBarSpaces = ' '.repeat(removedBarWidth)
378+
// Full-width colored sections with numbers inside:
379+
// - Added section: green bar extending to center with +N in white (right-aligned)
380+
// - Removed section: red bar extending from center with -N in white (left-aligned)
381+
const addedSectionWidth = maxBarWidth + maxAddedStrWidth
382+
const removedSectionWidth = maxBarWidth + maxRemovedStrWidth
401383

402-
// Format numbers - always show counts, including +0 and -0
403-
const addedStr = `+${linesAdded}`
404-
const removedStr = `-${linesRemoved}`
405-
406-
// Calculate left padding for center alignment
407-
// Left padding: space for missing bar width + missing number width
408-
// This ensures all "+N" values align at a center axis
409-
const leftPadding = ' '.repeat(
410-
(maxBarWidth - addedBarWidth) + (maxAddedStrWidth - addedStr.length)
411-
)
412-
// No right padding needed - bars extend to the edge of the card
384+
// +N right-aligned within the green section with 1 space padding before the center edge
385+
const addedContent = (addedStr + ' ').padStart(addedSectionWidth)
386+
// -N left-aligned within the red section with 1 space padding after the center edge
387+
const removedContent = (' ' + removedStr).padEnd(removedSectionWidth)
413388

414389
// Calculate available width for file path
415390
// Layout: changeType(1) + spaces(2) + filePath + spaces(2) + hunks + spaces(2) + bars
416391
const hunkText = `${file.stats.hunks} ${file.stats.hunks === 1 ? 'hunk' : 'hunks'}`
417-
const barWidth = maxBarWidth + maxAddedStrWidth + 1 + 1 + maxRemovedStrWidth + maxBarWidth // bars + numbers + spaces between
392+
// Total bar section width: 2*maxBarWidth + maxAddedStrWidth + maxRemovedStrWidth (no center gap)
393+
const barWidth = 2 * maxBarWidth + maxAddedStrWidth + maxRemovedStrWidth
418394
const fixedWidth = 1 + 2 + 2 + hunkText.length + 2 + barWidth
419395
const maxFilePathWidth = Math.max(10, availableWidth - fixedWidth)
420396

@@ -458,15 +434,16 @@ const CompactFileRow = memo(({
458434

459435
{/* Hunk count */}
460436
<text fg={theme.muted} style={{ flexShrink: 0, wrapMode: 'none' }}>
461-
{file.stats.hunks} {file.stats.hunks === 1 ? 'hunk' : 'hunks'}
437+
{hunkText}
462438
</text>
463439
<text style={{ flexShrink: 0 }}> </text>
464440

465-
{/* Bar visualization: left-padded for center alignment, extends to edge */}
441+
{/* Bar visualization: full-width bars meeting at center with numbers inside */}
466442
<text style={{ flexShrink: 0, wrapMode: 'none' }}>
467-
<span>{leftPadding}</span>
468-
<span fg={theme.inputFocusedFg} bg={theme.success}>{addedBarSpaces}{addedStr} </span>
469-
<span fg={theme.inputFocusedFg} bg={theme.error}> {removedStr}{removedBarSpaces}</span>
443+
{/* Added section: full green bar with +N in white inside, right-aligned to center */}
444+
<span fg="white" bg={theme.success}>{addedContent}</span>
445+
{/* Removed section: full red bar with -N in white inside, left-aligned from center */}
446+
<span fg="white" bg={theme.error}>{removedContent}</span>
470447
</text>
471448
</box>
472449

0 commit comments

Comments
 (0)