feat(02-02): rewrite mobile layout to wire HeaderBar + BottomNav + MoreDrawer
- Replace legacy 3-tab layout with new shell components from Plan 01 - Single useState(drawerOpen) shared between avatar and More button triggers - SHELL-05: main content padded pb-[calc(theme(spacing.16)+env(safe-area-inset-bottom))] - max-w-lg mx-auto container, no legacy /mobile/nav reference
This commit is contained in:
parent
bb5b62af86
commit
7a095fbe53
1 changed files with 22 additions and 35 deletions
|
|
@ -1,50 +1,37 @@
|
|||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { LayoutDashboard, Ticket, DollarSign, Menu } from 'lucide-react';
|
||||
/* Mobile shell — phase 02 (SHELL-01, SHELL-05).
|
||||
*
|
||||
* Header: <HeaderBar /> (sticky, brand + Bell + avatar)
|
||||
* Body: <main> (scrollable, padded so content clears the bottom nav)
|
||||
* Foot: <BottomNav /> (fixed, 4 tabs + More)
|
||||
* Drawer: <MoreDrawer /> opened from BOTH the header avatar and the More cell.
|
||||
*
|
||||
* The drawer's open state lives here so a single Sheet instance is shared
|
||||
* between the two triggers — no duplicate Sheets, no prop-drilling sagas. */
|
||||
|
||||
const NAV = [
|
||||
{ href: '/mobile/dashboard', label: 'Dashboard', icon: LayoutDashboard },
|
||||
{ href: '/mobile/tickets', label: 'Tickets', icon: Ticket },
|
||||
{ href: '/mobile/finance', label: 'Finance', icon: DollarSign },
|
||||
];
|
||||
import { useState } from 'react';
|
||||
import { HeaderBar } from '@/components/mobile/HeaderBar';
|
||||
import { BottomNav } from '@/components/mobile/BottomNav';
|
||||
import { MoreDrawer } from '@/components/mobile/MoreDrawer';
|
||||
|
||||
export default function MobileLayout({ children }: { children: React.ReactNode }) {
|
||||
const pathname = usePathname();
|
||||
const [drawerOpen, setDrawerOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col min-h-screen bg-background max-w-lg mx-auto">
|
||||
{/* Top bar */}
|
||||
<header className="sticky top-0 z-20 bg-background border-b px-4 py-3 flex items-center justify-between">
|
||||
<Link href="/mobile" className="font-bold text-lg tracking-tight">Pulse</Link>
|
||||
<Link href="/mobile/nav" className="p-1.5 rounded-lg hover:bg-accent transition-colors" aria-label="Navigation menu">
|
||||
<Menu className="w-5 h-5" />
|
||||
</Link>
|
||||
</header>
|
||||
<HeaderBar onAvatarClick={() => setDrawerOpen(true)} />
|
||||
|
||||
{/* Page content */}
|
||||
<main className="flex-1 overflow-y-auto pb-20">
|
||||
{/* SHELL-05: scrollable content area; bottom padding = bottom-nav (h-16
|
||||
= 64px = pb-16) plus the device safe-area inset, so content never
|
||||
hides under the bar. */}
|
||||
<main className="flex-1 overflow-y-auto pb-[calc(theme(spacing.16)+env(safe-area-inset-bottom))]">
|
||||
{children}
|
||||
</main>
|
||||
|
||||
{/* Bottom nav */}
|
||||
<nav className="fixed bottom-0 left-0 right-0 z-20 border-t bg-background max-w-lg mx-auto">
|
||||
<div className="flex">
|
||||
{NAV.map(({ href, label, icon: Icon }) => {
|
||||
const active = pathname.startsWith(href);
|
||||
return (
|
||||
<Link key={href} href={href}
|
||||
className={`flex-1 flex flex-col items-center justify-center gap-0.5 py-2.5 text-xs transition-colors
|
||||
${active ? 'text-primary' : 'text-muted-foreground hover:text-foreground'}`}
|
||||
>
|
||||
<Icon className="w-5 h-5" />
|
||||
<span>{label}</span>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</nav>
|
||||
<BottomNav onMoreClick={() => setDrawerOpen(true)} />
|
||||
|
||||
<MoreDrawer open={drawerOpen} onOpenChange={setDrawerOpen} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue