From 602effde732aa6e20281194f5a89829e76895e53 Mon Sep 17 00:00:00 2001 From: Paul Trowbridge Date: Thu, 17 Sep 2026 23:00:27 -0400 Subject: [PATCH] Give the segment table room, and size its text columns by content The page was capped at max-w-4xl. Eleven columns in 896px meant something was always smashed, and the previous fix just moved which one -- w-full on the note cell let it claim the slack, and w-48 on label is only a hint in an auto-layout table, so the browser shrank the label input to min-content. The cap is gone; the blocks that read better narrow keep their own. label, note and counts-toward are now measured off the longest value in the log, in ch, with floors so an empty table keeps its headers and ceilings so one long note cannot push the numbers off the side. The note's one-line clip moved onto its inner div: a max-width on a table cell is only a hint too, so pinning it to the cell could collapse the column to min-content or let it grow past the measurement. Co-Authored-By: Claude Opus 5 (1M context) --- ui/src/views/Baseline.jsx | 42 +++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/ui/src/views/Baseline.jsx b/ui/src/views/Baseline.jsx index 23611bd..c145c03 100644 --- a/ui/src/views/Baseline.jsx +++ b/ui/src/views/Baseline.jsx @@ -165,6 +165,19 @@ export default function Baseline({ sources = [], sourceId, versions = [], versio } catch (err) { flash(err.message, 'error') } } + // Column widths read off the content rather than guessed. ch is the width of a + // '0', so for proportional text it runs slightly generous -- which is what is + // wanted for an input you are about to type a longer name into. The floors keep + // an empty table from collapsing its headers; the ceilings keep one long note + // from pushing the numbers off the side. + function widthCh(values, min, max) { + const longest = values.reduce((n, v) => Math.max(n, String(v || '').length), 0) + return `${Math.min(max, Math.max(min, longest + 2))}ch` + } + const labelW = widthCh(log.map(e => e.label || e.tag || e.note), 18, 40) + const bucketW = widthCh(log.map(e => e.bucket), 16, 28) + const noteW = widthCh(log.map(e => e.note), 24, 60) + function loadLog() { fetch(`/api/versions/${versionId}/log`).then(r => r.json()).then(data => { setLog(data.filter(e => e.operation === 'baseline' || e.operation === 'reference')) @@ -341,7 +354,10 @@ export default function Baseline({ sources = [], sourceId, versions = [], versio return (
-
+ {/* Uncapped: the segment table is eleven columns, and at max-w-4xl (896px) + something always got smashed no matter how the widths were divided. The + blocks that read better narrow keep their own caps. */} +
{msg && (
@@ -408,9 +424,9 @@ export default function Baseline({ sources = [], sourceId, versions = [], versio # kind - label - note - counts toward + label + note + counts toward rows {log[0]?.value_col || 'value'} by @@ -464,16 +480,16 @@ export default function Baseline({ sources = [], sourceId, versions = [], versio focus:border-blue-400 rounded px-1 py-0.5 text-xs focus:outline-none bg-transparent" /> - {/* One line, clipped. The note is provenance -- it can run - long -- and this row is eleven columns wide, so it used - to wrap and push every row to two or three lines. w-full - plus max-w-0 is what lets a cell in an auto-layout table - absorb the slack and still clip: without the max-w-0 the - column simply grows to fit the text. Expanding the row - shows it in full. */} - + {/* One line, clipped against the measured width above. The + note is provenance and can run long, so left to itself it + wrapped and pushed every row to two or three lines. + Expanding the row shows it in full. The cap is on the div, + not the cell: a max-width on a cell in an auto-layout table + is only a hint, and the column can still collapse to + min-content or grow past it. */} + {entry.note - ?
{entry.note}
+ ?
{entry.note}
: } e.stopPropagation()}>