Isaac Mann 0066543096
fix(nx-dev): fix home page mobile menu (#23250)
Fix the home page mobile menu
2024-05-08 11:47:23 -06:00

521 lines
24 KiB
TypeScript

import { Dialog, Disclosure, Popover, Transition } from '@headlessui/react';
import {
ArrowUpRightIcon,
Bars4Icon,
ChevronDownIcon,
XMarkIcon,
} from '@heroicons/react/24/outline';
import cx from 'classnames';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { Fragment, useEffect, useState } from 'react';
import { ButtonLink } from '../button';
import {
eventItems,
featuresItems,
learnItems,
plans,
resourceMenuItems,
solutionsMenuItems,
} from './menu-items';
import { NxIcon } from '../nx-icon';
import { GitHubIcon } from '../github-icon';
import { MobileMenuItem } from './mobile-menu-item';
import { SectionsMenu } from './sections-menu';
import { TwoColumnsMenu } from './two-columns-menu';
import { AlgoliaSearch } from '@nx/nx-dev/feature-search';
import { NxCloudIcon } from '../nx-cloud-icon';
export function Header(): JSX.Element {
let [isOpen, setIsOpen] = useState(false);
const router = useRouter();
// We need to close the popover if the route changes or the window is resized to prevent the popover from being stuck open.
const checkSizeAndClosePopover = () => {
const breakpoint = 1024; // This is the standard Tailwind lg breakpoint value
if (window.innerWidth < breakpoint) {
setIsOpen(false);
}
};
useEffect(() => {
window.addEventListener('resize', checkSizeAndClosePopover);
return () => {
window.removeEventListener('resize', checkSizeAndClosePopover);
};
}, []);
return (
<div className="z-5 relative inset-x-0 top-0 flex print:hidden">
{/*DESKTOP*/}
<div className="mx-auto hidden w-full max-w-7xl items-center justify-between space-x-10 p-4 px-8 lg:flex">
{/*PRIMARY NAVIGATION*/}
<div className="flex flex-shrink-0 text-sm">
{/*LOGO*/}
<Link
href="/"
className="mr-4 flex items-center text-slate-900 dark:text-white"
>
<span className="sr-only">Nx</span>
<NxIcon aria-hidden="true" className="h-8 w-8" />
</Link>
<nav
role="menu"
className="items-justified flex items-center justify-center space-x-2 py-0.5"
>
<h2 className="sr-only">Main navigation</h2>
{/*FEATURES*/}
<Popover className="relative">
{({ open }) => (
<>
<Popover.Button
className={cx(
open ? 'text-blue-500 dark:text-sky-500' : '',
'group inline-flex items-center gap-2 px-3 py-2 font-medium leading-tight outline-0 dark:text-slate-200'
)}
>
<span
className={cx(
open ? 'text-blue-500 dark:text-sky-500' : '',
'transition duration-150 ease-in-out group-hover:text-blue-500 dark:group-hover:text-sky-500'
)}
>
Features
</span>
<ChevronDownIcon
aria-hidden="true"
className={cx(
open
? 'rotate-180 transform text-blue-500 dark:text-sky-500'
: '',
'h-3 w-3 transition duration-150 ease-in-out group-hover:text-blue-500 dark:group-hover:text-sky-500'
)}
/>
</Popover.Button>
<Transition
as={Fragment}
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<Popover.Panel className="absolute z-10 mt-3 w-max max-w-3xl xl:max-w-3xl">
<TwoColumnsMenu items={featuresItems} />
</Popover.Panel>
</Transition>
</>
)}
</Popover>
{/*SOLUTIONS*/}
<Popover className="relative">
{({ open }) => (
<>
<Popover.Button
className={cx(
open ? 'text-blue-500 dark:text-sky-500' : '',
'group inline-flex items-center px-3 py-2 font-medium leading-tight outline-0 dark:text-slate-200'
)}
>
<span
className={cx(
open ? 'text-blue-500 dark:text-sky-500' : '',
'transition duration-150 ease-in-out group-hover:text-blue-500 dark:group-hover:text-sky-500'
)}
>
Solutions
</span>
<ChevronDownIcon
className={cx(
open
? 'rotate-180 transform text-blue-500 dark:text-sky-500'
: '',
'ml-2 h-3 w-3 transition duration-150 ease-in-out group-hover:text-blue-500 dark:group-hover:text-sky-500'
)}
aria-hidden="true"
/>
</Popover.Button>
<Transition
as={Fragment}
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<Popover.Panel className="absolute z-10 mt-3 w-max max-w-2xl">
<SectionsMenu sections={solutionsMenuItems} />
</Popover.Panel>
</Transition>
</>
)}
</Popover>
<Link
href="/getting-started/intro"
title="Documentation"
className="hidden px-3 py-2 font-medium leading-tight hover:text-blue-500 md:inline-flex dark:text-slate-200 dark:hover:text-sky-500"
>
Documentation
</Link>
<Link
href="/blog"
title="Blog"
className="hidden px-3 py-2 font-medium leading-tight hover:text-blue-500 md:inline-flex dark:text-slate-200 dark:hover:text-sky-500"
>
Blog
</Link>
<a
href="https://nx.app/pricing"
title="Nx Cloud"
target="_blank"
className="hidden gap-2 px-3 py-2 font-medium leading-tight hover:text-blue-500 md:inline-flex dark:text-slate-200 dark:hover:text-sky-500"
>
CI Pricing
<ArrowUpRightIcon className="h-2 w-2 align-super" />
</a>
{/*RESOURCES*/}
<Popover className="relative">
{({ open }) => (
<>
<Popover.Button
className={cx(
open ? 'text-blue-500 dark:text-sky-500' : '',
'group inline-flex items-center px-3 py-2 font-medium leading-tight outline-0 dark:text-slate-200'
)}
>
<span className="transition duration-150 ease-in-out group-hover:text-blue-500 dark:group-hover:text-sky-500">
Resources
</span>
<ChevronDownIcon
className={cx(
open
? 'rotate-180 transform text-blue-500 dark:text-sky-500'
: '',
'ml-2 h-3 w-3 transition duration-150 ease-in-out group-hover:text-blue-500 dark:group-hover:text-sky-500'
)}
aria-hidden="true"
/>
</Popover.Button>
<Transition
as={Fragment}
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<Popover.Panel className="absolute left-60 z-10 mt-3 w-max max-w-2xl -translate-x-1/2 transform lg:left-20">
<SectionsMenu sections={resourceMenuItems} />
</Popover.Panel>
</Transition>
</>
)}
</Popover>
<div className="opacity-50 hover:opacity-100">
<AlgoliaSearch tiny={true} />
</div>
</nav>
</div>
{/*SECONDARY NAVIGATION*/}
<div className="flex-shrink-0 text-sm">
<nav className="flex items-center justify-center space-x-1">
<Link
className="hidden cursor-pointer px-3 py-2 font-medium leading-tight hover:text-blue-500 md:inline-flex dark:text-slate-200 dark:hover:text-sky-500"
title="Contact Us"
href="/contact"
>
Contact
</Link>
<ButtonLink
href="https://cloud.nx.app"
variant="secondary"
size="small"
target="_blank"
title="Log in to your Nx Cloud Account"
>
<NxCloudIcon className="h-4 w-4" aria-hidden="true" />
<span>Go to App</span>
</ButtonLink>
<a
title="Nx is open source, check the code on GitHub"
href="https://github.com/nrwl/nx"
target="_blank"
rel="noreferrer"
className="inline-flex items-center px-3 py-2 opacity-60 hover:opacity-90"
>
<span className="sr-only">Nx on GitHub</span>
<GitHubIcon aria-hidden="true" className="h-5 w-5" />
</a>
</nav>
</div>
</div>
{/*MOBILE*/}
<div className="relative mx-auto flex w-full items-center justify-between p-4 lg:hidden">
<div className="flex w-full items-center justify-between">
{/*LOGO*/}
<Link
href="/"
className="flex items-center text-slate-900 dark:text-white"
>
<span className="sr-only">Nx</span>
<NxIcon aria-hidden="true" className="h-8 w-8" />
</Link>
<div className="flex items-center gap-6">
<a
title="Nx is open source, check the code on GitHub"
href="https://github.com/nrwl/nx"
target="_blank"
rel="noreferrer"
className="inline-flex items-center px-3 py-2 opacity-60 hover:opacity-90"
>
<span className="sr-only">Nx on GitHub</span>
<GitHubIcon aria-hidden="true" className="h-5 w-5" />
</a>
{/*MENU*/}
<button onClick={() => setIsOpen(!isOpen)} className="shrink-0 p-2">
<Bars4Icon
aria-hidden="true"
title="Open navigation menu"
strokeWidth="2"
className="h-6 w-6"
/>
<span className="sr-only">Open navigation panel</span>
</button>
</div>
</div>
</div>
<Transition.Root show={isOpen} as={Fragment}>
<Dialog
as="div"
className="relative z-10"
onClose={() => setIsOpen(!isOpen)}
>
<div className="fixed inset-0" />
<div className="fixed inset-0 overflow-hidden">
<div className="absolute inset-0 overflow-hidden">
<div className="pointer-events-none fixed inset-y-0 right-0 flex max-w-full">
<Transition.Child
as={Fragment}
enter="transform transition ease-in-out duration-250 sm:duration-500"
enterFrom="translate-x-full"
enterTo="translate-x-0"
leave="transform transition ease-in-out duration-250 sm:duration-500"
leaveFrom="translate-x-0"
leaveTo="translate-x-full"
>
<Dialog.Panel className="pointer-events-auto w-screen">
<div className="flex h-full flex-col overflow-y-scroll bg-white py-6 shadow-xl dark:bg-slate-900">
<div className="px-4 sm:px-6">
<div className="flex items-start justify-between">
<Dialog.Title>
<Link
href="/"
className="flex items-center text-slate-900 dark:text-white"
>
<svg
role="img"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
className="h-8 w-8"
fill="currentColor"
>
<title>Nx</title>
<path d="M11.987 14.138l-3.132 4.923-5.193-8.427-.012 8.822H0V4.544h3.691l5.247 8.833.005-3.998 3.044 4.759zm.601-5.761c.024-.048 0-3.784.008-3.833h-3.65c.002.059-.005 3.776-.003 3.833h3.645zm5.634 4.134a2.061 2.061 0 0 0-1.969 1.336 1.963 1.963 0 0 1 2.343-.739c.396.161.917.422 1.33.283a2.1 2.1 0 0 0-1.704-.88zm3.39 1.061c-.375-.13-.8-.277-1.109-.681-.06-.08-.116-.17-.176-.265a2.143 2.143 0 0 0-.533-.642c-.294-.216-.68-.322-1.18-.322a2.482 2.482 0 0 0-2.294 1.536 2.325 2.325 0 0 1 4.002.388.75.75 0 0 0 .836.334c.493-.105.46.36 1.203.518v-.133c-.003-.446-.246-.55-.75-.733zm2.024 1.266a.723.723 0 0 0 .347-.638c-.01-2.957-2.41-5.487-5.37-5.487a5.364 5.364 0 0 0-4.487 2.418c-.01-.026-1.522-2.39-1.538-2.418H8.943l3.463 5.423-3.379 5.32h3.54l1.54-2.366 1.568 2.366h3.541l-3.21-5.052a.7.7 0 0 1-.084-.32 2.69 2.69 0 0 1 2.69-2.691h.001c1.488 0 1.736.89 2.057 1.308.634.826 1.9.464 1.9 1.541a.707.707 0 0 0 1.066.596zm.35.133c-.173.372-.56.338-.755.639-.176.271.114.412.114.412s.337.156.538-.311c.104-.231.14-.488.103-.74z" />
</svg>
<span className="sr-only">Nx</span>
</Link>
</Dialog.Title>
<div className="ml-3 flex h-7 items-center">
<button
type="button"
className="dark:hovers:text-sky-500 relative rounded-md text-slate-600 hover:text-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:text-slate-400 dark:focus:ring-sky-500"
onClick={() => setIsOpen(!isOpen)}
>
<span className="absolute -inset-2.5" />
<span className="sr-only">
Close navigation panel
</span>
<XMarkIcon
aria-hidden="true"
className="h-6 w-6"
/>
</button>
</div>
</div>
</div>
<div className="relative mt-6 flex-1 px-4 sm:px-6">
<ButtonLink
href="https://cloud.nx.app"
variant="primary"
size="small"
target="_blank"
title="Log in to your Nx Cloud Account"
className="w-full"
>
Go to App
</ButtonLink>
<div className="mt-4 divide-y divide-slate-200 border-b border-slate-200 dark:divide-slate-800 dark:border-slate-800">
{/*FEATURES*/}
<Disclosure as="div">
{({ open }) => (
<>
<Disclosure.Button
className={cx(
open
? 'text-blue-500 dark:text-sky-500'
: 'tex-slate-800 dark:text-slate-200',
'flex w-full items-center justify-between py-4 text-left text-base font-medium focus:outline-none'
)}
>
<span>Features</span>
<ChevronDownIcon
aria-hidden="true"
className={cx(
open
? 'rotate-180 transform text-blue-500 dark:text-sky-500'
: 'tex-slate-800 dark:text-slate-200',
'h-3 w-3 transition duration-150 ease-in-out group-hover:text-blue-500 dark:group-hover:text-sky-500'
)}
/>
</Disclosure.Button>
<Disclosure.Panel
as="ul"
className="space-y-1 pb-2"
>
{featuresItems.map((item) => (
<MobileMenuItem
key={item.name}
item={item}
/>
))}
</Disclosure.Panel>
</>
)}
</Disclosure>
{/*SOLUTIONS*/}
<Disclosure as="div">
{({ open }) => (
<>
<Disclosure.Button
className={cx(
open
? 'text-blue-500 dark:text-sky-500'
: 'tex-slate-800 dark:text-slate-200',
'flex w-full items-center justify-between py-4 text-left text-base font-medium focus:outline-none'
)}
>
<span>Solutions</span>
<ChevronDownIcon
aria-hidden="true"
className={cx(
open
? 'rotate-180 transform text-blue-500 dark:text-sky-500'
: 'tex-slate-800 dark:text-slate-200',
'h-3 w-3 transition duration-150 ease-in-out group-hover:text-blue-500 dark:group-hover:text-sky-500'
)}
/>
</Disclosure.Button>
<Disclosure.Panel as="ul" className="space-y-1">
{plans.map((item) => (
<MobileMenuItem
key={item.name}
item={item}
/>
))}
</Disclosure.Panel>
</>
)}
</Disclosure>
<Link
href="/getting-started/intro"
title="Documentation"
className="block py-4 font-medium leading-tight hover:text-blue-500 dark:text-slate-200 dark:hover:text-sky-500"
>
Documentation
</Link>
<Link
href="/blog"
title="Blog"
className="block py-4 font-medium leading-tight hover:text-blue-500 dark:text-slate-200 dark:hover:text-sky-500"
>
Blog
</Link>
<a
href="https://nx.app/pricing"
title="Nx Cloud"
target="_blank"
className="flex w-full gap-2 py-4 font-medium leading-tight hover:text-blue-500 dark:text-slate-200 dark:hover:text-sky-500"
>
CI Pricing
<ArrowUpRightIcon className="h-2 w-2 align-super" />
</a>
{/*RESOURCES*/}
<Disclosure as="div">
{({ open }) => (
<>
<Disclosure.Button
className={cx(
'flex w-full items-center justify-between py-4 text-left text-base font-medium focus:outline-none',
open
? 'text-blue-500 dark:text-sky-500'
: 'tex-slate-800 dark:text-slate-200'
)}
>
<span>Resources</span>
<ChevronDownIcon
aria-hidden="true"
className={cx(
open
? 'rotate-180 transform text-blue-500 dark:text-sky-500'
: 'tex-slate-800 dark:text-slate-200',
'h-3 w-3 transition duration-150 ease-in-out group-hover:text-blue-500 dark:group-hover:text-sky-500'
)}
/>
</Disclosure.Button>
<Disclosure.Panel
as="ul"
className="space-y-1 pb-2"
>
{learnItems.map((item) => (
<MobileMenuItem
key={item.name}
item={item}
/>
))}
{eventItems.map((item) => (
<MobileMenuItem
key={item.name}
item={item}
/>
))}
</Disclosure.Panel>
</>
)}
</Disclosure>
<Link
href="/contact"
title="Contact"
className="block py-4 font-medium leading-tight hover:text-blue-500 dark:text-slate-200 dark:hover:text-sky-500"
>
Contact
</Link>
</div>
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</div>
</Dialog>
</Transition.Root>
</div>
);
}