refactor(managers): full About overlay + center the wider channel content (E4 S2 follow-up)

- The About overlay now shows the FULL channel About (description, external links,
  country, language, topics, keywords) — the same content as the detail page's About
  tab, via a new shared ChannelAboutContent component (reused by ChannelPage + AboutCell)
- AboutCell fetches the channel detail ON DEMAND on hover (shared [channel,id] react-query
  cache with the channel page), so the list stays light; the overlay is interactive
  (scrollable + clickable links) via a small hover-bridge, and closes on page scroll/resize
- Center the content: max-w-7xl -> max-w-[96rem] on the channel tables + header, so the
  wider About table stays symmetric with the header (mx-auto handles the responsive centering)
- Topic chips are display-only for now; the future search epic makes them clickable
This commit is contained in:
2026-07-19 20:25:06 +02:00
parent 9db1d3fba3
commit 8abb78b0bd
5 changed files with 212 additions and 138 deletions
+6 -6
View File
@@ -306,7 +306,7 @@ export default function Channels() {
key: "about",
header: t("channels.cols.about"),
hideInCard: true,
render: (c) => <AboutCell text={c.description} />,
render: (c) => <AboutCell text={c.description} channelId={c.id} />,
},
{
key: "stored",
@@ -464,7 +464,7 @@ export default function Channels() {
);
const tabs = (
<div className="px-4 pt-4 max-w-7xl mx-auto flex items-center justify-between gap-4 flex-wrap">
<div className="px-4 pt-4 max-w-[96rem] mx-auto flex items-center justify-between gap-4 flex-wrap">
<div className="flex flex-wrap items-center gap-1.5">
{(["subscribed", "discovery", "blocked"] as ChannelsView[]).map((v) => (
<button
@@ -492,7 +492,7 @@ export default function Channels() {
<PageToolbar>
{tabs}
{view === "subscribed" && (
<div className="px-4 pt-2 pb-2 max-w-7xl mx-auto">
<div className="px-4 pt-2 pb-2 max-w-[96rem] mx-auto">
{/* Your tags (left) share one row with the two catalog-wide actions (right); the channel-name
search lives in the shared top SearchBar, tag create/delete in the manager. */}
<div className="flex items-center justify-between gap-4 flex-wrap">
@@ -555,7 +555,7 @@ export default function Channels() {
/>
) : view === "blocked" ? (
/* Blocked channels — videos from these are hidden everywhere and dropped from live search. */
<div className="px-4 pb-4 pt-3 max-w-7xl mx-auto">
<div className="px-4 pb-4 pt-3 max-w-[96rem] mx-auto">
{(blockedQuery.data?.length ?? 0) === 0 ? (
<p className="text-sm text-muted py-8">{t("channels.blocked.empty")}</p>
) : (
@@ -592,7 +592,7 @@ export default function Channels() {
/* No top padding: the sticky header sits flush at the scroller top so it doesn't shift when
`position: sticky` engages on the first scroll (the band's controls row above gives the
visual gap). */
<div className="px-4 pb-4 max-w-7xl mx-auto">
<div className="px-4 pb-4 max-w-[96rem] mx-auto">
{/* Channel table — only the rows scroll; the header row is sticky, and the controls row
(status chips + pager) rides in the fixed band right above it (controlsInBand). */}
{channelsQuery.isLoading ? (
@@ -606,7 +606,7 @@ export default function Channels() {
controlsPosition="both"
controlsLeading={statusChips}
controlsInBand
controlsBandClassName="px-4 max-w-7xl mx-auto"
controlsBandClassName="px-4 max-w-[96rem] mx-auto"
rowClassName={(c) => (c.hidden ? "opacity-60" : "")}
emptyText={t("channels.empty")}
/>