feat(nx-dev): new main navigation menu (#22829)
It adds a new main navigation menu on the website and in the documentation, offering more choices and simpler access to different parts of the content for the visitor. Co-authored-by: Benjamin Cabanes <3447705+bcabanes@users.noreply.github.com>
This commit is contained in:
parent
25f598ffbe
commit
4d6cd36f5c
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"endOfLine": "lf"
|
"endOfLine": "lf",
|
||||||
|
"plugins": ["prettier-plugin-tailwindcss"]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,7 @@ export function SourcemapInfoToolTip({
|
|||||||
<>
|
<>
|
||||||
<p className="flex grow items-center gap-2">
|
<p className="flex grow items-center gap-2">
|
||||||
<span className="font-bold">{isTarget ? 'Created' : 'Set'} by:</span>
|
<span className="font-bold">{isTarget ? 'Created' : 'Set'} by:</span>
|
||||||
<span className="inline-flex grow justify-between items-center">
|
<span className="inline-flex grow items-center justify-between">
|
||||||
{docsUrlSlug ? (
|
{docsUrlSlug ? (
|
||||||
<ExternalLink
|
<ExternalLink
|
||||||
text={plugin}
|
text={plugin}
|
||||||
@ -46,10 +46,10 @@ export function SourcemapInfoToolTip({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="text-sm text-slate-700 dark:text-slate-400 max-w-md sm:max-w-full">
|
<div className="max-w-md text-sm text-slate-700 dark:text-slate-400 sm:max-w-full">
|
||||||
<div
|
<div
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
`flex flex-col font-mono py-2`,
|
`flex flex-col py-2 font-mono`,
|
||||||
showLink ? 'border-b border-slate-200 dark:border-slate-700/60' : ''
|
showLink ? 'border-b border-slate-200 dark:border-slate-700/60' : ''
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -86,8 +86,8 @@ export function AlgoliaSearch({
|
|||||||
className="flex w-full items-center rounded-md bg-white py-1.5 px-2 text-sm leading-4 ring-1 ring-slate-300 transition dark:bg-slate-700 dark:ring-slate-900"
|
className="flex w-full items-center rounded-md bg-white py-1.5 px-2 text-sm leading-4 ring-1 ring-slate-300 transition dark:bg-slate-700 dark:ring-slate-900"
|
||||||
>
|
>
|
||||||
<MagnifyingGlassIcon className="h-4 w-4 flex-none" />
|
<MagnifyingGlassIcon className="h-4 w-4 flex-none" />
|
||||||
<span className="mx-3 text-xs text-slate-300 dark:text-slate-400 md:text-sm inline-flex">
|
<span className="mx-3 inline-flex text-xs text-slate-300 dark:text-slate-400 md:text-sm">
|
||||||
Search <span className="ml-1 hidden lg:inline">the docs ...</span>
|
Search
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
style={{ opacity: browserDetected ? '1' : '0' }}
|
style={{ opacity: browserDetected ? '1' : '0' }}
|
||||||
|
|||||||
@ -33,13 +33,6 @@
|
|||||||
"command": "pnpm next-sitemap --config ./nx-dev/nx-dev/next-sitemap.config.js"
|
"command": "pnpm next-sitemap --config ./nx-dev/nx-dev/next-sitemap.config.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sync-documentation": {
|
|
||||||
"executor": "nx:run-commands",
|
|
||||||
"outputs": ["{projectRoot}/public/documentation"],
|
|
||||||
"options": {
|
|
||||||
"command": "ts-node -P ./scripts/tsconfig.scripts.json ./scripts/documentation/nx-dev-docs-latest-sync.ts"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"generate-og-images": {
|
"generate-og-images": {
|
||||||
"executor": "nx:run-commands",
|
"executor": "nx:run-commands",
|
||||||
"outputs": ["{projectRoot}/public/images/open-graph"],
|
"outputs": ["{projectRoot}/public/images/open-graph"],
|
||||||
@ -133,12 +126,6 @@
|
|||||||
"parallel": false
|
"parallel": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"export": {
|
|
||||||
"executor": "@nx/next:export",
|
|
||||||
"options": {
|
|
||||||
"buildTarget": "nx-dev:build:production"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"lint": {},
|
"lint": {},
|
||||||
"test": {}
|
"test": {}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
export * from './lib/announcement-banner';
|
export * from './lib/announcement-banner';
|
||||||
export * from './lib/documentation-header';
|
export * from './lib/headers/documentation-header';
|
||||||
export * from './lib/breadcrumbs';
|
export * from './lib/breadcrumbs';
|
||||||
export * from './lib/button';
|
export * from './lib/button';
|
||||||
export * from './lib/champion-card';
|
export * from './lib/champion-card';
|
||||||
export * from './lib/champion-perks';
|
export * from './lib/champion-perks';
|
||||||
export * from './lib/header';
|
export * from './lib/headers/header';
|
||||||
export * from './lib/flip-card';
|
export * from './lib/flip-card';
|
||||||
export * from './lib/nx-cloud-icon';
|
export * from './lib/nx-cloud-icon';
|
||||||
export * from './lib/footer';
|
export * from './lib/footer';
|
||||||
@ -15,3 +15,14 @@ export * from './lib/testimonial-card';
|
|||||||
export * from './lib/typography';
|
export * from './lib/typography';
|
||||||
export * from './lib/github-star-widget';
|
export * from './lib/github-star-widget';
|
||||||
export * from './lib/youtube.component';
|
export * from './lib/youtube.component';
|
||||||
|
export { resourceMenuItems } from './lib/headers/menu-items';
|
||||||
|
export { solutionsMenuItems } from './lib/headers/menu-items';
|
||||||
|
export { eventItems } from './lib/headers/menu-items';
|
||||||
|
export { learnItems } from './lib/headers/menu-items';
|
||||||
|
export { useCaseItems } from './lib/headers/menu-items';
|
||||||
|
export { plans } from './lib/headers/menu-items';
|
||||||
|
export { featuresItems } from './lib/headers/menu-items';
|
||||||
|
export { DefaultMenuItem } from './lib/headers/default-menu-item';
|
||||||
|
export { MobileMenuItem } from './lib/headers/mobile-menu-item';
|
||||||
|
export { SectionsMenu } from './lib/headers/sections-menu';
|
||||||
|
export { TwoColumnsMenu } from './lib/headers/two-columns-menu';
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { HeartIcon } from '@heroicons/react/24/solid';
|
import { HeartIcon } from '@heroicons/react/24/solid';
|
||||||
|
import { ThemeSwitcher } from '@nx/nx-dev/ui-theme';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
export function Footer(): JSX.Element {
|
export function Footer(): JSX.Element {
|
||||||
@ -179,6 +180,9 @@ export function Footer(): JSX.Element {
|
|||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex items-center text-sm">
|
||||||
|
Preferences <ThemeSwitcher />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-12 grid grid-cols-2 gap-8 xl:col-span-2 xl:mt-0">
|
<div className="mt-12 grid grid-cols-2 gap-8 xl:col-span-2 xl:mt-0">
|
||||||
<div className="md:grid md:grid-cols-2 md:gap-8">
|
<div className="md:grid md:grid-cols-2 md:gap-8">
|
||||||
|
|||||||
14
nx-dev/ui-common/src/lib/github-icon.tsx
Normal file
14
nx-dev/ui-common/src/lib/github-icon.tsx
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { FC, SVGProps } from 'react';
|
||||||
|
|
||||||
|
export const GitHubIcon: FC<SVGProps<SVGSVGElement>> = (props) => (
|
||||||
|
<svg
|
||||||
|
role="img"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="currentColor"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<title>GitHub</title>
|
||||||
|
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
@ -1,326 +0,0 @@
|
|||||||
import { Popover, Transition } from '@headlessui/react';
|
|
||||||
import { Bars4Icon, ChevronDownIcon } from '@heroicons/react/24/outline';
|
|
||||||
import { AlgoliaSearch } from '@nx/nx-dev/feature-search';
|
|
||||||
import { ThemeSwitcher } from '@nx/nx-dev/ui-theme';
|
|
||||||
import cx from 'classnames';
|
|
||||||
import Link from 'next/link';
|
|
||||||
import { useRouter } from 'next/router';
|
|
||||||
import { Fragment } from 'react';
|
|
||||||
|
|
||||||
export function Header(): JSX.Element {
|
|
||||||
const router = useRouter();
|
|
||||||
const flyoutMenu = [
|
|
||||||
{
|
|
||||||
name: 'Getting started',
|
|
||||||
description: 'Jump right in and start building!',
|
|
||||||
href: '/getting-started/intro',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Nx on CI',
|
|
||||||
description: 'Learn how to efficiently use Nx on CI',
|
|
||||||
href: '/ci/intro/ci-with-nx',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Features',
|
|
||||||
description:
|
|
||||||
'Learn the features of Nx with in depth guides and explainers.',
|
|
||||||
href: '/features',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Nx Replay',
|
|
||||||
description:
|
|
||||||
'Built-in local and remote caching to speed up your tasks and save you time and money.',
|
|
||||||
href: '/features/cache-task-results',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Recipes',
|
|
||||||
description: 'Follow instructions to do common specific tasks.',
|
|
||||||
href: '/recipes',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Nx Agents',
|
|
||||||
description:
|
|
||||||
'Executes tasks remotely on different agents in parallel. Enable remote cache in one command.',
|
|
||||||
href: '/ci/features/distribute-task-execution',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Nx Console',
|
|
||||||
description:
|
|
||||||
'The official VSCode & JetBrains plugin bringing Nx to your editor.',
|
|
||||||
href: '/getting-started/editor-setup#vscode',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Set Up CI',
|
|
||||||
description: 'Configure Nx for your CI provider',
|
|
||||||
href: '/ci/recipes/set-up',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const flyoutMobileMenu = [
|
|
||||||
{
|
|
||||||
name: 'Getting started',
|
|
||||||
description: 'Jump right in and start building!',
|
|
||||||
href: '/getting-started/intro',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Blog',
|
|
||||||
description: 'Latest news from the Nx & Nx Cloud core team',
|
|
||||||
href: '/blog',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Community',
|
|
||||||
description: 'Check how to reach out and be part of the Nx community.',
|
|
||||||
href: '/community',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Launch Nx',
|
|
||||||
description: 'A week of exciting announcements about Nx and Nx Cloud!',
|
|
||||||
href: '/launch-nx',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Contact us',
|
|
||||||
description: 'Give us a call!',
|
|
||||||
href: '/contact',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="relative 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">
|
|
||||||
{/*LOGO*/}
|
|
||||||
<div className="flex items-center">
|
|
||||||
<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="m12 14.1-3.1 5-5.2-8.5v8.9H0v-15h3.7l5.2 8.9v-4l3 4.7zm.6-5.7V4.5H8.9v3.9h3.7zm5.6 4.1a2 2 0 0 0-2 1.3 2 2 0 0 1 2.4-.7c.4.2 1 .4 1.3.3a2.1 2.1 0 0 0-1.7-.9zm3.4 1c-.4 0-.8-.2-1.1-.6l-.2-.3a2.1 2.1 0 0 0-.5-.6 2 2 0 0 0-1.2-.3 2.5 2.5 0 0 0-2.3 1.5 2.3 2.3 0 0 1 4 .4.8.8 0 0 0 .9.3c.5 0 .4.4 1.2.5v-.1c0-.4-.3-.5-.8-.7zm2 1.3a.7.7 0 0 0 .4-.6c0-3-2.4-5.5-5.4-5.5a5.4 5.4 0 0 0-4.5 2.4l-1.5-2.4H8.9l3.5 5.4L9 19.5h3.6L14 17l1.6 2.4h3.5l-3.1-5a.7.7 0 0 1 0-.3 2.7 2.7 0 0 1 2.6-2.7c1.5 0 1.7.9 2 1.3.7.8 2 .5 2 1.5a.7.7 0 0 0 1 .6zm.4.2c-.2.3-.6.3-.8.6-.1.3.1.4.1.4s.4.2.6-.3V15z" />
|
|
||||||
</svg>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
{/*PRIMARY NAVIGATION*/}
|
|
||||||
<div className="flex-shrink-0 text-sm">
|
|
||||||
<nav
|
|
||||||
role="menu"
|
|
||||||
className="items-justified flex justify-center space-x-2 py-0.5"
|
|
||||||
>
|
|
||||||
<h2 className="sr-only">Main navigation</h2>
|
|
||||||
<Popover className="relative">
|
|
||||||
{({ open }) => (
|
|
||||||
<>
|
|
||||||
<Popover.Button
|
|
||||||
className={cx(
|
|
||||||
open ? 'text-blue-500 dark:text-sky-500' : '',
|
|
||||||
'text group inline-flex items-center px-3 py-2 font-medium leading-tight dark:text-slate-200'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<span className="transition duration-150 ease-in-out group-hover:text-blue-500 dark:group-hover:text-sky-500">
|
|
||||||
Documentation
|
|
||||||
</span>
|
|
||||||
<ChevronDownIcon
|
|
||||||
className={cx(
|
|
||||||
open ? 'text-blue-500 dark:text-sky-500' : '',
|
|
||||||
'ml-2 h-5 w-5 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-1/2 z-10 mt-3 w-screen max-w-md -translate-x-1/2 transform xl:max-w-3xl">
|
|
||||||
<div className="overflow-hidden rounded-lg bg-white shadow-lg ring-1 ring-black/5 dark:bg-slate-900 dark:ring-white/5">
|
|
||||||
<div className="relative grid gap-6 p-6 xl:grid-cols-2">
|
|
||||||
{flyoutMenu.map((item) => (
|
|
||||||
<Link
|
|
||||||
key={item.name}
|
|
||||||
href={item.href}
|
|
||||||
className="-m-3 flex items-start rounded-lg p-3 transition duration-150 ease-in-out hover:bg-slate-50 dark:hover:bg-slate-800/60"
|
|
||||||
>
|
|
||||||
<div className="ml-4">
|
|
||||||
<p className="text-base font-medium text-slate-900 dark:text-slate-200">
|
|
||||||
{item.name}
|
|
||||||
</p>
|
|
||||||
<p className="mt-1 text-sm text-slate-500 dark:text-slate-400">
|
|
||||||
{item.description}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</Link>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Popover.Panel>
|
|
||||||
</Transition>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Popover>
|
|
||||||
<Link
|
|
||||||
href="/blog"
|
|
||||||
title="Blog"
|
|
||||||
className="hidden px-3 py-2 font-medium leading-tight hover:text-blue-500 dark:text-slate-200 dark:hover:text-sky-500 md:inline-flex"
|
|
||||||
>
|
|
||||||
Blog
|
|
||||||
</Link>
|
|
||||||
<Link
|
|
||||||
href="/community"
|
|
||||||
title="Nx Community: Join us!"
|
|
||||||
className="hidden px-3 py-2 font-medium leading-tight hover:text-blue-500 dark:text-slate-200 dark:hover:text-sky-500 md:inline-flex"
|
|
||||||
>
|
|
||||||
Community
|
|
||||||
</Link>
|
|
||||||
<Link
|
|
||||||
href="/launch-nx"
|
|
||||||
title="Launch Nx"
|
|
||||||
className="relative hidden px-3 py-2 font-medium leading-tight hover:text-blue-500 dark:text-slate-200 dark:hover:text-sky-500 md:inline-flex"
|
|
||||||
>
|
|
||||||
{/*<span className="absolute top-0 right-0 -mt-1 -mr-1 flex h-3 w-3">*/}
|
|
||||||
{/* <span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-blue-500 opacity-75 dark:bg-sky-500" />*/}
|
|
||||||
{/* <span className="relative inline-flex h-3 w-3 rounded-full bg-blue-500 dark:bg-sky-500" />*/}
|
|
||||||
{/*</span>*/}Launch Nx
|
|
||||||
</Link>
|
|
||||||
<Link
|
|
||||||
href="/contact"
|
|
||||||
title="Contact us"
|
|
||||||
className="hidden px-3 py-2 font-medium leading-tight hover:text-blue-500 dark:text-slate-200 dark:hover:text-sky-500 md:inline-flex"
|
|
||||||
>
|
|
||||||
Contact us
|
|
||||||
</Link>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
<div className="flex-shrink-0 text-sm">
|
|
||||||
<nav className="items-justified flex justify-center space-x-1">
|
|
||||||
<AlgoliaSearch tiny={true} />
|
|
||||||
<ThemeSwitcher />
|
|
||||||
<a
|
|
||||||
title="Nx is open source, check the code on GitHub"
|
|
||||||
href="https://github.com/nrwl/nx"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
className="px-3 py-2 opacity-60 hover:opacity-90"
|
|
||||||
>
|
|
||||||
<span className="sr-only">Nx on GitHub</span>
|
|
||||||
<div className="item-center flex">
|
|
||||||
<svg
|
|
||||||
className="h-5 w-5"
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
fill="currentColor"
|
|
||||||
>
|
|
||||||
<path d="M8 0a8 8 0 0 0-2.53 15.59c.4.07.55-.17.55-.38l-.01-1.49c-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82a7.42 7.42 0 0 1 4 0c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48l-.01 2.2c0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8a8 8 0 0 0-8-8z" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/*MOBILE*/}
|
|
||||||
<div className="relative mx-auto flex w-full items-center justify-between p-4 lg:hidden">
|
|
||||||
<div className="flex flex-shrink-0">
|
|
||||||
{/*LOGO*/}
|
|
||||||
<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>
|
|
||||||
</Link>
|
|
||||||
{/*MENU*/}
|
|
||||||
<div className="ml-4 flex flex-shrink-0">
|
|
||||||
<Popover className="">
|
|
||||||
{({ open }) => (
|
|
||||||
<>
|
|
||||||
<Popover.Button
|
|
||||||
type="button"
|
|
||||||
className="inline-flex flex-shrink-0 items-center rounded-md border border-slate-200 bg-slate-50/60 px-3 py-2 text-sm text-sm font-semibold font-medium capitalize leading-4 shadow-sm transition hover:bg-slate-50 focus:outline-none dark:border-slate-700 dark:bg-slate-800/60 dark:hover:bg-slate-800"
|
|
||||||
>
|
|
||||||
<Bars4Icon
|
|
||||||
className="-ml-0.5 mr-2 h-4 w-4"
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
{router.pathname === '/'
|
|
||||||
? 'Home'
|
|
||||||
: router.pathname.replace('/', '')}
|
|
||||||
</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-0 z-10 mt-3 w-screen px-2">
|
|
||||||
<div className="overflow-hidden rounded-lg bg-white shadow-lg ring-1 ring-black/5 dark:bg-slate-900 dark:ring-white/5">
|
|
||||||
<nav className="relative grid gap-8 p-8 md:grid-cols-2">
|
|
||||||
{flyoutMobileMenu.map((item) => (
|
|
||||||
<Link
|
|
||||||
key={item.name}
|
|
||||||
href={item.href}
|
|
||||||
className="-m-3 flex items-start rounded-lg p-3 transition duration-150 ease-in-out hover:bg-slate-50 dark:hover:bg-slate-800/60"
|
|
||||||
>
|
|
||||||
<div className="ml-4">
|
|
||||||
<p className="text-base font-medium text-slate-900 dark:text-slate-200">
|
|
||||||
{item.name}
|
|
||||||
</p>
|
|
||||||
<p className="mt-1 text-sm text-slate-500 dark:text-slate-400">
|
|
||||||
{item.description}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</Link>
|
|
||||||
))}
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</Popover.Panel>
|
|
||||||
</Transition>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Popover>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="items-justified flex flex-shrink-0 justify-center space-x-1 text-sm">
|
|
||||||
<ThemeSwitcher />
|
|
||||||
<a
|
|
||||||
title="Nx is open source, check the code on GitHub"
|
|
||||||
href="https://github.com/nrwl/nx"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
className="px-3 py-2 opacity-60 hover:opacity-90"
|
|
||||||
>
|
|
||||||
<span className="sr-only">Nx on GitHub</span>
|
|
||||||
<div className="item-center flex">
|
|
||||||
<svg className="h-5 w-5" viewBox="0 0 16 16" fill="currentColor">
|
|
||||||
<path
|
|
||||||
fillRule="evenodd"
|
|
||||||
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
56
nx-dev/ui-common/src/lib/headers/default-menu-item.tsx
Normal file
56
nx-dev/ui-common/src/lib/headers/default-menu-item.tsx
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import { ElementType } from 'react';
|
||||||
|
import type { MenuItem } from './menu-items';
|
||||||
|
import cx from 'classnames';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export function DefaultMenuItem({
|
||||||
|
as = 'div',
|
||||||
|
className = '',
|
||||||
|
item,
|
||||||
|
...rest
|
||||||
|
}: {
|
||||||
|
as?: ElementType;
|
||||||
|
className?: string;
|
||||||
|
item: MenuItem;
|
||||||
|
}): JSX.Element {
|
||||||
|
const hasExternalLink =
|
||||||
|
item.href.startsWith('http') || item.href.startsWith('//');
|
||||||
|
const Tag = as;
|
||||||
|
return (
|
||||||
|
<Tag
|
||||||
|
className={cx(
|
||||||
|
'relative flex flex-1 gap-4 rounded-lg py-4 px-2 transition duration-150 ease-in-out',
|
||||||
|
item.isHighlight
|
||||||
|
? 'bg-slate-50 hover:bg-slate-100 dark:bg-slate-800/80 dark:hover:bg-slate-700/60'
|
||||||
|
: 'hover:bg-slate-50 dark:hover:bg-slate-800/60',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
{item.icon ? (
|
||||||
|
<item.icon aria-hidden="true" className="h-5 w-5 shrink-0" />
|
||||||
|
) : null}
|
||||||
|
<div className="grow">
|
||||||
|
<Link
|
||||||
|
href={item.href}
|
||||||
|
title={item.name}
|
||||||
|
target={hasExternalLink ? '_blank' : '_self'}
|
||||||
|
className="text-sm font-medium text-slate-900 dark:text-slate-200"
|
||||||
|
>
|
||||||
|
{item.name}
|
||||||
|
{item.isNew ? (
|
||||||
|
<span className="float-right inline-flex items-center rounded-md bg-blue-50 px-2 py-1 text-xs font-medium text-blue-700 ring-1 ring-inset ring-blue-700/10 dark:bg-blue-400/10 dark:text-sky-400 dark:ring-sky-400/30">
|
||||||
|
new
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
<span className="absolute inset-0" />
|
||||||
|
</Link>
|
||||||
|
{item.description ? (
|
||||||
|
<p className="mt-0.5 text-xs text-slate-400 dark:text-slate-500">
|
||||||
|
{item.description}
|
||||||
|
</p>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,13 +1,25 @@
|
|||||||
import { type JSX } from 'react';
|
import { Fragment, type JSX } from 'react';
|
||||||
import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline';
|
import {
|
||||||
|
ArrowUpRightIcon,
|
||||||
|
Bars3Icon,
|
||||||
|
ChevronDownIcon,
|
||||||
|
XMarkIcon,
|
||||||
|
} from '@heroicons/react/24/outline';
|
||||||
import { AlgoliaSearch } from '@nx/nx-dev/feature-search';
|
import { AlgoliaSearch } from '@nx/nx-dev/feature-search';
|
||||||
import { ThemeSwitcher } from '@nx/nx-dev/ui-theme';
|
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { ButtonLink } from './button';
|
import { ButtonLink } from '../button';
|
||||||
import { NxCloudIcon } from './nx-cloud-icon';
|
import { NxIcon } from '../nx-icon';
|
||||||
import { AnnouncementBanner } from './announcement-banner';
|
import { Popover, Transition } from '@headlessui/react';
|
||||||
|
import { TwoColumnsMenu } from './two-columns-menu';
|
||||||
|
import {
|
||||||
|
featuresItems,
|
||||||
|
resourceMenuItems,
|
||||||
|
solutionsMenuItems,
|
||||||
|
} from './menu-items';
|
||||||
|
import { SectionsMenu } from './sections-menu';
|
||||||
|
import { NxCloudIcon } from '../nx-cloud-icon';
|
||||||
|
|
||||||
function Menu({ tabs }: { tabs: any[] }): JSX.Element {
|
function Menu({ tabs }: { tabs: any[] }): JSX.Element {
|
||||||
return (
|
return (
|
||||||
@ -197,20 +209,12 @@ export function DocumentationHeader({
|
|||||||
href="/"
|
href="/"
|
||||||
className="flex flex-grow items-center px-4 text-slate-900 dark:text-white lg:px-0"
|
className="flex flex-grow items-center px-4 text-slate-900 dark:text-white lg:px-0"
|
||||||
>
|
>
|
||||||
<svg
|
<span className="sr-only">Nx</span>
|
||||||
role="img"
|
<NxIcon aria-hidden="true" className="h-8 w-8" />
|
||||||
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>
|
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
href="/getting-started/intro"
|
href="/getting-started/intro"
|
||||||
className="hidden lg:flex ml-2 items-center px-4 text-slate-900 dark:text-white lg:px-0"
|
className="ml-2 hidden items-center px-4 text-slate-900 dark:text-white lg:flex lg:px-0"
|
||||||
>
|
>
|
||||||
<span className="text-xl font-bold uppercase tracking-wide">
|
<span className="text-xl font-bold uppercase tracking-wide">
|
||||||
Docs
|
Docs
|
||||||
@ -218,66 +222,193 @@ export function DocumentationHeader({
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
{/*SEARCH*/}
|
{/*SEARCH*/}
|
||||||
<div className="hidden w-full max-w-sm lg:inline">
|
<div className="hidden w-full max-w-[14rem] lg:inline">
|
||||||
<AlgoliaSearch />
|
<AlgoliaSearch />
|
||||||
</div>
|
</div>
|
||||||
{/*NAVIGATION*/}
|
{/*NAVIGATION*/}
|
||||||
<div className="hidden flex-shrink-0 lg:flex">
|
<div className="hidden flex-shrink-0 xl:flex">
|
||||||
<nav
|
<nav
|
||||||
role="menu"
|
role="menu"
|
||||||
className="items-justified hidden justify-center space-x-2 text-sm lg:flex"
|
className="items-justified hidden justify-center space-x-2 text-sm lg:flex"
|
||||||
>
|
>
|
||||||
<h2 className="sr-only">Main navigation</h2>
|
<h2 className="sr-only">Main navigation</h2>
|
||||||
{/* <Link
|
{/*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-30 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-30 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 dark:text-slate-200 dark:hover:text-sky-500 md:inline-flex"
|
||||||
|
>
|
||||||
|
Documentation
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
href="/blog"
|
href="/blog"
|
||||||
title="Blog"
|
title="Blog"
|
||||||
className="hidden px-3 py-2 font-medium leading-tight hover:text-blue-500 dark:text-slate-200 dark:hover:text-sky-500 md:inline-flex"
|
className="hidden px-3 py-2 font-medium leading-tight hover:text-blue-500 dark:text-slate-200 dark:hover:text-sky-500 md:inline-flex"
|
||||||
>
|
>
|
||||||
Blog
|
Blog
|
||||||
</Link> */}
|
|
||||||
<Link
|
|
||||||
href="/community"
|
|
||||||
title="Nx Community: Join us!"
|
|
||||||
className="hidden px-3 py-2 font-medium leading-tight hover:text-blue-500 dark:text-slate-200 dark:hover:text-sky-500 md:inline-flex"
|
|
||||||
>
|
|
||||||
Community
|
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
<a
|
||||||
href="/launch-nx"
|
href="https://nx.app/pricing"
|
||||||
title="Launch Nx"
|
title="Nx Cloud"
|
||||||
className="relative hidden px-3 py-2 font-medium leading-tight hover:text-blue-500 dark:text-slate-200 dark:hover:text-sky-500 md:inline-flex"
|
target="_blank"
|
||||||
|
className="hidden gap-2 px-3 py-2 font-medium leading-tight hover:text-blue-500 dark:text-slate-200 dark:hover:text-sky-500 md:inline-flex"
|
||||||
>
|
>
|
||||||
{/*<span className="absolute top-0 right-0 -mt-1 -mr-1 flex h-3 w-3">*/}
|
CI Pricing
|
||||||
{/* <span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-blue-500 opacity-75 dark:bg-sky-500" />*/}
|
<ArrowUpRightIcon className="h-2 w-2 align-super" />
|
||||||
{/* <span className="relative inline-flex h-3 w-3 rounded-full bg-blue-500 dark:bg-sky-500" />*/}
|
</a>
|
||||||
{/*</span>*/}Launch Nx
|
{/*RESOURCES*/}
|
||||||
</Link>
|
<Popover className="relative">
|
||||||
<Link
|
{({ open }) => (
|
||||||
href="/contact"
|
<>
|
||||||
title="Contact us"
|
<Popover.Button
|
||||||
className="hidden px-3 py-2 font-medium leading-tight hover:text-blue-500 dark:text-slate-200 dark:hover:text-sky-500 md:inline-flex"
|
className={cx(
|
||||||
>
|
open ? 'text-blue-500 dark:text-sky-500' : '',
|
||||||
Contact us
|
'group inline-flex items-center px-3 py-2 font-medium leading-tight outline-0 dark:text-slate-200'
|
||||||
</Link>
|
)}
|
||||||
|
>
|
||||||
|
<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-30 mt-3 w-max max-w-2xl -translate-x-1/2 transform lg:left-20">
|
||||||
|
<SectionsMenu sections={resourceMenuItems} />
|
||||||
|
</Popover.Panel>
|
||||||
|
</Transition>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Popover>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
<div className="hidden flex-grow lg:flex">{/* SPACER */}</div>
|
<div className="hidden flex-grow lg:flex">{/* SPACER */}</div>
|
||||||
<div className="hidden w-full xl:flex">
|
{/*<div className="hidden w-full xl:flex">*/}
|
||||||
<AnnouncementBanner />
|
{/* <AnnouncementBanner />*/}
|
||||||
</div>
|
{/*</div>*/}
|
||||||
<div className="hidden flex-shrink-0 lg:flex">
|
<div className="hidden flex-shrink-0 lg:flex">
|
||||||
<nav
|
<nav
|
||||||
role="menu"
|
role="menu"
|
||||||
className="items-justified hidden justify-center space-x-4 lg:flex"
|
className="items-justified hidden justify-center space-x-4 lg:flex"
|
||||||
>
|
>
|
||||||
<ThemeSwitcher />
|
<Link
|
||||||
|
className="hidden cursor-pointer px-3 py-2 text-sm font-medium leading-tight hover:text-blue-500 dark:text-slate-200 dark:hover:text-sky-500 md:inline-flex"
|
||||||
|
title="Contact Us"
|
||||||
|
href="/contact"
|
||||||
|
>
|
||||||
|
Contact
|
||||||
|
</Link>
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
href="https://nx.app/?utm_source=nx.dev&utm_medium=header-menu"
|
href="https://nx.app/?utm_source=nx.dev&utm_medium=header-menu"
|
||||||
title="Go to app"
|
title="Go to app"
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
size="small"
|
size="small"
|
||||||
>
|
>
|
||||||
<NxCloudIcon className="w-4 h-4" aria-hidden="true" />
|
<NxCloudIcon className="h-4 w-4" aria-hidden="true" />
|
||||||
<span>Go to app</span>
|
<span>Go to app</span>
|
||||||
</ButtonLink>
|
</ButtonLink>
|
||||||
</nav>
|
</nav>
|
||||||
520
nx-dev/ui-common/src/lib/headers/header.tsx
Normal file
520
nx-dev/ui-common/src/lib/headers/header.tsx
Normal file
@ -0,0 +1,520 @@
|
|||||||
|
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="relative 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 dark:text-slate-200 dark:hover:text-sky-500 md:inline-flex"
|
||||||
|
>
|
||||||
|
Documentation
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
href="/blog"
|
||||||
|
title="Blog"
|
||||||
|
className="hidden px-3 py-2 font-medium leading-tight hover:text-blue-500 dark:text-slate-200 dark:hover:text-sky-500 md:inline-flex"
|
||||||
|
>
|
||||||
|
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 dark:text-slate-200 dark:hover:text-sky-500 md:inline-flex"
|
||||||
|
>
|
||||||
|
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 dark:text-slate-200 dark:hover:text-sky-500 md:inline-flex"
|
||||||
|
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>
|
||||||
|
);
|
||||||
|
}
|
||||||
214
nx-dev/ui-common/src/lib/headers/menu-items.ts
Normal file
214
nx-dev/ui-common/src/lib/headers/menu-items.ts
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
import {
|
||||||
|
AcademicCapIcon,
|
||||||
|
ArrowPathIcon,
|
||||||
|
BoltIcon,
|
||||||
|
CircleStackIcon,
|
||||||
|
CodeBracketIcon,
|
||||||
|
CubeIcon,
|
||||||
|
NewspaperIcon,
|
||||||
|
PlayCircleIcon,
|
||||||
|
ShareIcon,
|
||||||
|
Squares2X2Icon,
|
||||||
|
} from '@heroicons/react/24/outline';
|
||||||
|
import { FC, SVGProps } from 'react';
|
||||||
|
import { NxAgentsIcon } from '../nx-agents-icon';
|
||||||
|
import { NxReplayIcon } from '../nx-replay-icon';
|
||||||
|
|
||||||
|
export interface MenuItem {
|
||||||
|
name: string;
|
||||||
|
href: string;
|
||||||
|
description: string | null;
|
||||||
|
icon: FC<SVGProps<SVGSVGElement>> | null;
|
||||||
|
isHighlight: boolean;
|
||||||
|
isNew: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const featuresItems: MenuItem[] = [
|
||||||
|
{
|
||||||
|
name: 'Task Running',
|
||||||
|
// description: 'Run one or many tasks in parallel.',
|
||||||
|
description: null,
|
||||||
|
href: '/features/run-tasks',
|
||||||
|
icon: BoltIcon,
|
||||||
|
isNew: false,
|
||||||
|
isHighlight: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Local Caching',
|
||||||
|
// description: 'Speeds up your local workflow.',
|
||||||
|
description: null,
|
||||||
|
href: '/features/cache-task-results',
|
||||||
|
icon: CircleStackIcon,
|
||||||
|
isNew: false,
|
||||||
|
isHighlight: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Nx Graph',
|
||||||
|
// description: 'See interactions for tasks and modules.',
|
||||||
|
description: null,
|
||||||
|
href: '/features/explore-graph',
|
||||||
|
icon: ShareIcon,
|
||||||
|
isNew: false,
|
||||||
|
isHighlight: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Automated updates',
|
||||||
|
// description: 'Keep running on latest without effort.',
|
||||||
|
description: null,
|
||||||
|
href: '/features/automate-updating-dependencies',
|
||||||
|
icon: ArrowPathIcon,
|
||||||
|
isNew: false,
|
||||||
|
isHighlight: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Module Boundaries',
|
||||||
|
// description: 'Partition your code into defined units.',
|
||||||
|
description: null,
|
||||||
|
href: '/features/enforce-module-boundaries',
|
||||||
|
icon: Squares2X2Icon,
|
||||||
|
isNew: false,
|
||||||
|
isHighlight: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Nx Release',
|
||||||
|
// description: 'Versioning, changelog, publishing.',
|
||||||
|
description: null,
|
||||||
|
href: '/features/manage-releases',
|
||||||
|
icon: CubeIcon,
|
||||||
|
isNew: true,
|
||||||
|
isHighlight: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Nx Replay',
|
||||||
|
description: 'Zero-config, fast & secure remote cache solution.',
|
||||||
|
href: '/ci/features/remote-cache',
|
||||||
|
icon: NxReplayIcon,
|
||||||
|
isNew: false,
|
||||||
|
isHighlight: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Nx Agents',
|
||||||
|
description:
|
||||||
|
'One-line config for distributing tasks, E2E tests split & flaky tasks rerun.',
|
||||||
|
href: '/ci/features/distribute-task-execution',
|
||||||
|
icon: NxAgentsIcon,
|
||||||
|
isNew: true,
|
||||||
|
isHighlight: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
export const plans: MenuItem[] = [
|
||||||
|
{
|
||||||
|
name: 'Nx Cloud',
|
||||||
|
description:
|
||||||
|
'End-to-end solution for smart, efficient and maintainable CI.',
|
||||||
|
href: 'https://nx.app',
|
||||||
|
icon: null,
|
||||||
|
isNew: false,
|
||||||
|
isHighlight: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Nx Enterprise',
|
||||||
|
description:
|
||||||
|
'The ultimate Nx & Nx Cloud toolchain, tailored to your needs.',
|
||||||
|
href: 'https://nx.app/enterprise',
|
||||||
|
icon: null,
|
||||||
|
isNew: false,
|
||||||
|
isHighlight: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const useCaseItems: MenuItem[] = [
|
||||||
|
{
|
||||||
|
name: 'Get actionable feedback',
|
||||||
|
description: 'Enhanced analysis & analytics of your workflows.',
|
||||||
|
href: '',
|
||||||
|
icon: null,
|
||||||
|
isNew: false,
|
||||||
|
isHighlight: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Reduce CI timings with remote caching',
|
||||||
|
description: 'Share task results & artifacts between CI & teams.',
|
||||||
|
href: '',
|
||||||
|
icon: null,
|
||||||
|
isNew: false,
|
||||||
|
isHighlight: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Performant task distribution at scale',
|
||||||
|
description: 'Faster & cheaper CI workflows.',
|
||||||
|
href: '',
|
||||||
|
icon: null,
|
||||||
|
isNew: false,
|
||||||
|
isHighlight: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Improve E2E time execution on CI',
|
||||||
|
description: 'Automatic task splitting.',
|
||||||
|
href: '',
|
||||||
|
icon: null,
|
||||||
|
isNew: false,
|
||||||
|
isHighlight: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
export const learnItems: MenuItem[] = [
|
||||||
|
{
|
||||||
|
name: 'Step by step tutorials',
|
||||||
|
description: null,
|
||||||
|
href: '/getting-started/intro#learn-nx',
|
||||||
|
icon: AcademicCapIcon,
|
||||||
|
isNew: false,
|
||||||
|
isHighlight: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Code examples for your stack',
|
||||||
|
description: null,
|
||||||
|
href: '/showcase/example-repos',
|
||||||
|
icon: CodeBracketIcon,
|
||||||
|
isNew: false,
|
||||||
|
isHighlight: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Video tutorials',
|
||||||
|
description: null,
|
||||||
|
href: 'https://www.youtube.com/@nxdevtools',
|
||||||
|
icon: PlayCircleIcon,
|
||||||
|
isNew: false,
|
||||||
|
isHighlight: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Newsletter',
|
||||||
|
description: null,
|
||||||
|
href: 'https://go.nrwl.io/nx-newsletter',
|
||||||
|
icon: NewspaperIcon,
|
||||||
|
isNew: false,
|
||||||
|
isHighlight: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
export const eventItems: MenuItem[] = [
|
||||||
|
{
|
||||||
|
name: 'Nx Conf',
|
||||||
|
description:
|
||||||
|
'In person & virtual conference about latest monorepo advancements.',
|
||||||
|
href: '/conf',
|
||||||
|
icon: null,
|
||||||
|
isNew: false,
|
||||||
|
isHighlight: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Webinars',
|
||||||
|
description:
|
||||||
|
'Virtual courses to get a deeper understanding on monorepos animated by the Nx team.',
|
||||||
|
href: 'https://go.nx.dev/april-webinar',
|
||||||
|
icon: null,
|
||||||
|
isNew: false,
|
||||||
|
isHighlight: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
export const solutionsMenuItems = {
|
||||||
|
'Helping you grow': plans,
|
||||||
|
// 'Use cases': useCaseItems
|
||||||
|
};
|
||||||
|
export const resourceMenuItems = {
|
||||||
|
Learn: learnItems,
|
||||||
|
Events: eventItems,
|
||||||
|
};
|
||||||
54
nx-dev/ui-common/src/lib/headers/mobile-menu-item.tsx
Normal file
54
nx-dev/ui-common/src/lib/headers/mobile-menu-item.tsx
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { ElementType } from 'react';
|
||||||
|
import type { MenuItem } from './menu-items';
|
||||||
|
import cx from 'classnames';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export function MobileMenuItem({
|
||||||
|
as = 'div',
|
||||||
|
className = '',
|
||||||
|
item,
|
||||||
|
...rest
|
||||||
|
}: {
|
||||||
|
as?: ElementType;
|
||||||
|
className?: string;
|
||||||
|
item: MenuItem;
|
||||||
|
}): JSX.Element {
|
||||||
|
const hasExternalLink =
|
||||||
|
item.href.startsWith('http') || item.href.startsWith('//');
|
||||||
|
const Tag = as;
|
||||||
|
return (
|
||||||
|
<Tag
|
||||||
|
className={cx(
|
||||||
|
'relative flex flex-1 items-center gap-2 rounded-lg py-3',
|
||||||
|
item.isHighlight ? 'bg-slate-50 px-2 dark:bg-slate-800/80' : '',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
{item.icon ? (
|
||||||
|
<item.icon aria-hidden="true" className="h-4 w-4 shrink-0" />
|
||||||
|
) : null}
|
||||||
|
<div className="grow">
|
||||||
|
<Link
|
||||||
|
href={item.href}
|
||||||
|
title={item.name}
|
||||||
|
target={hasExternalLink ? '_blank' : '_self'}
|
||||||
|
className="text-sm font-medium text-slate-900 dark:text-slate-200"
|
||||||
|
>
|
||||||
|
{item.name}
|
||||||
|
{item.isNew ? (
|
||||||
|
<span className="float-right inline-flex items-center rounded-md bg-blue-50 px-2 py-1 text-xs font-medium text-blue-700 ring-1 ring-inset ring-blue-700/10 dark:bg-blue-400/10 dark:text-sky-400 dark:ring-sky-400/30">
|
||||||
|
new
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
<span className="absolute inset-0" />
|
||||||
|
</Link>
|
||||||
|
{item.description ? (
|
||||||
|
<p className="mt-0.5 text-xs text-slate-400 dark:text-slate-500">
|
||||||
|
{item.description}
|
||||||
|
</p>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
}
|
||||||
27
nx-dev/ui-common/src/lib/headers/sections-menu.tsx
Normal file
27
nx-dev/ui-common/src/lib/headers/sections-menu.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import type { MenuItem } from './menu-items';
|
||||||
|
import { DefaultMenuItem } from './default-menu-item';
|
||||||
|
|
||||||
|
export function SectionsMenu({
|
||||||
|
sections,
|
||||||
|
}: {
|
||||||
|
sections: Record<string, MenuItem[]>;
|
||||||
|
}): JSX.Element {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col gap-2 overflow-hidden rounded-lg bg-white shadow-lg ring-1 ring-slate-200 dark:bg-slate-900 dark:ring-slate-800">
|
||||||
|
<div className="divide-y divide-slate-200 dark:divide-slate-800">
|
||||||
|
{Object.keys(sections).map((section) => (
|
||||||
|
<div>
|
||||||
|
<h5 className="px-4 pt-6 text-sm text-slate-500 dark:text-slate-400">
|
||||||
|
{section}
|
||||||
|
</h5>
|
||||||
|
<div className="grid grid-cols-2 gap-2 p-2">
|
||||||
|
{sections[section].map((item) => (
|
||||||
|
<DefaultMenuItem key={item.name} item={item} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
23
nx-dev/ui-common/src/lib/headers/two-columns-menu.tsx
Normal file
23
nx-dev/ui-common/src/lib/headers/two-columns-menu.tsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import type { MenuItem } from './menu-items';
|
||||||
|
import { DefaultMenuItem } from './default-menu-item';
|
||||||
|
|
||||||
|
export function TwoColumnsMenu({ items }: { items: MenuItem[] }): JSX.Element {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col gap-2 overflow-hidden rounded-lg bg-white shadow-lg ring-1 ring-slate-200 dark:bg-slate-900 dark:ring-slate-800">
|
||||||
|
<div className="grid grid-cols-2 gap-2 p-2">
|
||||||
|
{items
|
||||||
|
.filter((i) => !i.isHighlight)
|
||||||
|
.map((item) => (
|
||||||
|
<DefaultMenuItem key={item.name} item={item} />
|
||||||
|
))}
|
||||||
|
<div className="col-span-2 flex gap-2">
|
||||||
|
{items
|
||||||
|
.filter((i) => i.isHighlight)
|
||||||
|
.map((item) => (
|
||||||
|
<DefaultMenuItem key={item.name} item={item} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
17
nx-dev/ui-common/src/lib/nx-agents-icon.tsx
Normal file
17
nx-dev/ui-common/src/lib/nx-agents-icon.tsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { FC, SVGProps } from 'react';
|
||||||
|
|
||||||
|
export const NxAgentsIcon: FC<SVGProps<SVGSVGElement>> = (props) => (
|
||||||
|
<svg
|
||||||
|
role="img"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
stroke="currentColor"
|
||||||
|
fill="none"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinejoin="round"
|
||||||
|
d="M21 12.5h-4m4 0a1 1 0 1 0 2 0 1 1 0 0 0-2 0Zm-2 8h-5v-3m5 3a1 1 0 1 0 2 0 1 1 0 0 0-2 0Zm-16-8h4m-4 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0Zm2 8h5v-3m-5 3a1 1 0 1 1-2 0 1 1 0 0 1 2 0Zm0-17h5v4m-5-4a1 1 0 1 0-2 0 1 1 0 0 0 2 0Zm14 0h-5v4m5-4a1 1 0 1 1 2 0 1 1 0 0 1-2 0Zm-3 14H8a1 1 0 0 1-1-1v-8a1 1 0 0 1 1-1h8a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1Zm-5-8h2l-.667 1.875L14 11.346 11.333 15.5l.334-2.77H10l1-3.23Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
14
nx-dev/ui-common/src/lib/nx-icon.tsx
Normal file
14
nx-dev/ui-common/src/lib/nx-icon.tsx
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { FC, SVGProps } from 'react';
|
||||||
|
|
||||||
|
export const NxIcon: FC<SVGProps<SVGSVGElement>> = (props) => (
|
||||||
|
<svg
|
||||||
|
role="img"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="currentColor"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<title>Nx</title>
|
||||||
|
<path d="m12 14.1-3.1 5-5.2-8.5v8.9H0v-15h3.7l5.2 8.9v-4l3 4.7zm.6-5.7V4.5H8.9v3.9h3.7zm5.6 4.1a2 2 0 0 0-2 1.3 2 2 0 0 1 2.4-.7c.4.2 1 .4 1.3.3a2.1 2.1 0 0 0-1.7-.9zm3.4 1c-.4 0-.8-.2-1.1-.6l-.2-.3a2.1 2.1 0 0 0-.5-.6 2 2 0 0 0-1.2-.3 2.5 2.5 0 0 0-2.3 1.5 2.3 2.3 0 0 1 4 .4.8.8 0 0 0 .9.3c.5 0 .4.4 1.2.5v-.1c0-.4-.3-.5-.8-.7zm2 1.3a.7.7 0 0 0 .4-.6c0-3-2.4-5.5-5.4-5.5a5.4 5.4 0 0 0-4.5 2.4l-1.5-2.4H8.9l3.5 5.4L9 19.5h3.6L14 17l1.6 2.4h3.5l-3.1-5a.7.7 0 0 1 0-.3 2.7 2.7 0 0 1 2.6-2.7c1.5 0 1.7.9 2 1.3.7.8 2 .5 2 1.5a.7.7 0 0 0 1 .6zm.4.2c-.2.3-.6.3-.8.6-.1.3.1.4.1.4s.4.2.6-.3V15z" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
17
nx-dev/ui-common/src/lib/nx-replay-icon.tsx
Normal file
17
nx-dev/ui-common/src/lib/nx-replay-icon.tsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { FC, SVGProps } from 'react';
|
||||||
|
|
||||||
|
export const NxReplayIcon: FC<SVGProps<SVGSVGElement>> = (props) => (
|
||||||
|
<svg
|
||||||
|
role="img"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
stroke="currentColor"
|
||||||
|
fill="none"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
d="m8.625 2.621-.014.004c-.317.09-.622.22-.907.387m4.796-.965-.014-.002a3.958 3.958 0 0 0-.986.002m3.875.574.014.004c.317.09.622.22.907.387m-.92 18.367.013-.004c.317-.09.622-.22.907-.387m-4.796.965.014.002c.328.04.659.04.986-.002m-3.875-.574-.014-.004a3.96 3.96 0 0 1-.907-.387M21.38 8.625l-.004-.014a3.96 3.96 0 0 0-.387-.907m.965 4.796.002-.014c.04-.328.04-.659-.002-.986m-.574 3.875-.004.014a3.96 3.96 0 0 1-.387.907m-18.367-.92.004.013c.09.317.22.622.387.907M2.047 11.5l-.002.014c-.04.328-.04.659.002.986m.574-3.875.004-.014c.09-.317.22-.622.387-.907M7.5 10.516h9m-9 0a1.5 1.5 0 0 1 0-3h9a1.5 1.5 0 0 1 0 3m-9 0a1.5 1.5 0 0 0 0 3m9-3a1.5 1.5 0 0 1 0 3m-6.412-4.5h.01m-1.883 0h.01m-.725 4.5h9m-9 0a1.5 1.5 0 0 0 0 3h9a1.5 1.5 0 0 0 0-3m-6.412-1.5h.01m-1.883 0h.01m1.863 3h.01m-1.883 0h.01M3 4.516a1.5 1.5 0 1 0 3 0 1.5 1.5 0 0 0-3 0Zm15 0a1.5 1.5 0 1 0 3 0 1.5 1.5 0 0 0-3 0Zm-15 15a1.5 1.5 0 1 0 3 0 1.5 1.5 0 0 0-3 0Zm15 0a1.5 1.5 0 1 0 3 0 1.5 1.5 0 0 0-3 0Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
@ -5,10 +5,10 @@ import {
|
|||||||
SunIcon,
|
SunIcon,
|
||||||
} from '@heroicons/react/24/outline';
|
} from '@heroicons/react/24/outline';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import { Fragment } from 'react';
|
import { ElementType, Fragment } from 'react';
|
||||||
import { useTheme } from './theme.provider';
|
import { Theme, useTheme } from './theme.provider';
|
||||||
|
|
||||||
export function ThemeSwitcher() {
|
export function ThemeSwitcher(): JSX.Element {
|
||||||
const [theme, setTheme] = useTheme();
|
const [theme, setTheme] = useTheme();
|
||||||
const themeMap = {
|
const themeMap = {
|
||||||
dark: {
|
dark: {
|
||||||
@ -24,23 +24,24 @@ export function ThemeSwitcher() {
|
|||||||
icon: <ComputerDesktopIcon className="h-4 w-4" />,
|
icon: <ComputerDesktopIcon className="h-4 w-4" />,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const availableThemes = [
|
const availableThemes: { label: string; value: Theme; icon: ElementType }[] =
|
||||||
{
|
[
|
||||||
label: 'Light',
|
{
|
||||||
value: 'light',
|
label: 'Light',
|
||||||
icon: <SunIcon className="mr-4 h-4 w-4" />,
|
value: 'light',
|
||||||
},
|
icon: SunIcon,
|
||||||
{
|
},
|
||||||
label: 'Dark',
|
{
|
||||||
value: 'dark',
|
label: 'Dark',
|
||||||
icon: <MoonIcon className="mr-4 h-4 w-4" />,
|
value: 'dark',
|
||||||
},
|
icon: MoonIcon,
|
||||||
{
|
},
|
||||||
label: 'System',
|
{
|
||||||
value: 'system',
|
label: 'System',
|
||||||
icon: <ComputerDesktopIcon className="mr-4 h-4 w-4" />,
|
value: 'system',
|
||||||
},
|
icon: ComputerDesktopIcon,
|
||||||
];
|
},
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="inline-block">
|
<div className="inline-block">
|
||||||
@ -66,13 +67,13 @@ export function ThemeSwitcher() {
|
|||||||
leaveFrom="transform opacity-100 scale-100"
|
leaveFrom="transform opacity-100 scale-100"
|
||||||
leaveTo="transform opacity-0 scale-95"
|
leaveTo="transform opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<Listbox.Options className="absolute top-full right-0 z-50 mt-2 w-36 origin-top-right divide-y divide-slate-100 rounded-md bg-white shadow-lg ring-1 ring-black/5 focus:outline-none dark:divide-slate-800 dark:bg-slate-900 dark:ring-white/5">
|
<Listbox.Options className="absolute top-full -right-10 z-50 mt-2 w-36 origin-top-right divide-y divide-slate-100 rounded-md bg-white shadow-lg ring-1 ring-black/5 focus:outline-none dark:divide-slate-800 dark:bg-slate-900 dark:ring-white/5">
|
||||||
{availableThemes.map(({ value, label, icon }) => (
|
{availableThemes.map((t) => (
|
||||||
<Listbox.Option key={value} value={value} as={Fragment}>
|
<Listbox.Option key={t.value} value={t.value} as={Fragment}>
|
||||||
{({ active, selected }) => (
|
{({ active, selected }) => (
|
||||||
<li
|
<li
|
||||||
className={cx(
|
className={cx(
|
||||||
'flex cursor-pointer items-center px-4 py-2 text-sm',
|
'flex cursor-pointer items-center gap-2 px-4 py-2 text-sm',
|
||||||
{
|
{
|
||||||
'bg-slate-100 dark:bg-slate-800/60': active,
|
'bg-slate-100 dark:bg-slate-800/60': active,
|
||||||
'text-blue-500 dark:text-sky-500': active || selected,
|
'text-blue-500 dark:text-sky-500': active || selected,
|
||||||
@ -80,8 +81,8 @@ export function ThemeSwitcher() {
|
|||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{icon}
|
<t.icon aria-hidden="true" className="h-4 w-4 shrink-0" />
|
||||||
{label}
|
{t.label}
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
</Listbox.Option>
|
</Listbox.Option>
|
||||||
|
|||||||
@ -124,7 +124,6 @@
|
|||||||
"@types/marked": "^2.0.0",
|
"@types/marked": "^2.0.0",
|
||||||
"@types/node": "18.19.8",
|
"@types/node": "18.19.8",
|
||||||
"@types/npm-package-arg": "6.1.1",
|
"@types/npm-package-arg": "6.1.1",
|
||||||
"@types/prettier": "^2.6.2",
|
|
||||||
"@types/react": "18.2.33",
|
"@types/react": "18.2.33",
|
||||||
"@types/react-dom": "18.2.14",
|
"@types/react-dom": "18.2.14",
|
||||||
"@types/semver": "^7.5.2",
|
"@types/semver": "^7.5.2",
|
||||||
@ -169,7 +168,7 @@
|
|||||||
"esbuild": "0.19.5",
|
"esbuild": "0.19.5",
|
||||||
"eslint": "8.57.0",
|
"eslint": "8.57.0",
|
||||||
"eslint-config-next": "14.0.4",
|
"eslint-config-next": "14.0.4",
|
||||||
"eslint-config-prettier": "9.0.0",
|
"eslint-config-prettier": "9.1.0",
|
||||||
"eslint-plugin-cypress": "2.14.0",
|
"eslint-plugin-cypress": "2.14.0",
|
||||||
"eslint-plugin-import": "2.27.5",
|
"eslint-plugin-import": "2.27.5",
|
||||||
"eslint-plugin-jsx-a11y": "6.7.1",
|
"eslint-plugin-jsx-a11y": "6.7.1",
|
||||||
@ -245,8 +244,8 @@
|
|||||||
"postcss-import": "~14.1.0",
|
"postcss-import": "~14.1.0",
|
||||||
"postcss-preset-env": "~7.5.0",
|
"postcss-preset-env": "~7.5.0",
|
||||||
"postcss-url": "~10.1.3",
|
"postcss-url": "~10.1.3",
|
||||||
"prettier": "^2.6.2",
|
"prettier": "^2.7.1",
|
||||||
"prettier-plugin-tailwindcss": "^0.1.5",
|
"prettier-plugin-tailwindcss": "^0.1.13",
|
||||||
"pretty-quick": "^3.1.0",
|
"pretty-quick": "^3.1.0",
|
||||||
"raw-loader": "^4.0.2",
|
"raw-loader": "^4.0.2",
|
||||||
"react-markdown": "^8.0.7",
|
"react-markdown": "^8.0.7",
|
||||||
@ -375,4 +374,3 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
32
pnpm-lock.yaml
generated
32
pnpm-lock.yaml
generated
@ -289,7 +289,7 @@ devDependencies:
|
|||||||
version: 18.3.0-beta.3(@swc-node/register@1.8.0)(@swc/core@1.3.86)(@types/node@18.19.8)(js-yaml@4.1.0)(nx@18.3.0-beta.3)(verdaccio@5.15.4)
|
version: 18.3.0-beta.3(@swc-node/register@1.8.0)(@swc/core@1.3.86)(@types/node@18.19.8)(js-yaml@4.1.0)(nx@18.3.0-beta.3)(verdaccio@5.15.4)
|
||||||
'@nx/eslint-plugin':
|
'@nx/eslint-plugin':
|
||||||
specifier: 18.3.0-beta.3
|
specifier: 18.3.0-beta.3
|
||||||
version: 18.3.0-beta.3(@swc-node/register@1.8.0)(@swc/core@1.3.86)(@types/node@18.19.8)(@typescript-eslint/parser@7.4.0)(eslint-config-prettier@9.0.0)(eslint@8.57.0)(nx@18.3.0-beta.3)(typescript@5.4.2)(verdaccio@5.15.4)
|
version: 18.3.0-beta.3(@swc-node/register@1.8.0)(@swc/core@1.3.86)(@types/node@18.19.8)(@typescript-eslint/parser@7.4.0)(eslint-config-prettier@9.1.0)(eslint@8.57.0)(nx@18.3.0-beta.3)(typescript@5.4.2)(verdaccio@5.15.4)
|
||||||
'@nx/jest':
|
'@nx/jest':
|
||||||
specifier: 18.3.0-beta.3
|
specifier: 18.3.0-beta.3
|
||||||
version: 18.3.0-beta.3(@swc-node/register@1.8.0)(@swc/core@1.3.86)(@types/node@18.19.8)(nx@18.3.0-beta.3)(ts-node@10.9.1)(typescript@5.4.2)(verdaccio@5.15.4)
|
version: 18.3.0-beta.3(@swc-node/register@1.8.0)(@swc/core@1.3.86)(@types/node@18.19.8)(nx@18.3.0-beta.3)(ts-node@10.9.1)(typescript@5.4.2)(verdaccio@5.15.4)
|
||||||
@ -449,9 +449,6 @@ devDependencies:
|
|||||||
'@types/npm-package-arg':
|
'@types/npm-package-arg':
|
||||||
specifier: 6.1.1
|
specifier: 6.1.1
|
||||||
version: 6.1.1
|
version: 6.1.1
|
||||||
'@types/prettier':
|
|
||||||
specifier: ^2.6.2
|
|
||||||
version: 2.7.1
|
|
||||||
'@types/react':
|
'@types/react':
|
||||||
specifier: 18.2.33
|
specifier: 18.2.33
|
||||||
version: 18.2.33
|
version: 18.2.33
|
||||||
@ -585,8 +582,8 @@ devDependencies:
|
|||||||
specifier: 14.0.4
|
specifier: 14.0.4
|
||||||
version: 14.0.4(eslint@8.57.0)(typescript@5.4.2)
|
version: 14.0.4(eslint@8.57.0)(typescript@5.4.2)
|
||||||
eslint-config-prettier:
|
eslint-config-prettier:
|
||||||
specifier: 9.0.0
|
specifier: 9.1.0
|
||||||
version: 9.0.0(eslint@8.57.0)
|
version: 9.1.0(eslint@8.57.0)
|
||||||
eslint-plugin-cypress:
|
eslint-plugin-cypress:
|
||||||
specifier: 2.14.0
|
specifier: 2.14.0
|
||||||
version: 2.14.0(eslint@8.57.0)
|
version: 2.14.0(eslint@8.57.0)
|
||||||
@ -813,10 +810,10 @@ devDependencies:
|
|||||||
specifier: ~10.1.3
|
specifier: ~10.1.3
|
||||||
version: 10.1.3(postcss@8.4.19)
|
version: 10.1.3(postcss@8.4.19)
|
||||||
prettier:
|
prettier:
|
||||||
specifier: ^2.6.2
|
specifier: ^2.7.1
|
||||||
version: 2.7.1
|
version: 2.7.1
|
||||||
prettier-plugin-tailwindcss:
|
prettier-plugin-tailwindcss:
|
||||||
specifier: ^0.1.5
|
specifier: ^0.1.13
|
||||||
version: 0.1.13(prettier@2.7.1)
|
version: 0.1.13(prettier@2.7.1)
|
||||||
pretty-quick:
|
pretty-quick:
|
||||||
specifier: ^3.1.0
|
specifier: ^3.1.0
|
||||||
@ -7819,10 +7816,10 @@ packages:
|
|||||||
- verdaccio
|
- verdaccio
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@nrwl/eslint-plugin-nx@18.3.0-beta.3(@swc-node/register@1.8.0)(@swc/core@1.3.86)(@types/node@18.19.8)(@typescript-eslint/parser@7.4.0)(eslint-config-prettier@9.0.0)(eslint@8.57.0)(nx@18.3.0-beta.3)(typescript@5.4.2)(verdaccio@5.15.4):
|
/@nrwl/eslint-plugin-nx@18.3.0-beta.3(@swc-node/register@1.8.0)(@swc/core@1.3.86)(@types/node@18.19.8)(@typescript-eslint/parser@7.4.0)(eslint-config-prettier@9.1.0)(eslint@8.57.0)(nx@18.3.0-beta.3)(typescript@5.4.2)(verdaccio@5.15.4):
|
||||||
resolution: {integrity: sha512-M1XcAYnavTKZTC/kj1D4fYx9w2Q5Rbr6nyQ8vuZpukwWgxoDiNZ7CcHBdsUYO6EyFL3b331iCpQgcK+8tmSAhA==}
|
resolution: {integrity: sha512-M1XcAYnavTKZTC/kj1D4fYx9w2Q5Rbr6nyQ8vuZpukwWgxoDiNZ7CcHBdsUYO6EyFL3b331iCpQgcK+8tmSAhA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nx/eslint-plugin': 18.3.0-beta.3(@swc-node/register@1.8.0)(@swc/core@1.3.86)(@types/node@18.19.8)(@typescript-eslint/parser@7.4.0)(eslint-config-prettier@9.0.0)(eslint@8.57.0)(nx@18.3.0-beta.3)(typescript@5.4.2)(verdaccio@5.15.4)
|
'@nx/eslint-plugin': 18.3.0-beta.3(@swc-node/register@1.8.0)(@swc/core@1.3.86)(@types/node@18.19.8)(@typescript-eslint/parser@7.4.0)(eslint-config-prettier@9.1.0)(eslint@8.57.0)(nx@18.3.0-beta.3)(typescript@5.4.2)(verdaccio@5.15.4)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@babel/traverse'
|
- '@babel/traverse'
|
||||||
- '@swc-node/register'
|
- '@swc-node/register'
|
||||||
@ -8477,7 +8474,7 @@ packages:
|
|||||||
- verdaccio
|
- verdaccio
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@nx/eslint-plugin@18.3.0-beta.3(@swc-node/register@1.8.0)(@swc/core@1.3.86)(@types/node@18.19.8)(@typescript-eslint/parser@7.4.0)(eslint-config-prettier@9.0.0)(eslint@8.57.0)(nx@18.3.0-beta.3)(typescript@5.4.2)(verdaccio@5.15.4):
|
/@nx/eslint-plugin@18.3.0-beta.3(@swc-node/register@1.8.0)(@swc/core@1.3.86)(@types/node@18.19.8)(@typescript-eslint/parser@7.4.0)(eslint-config-prettier@9.1.0)(eslint@8.57.0)(nx@18.3.0-beta.3)(typescript@5.4.2)(verdaccio@5.15.4):
|
||||||
resolution: {integrity: sha512-3LNegAAk+ENBwM7frkoC7WSZ/K1n05mCDZOc6jKdHhP68KNiS1NeHn872l66qDgyf1Lb/qFizlZACWoVWVtkOw==}
|
resolution: {integrity: sha512-3LNegAAk+ENBwM7frkoC7WSZ/K1n05mCDZOc6jKdHhP68KNiS1NeHn872l66qDgyf1Lb/qFizlZACWoVWVtkOw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@typescript-eslint/parser': ^6.13.2 || ^7.0.0
|
'@typescript-eslint/parser': ^6.13.2 || ^7.0.0
|
||||||
@ -8486,7 +8483,7 @@ packages:
|
|||||||
eslint-config-prettier:
|
eslint-config-prettier:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nrwl/eslint-plugin-nx': 18.3.0-beta.3(@swc-node/register@1.8.0)(@swc/core@1.3.86)(@types/node@18.19.8)(@typescript-eslint/parser@7.4.0)(eslint-config-prettier@9.0.0)(eslint@8.57.0)(nx@18.3.0-beta.3)(typescript@5.4.2)(verdaccio@5.15.4)
|
'@nrwl/eslint-plugin-nx': 18.3.0-beta.3(@swc-node/register@1.8.0)(@swc/core@1.3.86)(@types/node@18.19.8)(@typescript-eslint/parser@7.4.0)(eslint-config-prettier@9.1.0)(eslint@8.57.0)(nx@18.3.0-beta.3)(typescript@5.4.2)(verdaccio@5.15.4)
|
||||||
'@nx/devkit': 18.3.0-beta.3(nx@18.3.0-beta.3)
|
'@nx/devkit': 18.3.0-beta.3(nx@18.3.0-beta.3)
|
||||||
'@nx/js': 18.3.0-beta.3(@swc-node/register@1.8.0)(@swc/core@1.3.86)(@types/node@18.19.8)(nx@18.3.0-beta.3)(typescript@5.4.2)(verdaccio@5.15.4)
|
'@nx/js': 18.3.0-beta.3(@swc-node/register@1.8.0)(@swc/core@1.3.86)(@types/node@18.19.8)(nx@18.3.0-beta.3)(typescript@5.4.2)(verdaccio@5.15.4)
|
||||||
'@typescript-eslint/parser': 7.4.0(eslint@8.57.0)(typescript@5.4.2)
|
'@typescript-eslint/parser': 7.4.0(eslint@8.57.0)(typescript@5.4.2)
|
||||||
@ -8494,7 +8491,7 @@ packages:
|
|||||||
'@typescript-eslint/utils': 7.4.0(eslint@8.57.0)(typescript@5.4.2)
|
'@typescript-eslint/utils': 7.4.0(eslint@8.57.0)(typescript@5.4.2)
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
confusing-browser-globals: 1.0.11
|
confusing-browser-globals: 1.0.11
|
||||||
eslint-config-prettier: 9.0.0(eslint@8.57.0)
|
eslint-config-prettier: 9.1.0(eslint@8.57.0)
|
||||||
jsonc-eslint-parser: 2.1.0
|
jsonc-eslint-parser: 2.1.0
|
||||||
semver: 7.6.0
|
semver: 7.6.0
|
||||||
tslib: 2.6.2
|
tslib: 2.6.2
|
||||||
@ -13165,6 +13162,7 @@ packages:
|
|||||||
|
|
||||||
/@types/prettier@2.7.1:
|
/@types/prettier@2.7.1:
|
||||||
resolution: {integrity: sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==}
|
resolution: {integrity: sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/pretty-hrtime@1.0.1:
|
/@types/pretty-hrtime@1.0.1:
|
||||||
resolution: {integrity: sha512-VjID5MJb1eGKthz2qUerWT8+R4b9N+CHvGCzg9fn4kWZgaF9AhdYikQio3R7wV8YY1NsQKPaCwKz1Yff+aHNUQ==}
|
resolution: {integrity: sha512-VjID5MJb1eGKthz2qUerWT8+R4b9N+CHvGCzg9fn4kWZgaF9AhdYikQio3R7wV8YY1NsQKPaCwKz1Yff+aHNUQ==}
|
||||||
@ -18946,8 +18944,8 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/eslint-config-prettier@9.0.0(eslint@8.57.0):
|
/eslint-config-prettier@9.1.0(eslint@8.57.0):
|
||||||
resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==}
|
resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: '>=7.0.0'
|
eslint: '>=7.0.0'
|
||||||
@ -23371,6 +23369,8 @@ packages:
|
|||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
webpack:
|
webpack:
|
||||||
optional: true
|
optional: true
|
||||||
|
webpack-sources:
|
||||||
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
webpack: 5.88.0(@swc/core@1.3.86)(esbuild@0.19.5)
|
webpack: 5.88.0(@swc/core@1.3.86)(esbuild@0.19.5)
|
||||||
webpack-sources: 3.2.3
|
webpack-sources: 3.2.3
|
||||||
@ -23383,6 +23383,8 @@ packages:
|
|||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
webpack:
|
webpack:
|
||||||
optional: true
|
optional: true
|
||||||
|
webpack-sources:
|
||||||
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
webpack: 5.90.3(@swc/core@1.3.86)(esbuild@0.20.1)
|
webpack: 5.90.3(@swc/core@1.3.86)(esbuild@0.20.1)
|
||||||
webpack-sources: 3.2.3
|
webpack-sources: 3.2.3
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user