From e1c66f3bbabf13a288a38c03bf883b1fd4f5af82 Mon Sep 17 00:00:00 2001 From: mkfain Date: Fri, 22 May 2026 00:39:07 -0500 Subject: [PATCH] Slide profile tabs away with the mobile top bar on scroll MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MobileTopBar slides off-screen on scroll-down, but ProfileTabs stayed pinned at `top-mobile-bar`, leaving a translucent gap above the tabs where the top bar used to be — and on scroll-up, the returning top bar (z-20) visibly crossed over the top of the tab bar (z-10) until it docked flush above them. Mirror the global `SubHeaderBar`'s default behavior: track `useNavHidden()` and apply `nav-hidden-slide` with a transform transition so the tabs ride up off-screen together with the top bar. Regression-of: 121991f3 --- src/components/profile/ProfileTabs.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/components/profile/ProfileTabs.tsx b/src/components/profile/ProfileTabs.tsx index d0ed36ca..e90485a1 100644 --- a/src/components/profile/ProfileTabs.tsx +++ b/src/components/profile/ProfileTabs.tsx @@ -1,5 +1,6 @@ import { useEffect, useLayoutEffect, useRef, useState } from 'react'; import { cn } from '@/lib/utils'; +import { useNavHidden } from '@/contexts/LayoutContext'; export interface ProfileTabsProps { tabs: Array<{ id: string; label: string }>; @@ -27,6 +28,7 @@ export function ProfileTabs({ tabs, activeTab, onChange }: ProfileTabsProps) { const trackRef = useRef(null); const tabRefs = useRef>(new Map()); const [indicator, setIndicator] = useState<{ left: number; width: number } | null>(null); + const navHidden = useNavHidden(); // Measure the active tab and update the underline indicator. useLayoutEffect(() => { @@ -72,6 +74,14 @@ export function ProfileTabs({ tabs, activeTab, onChange }: ProfileTabsProps) { // matches the existing app convention so it sits flush with the // mobile top nav. On desktop the chrome shifts and we use top-0. 'sticky top-mobile-bar sidebar:top-0 z-10', + // On mobile, slide out of view together with the MobileTopBar when + // the user scrolls down — otherwise the tabs sit at `top-mobile-bar` + // while the top bar slides away, leaving a translucent gap above + // them, and when the top bar slides back in it visibly crosses over + // the top of the tab bar (top bar is z-20, tabs z-10). Mirrors the + // global `SubHeaderBar`'s default behavior. + 'max-sidebar:transition-transform max-sidebar:duration-300 max-sidebar:ease-in-out', + navHidden && 'nav-hidden-slide', // Visual separation — translucent backdrop so feed content doesn't // bleed through, with a single hairline border below. 'bg-background/80 backdrop-blur supports-[backdrop-filter]:bg-background/60',