feat(nx-dev): add React landing page (#30612)

Co-authored-by: Juri <juri.strumpflohner@gmail.com>
This commit is contained in:
Mike Hartington 2025-04-16 07:59:43 -04:00 committed by GitHub
parent 6b081363c1
commit 68c481f7d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 1192 additions and 2 deletions

View File

@ -0,0 +1,58 @@
import { DefaultLayout } from '@nx/nx-dev/ui-common';
import {
CallToAction,
Features,
GettingStarted,
Hero,
} from '@nx/nx-dev/ui-react';
import { NxBenefitsVideo } from '@nx/nx-dev/ui-react';
import type { Metadata } from 'next';
export const metadata: Metadata = {
title: 'Nx For React',
description:
'Add Nx to your React project for distributed task execution, intelligent caching, and affected commands.',
alternates: {
canonical: 'https://nx.dev/react',
},
openGraph: {
url: 'https://nx.dev/react',
title: 'Nx For React',
description:
'Add Nx to your React project for distributed task execution, intelligent caching, and affected commands.',
images: [
{
url: 'https://nx.dev/socials/nx-react-media.png',
width: 800,
height: 421,
alt: 'Nx For React',
type: 'image/jpeg',
},
],
siteName: 'Nx',
type: 'website',
},
};
export default function ReactPage(): JSX.Element {
return (
<DefaultLayout>
<Hero />
<div className="mt-8 scroll-mt-8 lg:mt-16">
<NxBenefitsVideo />
</div>
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mt-16 scroll-mt-16 lg:mt-32" id="features">
<Features />
</div>
</div>
<div className="mt-16 scroll-mt-16 lg:mt-32">
<GettingStarted />
</div>
<div className="overflow-hidden py-8 sm:py-8">
<CallToAction />
</div>
</DefaultLayout>
);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 625 KiB

View File

@ -656,7 +656,6 @@ const packagesIndexes = {
'/nest': '/packages/nest', '/nest': '/packages/nest',
'/next': '/packages/next', '/next': '/packages/next',
'/node': '/packages/node', '/node': '/packages/node',
'/react': '/packages/react',
'/react-native': '/packages/react', '/react-native': '/packages/react',
'/rollup': '/packages/rollup', '/rollup': '/packages/rollup',
'/storybook': '/packages/storybook', '/storybook': '/packages/storybook',
@ -879,7 +878,7 @@ const missingAndCatchAllRedirects = {
// catch all // catch all
'/(l|latest|p|previous)/(a|angular|r|react|n|node)/:path*': '/:path*', '/(l|latest|p|previous)/(a|angular|r|react|n|node)/:path*': '/:path*',
'/(l|latest|p|previous)/:path*': '/:path*', '/(l|latest|p|previous)/:path*': '/:path*',
'/(a|angular|r|react|n|node)/:path*': '/:path*', '/(a|angular|n|node)/:path*': '/:path*',
// Storybook // Storybook
'/(l|latest)/(r|react)/storybook/overview': '/storybook/overview-react', '/(l|latest)/(r|react)/storybook/overview': '/storybook/overview-react',
'/(l|latest)/(a|angular)/storybook/overview': '/storybook/overview-angular', '/(l|latest)/(a|angular)/storybook/overview': '/storybook/overview-angular',

View File

@ -0,0 +1,7 @@
# ui-react
This library was generated with [Nx](https://nx.dev).
## Running unit tests
Run `nx test ui-react` to execute the unit tests via [Jest](https://jestjs.io).

View File

@ -0,0 +1,9 @@
{
"name": "ui-react",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "nx-dev/ui-react/src",
"projectType": "library",
"tags": [],
"// targets": "to see all targets run: nx show project ui-react --web",
"targets": {}
}

View File

@ -0,0 +1 @@
export * from './lib';

View File

@ -0,0 +1,91 @@
import { ButtonLink, SectionHeading } from '@nx/nx-dev/ui-common';
import { GradleIcon, ReactIcon } from '@nx/nx-dev/ui-icons';
import { cx } from '@nx/nx-dev/ui-primitives';
import React, { ReactElement } from 'react';
import Link from 'next/link';
export function CallToAction(): ReactElement {
return (
<section className="relative isolate px-6 py-32 sm:py-40 lg:px-8">
{/* Background pattern */}
<svg
className="absolute inset-0 -z-10 h-full w-full stroke-black/10 [mask-image:radial-gradient(100%_100%_at_top_right,white,transparent)] dark:stroke-white/10"
aria-hidden="true"
>
<defs>
<pattern
id="gradle-cta-pattern"
width={200}
height={200}
x="50%"
y={0}
patternUnits="userSpaceOnUse"
>
<path d="M.5 200V.5H200" fill="none" />
</pattern>
</defs>
<svg
x="50%"
y={0}
className="overflow-visible fill-slate-200/20 dark:fill-slate-800/20"
>
<path
d="M-200 0h201v201h-201Z M600 0h201v201h-201Z M-400 600h201v201h-201Z M200 800h201v201h-201Z"
strokeWidth={0}
/>
</svg>
<rect
width="100%"
height="100%"
strokeWidth={0}
fill="url(#gradle-cta-pattern)"
/>
</svg>
{/* Gradient background */}
<div
className="pointer-events-none absolute inset-x-0 top-10 -z-10 flex transform-gpu justify-center overflow-hidden blur-3xl"
aria-hidden="true"
>
<div
className="aspect-[1108/632] w-[69.25rem] flex-none bg-gradient-to-r from-blue-500 to-blue-600 opacity-20"
style={{
clipPath:
'polygon(73.6% 51.7%, 91.7% 11.8%, 100% 46.4%, 97.4% 82.2%, 92.5% 84.9%, 75.7% 64%, 55.3% 47.5%, 46.5% 49.4%, 45% 62.9%, 50.3% 87.2%, 21.3% 64.1%, 0.1% 100%, 5.4% 51.1%, 21.4% 63.9%, 58.9% 0.2%, 73.6% 51.7%)',
}}
/>
</div>
{/* Content */}
<div className="mx-auto max-w-2xl text-center">
<div className="mb-8 flex justify-center">
<ReactIcon className="h-24 w-24 text-slate-900 dark:text-white" />
</div>
<h2 className="text-3xl font-medium tracking-tight text-slate-950 sm:text-5xl dark:text-white">
Get Started With Nx React
</h2>
<p className="mt-8">
Check out the documentation for the <code>@nx/react</code> plugin to
learn more
</p>
<div className="mt-10 flex items-center justify-center gap-x-6">
<Link
href="/nx-api/react/documents/overview"
title="Get started with the tutorial"
prefetch={false}
className="rounded-md bg-slate-950 px-3.5 py-2.5 text-sm font-semibold text-slate-100 shadow-sm hover:bg-slate-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white dark:bg-white dark:text-slate-900 dark:hover:bg-slate-100"
>
Read the Docs{' '}
<span
aria-hidden="true"
className="inline-block transition group-hover:translate-x-1"
>
</span>
</Link>
</div>
</div>
</section>
);
}

View File

@ -0,0 +1,137 @@
import { ReactElement } from 'react';
import { ButtonLink, SectionHeading } from '@nx/nx-dev/ui-common';
export function FeatureSections(): ReactElement {
return (
<section className="feature-sections py-16 sm:py-24">
<div className="mx-auto px-6 lg:max-w-7xl">
<SectionHeading id="nx-gradle-features" as="h2" variant="title">
Supercharge your Java Projects{' '}
<span className="rounded-lg bg-gradient-to-r from-cyan-500 to-blue-500 bg-clip-text text-transparent">
with Nx
</span>
</SectionHeading>
<div className="mt-10 grid grid-cols-1 gap-8 sm:mt-16 md:grid-cols-2 lg:grid-cols-3 ">
{/* Affected Section */}
<FeatureSection
title="Affected"
description="Run tasks only on projects affected by your changes, saving time and resources. Nx understands your project's dependency graph and automatically determines which projects need to be rebuilt."
imageSrc="/images/enterprise/nx-affected.avif"
alt="Nx Affected: Run tasks only on affected projects"
tag="Affected"
href="/ci/features/affected"
/>
{/* Remote Caching Section */}
<FeatureSection
title="Never build the same code twice"
description="Nx Replay (Remote Caching) ensures tasks are never rebuilt unnecessarily. Share cached results across your team and CI pipelines to dramatically reduce build times and resource usage."
imageSrc="/images/enterprise/nx-replay.avif"
alt="Nx Replay: Remote caching"
tag="Nx Replay"
href="/features/cache-task-results"
/>
{/* Distribution Section */}
<FeatureSection
title="Distribute tasks across machines"
description="Nx Agents intelligently distribute your Gradle tasks across multiple machines, significantly reducing build times. Dynamically allocate agents based on PR size to balance speed and cost."
imageSrc="/images/enterprise/nx-agents.avif"
alt="Nx Agents: Task distribution"
tag="Nx Agents"
href="/ci/features/distribute-task-execution"
/>
{/* Atomizer Section */}
<FeatureSection
title="Break tests down, speed execution up"
description="Atomizer automatically splits large Gradle test tasks into smaller, atomized units, enabling lightning fast parallel testing. No code changes required - just configure and run."
imageSrc="/images/enterprise/nx-atomizer.avif"
alt="Nx Atomizer: Split large test tasks"
tag="Atomizer"
href="/ci/features/split-e2e-tasks"
/>
{/* Flaky Test Retries Section */}
<FeatureSection
title="Automatically handle flaky tests"
description="Nx detects and automatically retries flaky tests, enhancing the reliability of your CI processes and minimizing time spent debugging intermittent failures."
imageSrc="/images/enterprise/nx-flaky-tasks-detection.avif"
alt="Nx flaky task detection & rerun"
tag="Flaky test retries"
href="/nx-api/gradle/documents/overview"
/>
</div>
</div>
</section>
);
}
interface FeatureSectionProps {
title: string;
description: string;
imageSrc: string;
alt: string;
tag: string;
href: string;
reversed?: boolean;
}
function FeatureSection({
title,
description,
imageSrc,
alt,
tag,
href,
}: FeatureSectionProps): ReactElement {
return (
<div
className={`feature-section flex flex-col overflow-hidden rounded-2xl bg-white shadow ring-1 ring-black/5 dark:bg-slate-950 dark:ring-white/10 `}
>
<div className="h-0 w-full md:h-72">
<img
alt={alt}
src={imageSrc}
className="h-full w-full object-cover object-center"
/>
</div>
<div className="relative flex flex-1 flex-col justify-center p-8 lg:p-10">
<div>
<span className="mb-3 inline-flex items-center rounded-full bg-slate-400/10 px-3 py-1 text-sm font-medium text-slate-600 ring-1 ring-inset ring-slate-400/20 dark:text-slate-300">
{tag}
</span>
<h3 className="mt-2 text-xl font-medium tracking-tight text-slate-950 lg:text-2xl dark:text-white">
{title}
</h3>
<p className="mt-4 text-base/relaxed text-slate-600 dark:text-slate-300">
{description}
</p>
<div className="mt-6">
<ButtonLink
href={href}
title={`Learn more about ${title}`}
variant="secondary"
size="default"
>
Learn more
<svg
className="ml-2 h-4 w-4"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fillRule="evenodd"
d="M3 10a.75.75 0 01.75-.75h10.638L10.23 5.29a.75.75 0 111.04-1.08l5.5 5.25a.75.75 0 010 1.08l-5.5 5.25a.75.75 0 11-1.04-1.08l4.158-3.96H3.75A.75.75 0 013 10z"
clipRule="evenodd"
/>
</svg>
</ButtonLink>
</div>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,278 @@
import { SectionHeading } from '@nx/nx-dev/ui-common';
import { cx } from '@nx/nx-dev/ui-primitives';
import React, { ReactElement } from 'react';
export function Features(): ReactElement {
return (
<>
<SectionHeading as="h2" variant="title">
Features
</SectionHeading>
<p className="mt-4 text-lg text-slate-500 dark:text-slate-400">
Nx allows you to take existing React projects and add powerful
capabilities to your workflow.
</p>
<div className="mt-12 grid grid-cols-1 gap-6 sm:gap-8 md:grid-cols-2 lg:grid-cols-3">
<FeatureCard
title="Task Caching"
description="Cache task results locally and remotely, avoiding redundant builds and speeding up your development workflow."
href="/features/cache-task-results"
icon={
<svg
className="h-6 w-6"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="2"
/>
<polyline
points="12 6 12 12 16 14"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
}
/>
<FeatureCard
title="Distributed Task Execution"
description="Run your project tasks across multiple machines, dramatically reducing build times for large repositories."
href="/ci/features/distribute-task-execution"
icon={
<svg
className="h-6 w-6"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect
x="2"
y="7"
width="20"
height="14"
rx="2"
stroke="currentColor"
strokeWidth="2"
/>
<path
d="M6 7V4.5C6 3.67157 6.67157 3 7.5 3H16.5C17.3284 3 18 3.67157 18 4.5V7"
stroke="currentColor"
strokeWidth="2"
/>
<path
d="M12 14L12 10"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
/>
<path
d="M9 12L15 12"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
/>
</svg>
}
/>
<FeatureCard
title="Affected Targets"
description="Run tasks only on projects affected by your changes, saving time and computing resources."
href="/ci/features/affected"
icon={
<svg
className="h-6 w-6"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M22 11.08V12C21.9988 14.1564 21.3005 16.2547 20.0093 17.9818C18.7182 19.709 16.9033 20.9725 14.8354 21.5839C12.7674 22.1953 10.5573 22.1219 8.53447 21.3746C6.51168 20.6273 4.78465 19.2461 3.61096 17.4371C2.43727 15.628 1.87979 13.4881 2.02168 11.3363C2.16356 9.18455 2.99721 7.13631 4.39828 5.49706C5.79935 3.85781 7.69279 2.71537 9.79619 2.24013C11.8996 1.7649 14.1003 1.98232 16.07 2.85999"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M22 4L12 14L9 11"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
}
/>
<FeatureCard
title="Project Graph"
description="Nx automatically infers your project graph from project's configuration, providing visualization and dependency analysis."
href="/features/explore-graph"
icon={
<svg
className="h-6 w-6"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="5"
cy="5"
r="2"
stroke="currentColor"
strokeWidth="2"
/>
<circle
cx="19"
cy="5"
r="2"
stroke="currentColor"
strokeWidth="2"
/>
<circle
cx="5"
cy="19"
r="2"
stroke="currentColor"
strokeWidth="2"
/>
<circle
cx="19"
cy="19"
r="2"
stroke="currentColor"
strokeWidth="2"
/>
<path d="M7 5H17" stroke="currentColor" strokeWidth="2" />
<path d="M5 7V17" stroke="currentColor" strokeWidth="2" />
<path d="M7 19H17" stroke="currentColor" strokeWidth="2" />
<path d="M19 7V17" stroke="currentColor" strokeWidth="2" />
</svg>
}
/>
<FeatureCard
title="Split E2E Tests"
description="Automatically split your E2E tests for faster parallel execution in CI environments with Atomizer."
href="/ci/features/split-e2e-tasks"
icon={
<svg
className="h-6 w-6"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14 3V7C14 7.55228 14.4477 8 15 8H19"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M17 21H7C5.89543 21 5 20.1046 5 19V5C5 3.89543 5.89543 3 7 3H14L19 8V19C19 20.1046 18.1046 21 17 21Z"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M10 12L8 14L10 16"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M14 12L16 14L14 16"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
}
/>
<FeatureCard
title="Zero Configuration"
j
description="Add Nx to your existing monorepo in minutes."
href="/recipes/adopting-nx/adding-to-monorepo"
icon={
<svg
className="h-6 w-6"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 2L2 7L12 12L22 7L12 2Z"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M2 17L12 22L22 17"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M2 12L12 17L22 12"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
}
/>
</div>
</>
);
}
interface FeatureCardProps {
title: string;
description: string;
icon: JSX.Element;
href?: string;
}
function FeatureCard({
title,
description,
icon,
href = '#',
}: FeatureCardProps): ReactElement {
return (
<a href={href} className="block h-full transform-gpu">
<div
className={cx(
'group relative h-full w-full overflow-hidden rounded-lg border border-slate-200 bg-white p-6',
'dark:border-slate-800 dark:bg-slate-900 dark:hover:border-blue-900 dark:hover:shadow-blue-900/20',
'before:absolute before:inset-0 before:z-0 before:bg-gradient-to-br before:from-blue-50 before:to-transparent before:opacity-0 before:transition-opacity',
'transition-all duration-300 ease-out',
'hover:-translate-y-2 hover:border-blue-200 hover:shadow-xl hover:shadow-blue-100/50',
'hover:before:opacity-100 dark:before:from-blue-950'
)}
>
<div className="relative z-10">
<div className="mb-4 flex h-12 w-12 items-center justify-center rounded-lg bg-blue-50 text-blue-600 transition-transform duration-300 group-hover:scale-110 dark:bg-slate-800 dark:text-blue-400 dark:group-hover:bg-blue-900">
{icon}
</div>
<h3 className="mb-2 text-lg font-medium">{title}</h3>
<p className="text-slate-500 dark:text-slate-400">{description}</p>
</div>
</div>
</a>
);
}

View File

@ -0,0 +1,152 @@
/* eslint-disable @nx/enforce-module-boundaries */
import {
ButtonLink,
SectionHeading,
Strong,
SectionDescription,
} from '@nx/nx-dev/ui-common';
import { ReactIcon } from '@nx/nx-dev/ui-icons';
/* eslint-enable @nx/enforce-module-boundaries */
import { ReactElement } from 'react';
export function Hero(): ReactElement {
return (
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto max-w-2xl text-center">
{/* Logo displayed above the title */}
<div className="mb-6 flex justify-center">
<div className="rounded-full bg-slate-100 p-4 dark:bg-slate-800">
<ReactIcon className="h-20 w-20" />
</div>
</div>
<SectionHeading as="h1" variant="title" className="mt-6">
Experience the{' '}
<span className="rounded-lg bg-gradient-to-r from-cyan-500 to-blue-500 bg-clip-text text-transparent">
power of Nx
</span>{' '}
<br className="hidden md:block" />
in your{' '}
<span className="rounded-lg bg-gradient-to-r from-cyan-500 to-blue-500 bg-clip-text text-transparent">
React monorepo
</span>
</SectionHeading>
<SectionDescription as="p" className="mt-6">
Get distributed tasks, intelligent caching, and target affected
<br />
packages to optimize your build process and CI pipeline.
</SectionDescription>
<div className="mt-10 flex flex-col items-center justify-center gap-6 sm:flex-row">
<ButtonLink
href="/getting-started/tutorials/react-monorepo-tutorial"
variant="primary"
size="default"
title="Get Started"
>
Get Started with Nx for React
</ButtonLink>
<a
href="https://github.com/nrwl/nx-recipes/tree/main/react-monorepo"
target="_blank"
rel="noopener noreferrer"
className="group inline-flex items-center text-sm font-semibold leading-6 text-slate-800 dark:text-white"
>
View Example Project{' '}
<span
aria-hidden="true"
className="ml-1 inline-block transition-transform group-hover:translate-x-1"
>
</span>
</a>
</div>
</div>
</div>
);
}
export function GettingStarted(): ReactElement {
return (
<section className="relative py-16 sm:py-24">
<div className="absolute inset-0 bg-white dark:bg-slate-900"></div>
<div className="relative mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto max-w-2xl text-center">
<h2 className="text-3xl font-bold tracking-tight text-slate-900 sm:text-4xl dark:text-white">
Add Nx To An Existing Project
</h2>
</div>
<div className="mt-12 grid grid-cols-1 gap-6 sm:gap-8 md:grid-cols-3 ">
<GetStartedCard
title="Add Nx To Your Project"
command="npx init nx"
description="Initialize Nx in an existing React Project"
/>
<GetStartedCard
title="Run Tasks With Nx"
command="nx build <project>"
description="Nx will automatically infers tasks from your projects."
/>
<GetStartedCard
title="Run Affected Tasks"
command="nx affected -t build"
description="Nx adds caching, distribution, and affected commands without changing your setup."
/>
</div>
{/* GitHub example project link */}
<div className="mt-12 flex justify-center">
<a
href="https://github.com/nrwl/nx-recipes/tree/main/react-monorepo"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 rounded-lg border border-slate-200 bg-white px-6 py-3 font-medium text-slate-900 shadow-sm transition-all hover:-translate-y-1 hover:border-blue-400 hover:shadow-md dark:border-slate-700 dark:bg-slate-800 dark:text-white dark:hover:border-blue-500"
>
<svg
className="h-5 w-5"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 2C6.477 2 2 6.477 2 12C2 16.418 4.865 20.166 8.839 21.489C9.339 21.581 9.521 21.284 9.521 21.029C9.521 20.799 9.513 20.065 9.508 19.27C6.726 19.891 6.139 17.962 6.139 17.962C5.685 16.812 5.029 16.516 5.029 16.516C4.121 15.89 5.098 15.902 5.098 15.902C6.101 15.97 6.629 16.925 6.629 16.925C7.521 18.43 8.97 18.008 9.539 17.762C9.631 17.097 9.889 16.676 10.175 16.419C7.954 16.159 5.62 15.304 5.62 11.453C5.62 10.355 6.009 9.457 6.649 8.758C6.546 8.514 6.203 7.543 6.746 6.161C6.746 6.161 7.585 5.902 9.497 7.203C10.295 6.988 11.15 6.88 12 6.876C12.85 6.88 13.705 6.988 14.505 7.203C16.415 5.902 17.253 6.161 17.253 6.161C17.798 7.543 17.455 8.514 17.352 8.758C17.994 9.457 18.38 10.355 18.38 11.453C18.38 15.313 16.042 16.156 13.815 16.411C14.174 16.726 14.495 17.347 14.495 18.297C14.495 19.648 14.483 20.709 14.483 21.029C14.483 21.287 14.661 21.586 15.171 21.487C19.138 20.161 22 16.417 22 12C22 6.477 17.523 2 12 2Z"
fill="currentColor"
/>
</svg>
View Example Project on GitHub
</a>
</div>
</div>
</section>
);
}
interface GetStartedCardProps {
title: string;
command: string;
description: string;
}
function GetStartedCard({
title,
command,
description,
}: GetStartedCardProps): ReactElement {
return (
<div className="h-full rounded-xl border border-slate-200 bg-white p-6 shadow-sm transition-all hover:shadow-md dark:border-slate-700 dark:bg-slate-800">
<h3 className="text-lg font-medium text-slate-900 dark:text-white">
{title}
</h3>
<div className="mt-3 overflow-hidden rounded-md bg-slate-800 px-4 py-3 text-sm text-white dark:bg-slate-950">
<code style={{ whiteSpace: 'pre-line' }}>{command}</code>
</div>
<p
className="mt-3 text-sm text-slate-600 dark:text-slate-300"
dangerouslySetInnerHTML={{ __html: description }}
></p>
</div>
);
}

View File

@ -0,0 +1,7 @@
export * from './hero';
export * from './features';
export * from './resources';
export * from './call-to-action';
export * from './feature-sections';
export * from './webinar';
export * from './nx-benefits-video';

View File

@ -0,0 +1 @@
export * from './nx-benefits-video';

View File

@ -0,0 +1,267 @@
'use client';
import { ComponentProps, ReactElement, useState } from 'react';
import { SectionHeading, computeThumbnailURL } from '@nx/nx-dev/ui-common';
import {
BoltIcon,
RocketLaunchIcon,
PuzzlePieceIcon,
PlayIcon,
} from '@heroicons/react/24/outline';
import { VideoModal } from '@nx/nx-dev/ui-common';
import { sendCustomEvent } from '@nx/nx-dev/feature-analytics';
import { motion } from 'framer-motion';
import { MovingBorder } from '@nx/nx-dev/ui-animations';
import { cx } from '@nx/nx-dev/ui-primitives';
import Image from 'next/image';
function PlayButton({
className,
...props
}: ComponentProps<'div'>): ReactElement {
const parent = {
initial: {
width: 82,
transition: {
when: 'afterChildren',
},
},
hover: {
width: 296,
transition: {
duration: 0.125,
type: 'tween',
ease: 'easeOut',
},
},
};
const child = {
initial: {
opacity: 0,
x: -6,
},
hover: {
x: 0,
opacity: 1,
transition: {
duration: 0.015,
type: 'tween',
ease: 'easeOut',
},
},
};
return (
<div
className={cx(
'group relative overflow-hidden rounded-full bg-transparent p-[1px] shadow-md',
className
)}
{...props}
>
<div className="absolute inset-0">
<MovingBorder duration={5000} rx="5%" ry="5%">
<div className="size-20 bg-[radial-gradient(var(--blue-500)_40%,transparent_60%)] opacity-[0.8] dark:bg-[radial-gradient(var(--pink-500)_40%,transparent_60%)]" />
</MovingBorder>
</div>
<motion.div
initial="initial"
whileHover="hover"
variants={parent}
className="relative isolate flex size-20 cursor-pointer items-center justify-center gap-6 rounded-full border-2 border-slate-100 bg-white/10 p-6 text-white antialiased backdrop-blur-xl"
>
<PlayIcon aria-hidden="true" className="absolute left-6 top-6 size-8" />
<motion.div variants={child} className="absolute left-20 top-4 w-48">
<p className="text-base font-medium">Watch the video</p>
<p className="text-xs">Learn how Nx works.</p>
</motion.div>
</motion.div>
</div>
);
}
export function NxBenefitsVideo(): ReactElement {
const [isOpen, setIsOpen] = useState(false);
const videoUrl = 'https://youtu.be/qotrgWQKqZQ';
const thumbnailUrl = computeThumbnailURL(videoUrl);
return (
<div className="border-b border-t border-slate-200 bg-slate-50 py-16 sm:py-8 dark:border-slate-800 dark:bg-slate-900">
<section
id="nx-benefits-video"
className="z-0 mx-auto max-w-7xl scroll-mt-20 px-4 sm:px-6 lg:px-8"
>
<div className="md:grid md:grid-cols-2 md:items-center md:gap-10 lg:gap-12">
<div className="mb-24 block sm:px-6 md:mb-0">
<div className="relative">
<div className="absolute bottom-0 start-0 -translate-x-14 translate-y-10">
<svg
className="h-auto max-w-40 text-slate-200 dark:text-slate-800"
width="696"
height="653"
viewBox="0 0 696 653"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="72.5" cy="29.5" r="29.5" fill="currentColor" />
<circle cx="171.5" cy="29.5" r="29.5" fill="currentColor" />
<circle cx="270.5" cy="29.5" r="29.5" fill="currentColor" />
<circle cx="369.5" cy="29.5" r="29.5" fill="currentColor" />
<circle cx="468.5" cy="29.5" r="29.5" fill="currentColor" />
<circle cx="567.5" cy="29.5" r="29.5" fill="currentColor" />
<circle cx="666.5" cy="29.5" r="29.5" fill="currentColor" />
<circle cx="29.5" cy="128.5" r="29.5" fill="currentColor" />
<circle cx="128.5" cy="128.5" r="29.5" fill="currentColor" />
<circle cx="227.5" cy="128.5" r="29.5" fill="currentColor" />
<circle cx="326.5" cy="128.5" r="29.5" fill="currentColor" />
<circle cx="425.5" cy="128.5" r="29.5" fill="currentColor" />
<circle cx="524.5" cy="128.5" r="29.5" fill="currentColor" />
<circle cx="623.5" cy="128.5" r="29.5" fill="currentColor" />
<circle cx="72.5" cy="227.5" r="29.5" fill="currentColor" />
<circle cx="171.5" cy="227.5" r="29.5" fill="currentColor" />
<circle cx="270.5" cy="227.5" r="29.5" fill="currentColor" />
<circle cx="369.5" cy="227.5" r="29.5" fill="currentColor" />
<circle cx="468.5" cy="227.5" r="29.5" fill="currentColor" />
<circle cx="567.5" cy="227.5" r="29.5" fill="currentColor" />
<circle cx="666.5" cy="227.5" r="29.5" fill="currentColor" />
<circle cx="29.5" cy="326.5" r="29.5" fill="currentColor" />
<circle cx="128.5" cy="326.5" r="29.5" fill="currentColor" />
<circle cx="227.5" cy="326.5" r="29.5" fill="currentColor" />
<circle cx="326.5" cy="326.5" r="29.5" fill="currentColor" />
<circle cx="425.5" cy="326.5" r="29.5" fill="currentColor" />
<circle cx="524.5" cy="326.5" r="29.5" fill="currentColor" />
<circle cx="623.5" cy="326.5" r="29.5" fill="currentColor" />
<circle cx="72.5" cy="425.5" r="29.5" fill="currentColor" />
<circle cx="171.5" cy="425.5" r="29.5" fill="currentColor" />
<circle cx="270.5" cy="425.5" r="29.5" fill="currentColor" />
<circle cx="369.5" cy="425.5" r="29.5" fill="currentColor" />
<circle cx="468.5" cy="425.5" r="29.5" fill="currentColor" />
<circle cx="567.5" cy="425.5" r="29.5" fill="currentColor" />
<circle cx="666.5" cy="425.5" r="29.5" fill="currentColor" />
<circle cx="29.5" cy="524.5" r="29.5" fill="currentColor" />
<circle cx="128.5" cy="524.5" r="29.5" fill="currentColor" />
<circle cx="227.5" cy="524.5" r="29.5" fill="currentColor" />
<circle cx="326.5" cy="524.5" r="29.5" fill="currentColor" />
<circle cx="425.5" cy="524.5" r="29.5" fill="currentColor" />
<circle cx="524.5" cy="524.5" r="29.5" fill="currentColor" />
<circle cx="623.5" cy="524.5" r="29.5" fill="currentColor" />
<circle cx="72.5" cy="623.5" r="29.5" fill="currentColor" />
<circle cx="171.5" cy="623.5" r="29.5" fill="currentColor" />
<circle cx="270.5" cy="623.5" r="29.5" fill="currentColor" />
<circle cx="369.5" cy="623.5" r="29.5" fill="currentColor" />
<circle cx="468.5" cy="623.5" r="29.5" fill="currentColor" />
<circle cx="567.5" cy="623.5" r="29.5" fill="currentColor" />
<circle cx="666.5" cy="623.5" r="29.5" fill="currentColor" />
</svg>
</div>
<Image
src={thumbnailUrl}
alt="Nx tutorial video thumbnail"
width={960}
height={540}
loading="lazy"
unoptimized
className="relative rounded-xl"
/>
<div className="absolute inset-0 grid h-full w-full items-center justify-center">
<PlayButton
onClick={() => {
setIsOpen(true);
sendCustomEvent(
'nx-benefits-video-click',
'nx-benefits-video',
'react'
);
}}
/>
</div>
</div>
</div>
<div className="w-full flex-auto">
<a
href="https://nx.dev/recipes/adopting-nx/adding-to-monorepo"
className="group block"
>
<div className="mt-8 flex gap-4 rounded-lg p-3 transition-colors hover:bg-slate-100 dark:hover:bg-slate-800">
<BoltIcon
aria-hidden="true"
className="size-6 shrink-0 text-blue-500"
/>
<div>
<h4 className="relative text-base font-medium leading-6 text-slate-900 group-hover:text-blue-500 dark:text-slate-100 dark:group-hover:text-blue-400">
Add Nx to any existing monorepo
<span className="ml-1 opacity-0 transition-opacity group-hover:opacity-100">
</span>
</h4>
<p className="mt-2">
Nx seamlessly integrates into your existing React monorepo
with a simple <code>nx init</code> command, providing
immediate benefits without disrupting your workflow.
</p>
</div>
</div>
</a>
<a
href="https://nx.dev/features/cache-task-results"
className="group block"
>
<div className="mt-8 flex gap-4 rounded-lg p-3 transition-colors hover:bg-slate-100 dark:hover:bg-slate-800">
<RocketLaunchIcon
aria-hidden="true"
className="size-6 shrink-0 text-blue-500"
/>
<div>
<h4 className="relative text-base font-medium leading-6 text-slate-900 group-hover:text-blue-500 dark:text-slate-100 dark:group-hover:text-blue-400">
Immediate speed and efficiency gains
<span className="ml-1 opacity-0 transition-opacity group-hover:opacity-100">
</span>
</h4>
<p className="mt-2">
Dramatically improve build times by running tasks in
parallel with local and remote caching that intelligently
avoids unnecessary work and keeps your team in sync.
</p>
</div>
</div>
</a>
<a href="https://nx.dev/plugin-registry" className="group block">
<div className="mt-8 flex gap-4 rounded-lg p-3 transition-colors hover:bg-slate-100 dark:hover:bg-slate-800">
<PuzzlePieceIcon
aria-hidden="true"
className="size-6 shrink-0 text-blue-500"
/>
<div>
<h4 className="relative text-base font-medium leading-6 text-slate-900 group-hover:text-blue-500 dark:text-slate-100 dark:group-hover:text-blue-400">
Enhanced developer experience
<span className="ml-1 opacity-0 transition-opacity group-hover:opacity-100">
</span>
</h4>
<p className="mt-2">
Add optional Nx plugins to boost your development workflow
with low-level monorepo configuration assistance,
streamlined tooling, and specialized generators for your
tech stack.
</p>
</div>
</div>
</a>
</div>
</div>
</section>
<VideoModal
isOpen={isOpen}
onClose={() => setIsOpen(false)}
videoUrl={videoUrl}
/>
</div>
);
}

View File

@ -0,0 +1,71 @@
import { ButtonLink, SectionHeading, TextLink } from '@nx/nx-dev/ui-common';
import { cx } from '@nx/nx-dev/ui-primitives';
import React, { ReactElement } from 'react';
export function Resources(): ReactElement {
return (
<>
<SectionHeading as="h2" variant="title">
Resources
</SectionHeading>
<p className="mt-4 text-lg text-slate-500 dark:text-slate-400">
Learn more about using Nx with Java projects with these resources.
</p>
<div className="mt-12 grid grid-cols-1 gap-6 sm:gap-8 md:grid-cols-3">
<ResourceCard
title="Gradle Tutorial"
description="Follow this step-by-step tutorial to add Nx to an existing Gradle project."
linkText="View tutorial"
href="/tutorials/gradle"
/>
<ResourceCard
title="Gradle Plugin Documentation"
description="Learn all the details about the Nx Gradle plugin configuration and usage."
linkText="View docs"
href="/packages/gradle/gradle-plugin"
/>
<ResourceCard
title="CI with Nx"
description="Learn how to configure Continuous Integration with Nx for faster builds."
linkText="View CI docs"
href="/ci/intro/ci-with-nx"
/>
</div>
</>
);
}
interface ResourceCardProps {
title: string;
description: string;
linkText: string;
href: string;
}
function ResourceCard({
title,
description,
linkText,
href,
}: ResourceCardProps): ReactElement {
return (
<div
className={cx(
'flex h-full flex-col justify-between rounded-lg border border-slate-200 bg-white p-6 shadow-sm transition-all hover:shadow-md dark:border-slate-800 dark:bg-slate-900'
)}
>
<div>
<h3 className="mb-2 text-lg font-medium">{title}</h3>
<p className="text-slate-500 dark:text-slate-400">{description}</p>
</div>
<div className="mt-6">
<ButtonLink href={href} size="small" variant="primary" title={linkText}>
{linkText}
</ButtonLink>
</div>
</div>
);
}

View File

@ -0,0 +1,71 @@
import { ButtonLink, SectionHeading, TextLink } from '@nx/nx-dev/ui-common';
import { cx } from '@nx/nx-dev/ui-primitives';
import React, { ReactElement } from 'react';
export function WebinarCallout(): ReactElement {
return (
<>
<SectionHeading as="h2" variant="title">
Resources
</SectionHeading>
<p className="mt-4 text-lg text-slate-500 dark:text-slate-400">
Learn more about using Nx with Java projects with these resources.
</p>
<div className="mt-12 grid grid-cols-1 gap-6 sm:gap-8 md:grid-cols-3">
<ResourceCard
title="Gradle Tutorial"
description="Follow this step-by-step tutorial to add Nx to an existing Gradle project."
linkText="View tutorial"
href="/tutorials/gradle"
/>
<ResourceCard
title="Gradle Plugin Documentation"
description="Learn all the details about the Nx Gradle plugin configuration and usage."
linkText="View docs"
href="/packages/gradle/gradle-plugin"
/>
<ResourceCard
title="CI with Nx"
description="Learn how to configure Continuous Integration with Nx for faster builds."
linkText="View CI docs"
href="/ci/intro/ci-with-nx"
/>
</div>
</>
);
}
interface ResourceCardProps {
title: string;
description: string;
linkText: string;
href: string;
}
function ResourceCard({
title,
description,
linkText,
href,
}: ResourceCardProps): ReactElement {
return (
<div
className={cx(
'flex h-full flex-col justify-between rounded-lg border border-slate-200 bg-white p-6 shadow-sm transition-all hover:shadow-md dark:border-slate-800 dark:bg-slate-900'
)}
>
<div>
<h3 className="mb-2 text-lg font-medium">{title}</h3>
<p className="text-slate-500 dark:text-slate-400">{description}</p>
</div>
<div className="mt-6">
<ButtonLink href={href} size="small" variant="primary" title={linkText}>
{linkText}
</ButtonLink>
</div>
</div>
);
}

View File

@ -0,0 +1,17 @@
{
"compilerOptions": {
"jsx": "react-jsx",
"allowJs": false,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
}
],
"extends": "../../tsconfig.base.json"
}

View File

@ -0,0 +1,23 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"types": [
"node",
"@nx/react/typings/cssmodule.d.ts",
"@nx/react/typings/image.d.ts"
]
},
"exclude": [
"jest.config.ts",
"src/**/*.spec.ts",
"src/**/*.test.ts",
"src/**/*.spec.tsx",
"src/**/*.test.tsx",
"src/**/*.spec.js",
"src/**/*.test.js",
"src/**/*.spec.jsx",
"src/**/*.test.jsx"
],
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
}

View File

@ -117,6 +117,7 @@
"@nx/nx-dev/ui-powerpack": ["nx-dev/ui-powerpack/src/index.ts"], "@nx/nx-dev/ui-powerpack": ["nx-dev/ui-powerpack/src/index.ts"],
"@nx/nx-dev/ui-pricing": ["nx-dev/ui-pricing/src/index.ts"], "@nx/nx-dev/ui-pricing": ["nx-dev/ui-pricing/src/index.ts"],
"@nx/nx-dev/ui-primitives": ["nx-dev/ui-primitives/src/index.ts"], "@nx/nx-dev/ui-primitives": ["nx-dev/ui-primitives/src/index.ts"],
"@nx/nx-dev/ui-react": ["nx-dev/ui-react/src/index.ts"],
"@nx/nx-dev/ui-references": ["nx-dev/ui-references/src/index.ts"], "@nx/nx-dev/ui-references": ["nx-dev/ui-references/src/index.ts"],
"@nx/nx-dev/ui-remote-cache": ["nx-dev/ui-remote-cache/src/index.ts"], "@nx/nx-dev/ui-remote-cache": ["nx-dev/ui-remote-cache/src/index.ts"],
"@nx/nx-dev/ui-sponsor-card": ["nx-dev/ui-sponsor-card/src/index.ts"], "@nx/nx-dev/ui-sponsor-card": ["nx-dev/ui-sponsor-card/src/index.ts"],