fix(feed): give the small card the icon-only thumbnail controls too

Its column bottoms out at 180px, so its image is narrower than a row's
(measured 170px) while still carrying the 194px labelled pair — the same
overflow the row fix was for. The rule is the thumbnail's size class, not
the family: only the large card has room for labels.
This commit is contained in:
2026-07-16 04:18:31 +02:00
parent ace4a144e8
commit f8a6ce69c7
+17 -13
View File
@@ -243,8 +243,8 @@ function Thumb({
title={t("card.continueTitle")}
aria-label={t("card.continue")}
className={clsx(
"inline-flex items-center justify-center gap-1.5 rounded-lg font-semibold bg-accent text-accent-fg shadow-lg hover:opacity-90 transition",
small ? "w-9 h-9 rounded-full" : "px-3 py-1.5 text-sm"
"inline-flex items-center justify-center gap-1.5 font-semibold bg-accent text-accent-fg shadow-lg hover:opacity-90 transition",
small ? "w-9 h-9 rounded-full" : "px-3 py-1.5 rounded-lg text-sm"
)}
>
<Play className="w-4 h-4 fill-current" />
@@ -255,8 +255,8 @@ function Thumb({
title={t("card.restartTitle")}
aria-label={t("card.restart")}
className={clsx(
"inline-flex items-center justify-center gap-1.5 rounded-lg font-medium bg-white/15 text-white backdrop-blur-sm hover:bg-white/25 transition",
small ? "w-9 h-9 rounded-full" : "px-3 py-1.5 text-sm"
"inline-flex items-center justify-center gap-1.5 font-medium bg-white/15 text-white backdrop-blur-sm hover:bg-white/25 transition",
small ? "w-9 h-9 rounded-full" : "px-3 py-1.5 rounded-lg text-sm"
)}
>
<RotateCcw className="w-4 h-4" />
@@ -387,18 +387,13 @@ function VideoCard({
// cards never did this because glass-card always paints. No hover lift here: a 900px-wide row
// jumping as the pointer crosses it is a lot more restless than a card doing it.
const rowShell = "cv-row group glass-card glass-hover relative rounded-xl transition";
const resumeBar = (pct: number) =>
pct > 0 && (
<div className="absolute bottom-0 left-2 right-2 h-1 rounded-full bg-black/40">
<div className="h-full rounded-full bg-accent" style={{ width: `${pct}%` }} />
</div>
);
if (spec.family === "row") {
// No thumbnail => everything fits on ONE line: title (truncating into whatever's left), then
// channel, badges+meta and the actions all holding a fixed place at the right. How wide the
// line is allowed to get is the layout's call — see each view's maxCol in lib/feedView.ts.
if (noThumb) {
const pct = resumePct(video);
return (
<div className={clsx(rowShell, "flex items-center gap-3 px-3 py-2", watched && "opacity-55")}>
<div className="min-w-0 flex-1">{title}</div>
@@ -407,9 +402,15 @@ function VideoCard({
{/* Fixed slot, right-aligned: the reset button only exists for videos that have watch
state, so without a reserved width the meta ahead of it would sit 32px further right
on some rows than others — visible jitter in a layout whose whole point is that the
columns line up. Sized for the full six (6 x 28px + 5 x 4px gap = 188). */}
columns line up. The six buttons measure 188px (6 x 28 + 5 x 4 gap); w-48 is the
nearest step above that. */}
<div className="shrink-0 w-48 flex justify-end">{actions}</div>
{resumeBar(resumePct(video))}
{/* Thumb draws this over the image; with no image it goes on the row itself. */}
{pct > 0 && (
<div className="absolute bottom-0 left-2 right-2 h-1 rounded-full bg-black/40">
<div className="h-full rounded-full bg-accent" style={{ width: `${pct}%` }} />
</div>
)}
</div>
);
}
@@ -449,7 +450,10 @@ function VideoCard({
watched && "opacity-55"
)}
>
<Thumb video={video} className="aspect-video" onOpen={onOpen} />
{/* The small card's image is in the SAME size class as a row's (its column bottoms out at
180px), so it needs the icon-only controls just as much — the labelled pair is 194px wide
and would spill straight out of it. */}
<Thumb video={video} className="aspect-video" onOpen={onOpen} small={spec.dense} />
<div className={clsx("flex gap-3 px-0.5 pb-0.5 flex-1", spec.dense ? "mt-2" : "mt-2.5")}>
{/* The small card drops the channel avatar: at its ~180px column the 36px avatar plus the
gap would leave the title barely half the width. The channel name is still below it. */}