"use client";
import { usePathname } from "next/navigation";
import { useMobileNavigationItems, type MobileNavigationItem } from "../../contexts/MobileNavigationContext";
import { Link } from "../../shadcnui";
import { cn } from "../../utils/cn";
import { useIsMobile } from "../../utils/use-mobile";
/**
* Active only for navigational slots.
*
* Exact-or-prefix, NOT a bare `startsWith`: the prefix arm keeps a detail route
* (/accounts/123) highlighting its section (/accounts).
*
* "/" is special-cased to EXACT match. Without that, its prefix arm degenerates
* to `pathname.startsWith("/")`, which is true for every route, and the Home
* slot highlights everywhere. This is pinned by a unit test in Task C.
*/
function isActiveHref(pathname: string, href: string): boolean {
if (href === "/") return pathname === "/";
return pathname === href || pathname.startsWith(`${href}/`);
}
const slotClass = cn(
// min-h-12/min-w-12 = 48px touch target (Material/HIG guidance).
"relative flex min-h-12 min-w-12 flex-1 items-center justify-center",
"transition-colors",
);
function SlotContent({ item }: { item: MobileNavigationItem }) {
if (item.render) return <>{item.render}>;
const Icon = item.icon;
return Icon ? : null;
}
/**
* The mobile bottom navigation bar.
*
* Renders nothing on desktop, and nothing when the application supplied no
* items — so page containers can render it unconditionally.
*
* Rendered as an in-flow flex sibling of the page content (NOT position:fixed),
* so the content column shrinks to fit and can never be hidden behind the bar.
*/
export function MobileNavigationBar() {
const items = useMobileNavigationItems();
const isMobile = useIsMobile();
const pathname = usePathname();
if (!isMobile || items.length === 0) return null;
// A detached surface sitting BELOW the page card with a gap, so it carries a
// rounded border rather than a `border-t`, which would read as if the bar were
// welded to the card's bottom edge. `bg-sidebar` deliberately matches the
// Header's own background so the two chrome edges of the viewport agree.
//
// Deliberately NO bottom safe-area padding here, and none on the page shell
// either. iOS reports a 34px bottom inset but paints nothing in that strip on
// current devices, so honouring it only produced dead space — 78px of bar for
// a 42px icon row when held inside this border, and an empty band under the
// bar when held by the shell instead.
return (
);
}