commit dda46eb4db9fda0e3c8a450c36094c7f0f1ad36d
parent da102eab935821d0e19695a72c31bb1dfa83de36
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Sun, 13 Sep 2026 11:20:02 -0400
channels: one primary in the header, and the caveat beside the title
Four dark pills of equal weight shared the header: three that sweep the
WHOLE channel pool and are used rarely, and one that creates a channel and
is the actual call to action. The three become outlines under an "Every
channel" eyebrow that says what they act on; New channel is the only fill.
The freshness note moves from the very bottom of the page - 11px type under
a floating bar, ~6,000px below the numbers it is a caveat about - to the
subtitle slot beside the h1, prefixed with the channel count. It is the same
element with the same data-testid and the same text; it was written before
and it is said now.
On md+ the page root becomes a viewport-height flex column so the rack
scrolls inside its own region and the chrome around it stays put.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat:
1 file changed, 86 insertions(+), 62 deletions(-)
diff --git a/editor/app/channels/page.tsx b/editor/app/channels/page.tsx
@@ -259,20 +259,78 @@ export default async function ChannelsPage({
briefs.filter((b) => shown.has(b.slug)),
);
return (
- <div className="flex flex-col gap-4">
- <div className="flex items-center justify-between">
- <h1 className="text-2xl font-semibold">Channels</h1>
- <div className="flex items-center gap-2">
- <SyncAllChannelsButton />
- <RefreshAllReportsButton />
- <Link
- href="/channels/new"
- className="px-3 py-2 rounded-md bg-primary text-primary-foreground text-sm font-medium hover:opacity-90"
- >
- New channel
- </Link>
+ // ON md+ THE DOCUMENT STOPS SCROLLING. The page is a flex column exactly
+ // the height of the viewport (main carries py-6, hence -3rem) so that the
+ // header, the focus line, the instrument bar and the selection deck are
+ // fixed chrome and the rack between them is the only thing that moves.
+ // Below md there is no height and the document scrolls as it always has.
+ <div className="flex flex-col gap-3 md:h-[calc(100vh-3rem)] md:min-h-0">
+ <header className="flex flex-wrap items-start justify-between gap-x-4 gap-y-2 shrink-0">
+ <div className="min-w-0">
+ <h1 className="text-2xl font-semibold">Channels</h1>
+ {/* THE FRESHNESS NOTE IS THE PAGE'S CAVEAT, so it sits with the
+ page's title. It used to be the last thing on the page, in 11px
+ type under a floating bar, ~6,000px below the numbers it is a
+ caveat ABOUT — which is to say it was written but not said. */}
+ {channels.length > 0 && (
+ <p
+ className="max-w-3xl text-xs text-muted-foreground"
+ data-testid="channels-freshness"
+ >
+ <span className="tabular-nums">{channels.length}</span>{" "}
+ {channels.length === 1 ? "channel" : "channels"} ·{" "}
+ {freshness.oldest ? (
+ <>
+ Every pipeline on this page — downloads, transcripts,
+ digests and the speaker lanes — is read from each
+ channel’s last report; the oldest on this page was
+ generated{" "}
+ <time dateTime={freshness.oldest}>
+ {new Date(freshness.oldest).toLocaleString()}
+ </time>
+ . A just-finished job can take a moment to show up here.
+ </>
+ ) : (
+ <>
+ No channel on this page has a generated report yet, so every
+ pipeline reads empty. Run <em>Refresh report</em> from a row
+ here, or <em>Update all reports</em> above, to populate them.
+ </>
+ )}
+ {freshness.missing.length > 0 && freshness.oldest && (
+ <>
+ {" "}
+ No report yet for {freshness.missing.join(", ")} — those rows
+ read zero
+ {sections
+ ? ", and a group figure that counts one of them is marked with a trailing + to say it is a floor rather than a total."
+ : "."}
+ </>
+ )}
+ </p>
+ )}
</div>
- </div>
+ {/* FOUR DARK PILLS OF EQUAL WEIGHT was four things shouting. Three of
+ these sweep the WHOLE pool and are used rarely; one creates a
+ channel and is the page's actual call to action. So the three are
+ outlines under an eyebrow that says what they act on, and only
+ "New channel" is filled. */}
+ <div className="flex shrink-0 flex-col items-end gap-1">
+ <span className="font-mono text-[10px] uppercase tracking-[0.16em] text-muted-foreground">
+ Every channel
+ </span>
+ <div className="flex flex-wrap items-center justify-end gap-2">
+ <SyncAllChannelsButton />
+ <RefreshAllReportsButton />
+ <Link
+ href="/channels/new"
+ className="inline-flex h-8 items-center rounded-md bg-primary px-3 text-xs font-medium text-primary-foreground hover:opacity-90"
+ >
+ New channel
+ </Link>
+ </div>
+ </div>
+ </header>
{channels.length === 0 ? (
<p className="text-sm text-muted-foreground border border-dashed border-border rounded p-4">
{active.siteId && !active.isAll
@@ -280,55 +338,21 @@ export default async function ChannelsPage({
: "No channels yet."}
</p>
) : (
- <>
- <ChannelsTable
- channels={channels}
- columns={columns}
- sections={sections}
- siteId={activeSite?.siteId}
- // The configured cold root, for the bulk bar's box. Read here, not
- // in the client component — the settings page is its one writer.
- defaultMediaRoot={getSettings().storage.mediaRoot}
- sites={sites.map((s) => ({
- siteId: s.siteId,
- title: s.siteTitle || s.siteId,
- }))}
- focusLabel={focusLabel}
- />
- <p
- className="text-xs text-muted-foreground"
- data-testid="channels-freshness"
- >
- {freshness.oldest ? (
- <>
- Every pipeline on this page — downloads, transcripts,
- digests and the speaker lanes — is read from each
- channel’s last report; the oldest on this page was
- generated{" "}
- <time dateTime={freshness.oldest}>
- {new Date(freshness.oldest).toLocaleString()}
- </time>
- . A just-finished job can take a moment to show up here.
- </>
- ) : (
- <>
- No channel on this page has a generated report yet, so every
- pipeline reads empty. Run <em>Refresh report</em> from a row
- here, or <em>Update all reports</em> above, to populate them.
- </>
- )}
- {freshness.missing.length > 0 && freshness.oldest && (
- <>
- {" "}
- No report yet for {freshness.missing.join(", ")} — those rows
- read zero
- {sections
- ? ", and a group figure that counts one of them is marked with a trailing + to say it is a floor rather than a total."
- : "."}
- </>
- )}
- </p>
- </>
+ <ChannelsTable
+ channels={channels}
+ columns={columns}
+ sections={sections}
+ siteId={activeSite?.siteId}
+ // The configured cold root, for the selection deck's root box. Read
+ // here, not in the client component — the settings page is its one
+ // writer.
+ defaultMediaRoot={getSettings().storage.mediaRoot}
+ sites={sites.map((s) => ({
+ siteId: s.siteId,
+ title: s.siteTitle || s.siteId,
+ }))}
+ focusLabel={focusLabel}
+ />
)}
</div>
);