diff --git a/src/components/Header.jsx b/src/components/Header.jsx index a88f3dc..d29b9f1 100644 --- a/src/components/Header.jsx +++ b/src/components/Header.jsx @@ -14,6 +14,7 @@ function useDisclosure(initialState = false) { } function buildNavItems(country) { + const modelBase = country.modelUrl; return [ { label: 'Research', @@ -22,8 +23,28 @@ function buildNavItems(country) { }, { label: 'Model', - href: country.modelUrl, - hasDropdown: false, + hasDropdown: true, + dropdownItems: [ + { + label: 'Rules', + href: `${modelBase}/rules`, + children: [ + { label: 'Coverage', href: `${modelBase}/rules/coverage` }, + { label: 'Parameters', href: `${modelBase}/rules/parameters` }, + { label: 'Variables', href: `${modelBase}/rules/variables` }, + ], + }, + { + label: 'Data', + href: `${modelBase}/data`, + children: [ + { label: 'Pipeline', href: `${modelBase}/data/pipeline` }, + { label: 'Calibration', href: `${modelBase}/data/calibration` }, + { label: 'Validation', href: `${modelBase}/data/validation` }, + ], + }, + { label: 'Behavioral responses', href: `${modelBase}/behavioral` }, + ], }, { label: 'API', diff --git a/src/components/homeHeader/HeaderLogo.jsx b/src/components/homeHeader/HeaderLogo.jsx index 501177b..289ff97 100644 --- a/src/components/homeHeader/HeaderLogo.jsx +++ b/src/components/homeHeader/HeaderLogo.jsx @@ -1,25 +1,25 @@ 'use client'; -import { spacing } from '@policyengine/ui-kit/legacy/tokens'; const PolicyEngineLogo = 'https://www.policyengine.org/assets/logos/policyengine/white.svg'; const logoContainerStyles = { display: 'flex', alignItems: 'center', cursor: 'pointer', + // Wider gap than between nav items so the logo reads as an anchor + marginRight: '40px', }; const logoImageStyles = { height: '24px', width: 'auto', - marginRight: 12, }; export default function HeaderLogo({ country }) { const logoImage = PolicyEngine; return ( - + {logoImage} ); diff --git a/src/components/homeHeader/MobileMenu.jsx b/src/components/homeHeader/MobileMenu.jsx index 35ecaf5..5e1e8bb 100644 --- a/src/components/homeHeader/MobileMenu.jsx +++ b/src/components/homeHeader/MobileMenu.jsx @@ -151,7 +151,7 @@ export default function MobileMenu({ country, opened, onOpen, onClose, navItems className="flex flex-col" style={{ gap: spacing.xs, paddingLeft: spacing.md }} > - {item.dropdownItems.map((dropdownItem) => ( + {item.dropdownItems.flatMap((dropdownItem) => [ {dropdownItem.label} - - ))} + , + ...(dropdownItem.children ?? []).map((grand) => ( + + {grand.label} + + )), + ])} ) : ( diff --git a/src/components/homeHeader/NavItem.jsx b/src/components/homeHeader/NavItem.jsx index a2f32d4..e472a31 100644 --- a/src/components/homeHeader/NavItem.jsx +++ b/src/components/homeHeader/NavItem.jsx @@ -1,41 +1,112 @@ 'use client'; import { useCallback, useEffect, useRef, useState } from 'react'; +import { usePathname } from 'next/navigation'; import { IconChevronDown } from '@tabler/icons-react'; import { colors, typography } from '@policyengine/ui-kit/legacy/tokens'; +const NAV_ITEM_PADDING_X = 14; +const NAV_UNDERLINE_INSET = 10; +const DROPDOWN_GAP = 10; +const HOVER_OPEN_DELAY_MS = 100; +const HOVER_CLOSE_DELAY_MS = 200; + const navItemStyle = { color: colors.text.inverse, fontWeight: typography.fontWeight.medium, fontSize: '15px', fontFamily: typography.fontFamily.primary, textDecoration: 'none', - padding: '6px 14px', - borderRadius: '6px', - transition: 'background-color 0.15s ease', + padding: `8px ${NAV_ITEM_PADDING_X}px`, letterSpacing: '0.01em', + position: 'relative', }; -const hoverHandlers = { - onMouseEnter: (e) => { - e.currentTarget.style.backgroundColor = 'rgba(255, 255, 255, 0.12)'; - }, - onMouseLeave: (e) => { - e.currentTarget.style.backgroundColor = 'transparent'; - }, -}; +function NavUnderline({ visible }) { + return ( +