mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-08-29 01:35:39 -04:00
* 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>
64 lines
2.1 KiB
TypeScript
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>
|
|
);
|
|
}
|