Skip to content

fix(layout): single scroll owner, stable sidebar, working scroll restoration - #375

Open
ayebrian wants to merge 5 commits into
friendly-social:devfrom
ayebrian:fix/layout-scroll-sidebar
Open

fix(layout): single scroll owner, stable sidebar, working scroll restoration#375
ayebrian wants to merge 5 commits into
friendly-social:devfrom
ayebrian:fix/layout-scroll-sidebar

Conversation

@ayebrian

@ayebrian ayebrian commented Sep 7, 2026

Copy link
Copy Markdown

What this PR does

Fixes the layout/scroll bugs:

  1. Double scrolling + unstable sidebarScaffold had a dead h-full on the middle row (flex-1 already fills the remainder of the h-dvh column) and the scroll container was missing min-h-0, so content could overflow and the page itself started scrolling (double scroll, sidebar jitter).
  2. Broken scroll restorationScrollRestoration now operates on the actual scroll container (the previously referenced element wasn't the one that scrolls).
  3. Community scroll state clobbering activity — the virtualizer stored state under the activity.scroll key (copy-paste bug), so the two pages overwrote each other's scroll positions.

Also:

  • Profile page: min-h-[calc(100vh-64px)]min-h-full. The hardcoded 64px TopBar + vh (not dvh) + the unaccounted bottom MenuBar made the content always taller than the container on mobile.
  • Mobile bottom bar: rewritten as a proper 5-tab bar — visible labels (all 5 i18n keys exist in EN/RU), aria-label/aria-current on the active tab, the Q4 release badge, ~44px touch targets, and safe-area padding for notched phones.
  • Stable rail width: w-16 lg:w-55 + shrink-0 instead of a content-sized rail with lg:min-w-55 (circular sizing, ~160px jump at the lg breakpoint).
  • Icon-only rail (md): icons centered (max-lg:justify-center), Q4 badge hidden below lg (it overflowed the 64px rail by ~11px), stray whitespace text nodes dropped (base Button already has gap-2).

Files changed

  • src/app/scaffold.tsx — scroll owner + restoration
  • src/app/profile/page.tsx — full-bleed card, correct min-height
  • src/app/community/page.tsx — dedicated virtualizer scroll key
  • src/app/menu.tsx — stable rail, real bottom bar, centered icons
  • src/app/blocking-qr/page.tsx + src/components/session-provider.tsx?demo dev flag to render the app without backend auth
  • docs/screenshots/ — screenshots below

Screenshots

Desktop (1440×900) — labelled rail, stable 220px width:

desktop

Mid (900×800) — icons-only rail, icons centered:

mid

Mobile (390×844) — labelled 5-tab bar with Q4 badge + safe-area padding:

mobile

Verification

  • Manual: no double scroll at any breakpoint; sidebar stable across md/lg; back/forward restores the previous scroll position on community and activity (and no longer clobbers the other's state); profile fills the container without forced page scroll.
  • Rail geometry checked via DOM measurements: icon center == button center at md (cx 32/32); badge fits within the tab cell on mobile; lg rail spacing even (8px gaps).
  • pnpm lint — clean (tsc + eslint + prettier).

Follow-ups (not required for this fix)

  • Parameterize useListVirtualizer with a storage key — the activity/community copies are what produced the shared-key bug.
  • ?demo flag: docs/commit say ?demo=1, code checks has('demo') — align the check or the docs.

@ayebrian
ayebrian force-pushed the fix/layout-scroll-sidebar branch from 2d70bd1 to 86aa3af Compare September 7, 2026 13:52
…oration

- scaffold: drop dead h-full from the middle row (flex-1 already fills the
  remainder of the h-dvh column); add min-h-0 to the scroll container so it
  can actually shrink and own the scroll; shrink-0 on the sidebar wrapper
  so the rail cannot be squeezed below its width.
- profile: min-h-[calc(100vh-64px)] -> min-h-full. The hardcoded 64px
  TopBar + vh (not dvh) + the unaccounted bottom MenuBar made the content
  always taller than the container on mobile.
- community: the virtualizer scroll state was stored under the
  'activity.scroll' key (copy-paste), overwriting activity/page.tsx and
  vice versa. Now 'community.scroll'.
- menu: stable rail width w-16 lg:w-55 + shrink-0 instead of a
  content-sized rail with lg:min-w-55 (circular sizing, ~160px jump at
  the lg breakpoint); MobileBar now has labels, aria-label/aria-current,
  the Q4 badge, ~44px touch targets and safe-area padding for notched
  phones; removed the duplicate MENUBAR_ITEMS array and the dead
  size-icon class.
Dev-only (import.meta.env.DEV): shows the session as authed and skips the
blocking QR screen, so layout work can be done without a backend token.
Marked TODO(demo) in both spots.
At the md breakpoint the rail is icons-only (labels hidden <lg) and now
has a fixed w-16 (64px) width; the inline Q4 badge after the Chat icon
overflowed the rail edge by ~11px. Hide it below lg like the labels —
it stays visible on the lg+ rail and in the mobile MenuBar.
Rendered via pnpm dev with ?demo=1 (no backend): community page at
1440x900, 900x800 and 390x844 to show the stable rail, the icon-only
rail and the labelled bottom MenuBar with safe-area padding.
Below lg the rail is icons-only; with justify-start the icon sat
left-of-center (crooked). max-lg:justify-center fixes it. Also drop
the whitespace text nodes around the hidden label/badge — the base
Button already has gap-2, so the anonymous flex items only shifted
the icon.

Screenshots refreshed to match.
@ayebrian
ayebrian force-pushed the fix/layout-scroll-sidebar branch from 86aa3af to 22f7eda Compare September 7, 2026 13:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant