diff --git a/frontend/src/components/VideoCard.tsx b/frontend/src/components/VideoCard.tsx index 57a1551..5af3b53 100644 --- a/frontend/src/components/VideoCard.tsx +++ b/frontend/src/components/VideoCard.tsx @@ -322,33 +322,40 @@ function Thumb({ ); } -// The one-line row's column widths, in ONE place — the Tailwind classes below are generated from -// them, so the thresholds can't drift out of step with the boxes they describe (they did when both -// were written by hand). Each is measured against the worst case in the library AND in both -// languages; see the row's own comment for where each number comes from. +// The one-line row's column widths, in ONE place: the boxes below take these directly (as inline +// widths — Tailwind can't accept a runtime value), and so do the drop-out thresholds. Two +// hand-written sets would drift, and the symptom would be silent: a column appearing just before +// it actually fits. Each is measured against the worst case in the LIBRARY and in BOTH languages — +// see the row's own comment for where each number comes from. const ROW_COL = { - actions: 192, // w-48 — six buttons at 28 + five 4px gaps = 188 - title: 120, // — not a column: the floor below which a title isn't worth showing - channel: 128, // w-32 - meta: 104, // — RowMetaCells' own grid: 4rem + 1rem + 1rem + two 4px gaps - views: 64, // w-16 - published: 192, // w-48 + actions: 192, // six buttons at 28 + five 4px gaps = 188 + channel: 128, + meta: 104, // RowMetaCells' own grid: 4rem + 1rem + 1rem + two 4px gaps + views: 64, + published: 192, } as const; const ROW_GAP = 12; // gap-3 const ROW_PAD = 26; // px-3 both sides, plus a rounding allowance +const ROW_TITLE_MIN = 120; // not a column: the floor below which a title isn't worth showing -// What the row must measure before each column earns its place — cumulative from the left, so each -// one only appears once everything ahead of it AND a readable title already fit. -const ROW_FITS = (() => { - let w = ROW_PAD + ROW_COL.actions + ROW_GAP + ROW_COL.title; - const at = (px: number) => (w += ROW_GAP + px); - return { - channel: at(ROW_COL.channel), - meta: at(ROW_COL.meta), - views: at(ROW_COL.views), - published: at(ROW_COL.published), - }; -})(); +// What the row must measure before each column earns its place — cumulative, so each appears only +// once everything to its left AND a readable title already fit. +const ROW_BASE = ROW_PAD + ROW_COL.actions + ROW_GAP + ROW_TITLE_MIN; +const ROW_FITS = { + channel: ROW_BASE + ROW_GAP + ROW_COL.channel, + meta: ROW_BASE + ROW_GAP + ROW_COL.channel + ROW_GAP + ROW_COL.meta, + views: ROW_BASE + ROW_GAP + ROW_COL.channel + ROW_GAP + ROW_COL.meta + ROW_GAP + ROW_COL.views, + published: + ROW_BASE + + ROW_GAP + + ROW_COL.channel + + ROW_GAP + + ROW_COL.meta + + ROW_GAP + + ROW_COL.views + + ROW_GAP + + ROW_COL.published, +}; function VideoCard({ video, @@ -489,7 +496,9 @@ function VideoCard({