Files
sofa/components/mobile-tab-bar.tsx
T
jakeandClaude 57ce0fd85d Fix mobile pinch zoom and content overlapping header/footer on iOS Safari (#3)
* Fix mobile pinch zoom and content overlapping header/footer on iOS Safari

Add viewport export with maximumScale=1 and userScalable=false to prevent
pinch-to-zoom. Add viewportFit=cover for proper safe area support.

Fix content rendering above the sticky header and below the fixed mobile
tab bar on iOS Safari by adding relative z-0 to the content wrapper,
creating a stacking context that keeps page content below both navigation
elements.

https://claude.ai/code/session_01Re8ndXPAMVMtiHZFVNDK7S

* Add safe area inset support for iOS 26 and fix film grain z-index

- Add safe-area-inset-top padding to NavBar for notch/Dynamic Island
- Add safe-area-inset-left/right to NavBar, main content, and
  MobileTabBar for landscape mode
- Account for safe-area-inset-bottom in content wrapper padding so
  content isn't hidden behind MobileTabBar + home indicator
- Lower film grain overlay z-index from 9999 to 1 to avoid triggering
  iOS 26 Safari's fixed-element tab tinting behavior

https://claude.ai/code/session_01Re8ndXPAMVMtiHZFVNDK7S

* Hide ambient glow on mobile where it overwhelms the viewport

The 800x600px blurred glow blob dominates narrow mobile screens and
clashes with title backdrop images. Hidden below sm breakpoint.

https://claude.ai/code/session_01Re8ndXPAMVMtiHZFVNDK7S

* Fix asymmetric safe-area insets using separate pl/pr padding

The previous px-[max(...,env(safe-area-inset-left))] shorthand applied
only the left inset to both sides. Split into separate pl/pr with the
correct env() variable for each side.

https://claude.ai/code/session_01Re8ndXPAMVMtiHZFVNDK7S

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-06 09:41:47 -05:00

64 lines
2.1 KiB
TypeScript

"use client";
import { IconCompass, IconHome, IconSettings } from "@tabler/icons-react";
import { motion } from "motion/react";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useSession } from "@/lib/auth/client";
const tabs = [
{ href: "/dashboard", label: "Home", icon: IconHome },
{ href: "/explore", label: "Explore", icon: IconCompass },
{ href: "/settings", label: "Settings", icon: IconSettings },
] as const;
export function MobileTabBar() {
const { data: session } = useSession();
const pathname = usePathname();
if (!session?.user) return null;
return (
<nav className="fixed bottom-0 left-0 right-0 z-50 border-t border-border/50 bg-background/90 pl-[env(safe-area-inset-left)] pr-[env(safe-area-inset-right)] backdrop-blur-xl sm:hidden">
<div className="flex h-14 items-stretch">
{tabs.map((tab) => {
const Icon = tab.icon;
const isActive =
tab.href === "/dashboard"
? pathname === "/dashboard"
: pathname.startsWith(tab.href);
return (
<Link
key={tab.href}
href={tab.href}
className="relative flex flex-1 flex-col items-center justify-center gap-0.5"
>
<Icon
className={`size-5 ${isActive ? "text-primary" : "text-muted-foreground"}`}
/>
<span
className={`text-[10px] font-medium ${isActive ? "text-primary" : "text-muted-foreground"}`}
>
{tab.label}
</span>
{isActive && (
<motion.div
layoutId="mobile-tab-indicator"
className="absolute top-0 h-0.5 w-8 rounded-full bg-primary"
transition={{
type: "spring",
stiffness: 380,
damping: 30,
}}
/>
)}
</Link>
);
})}
</div>
{/* Safe area for devices with home indicator */}
<div className="h-[env(safe-area-inset-bottom)]" />
</nav>
);
}