"use client"; import { motion } from "framer-motion"; import { useAppReducedMotion as useReducedMotion } from "@/lib/motion-pref"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { CompassIcon, FlameIcon, GearIcon, HomeIcon, PlusIcon } from "@/components/icons"; import { haptic } from "@/lib/haptics"; import { useI18n } from "@/lib/i18n"; import { springSnappy } from "@/lib/motion"; import { openSettings } from "@/lib/ui-events"; import { cn } from "@/lib/utils"; /** * iOS-style bottom tab bar, phones only: Library · Progress · New deck (the * prominent centre button) · Exam mode · Settings. The active item sits on a * sliding pill (shared `layoutId`) and its icon gives a small bounce when you * land on it; re-tapping the active tab scrolls back to the top. * * Labels use the short `tab.*` keys so they fit on one line at 360px in both * languages — no ellipsis, no wrapping. */ export function TabBar() { const pathname = usePathname(); const { t } = useI18n(); const reduceMotion = useReducedMotion(); /* The wizards keep their own bottom action bar (Cancel / Next / Freeze) and chat keeps its own composer — the flow is deliberately focused, so the tab bar steps aside there. */ const inWizard = pathname === "/create" || pathname === "/homework" || pathname === "/chat"; const item = "relative flex min-h-[52px] min-w-0 flex-1 flex-col items-center justify-center gap-1 py-2 text-[10.5px] font-medium leading-none transition-colors"; const active = "text-[var(--text)]"; const idle = "text-[var(--text-subtle)]"; /** The pill glides between items; hidden under reduced motion. */ const pill = (isActive: boolean) => isActive && !reduceMotion ? ( ) : null; /** Small icon bounce on the item you just selected. */ const icon = (children: React.ReactNode, isActive: boolean, key: string) => ( {children} ); const label = (text: string, isActive: boolean) => ( {text} ); const isActive = (key: "library" | "progress" | "create" | "exam") => { if (key === "library") return pathname === "/"; if (key === "progress") return pathname === "/stats"; // The homework wizard is the other half of the New deck screen. if (key === "create") return pathname === "/create" || pathname === "/homework"; return pathname === "/exam"; }; const link = ( key: "library" | "progress" | "create" | "exam", href: string, labelText: string, iconNode: React.ReactNode, ) => { const current = isActive(key); return ( { haptic("tap"); // Re-tapping the active tab scrolls back to the top. if (current) { event.preventDefault(); window.scrollTo({ top: 0, behavior: reduceMotion ? "auto" : "smooth" }); } }} > {pill(current)} {icon(iconNode, current, key)} {label(labelText, current)} ); }; if (inWizard) return null; return ( ); }