feat(layout): centre the header on each page's content width, centre the playlist table

Every page's floating header (search bar + sync chip) and the toolbar band now centre on the SAME
max-width the content column uses, instead of spanning the whole column while a max-w page centres
its grid. So the search bar lines up with the left edge of the cards/table on every page, and sits
centred with the content — not against the full page width.

- PageShell takes a `maxWidth`, published as --content-mw; the header adds max-w-[--content-mw] mx-auto
  inside its left-4 / right-(1rem+scrollbar) span, so it centres on that width (`none` = full width).
- moduleRegistry PAGE_CONTENT carries each page's content max width (plex 1600px, channels 96rem,
  playlists 64rem, downloads 56rem, notifications/users 48rem; feed stays full width) — one source.
- Playlists: its content (header, filter row, table) was left-aligned max-w-5xl → now mx-auto, so the
  table is centred and the header lines up with it.

Verified at 1920px: header left edge == content left edge — feed 340, channels 213, playlists 487.
This commit is contained in:
2026-08-21 21:38:49 +02:00
parent 011acd919e
commit 1801a58f6b
6 changed files with 37 additions and 12 deletions
+13
View File
@@ -52,6 +52,7 @@ export default function PageShell({
children,
scrollKey,
fadeTop = true,
maxWidth,
}: {
header?: ReactNode;
banners?: ReactNode;
@@ -60,8 +61,20 @@ export default function PageShell({
scrollKey?: string;
// Off when this page's scroll region starts with a sticky header — see PageScroller.
fadeTop?: boolean;
// The content column's max width (e.g. "1600px"); the header + toolbar centre on the same width via
// --content-mw. Omit for a full-width page (feed). See index.css --content-mw.
maxWidth?: string;
}) {
const [toolbarSlot, setToolbarSlot] = useState<HTMLDivElement | null>(null);
// Publish this page's content max-width so the floating header (and toolbar band) can centre on the
// same width the content column uses. Global (one page shell renders at a time).
useLayoutEffect(() => {
const root = document.documentElement;
root.style.setProperty("--content-mw", maxWidth ?? "none");
return () => {
root.style.removeProperty("--content-mw");
};
}, [maxWidth]);
// The floating header pads the content below it by `--hdr-h`. That must equal the header's REAL
// height, which grows as the flex-wrap header wraps to 2–3 rows on a narrow window — a fixed pad
// would let the content toolbar slide up under it (E5 S7). Measure the header and write its height