import { useMemo } from "react"; import { buildLocalizedHref, getDirection, LanguageSwitcher, type Locale, } from "../LanguageSwitcher"; import { Brand } from "./Brand"; import { DesktopNav } from "./DesktopNav"; import { EuBadge } from "./EuBadge"; import { MobileNav } from "./MobileNav"; import { getDefaultNavItems, getNavigationStrings } from "./nav-items"; import { cx } from "./styles"; import type { NavItem, NavigationStrings, NavSurface } from "./types"; export interface NavigationProps { /** Reading locale. Drives the copy, the default hrefs and the arrow keys. */ locale?: Locale; /** Current pathname, e.g. "/ar/contact". Used for aria-current="page". */ pathname: string; /** Query string, carried across a language switch. */ search?: string; /** Fragment, carried across a language switch. */ hash?: string; /** * The navigation tree. The app shell feeds this from the Strapi * site-settings single type; omitting it renders the typed default IA. */ items?: readonly NavItem[]; /** Which tier-2 surface the bar paints. `:root` is dark, so dark is default. */ surface?: NavSurface; /** Override any of the navigation's own strings (e.g. from the CMS). */ strings?: Partial; /** Where the logo links. Defaults to the locale home, "/en" or "/ar". */ homeHref?: string; showLanguageSwitcher?: boolean; /** * Show the EU badge in the compact bar below xl as well. ON by default: * donor visibility is non-negotiable, and the Figma mobile frame (20:220), * which is logo + hamburger only, would leave the badge out of the header on * every phone, tablet and 1280px-narrow laptop. Below xl the lockup renders * at a reduced size rather than being dropped. Pass `false` only for a * surface where the funding statement is guaranteed elsewhere on screen. */ showEuBadgeOnMobileBar?: boolean; /** Stick the bar to the top of the viewport. */ sticky?: boolean; className?: string; } /** * The SHARP-ER site navigation - Figma frame 20:236. * * Logo at the inline start, the mandatory "Funded by the European Union" badge * at the inline end, and the mega-menu groups between them. Everything is laid * out with logical properties, so the Arabic bar mirrors (logo right, EU badge * left) from `` alone - there is no separate Arabic component. * * Below the xl breakpoint the bar collapses to logo + hamburger and the whole * tree moves into a full-screen drawer. */ export function Navigation({ locale = "en", pathname, search, hash, items, surface = "dark", strings: stringOverrides, homeHref, showLanguageSwitcher = true, showEuBadgeOnMobileBar = true, sticky = true, className, }: NavigationProps) { const navItems = useMemo( () => items ?? getDefaultNavItems(locale), [items, locale], ); const strings = useMemo( () => getNavigationStrings(locale, stringOverrides), [locale, stringOverrides], ); const resolvedHomeHref = homeHref ?? buildLocalizedHref("/", locale); const direction = getDirection(locale); return (
{/* Desktop-only cluster. Visibility lives on this wrapper rather than on the children: two display utilities on one element are resolved by the order Tailwind emits them, not by class-attribute order. */}
{showLanguageSwitcher && ( )} {!showEuBadgeOnMobileBar && ( )}
{showEuBadgeOnMobileBar && ( )}
); } export default Navigation; /* --------------------------------------------------------------------------- USAGE --------------------------------------------------------------------------- // Dark bar on the dark home page, default IA, English: // Arabic. The bar mirrors from - no extra props, no // separate component - and the arrow keys mirror with it. // Light bar on an interior page: // Fed from Strapi site-settings, with the CMS owning the labels and hrefs: // Wired from a route, using the router's own location so a language switch // keeps the query string and fragment: const { pathname, search, hash } = useLocation(); // The EU badge is in the compact bar by default. Opt out only where the // funding statement is guaranteed to be visible elsewhere on the screen: ------------------------------------------------------------------------ */