"use client"; import { Activity, Home, Lightbulb, MoreHorizontal, Pill, Target, Trophy, Waves, } from "lucide-react"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { useState } from "react"; import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, } from "@/components/ui/sheet"; import { cn } from "@/lib/utils"; import { useTranslations } from "@/lib/i18n/context"; interface NavLink { href: string; tKey: string; icon: typeof Home; } // v1.4.16 Wave-C MED — bottom-nav was rendering all 7 destinations // edge-to-edge on a 375 px viewport, which collapsed each touch // target to ~50 px wide and made the WCAG 2.5.5 44 px floor only // just-pass on iPhone-13-mini-class screens. The mobile audit // recommended 5+More — so the four most-used surfaces stay in the // strip (Home, Measurements, Mood, Medications) plus Insights as // the fifth, and Targets + Achievements move into a "More" sheet. // // Order is preserved relative to the v1.4.15 bottom-nav so muscle // memory keeps working for the four core actions. const PRIMARY: ReadonlyArray = [ { href: "/", tKey: "nav.dashboard", icon: Home }, { href: "/measurements", tKey: "nav.measurements", icon: Activity }, { href: "/mood", tKey: "nav.mood", icon: Waves }, { href: "/medications", tKey: "nav.medications", icon: Pill }, { href: "/insights", tKey: "nav.insights", icon: Lightbulb }, ]; const OVERFLOW: ReadonlyArray = [ { href: "/targets", tKey: "nav.targets", icon: Target }, { href: "/achievements", tKey: "nav.achievements", icon: Trophy }, ]; export function BottomNav() { const pathname = usePathname(); const { t } = useTranslations(); const [moreOpen, setMoreOpen] = useState(false); function isActiveLink(href: string) { return href === "/" ? pathname === "/" : pathname.startsWith(href); } // The "More" entry is treated as active when any of its children // is the current page — gives the user a clue that they've drilled // into a sub-route via overflow. const overflowActive = OVERFLOW.some((item) => isActiveLink(item.href)); return ( <> {/* v1.4.33 F14 — bar height and safe-area defence so the bar can never overlap the last viewport line of scrollable page content. - `min-h-16` floors the bar at 64px even if the inner flex row collapses (e.g. a future variant without one of the icons). - `pb-[env(safe-area-inset-bottom)]` reserves the home-indicator inset on iOS / iPadOS PWA installs. - `bg-card` (solid, not the previous `bg-card/80`) plus `border-t` give the bar a clean visual edge so any page content that scrolls under the bar is properly occluded rather than bleeding through a translucent surface. Page- level pb-* padding owners (auth-shell + per-page shells) still reserve room above the bar; this change hardens the bar itself so the visual contract holds even when a page shell forgets the bottom-padding contract. */} {t("nav.moreSheetTitle")} {t("nav.moreSheetDescription")}
{OVERFLOW.map((item) => { const isActive = isActiveLink(item.href); return ( setMoreOpen(false)} aria-current={isActive ? "page" : undefined} className={cn( "border-border flex min-h-11 items-center gap-3 rounded-lg border px-4 py-3 transition-colors", isActive ? "text-primary bg-primary/5" : "text-foreground hover:bg-accent/40", )} >
); }