feat(layout): a pinned filter rail no longer pushes content when there's room for it
On a page that centres its content at a max width, if the window is wide enough for the rail to fit in the content's LEFT margin without overlapping it, pinning the rail now leaves it OVERLAY — the content doesn't shift. It reverts to the old in-flow "push" only when there isn't room: a full-width page (feed) or a window too narrow for the rail to clear the centred content. PageShell computes --rail-pinned-w from the page's maxWidth vs the viewport (innerWidth >= maxWidth + ~576px → overlay 2.25rem, else in-flow 16.75rem) on a resize listener; the SidePanel slot reads it. Verified at 1920px: pinning the playlists rail leaves the table at left 487 (moved 0); the rail sits 256px wide ending at 312 — 175px clear of the content. Feed (full width) still pins in-flow.
This commit is contained in:
@@ -67,12 +67,30 @@ export default function PageShell({
|
||||
}) {
|
||||
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).
|
||||
// same width the content column uses. Global (one page shell renders at a time). Also decide whether
|
||||
// a PINNED filter rail should stay OVERLAY (keep the toolbar's fixed leading gutter, don't push the
|
||||
// centred content) or go in-flow: overlay only when the centred content leaves a wide-enough left
|
||||
// margin for the rail to sit in — else pinning would overlap the content, so it pushes (in-flow).
|
||||
useLayoutEffect(() => {
|
||||
const root = document.documentElement;
|
||||
root.style.setProperty("--content-mw", maxWidth ?? "none");
|
||||
// Room the pinned rail needs: its own width (~16rem) on each side of the centred content, plus the
|
||||
// nav rail (~4rem). Below that, or on a full-width page (no maxWidth), pin in-flow (w-67).
|
||||
const apply = () => {
|
||||
const mwPx = maxWidth
|
||||
? maxWidth.endsWith("rem")
|
||||
? parseFloat(maxWidth) * 16
|
||||
: parseFloat(maxWidth)
|
||||
: null;
|
||||
const roomy = mwPx != null && window.innerWidth >= mwPx + 576;
|
||||
root.style.setProperty("--rail-pinned-w", roomy ? "2.25rem" : "16.75rem");
|
||||
};
|
||||
apply();
|
||||
window.addEventListener("resize", apply);
|
||||
return () => {
|
||||
window.removeEventListener("resize", apply);
|
||||
root.style.removeProperty("--content-mw");
|
||||
root.style.removeProperty("--rail-pinned-w");
|
||||
};
|
||||
}, [maxWidth]);
|
||||
// The floating header pads the content below it by `--hdr-h`. That must equal the header's REAL
|
||||
|
||||
Reference in New Issue
Block a user