'use client'; import React from 'react'; import { cn } from '../../utils/cn'; export type TopNavigationCenterBreakpoint = 'md' | 'lg'; export type TopNavigationSize = 'small' | 'big'; // Bar height + square-cell width per size (Figma 2797-5978 `size` axis). // Heights are FIXED across breakpoints. `--top-nav-cell` is consumed by // `HeaderButton` (and any custom cell) so cell widths follow the size without // each cell knowing about it. const SIZE_CLASSES: Record = { small: 'h-14 [--top-nav-cell:3.5rem]', big: 'h-[72px] [--top-nav-cell:4.5rem]', }; // Literal class maps — Tailwind's scanner needs the full class strings. const CENTER_VISIBILITY: Record = { md: 'hidden md:flex', lg: 'hidden lg:flex', }; const LOGO_GROW: Record = { md: 'flex-1 md:flex-none', lg: 'flex-1 lg:flex-none', }; export interface TopNavigationProps extends React.HTMLAttributes { /** Leading cells (burger toggle, admin-sidebar toggle). Rendered raw, first * in the row — cells carry their own trailing divider * (`border-r border-ods-border`), matching the ODS spec where dividers * belong to the cells, not the bar. */ leading?: React.ReactNode; /** Logo zone content. Grows (`flex-1`) below `centerBreakpoint`, shrinks to * content above it. Wrap in a `` on the consumer side if clickable. */ logo?: React.ReactNode; /** Extra classes for the logo zone. Defaults follow the ODS spec paddings: * `p-m` on mobile, `pl-l` (24px) from md, `pl-xxl` (80px) from lg — the * desktop inset mirrors the leading menu-cell width so centered nav links * sit visually centered (Figma 2797-6808 / 2805-6194). */ logoClassName?: string; /** Center zone (marketing nav links, console global search). Hidden below * `centerBreakpoint`; above it, it is the `flex-1` region that pushes the * CTA and side actions to the right edge. Rendered even when empty so the * bar always has its spacer. */ center?: React.ReactNode; centerClassName?: string; /** Breakpoint at which the center zone appears (and the logo zone stops * growing). ODS spec default is `lg` (nav links are desktop-only); * the console header uses `md` for its global search. */ centerBreakpoint?: TopNavigationCenterBreakpoint; /** CTA zone — right-aligned, padded, no dividers (per ODS spec). */ cta?: React.ReactNode; ctaClassName?: string; /** Trailing action cells (time tracker, notifications, avatar, Mingo). * Rendered raw — each cell carries its own leading divider * (`border-l border-ods-border`). */ sideActions?: React.ReactNode; /** Opaque ODS background class. Defaults to `bg-ods-card`. Keep it opaque — * translucent backgrounds under a sticky bar need a deliberate * backdrop-blur treatment (see the note in `header.tsx`). */ backgroundClassName?: string; /** Top border on mobile (the ODS spec bar shows it below md). Default true. */ mobileTopBorder?: boolean; /** Bar size (Figma 2797-5978 `size` axis): `small` = 56px (console), * `big` = 72px (marketing/hub sites). Fixed across breakpoints. */ size?: TopNavigationSize; } const hasContent = (node: React.ReactNode): boolean => node !== null && node !== undefined && node !== false; /** * Unified ODS top-navigation bar (Figma `[UPD] top-navigation`, node * 2797-5978): the single 48px/56px (mobile / md+) cell-based header shell * shared by the console `AppHeader` and the marketing `Header` across all * platforms. * * The shell owns the bar geometry only — height, borders, background, and the * zone layout `[leading][logo][center][cta][sideActions]`. What goes inside * the zones (and each cell's divider) is the consumer's job, so platforms can * differ in background and in which elements they mount without forking the * bar itself. */ export function TopNavigation({ leading, logo, logoClassName, center, centerClassName, centerBreakpoint = 'lg', cta, ctaClassName, sideActions, backgroundClassName, mobileTopBorder = true, size = 'small', className, children, ...props }: TopNavigationProps) { return (
{leading} {hasContent(logo) && (
{logo}
)}
{center}
{hasContent(cta) && (
{cta}
)} {sideActions} {children}
); } export default TopNavigation;