fix(feed): stop the compact row eating its own title on a smaller window
Every column but the title is shrink-0, so once the fixed widths outgrow the row the title gives all of it: measured clientWidth 0 on every row at a 1000px window — a table of channel, duration, views and date with no titles. Columns now drop from the right as space runs out, least important first, in the order the user named: title, then channel, then the rest. Measured at 1000px: title 0 -> 351. I'd written this off as "E15's problem, bites below ~640px" — wrong by 600px, because I only ever measured at 1440.
This commit is contained in:
@@ -149,7 +149,7 @@ function resumePct(video: Video): number {
|
|||||||
// reading as a column. The flex row this replaces let a "36:36" and a "3:31:09" push the marker
|
// reading as a column. The flex row this replaces let a "36:36" and a "3:31:09" push the marker
|
||||||
// beside them to different places, and pulled it left again whenever the duration was absent
|
// beside them to different places, and pulled it left again whenever the duration was absent
|
||||||
// (live/upcoming) — visible as a ragged edge down the page.
|
// (live/upcoming) — visible as a ragged edge down the page.
|
||||||
function RowMetaCells({ video }: { video: Video }) {
|
function RowMetaCells({ video, className }: { video: Video; className?: string }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
// Icons, not the labelled chips the thumbnail uses: at a glance this is the least important thing
|
// Icons, not the labelled chips the thumbnail uses: at a glance this is the least important thing
|
||||||
// in the row, so it gets about a letter's worth of width. Icons rather than a coloured dot
|
// in the row, so it gets about a letter's worth of width. Icons rather than a coloured dot
|
||||||
@@ -168,7 +168,12 @@ function RowMetaCells({ video }: { video: Video }) {
|
|||||||
// widen a slot and the title column silently pays for it. rem, not px, so the whole cell tracks
|
// widen a slot and the title column silently pays for it. rem, not px, so the whole cell tracks
|
||||||
// the text-size setting the same way its contents do.
|
// the text-size setting the same way its contents do.
|
||||||
return (
|
return (
|
||||||
<div className="shrink-0 grid grid-cols-[4rem_1rem_1rem] gap-1 items-center text-sm text-muted">
|
<div
|
||||||
|
className={clsx(
|
||||||
|
"shrink-0 grid grid-cols-[4rem_1rem_1rem] gap-1 items-center text-sm text-muted",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
{/* Right-aligned: a duration is a number, so the digits line up on their own edge (30px for
|
{/* Right-aligned: a duration is a number, so the digits line up on their own edge (30px for
|
||||||
"1:52" up to 59px for an 11-hour stream — 4rem holds the longest). */}
|
"1:52" up to 59px for an 11-hour stream — 4rem holds the longest). */}
|
||||||
<span className="text-right tabular-nums">
|
<span className="text-right tabular-nums">
|
||||||
@@ -379,7 +384,9 @@ function VideoCard({
|
|||||||
const ro = new ResizeObserver(check);
|
const ro = new ResizeObserver(check);
|
||||||
els.forEach(([el]) => el && ro.observe(el));
|
els.forEach(([el]) => el && ro.observe(el));
|
||||||
return () => ro.disconnect();
|
return () => ro.disconnect();
|
||||||
}, [video.title, video.channel_title]);
|
// `view` matters as much as the text: switching views returns a different branch, so React can
|
||||||
|
// remount these nodes — without it the observer would be left watching detached ones.
|
||||||
|
}, [video.title, video.channel_title, view]);
|
||||||
const title = (
|
const title = (
|
||||||
<a
|
<a
|
||||||
ref={titleRef}
|
ref={titleRef}
|
||||||
@@ -451,11 +458,17 @@ function VideoCard({
|
|||||||
{/* Actions lead: this is where the eye already is (the title is the thing you read), so
|
{/* Actions lead: this is where the eye already is (the title is the thing you read), so
|
||||||
they're the shortest pointer trip from it. */}
|
they're the shortest pointer trip from it. */}
|
||||||
<div className="shrink-0 w-48">{actions}</div>
|
<div className="shrink-0 w-48">{actions}</div>
|
||||||
|
{/* Everything else is shrink-0, so the title is the only thing that can give — which means
|
||||||
|
once the fixed columns outgrow the row, it gives ALL of it and vanishes. Columns drop
|
||||||
|
from the right as space runs out, least important first: a title with no date beats a
|
||||||
|
date with no title. Breakpoints are the viewport, not this row, so they're rough — the
|
||||||
|
rail and filter panel move the row's width too — but they're pitched to keep the title
|
||||||
|
alive at the narrow end rather than to hold every column to the last pixel. */}
|
||||||
<div className="min-w-0 flex-1">{title}</div>
|
<div className="min-w-0 flex-1">{title}</div>
|
||||||
<div className="shrink-0 w-32">{channelButton}</div>
|
<div className="shrink-0 w-32 hidden sm:block">{channelButton}</div>
|
||||||
<RowMetaCells video={video} />
|
<RowMetaCells video={video} className="hidden md:grid" />
|
||||||
<div className="shrink-0 w-36 text-sm text-muted truncate">{views}</div>
|
<div className="shrink-0 w-36 text-sm text-muted truncate hidden lg:block">{views}</div>
|
||||||
<div className="shrink-0 w-48 text-sm text-muted truncate">{published}</div>
|
<div className="shrink-0 w-48 text-sm text-muted truncate hidden xl:block">{published}</div>
|
||||||
{/* Thumb draws this over the image; with no image it goes on the row itself. */}
|
{/* Thumb draws this over the image; with no image it goes on the row itself. */}
|
||||||
{pct > 0 && (
|
{pct > 0 && (
|
||||||
<div className="absolute bottom-0 left-2 right-2 h-1 rounded-full bg-black/40">
|
<div className="absolute bottom-0 left-2 right-2 h-1 rounded-full bg-black/40">
|
||||||
|
|||||||
Reference in New Issue
Block a user