/**
* Navigation Component
* Top header nav for desktop; bottom tab bar for mobile (≤640px).
*/
'use client';
import { useEffect } from 'react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { useComparison } from '@/hooks/useComparison';
import { LogoMark } from './Logo';
import styles from './Navigation.module.css';
type IconProps = { className?: string };
const SearchIcon = ({ className }: IconProps) => (
);
const CompareIcon = ({ className }: IconProps) => (
);
const RankingsIcon = ({ className }: IconProps) => (
);
const AdmissionsIcon = ({ className }: IconProps) => (
);
export function Navigation() {
const pathname = usePathname();
const { selectedSchools } = useComparison();
const isActive = (path: string) => {
if (path === '/') return pathname === '/';
return pathname.startsWith(path);
};
/**
* iOS Chrome (and some Android browsers) auto-hide their URL bar on scroll,
* which grows the visual viewport without changing the layout viewport.
* `position: fixed; bottom: 0` sticks to the layout viewport, so our tab
* bar appears to float mid-screen with a gap beneath it. Track the delta
* via VisualViewport and apply it as a translate so the bar always sits
* flush against the visible bottom edge.
*/
useEffect(() => {
const vv = window.visualViewport;
if (!vv) return;
const root = document.documentElement;
const update = () => {
const offset = window.innerHeight - (vv.height + vv.offsetTop);
// Only positive offsets are meaningful (bar hidden → push down).
root.style.setProperty('--mobile-bar-offset', `${Math.max(0, offset)}px`);
};
update();
vv.addEventListener('resize', update);
vv.addEventListener('scroll', update);
return () => {
vv.removeEventListener('resize', update);
vv.removeEventListener('scroll', update);
root.style.removeProperty('--mobile-bar-offset');
};
}, []);
/*
* The brand guideline's nav also carries Guides, About, Favourites and a
* "Sign in" button. None of the four is added here, deliberately: there are
* no Guides or About pages, and Favourites and Sign in both need an accounts
* system that does not exist. Drawing chrome for features we do not have
* would be a promise the product cannot keep. Rankings and Admissions —
* which the guideline omits — take their place, because they are real.
*
* If accounts ever ship, this is the list to extend.
*/
const items = [
{ href: '/', label: 'Search', Icon: SearchIcon },
{ href: '/compare', label: 'Compare', Icon: CompareIcon },
{ href: '/rankings', label: 'Rankings', Icon: RankingsIcon },
{ href: '/admissions', label: 'Admissions', Icon: AdmissionsIcon },
] as const;
return (
<>
{/*
LogoMark's defaults are already correct for this ground: the pin
takes var(--brand) and the leaf is knocked out in var(--bg-card),
which is exactly the header's own background in both themes. No
explicit pin/leaf needed here — the footer, which sits on the
sunken teal band, does have to pass them.
*/}
schoolcompare