fix(feed): size the badge column against the library's worst case
A 60-video sample topped out at 2:00:58, so the column was 8px short of an 11-hour stream that is also saved — and the library holds one. That row would wrap to two lines in the one layout that promises single ones. The stacked layouts' textBlock now builds after the one-line row returns, since only they use it.
This commit is contained in:
@@ -329,13 +329,6 @@ function VideoCard({
|
||||
{video.published_at && <>{" · "}{formatDate(video.published_at, i18n.language)}</>}
|
||||
</>
|
||||
);
|
||||
const meta = (
|
||||
<>
|
||||
{views}
|
||||
{views && " · "}
|
||||
{published}
|
||||
</>
|
||||
);
|
||||
// Show the full title in a native tooltip only when it's actually cut off — vertically where it
|
||||
// clamps to 2 lines, horizontally where the one-line row truncates it.
|
||||
const titleRef = useRef<HTMLAnchorElement>(null);
|
||||
@@ -377,16 +370,6 @@ function VideoCard({
|
||||
{video.channel_title}
|
||||
</button>
|
||||
);
|
||||
// Title + channel + meta stacked — the card and the thumbnailed row share this; only their
|
||||
// wrapper / Actions placement differs. Safe to reuse: exactly one branch below renders.
|
||||
const textBlock = (
|
||||
<>
|
||||
{title}
|
||||
<div className="mt-0.5">{channelButton}</div>
|
||||
<div className="text-xs text-muted mt-0.5">{meta}</div>
|
||||
</>
|
||||
);
|
||||
|
||||
const actions = (
|
||||
<Actions
|
||||
video={video}
|
||||
@@ -407,12 +390,13 @@ function VideoCard({
|
||||
// A table without being one. Every column is a FIXED width, which is what makes the same datum
|
||||
// land on the same vertical line in every row — a CSS grid can't do it for us, because
|
||||
// VirtualFeed renders each row as its own subtree, so there is no shared grid to align to.
|
||||
// Widths come from measuring the real data at text-sm (60-video sample), then taking the next
|
||||
// Tailwind step up: channel names run to 342px at worst (they truncate — most are far shorter),
|
||||
// views peak at 79, duration + a live chip + the saved pip at ~118, "11 months ago ·
|
||||
// Feb 28, 2026" at 181. The actions are 188 (6 x 28 + 5 x 4). Re-measure before trimming any
|
||||
// of them — badges first looked like 102 until the chips' own margins were counted, and the
|
||||
// column silently wrapped to a second line.
|
||||
// Widths come from measuring the real data at text-sm, then taking the next Tailwind step up:
|
||||
// channel names run to 342px at worst (they truncate — most are far shorter), views peak at 79,
|
||||
// the badges at 130 ("11:46:50" + a STREAM chip + the saved pip — the library really does hold
|
||||
// 11-hour streams), "11 months ago · Feb 28, 2026" at 181, and the actions 188 (6 x 28 + 5 x 4).
|
||||
// Size against the WORST case in the library, not a page of it: badges were sized 102 off a
|
||||
// 60-video sample, which missed both the chips' own margins and any stream over two hours, and
|
||||
// the column silently wrapped to a second line — in the one layout that promises single lines.
|
||||
// The title takes what's left, which is constant per container width — so it aligns too.
|
||||
if (noThumb) {
|
||||
const pct = resumePct(video);
|
||||
@@ -423,7 +407,7 @@ function VideoCard({
|
||||
<div className="shrink-0 w-48">{actions}</div>
|
||||
<div className="min-w-0 flex-1">{title}</div>
|
||||
<div className="shrink-0 w-40">{channelButton}</div>
|
||||
<div className="shrink-0 w-32 text-sm text-muted">
|
||||
<div className="shrink-0 w-36 text-sm text-muted">
|
||||
<InlineBadges video={video} />
|
||||
</div>
|
||||
<div className="shrink-0 w-24 text-sm text-muted truncate">{views}</div>
|
||||
@@ -437,6 +421,24 @@ function VideoCard({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Everything below is a STACKED layout — the card and the thumbnailed row. Only they run the
|
||||
// data together as one sentence; the one-line row above gives each datum its own column and has
|
||||
// already returned, so building this for it would be waste dressed up as shared code.
|
||||
const textBlock = (
|
||||
<>
|
||||
{title}
|
||||
<div className="mt-0.5">{channelButton}</div>
|
||||
<div className="text-xs text-muted mt-0.5">
|
||||
{views}
|
||||
{views && " · "}
|
||||
{published}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
if (spec.family === "row") {
|
||||
return (
|
||||
<div className={clsx(rowShell, "flex gap-3 p-2", watched && "opacity-55")}>
|
||||
<Thumb
|
||||
|
||||
Reference in New Issue
Block a user