improvement(feed): give the compact row's title the room back
Three from UAT: the row's cap goes 1280 -> 1472 (+15%), since with the rail and filters hidden there was a lot of page left over and the fixed columns mean the extra width can only go to the title; the views column drops the word and keeps it in the tooltip (a table doesn't repeat its unit every line), taking that column 144 -> 64; and the view switcher names the current mode where the toolbar has room, falling back to the icon alone below xl. Title: 431 -> 511 at 1440, 706 at 1900.
This commit is contained in:
@@ -353,8 +353,15 @@ function VideoCard({
|
||||
const noThumb = !spec.thumb;
|
||||
// Each datum on its own, so the one-line row can give each a column of its own while the stacked
|
||||
// layouts still run them together as one sentence.
|
||||
// Two shapes for the count: the stacked layouts read it as prose ("1.5K views · 2 min ago"), so
|
||||
// they need the word; the row's column doesn't — a table doesn't repeat its unit on every line,
|
||||
// and the tooltip has the exact figure anyway. Same tooltip either way.
|
||||
const viewsTitle = video.view_count != null ? `${video.view_count.toLocaleString()} ${t("card.views")}` : "";
|
||||
const viewsCount = video.view_count != null && (
|
||||
<span title={viewsTitle}>{formatViews(video.view_count)}</span>
|
||||
);
|
||||
const views = video.view_count != null && (
|
||||
<span title={`${video.view_count.toLocaleString()} ${t("card.views")}`}>
|
||||
<span title={viewsTitle}>
|
||||
{formatViews(video.view_count)} {t("card.views")}
|
||||
</span>
|
||||
);
|
||||
@@ -439,12 +446,12 @@ function VideoCard({
|
||||
// still right WITHIN a cell (see RowMetaCells): fixed slots, so they line up across rows too.
|
||||
// Widths are measured, not chosen by eye — against the worst case in the LIBRARY and in BOTH
|
||||
// languages, since both have caught me out here:
|
||||
// actions 188 (6 x 28 + 5 x 4) · meta cells 104 (see RowMetaCells) · views 139 ("101.7K
|
||||
// megtekintés"; the English "views" is only 79) · published 183 ("11 months ago ·
|
||||
// Feb 28, 2026"; HU is shorter) · channel 128, which is a deliberate cut rather than a fit:
|
||||
// names run to 342px, the median is 87, and 12 of 102 truncate here vs 5 at 160 — worth 32px
|
||||
// to the title, since a clipped channel name still reads while a clipped view count loses the
|
||||
// number.
|
||||
// actions 188 (6 x 28 + 5 x 4) · meta cells 104 (see RowMetaCells) · views 48 (the bare
|
||||
// "101.7K"; language-proof now the word is gone — with it, Hungarian's "megtekintés" needed
|
||||
// 139) · published 183 ("11 months ago · Feb 28, 2026"; HU is shorter) · channel 128,
|
||||
// which is a deliberate cut rather than a fit: names run to 342px, the median is 87, and 12
|
||||
// of 102 truncate here vs 5 at 160 — worth 32px to the title, since a clipped channel name
|
||||
// still reads while a clipped view count loses the number.
|
||||
// Three ways this went wrong before: sizing off a PAGE of data (the badges came from 60 videos
|
||||
// whose longest was 2:00:58, then wrapped on the 11-hour one); measuring with a hand-built probe
|
||||
// instead of the real element (it read "101.7K megtekintés" as 122px where the live cell renders
|
||||
@@ -467,7 +474,12 @@ function VideoCard({
|
||||
<div className="min-w-0 flex-1">{title}</div>
|
||||
<div className="shrink-0 w-32 hidden sm:block">{channelButton}</div>
|
||||
<RowMetaCells video={video} className="hidden md:grid" />
|
||||
<div className="shrink-0 w-36 text-sm text-muted truncate hidden lg:block">{views}</div>
|
||||
{/* Right-aligned like the duration: it's a number, so the digits share an edge. 64px
|
||||
holds the widest bare form ("101.7K" at 48) in either language — dropping the word
|
||||
took this from 144 and handed the difference to the title. */}
|
||||
<div className="shrink-0 w-16 text-sm text-muted text-right tabular-nums truncate hidden lg:block">
|
||||
{viewsCount}
|
||||
</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. */}
|
||||
{pct > 0 && (
|
||||
|
||||
@@ -96,12 +96,17 @@ export default function ViewSwitcher<T extends string>({
|
||||
onClick={() => (open ? close() : openMenu())}
|
||||
aria-haspopup="menu"
|
||||
aria-expanded={open}
|
||||
// The aria-label carries the mode's name at every size — the visible text below is a
|
||||
// nicety for wide windows, not the accessible name.
|
||||
aria-label={`${label}: ${current.label}`}
|
||||
title={`${label}: ${current.label}`}
|
||||
className="shrink-0 inline-flex items-center gap-1 pl-1.5 pr-1 py-1.5 rounded-lg border border-border bg-card text-fg hover:border-accent hover:text-accent active:translate-y-px transition"
|
||||
className="shrink-0 inline-flex items-center gap-1 pl-2 pr-1 py-1.5 rounded-lg border border-border bg-card text-fg hover:border-accent hover:text-accent active:translate-y-px transition"
|
||||
>
|
||||
<CurrentIcon className="w-4 h-4" />
|
||||
<ChevronDown className={`w-3 h-3 transition-transform ${open ? "rotate-180" : ""}`} />
|
||||
<CurrentIcon className="w-4 h-4 shrink-0" />
|
||||
{/* Name the current mode where the toolbar has room; below xl it's a busy row (show chips,
|
||||
content chips, source, count, sort) and the icon has to carry it alone. */}
|
||||
<span className="hidden xl:inline text-sm whitespace-nowrap">{current.label}</span>
|
||||
<ChevronDown className={`w-3 h-3 shrink-0 transition-transform ${open ? "rotate-180" : ""}`} />
|
||||
</button>
|
||||
{open && (
|
||||
<div
|
||||
|
||||
@@ -41,9 +41,10 @@ export const FEED_VIEW_SPEC: Record<FeedView, FeedViewSpec> = {
|
||||
// Keeps the 896px cap: its actions dock at the right edge, so a wider row would only stretch the
|
||||
// dead space between them and the meta.
|
||||
rows: { family: "row", minCol: null, maxCol: 896, thumb: true, dense: false, actionsBelow: false },
|
||||
// Wider (1280): everything sits on one line with the actions right-aligned, so there's no gap to
|
||||
// grow — the extra width just buys more title before it truncates.
|
||||
rowsCompact: { family: "row", minCol: null, maxCol: 1280, thumb: false, dense: false, actionsBelow: false },
|
||||
// Much wider (1472): everything sits on one line and the columns after the title are fixed, so
|
||||
// there's no gap for the extra width to stretch — it all goes to the title. Raised from 1280 at
|
||||
// the user's request once they saw how much room was left over with the rail and filters hidden.
|
||||
rowsCompact: { family: "row", minCol: null, maxCol: 1472, thumb: false, dense: false, actionsBelow: false },
|
||||
// 380 = thumbnail (160) + gap (12) + ~192 for the text + the block's own padding (16). The text
|
||||
// floor is the action row's measured 156px plus enough for a title to be worth reading.
|
||||
// Tuned by measuring the real layouts, not guessed: 3 columns need 3n+32 px, so 380 turns the
|
||||
|
||||
Reference in New Issue
Block a user