fix(ui): stop the header sliding sideways between routes - #75
Conversation
The shell bar took a `measure` prop and tracked whichever column the page under it used, so it was 960px on /account and /payouts/new and 1248px everywhere else. Every crossing moved the seal and the nav 144px sideways. That trade was made in #39 and priced as admin-only, on the premise that a member only ever sees /account. Payouts falsified it: /payouts is wide, /payouts/new is narrow, and a plain member walks that list -> form path in sequence, watching the chrome slide under them mid-task. Pin the bar to --measure-page on every route and drop the prop. The page measures are untouched: .page--narrow still holds the reading column at 60rem. The cost is that on the two narrow routes the seal sits 144px outboard of the H1, and the nav's right edge 144px outboard of the content's — symmetric, and less than chrome that won't hold still. e2e/shell.spec.ts asserts the bar's width and centring are identical on all seven routes that render one, measuring the rect rather than the absence of a class name.
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 32 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
Comment |
The bug
The shell bar took a
measureprop and tracked whichever column the page under it used: 960px on/accountand/payouts/new, 1248px everywhere else. Every crossing between the two moved the seal and the nav 144px sideways.Reported as "the header seems quite narrow in general, but also seems to change between page nav" — both halves were real, and they were the same cause. At 1920 the narrow bar's contents occupy exactly half the viewport, which is what reads as stranded.
Why it was like that
The trade was made deliberately in #39 and documented: the bar tracked the page column so the seal landed on the H1's vertical. It was priced as an admin-only cost, on the premise that a member only ever sees
/account.Payouts (#65) falsified that premise 32 commits later.
/payoutsis wide,/payouts/newis narrow, and a plain flygd member walks that list -> form path in sequence — watching the chrome slide under them mid-task.Worth knowing before reopening this: #39 shipped the fixed measure first and reversed itself to the tracking one within the same PR. This is the third position, not a fresh idea.
The change
Pin
.shell__barto--measure-pageon every route and drop the prop.globals.css— one measure for the bar;.shell__bar--narrowdeleted.ui.tsx—measureprop removed. JSX excess-property checking is the compile-time guard against a stale caller.account/page.tsx,payouts/new/page.tsx,error.tsx— droppedmeasure="narrow".Page measures are untouched.
.page--narrowstill holds the reading column at 60rem on the routes that want it; only the chrome stopped moving.The cost is symmetric and it is the whole of it: on the two narrow routes the seal sits 144px outboard of the H1, and the nav's right edge 144px outboard of the content's right edge. The ground was always full-bleed, so the bar's contents were never read as sitting inside the page column to begin with.
Test
e2e/shell.spec.tsasserts the bar's width and centring are identical on all seven routes that render one.It measures the rect rather than the absence of a class name — the class was one of several ways to reintroduce the shift (a
--narrowvariant, a:has()rule, a per-page override), and only the geometry is the property that matters. Slack is computed againstdocument.documentElement.clientWidthrather than a hardcoded 1440, because nothing setsscrollbar-gutter: stable.Three guards inside the loop stop it measuring a bar that isn't the one asked for, since all three failure modes otherwise end in a passing assertion:
/account, whose bar is already 1248SiteHeader— and this same commit dropped itsmeasure="narrow", so its bar is now exactly 1248 tooboundingBox()null, and a barebox!.xthrows aTypeErrornaming neither route nor reasonMutation-tested rather than trusted green: flipping
.shell__barto the narrow measure fails on all seven routes at once, which is the "everything moved together" case the spelled-out literal exists to catch.Verification
Where to look
src/app/_components/ui.tsx— theSiteHeaderdocblock carries the argument that has to be beaten before this is reversed a third time.Not in scope
e2e/admin.spec.ts:76has a pre-existing flake:getByRole("alert")matches both the.notice--badparagraph and Next's dev-only__next-route-announcer__. Confirmed unrelated to this diff by running the suite atc688880. One selector change fixes it; left for a separate PR.🤖 Generated with Claude Code