polish(channel): compact header — stats inline, slimmer banner
- Move the channel stats (subscribers / videos / views / joined) onto one meta line beside the handle under the name, dropping the separate stats row. - Cap the banner at 150px tall so it no longer dominates the page; the wide YouTube-style crop is kept. Net: the video grid starts much higher.
This commit is contained in:
parent
c59b53a51b
commit
50a7774588
1 changed files with 21 additions and 16 deletions
|
|
@ -123,6 +123,14 @@ export default function ChannelPage({
|
|||
const joined = ch?.published_at
|
||||
? new Date(ch.published_at).toLocaleDateString(i18n.language, { year: "numeric", month: "short" })
|
||||
: null;
|
||||
// Handle + stats on one compact meta line under the name (saves the separate stats row).
|
||||
const metaParts = [
|
||||
ch?.handle ? `@${ch.handle.replace(/^@/, "")}` : null,
|
||||
ch?.subscriber_count != null ? t("channel.subscribers", { formatted: formatViews(ch.subscriber_count) }) : null,
|
||||
ch?.video_count != null ? t("channel.videoCount", { count: ch.video_count }) : null,
|
||||
ch?.total_view_count != null ? t("channel.totalViews", { formatted: formatViews(ch.total_view_count) }) : null,
|
||||
joined ? t("channel.joined", { date: joined }) : null,
|
||||
].filter(Boolean) as string[];
|
||||
const tabClass = (active: boolean) =>
|
||||
active
|
||||
? "pb-2 text-sm font-medium border-b-2 border-fg text-fg"
|
||||
|
|
@ -136,7 +144,10 @@ export default function ChannelPage({
|
|||
// Match YouTube's banner: the stored bannerExternalUrl is the full 16:9 template at a
|
||||
// low default size, so request a crisp wide version (=w1707) and object-cover the
|
||||
// desktop "safe area" — the centre 2560×423 (~6:1) band — at full width.
|
||||
<div className="w-full overflow-hidden bg-surface" style={{ aspectRatio: "2560 / 423" }}>
|
||||
<div
|
||||
className="w-full overflow-hidden bg-surface"
|
||||
style={{ aspectRatio: "2560 / 423", maxHeight: "150px" }}
|
||||
>
|
||||
<img
|
||||
src={`${ch.banner_url}=w1707`}
|
||||
alt=""
|
||||
|
|
@ -173,9 +184,14 @@ export default function ChannelPage({
|
|||
</span>
|
||||
)}
|
||||
</div>
|
||||
{ch?.handle && (
|
||||
<div className="text-sm text-muted truncate">@{ch.handle.replace(/^@/, "")}</div>
|
||||
)}
|
||||
<div className="text-sm text-muted mt-0.5 flex flex-wrap gap-x-1.5 gap-y-0.5">
|
||||
{metaParts.map((part, i) => (
|
||||
<span key={i}>
|
||||
{i > 0 && <span className="mr-1.5">·</span>}
|
||||
{part}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 shrink-0 pb-1">
|
||||
<a
|
||||
|
|
@ -212,17 +228,6 @@ export default function ChannelPage({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{/* Stats */}
|
||||
<div className="flex flex-wrap items-center gap-x-2.5 gap-y-1 text-sm text-muted mt-3">
|
||||
{ch?.subscriber_count != null && (
|
||||
<span>{t("channel.subscribers", { formatted: formatViews(ch.subscriber_count) })}</span>
|
||||
)}
|
||||
{ch?.video_count != null && <span>· {t("channel.videoCount", { count: ch.video_count })}</span>}
|
||||
{ch?.total_view_count != null && (
|
||||
<span>· {t("channel.totalViews", { formatted: formatViews(ch.total_view_count) })}</span>
|
||||
)}
|
||||
{joined && <span>· {t("channel.joined", { date: joined })}</span>}
|
||||
</div>
|
||||
{exploring && (
|
||||
<div className="flex items-center gap-2 text-xs text-muted mt-2">
|
||||
<Loader2 className="w-3.5 h-3.5 animate-spin" />
|
||||
|
|
@ -231,7 +236,7 @@ export default function ChannelPage({
|
|||
)}
|
||||
|
||||
{/* Tabs */}
|
||||
<div className="flex items-center gap-4 mt-4 border-b border-border">
|
||||
<div className="flex items-center gap-4 mt-3 border-b border-border">
|
||||
<button onClick={() => setTab("videos")} className={tabClass(tab === "videos")}>
|
||||
{t("channel.tabVideos")}
|
||||
</button>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue