feat(nx-dev): Migrate pricing page from nx.app (#27012)
Co-authored-by: Juri <juri.strumpflohner@gmail.com>
This commit is contained in:
parent
6fd9cf4d45
commit
a0ca85841f
66
nx-dev/nx-dev/app/pricing/page.tsx
Normal file
66
nx-dev/nx-dev/app/pricing/page.tsx
Normal file
@ -0,0 +1,66 @@
|
||||
import type { Metadata } from 'next';
|
||||
import {
|
||||
StandardPlans,
|
||||
ComparablePlans,
|
||||
Oss,
|
||||
Faq,
|
||||
} from '@nx/nx-dev/ui-pricing';
|
||||
import {
|
||||
Testimonials,
|
||||
TrustedBy,
|
||||
DefaultLayout,
|
||||
CallToAction,
|
||||
} from '@nx/nx-dev/ui-common';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Nx Cloud - Available Plans',
|
||||
description:
|
||||
"Distribute everything, don't waste time waiting on CI. Use Nx Cloud's distributed task execution and caching features to release faster. Save time and money.",
|
||||
openGraph: {
|
||||
url: 'https://nx.dev/pricing',
|
||||
title: 'Nx Cloud - Available Plans',
|
||||
description:
|
||||
"Distribute everything, don't waste time waiting on CI. Use Nx Cloud's distributed task execution and caching features to release faster. Save time and money.",
|
||||
images: [
|
||||
{
|
||||
url: 'https://nx.dev/socials/nx-media.png',
|
||||
width: 800,
|
||||
height: 421,
|
||||
alt: 'Nx: Smart Monorepos · Fast CI',
|
||||
type: 'image/jpeg',
|
||||
},
|
||||
],
|
||||
siteName: 'NxDev',
|
||||
type: 'website',
|
||||
},
|
||||
};
|
||||
|
||||
export default function PricingPage() {
|
||||
return (
|
||||
<DefaultLayout>
|
||||
<StandardPlans />
|
||||
<div className="mt-18 lg:mt-32">
|
||||
<TrustedBy utmSource="pricingpage" utmCampaign="pricing" />
|
||||
</div>
|
||||
<div className="mt-32 lg:mt-56">
|
||||
<ComparablePlans />
|
||||
</div>
|
||||
<div className="mt-32 lg:mt-56">
|
||||
<Testimonials />
|
||||
</div>
|
||||
<div className="mt-32 lg:mt-56">
|
||||
<Oss />
|
||||
</div>
|
||||
<div className="mt-32 lg:mt-56">
|
||||
<Faq />
|
||||
</div>
|
||||
<div className="mt-32 lg:mt-56">
|
||||
<CallToAction
|
||||
mainActionLinkText="Sign up"
|
||||
mainActionLink="https://cloud.nx.app?utm_source=nx.dev&utm_medium=cta&utm_campaign=pricing"
|
||||
mainActionTitle="Sign up to Nx Cloud"
|
||||
/>
|
||||
</div>
|
||||
</DefaultLayout>
|
||||
);
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
import { CallToAction, DefaultLayout } from '@nx/nx-dev/ui-common';
|
||||
import { CallToAction, DefaultLayout, TrustedBy } from '@nx/nx-dev/ui-common';
|
||||
import { NextSeo } from 'next-seo';
|
||||
import {
|
||||
CiForMonorepos,
|
||||
@ -6,7 +6,6 @@ import {
|
||||
SmarterToolsForMonorepos,
|
||||
Statistics,
|
||||
TeamAndCommunity,
|
||||
TrustedBy,
|
||||
WorkBetterAchieveMoreShipQuicker,
|
||||
} from '@nx/nx-dev/ui-home';
|
||||
|
||||
|
||||
@ -485,6 +485,7 @@ const nxCloudUrls = {
|
||||
'/core-features/:path*': '/features/:path*',
|
||||
'/ci/recipes/set-up/connect-to-cloud': '/ci/intro/connect-to-nx-cloud',
|
||||
'/ci/intro/connect-to-cloud': '/ci/intro/connect-to-nx-cloud',
|
||||
'/pricing/special-offer': 'https://forms.gle/FBzvsspz1o63fDAz6',
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -19,6 +19,8 @@ export * from './lib/github-star-widget';
|
||||
export * from './lib/youtube.component';
|
||||
export * from './lib/x-icon';
|
||||
export * from './lib/discord-icon';
|
||||
export * from './lib/trusted-by';
|
||||
export * from './lib/testimonials';
|
||||
|
||||
export { resourceMenuItems } from './lib/headers/menu-items';
|
||||
export { solutionsMenuItems } from './lib/headers/menu-items';
|
||||
|
||||
@ -1,6 +1,16 @@
|
||||
import Link from 'next/link';
|
||||
|
||||
export function CallToAction(): JSX.Element {
|
||||
export interface CTAProps {
|
||||
mainActionLinkText?: string;
|
||||
mainActionTitle?: string;
|
||||
mainActionLink?: string;
|
||||
}
|
||||
|
||||
export function CallToAction({
|
||||
mainActionTitle = 'Get started with Nx',
|
||||
mainActionLinkText = 'Get started',
|
||||
mainActionLink = '/docs',
|
||||
}: CTAProps): JSX.Element {
|
||||
return (
|
||||
<section className="relative isolate px-6 py-32 sm:py-40 lg:px-8">
|
||||
<svg
|
||||
@ -59,12 +69,12 @@ export function CallToAction(): JSX.Element {
|
||||
</h2>
|
||||
<div className="mt-10 flex items-center justify-center gap-x-6">
|
||||
<Link
|
||||
href="/getting-started/intro"
|
||||
title="Get started with Nx"
|
||||
href={mainActionLink}
|
||||
title={mainActionTitle}
|
||||
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"
|
||||
>
|
||||
Get started
|
||||
{mainActionLinkText}
|
||||
</Link>
|
||||
<Link
|
||||
href="/contact"
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
'use client';
|
||||
import { Fragment, type JSX } from 'react';
|
||||
import {
|
||||
ArrowUpRightIcon,
|
||||
Bars3Icon,
|
||||
ChevronDownIcon,
|
||||
XMarkIcon,
|
||||
@ -334,15 +333,14 @@ export function DocumentationHeader({
|
||||
>
|
||||
Blog
|
||||
</Link>
|
||||
<a
|
||||
href="https://nx.app/pricing"
|
||||
<Link
|
||||
href="/pricing"
|
||||
title="Nx Cloud"
|
||||
target="_blank"
|
||||
className="hidden gap-2 px-3 py-2 font-medium leading-tight hover:text-blue-500 md:inline-flex dark:text-slate-200 dark:hover:text-sky-500"
|
||||
prefetch={false}
|
||||
>
|
||||
CI Pricing
|
||||
<ArrowUpRightIcon className="h-2 w-2 align-super" />
|
||||
</a>
|
||||
</Link>
|
||||
{/*RESOURCES*/}
|
||||
<Popover className="relative">
|
||||
{({ open }) => (
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
'use client';
|
||||
import { Dialog, Disclosure, Popover, Transition } from '@headlessui/react';
|
||||
import {
|
||||
ArrowUpRightIcon,
|
||||
Bars4Icon,
|
||||
ChevronDownIcon,
|
||||
XMarkIcon,
|
||||
@ -175,15 +174,14 @@ export function Header(): JSX.Element {
|
||||
>
|
||||
Blog
|
||||
</Link>
|
||||
<a
|
||||
href="https://nx.app/pricing"
|
||||
<Link
|
||||
href="/pricing"
|
||||
title="Nx Cloud"
|
||||
target="_blank"
|
||||
className="hidden gap-2 px-3 py-2 font-medium leading-tight hover:text-blue-500 md:inline-flex dark:text-slate-200 dark:hover:text-sky-500"
|
||||
prefetch={false}
|
||||
>
|
||||
CI Pricing
|
||||
<ArrowUpRightIcon className="h-2 w-2 align-super" />
|
||||
</a>
|
||||
</Link>
|
||||
{/*RESOURCES*/}
|
||||
<Popover className="relative">
|
||||
{({ open }) => (
|
||||
@ -459,15 +457,14 @@ export function Header(): JSX.Element {
|
||||
>
|
||||
Blog
|
||||
</Link>
|
||||
<a
|
||||
href="https://nx.app/pricing"
|
||||
<Link
|
||||
href="/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"
|
||||
prefetch={false}
|
||||
>
|
||||
CI Pricing
|
||||
<ArrowUpRightIcon className="h-2 w-2 align-super" />
|
||||
</a>
|
||||
</Link>
|
||||
{/*RESOURCES*/}
|
||||
<Disclosure as="div">
|
||||
{({ open }) => (
|
||||
|
||||
58
nx-dev/ui-common/src/lib/testimonials.tsx
Normal file
58
nx-dev/ui-common/src/lib/testimonials.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
import { ChatBubbleLeftEllipsisIcon } from '@heroicons/react/24/outline';
|
||||
import { SectionHeading } from './typography';
|
||||
|
||||
export function Testimonials(): JSX.Element {
|
||||
return (
|
||||
<section id="people-are-talking" className="relative">
|
||||
<header className="mx-auto max-w-2xl text-center">
|
||||
<SectionHeading as="h2" variant="title">
|
||||
People are talking
|
||||
</SectionHeading>
|
||||
<SectionHeading as="p" variant="subtitle" className="mt-6">
|
||||
Whether your workspace{' '}
|
||||
<span className="font-semibold">
|
||||
has a single project or thousands
|
||||
</span>
|
||||
, Nx will keep your CI fast and your workspace maintainable.
|
||||
</SectionHeading>
|
||||
</header>
|
||||
<div className="md:px-62 mx-auto grid max-w-7xl grid-cols-1 items-stretch gap-8 px-4 py-12 md:grid-cols-3 lg:px-8 lg:py-16">
|
||||
<div className="rounded-xl bg-slate-50 p-10 dark:bg-slate-800/60">
|
||||
<ChatBubbleLeftEllipsisIcon className="h-8 w-8 text-blue-500 dark:text-sky-500" />
|
||||
<p className="mt-4">
|
||||
"It made it possible to remove our hand-rolled code and to use a
|
||||
well-maintained and streamlined solution, increasing performance
|
||||
while saving us a lot of time and money. The developer experience is
|
||||
so good."
|
||||
</p>
|
||||
<div className="mt-8 font-semibold">Nitin Vericherla</div>
|
||||
<div className="mt-0.5 text-sm">UI Architect at Synapse Wireless</div>
|
||||
</div>
|
||||
<div className="rounded-xl bg-slate-50 p-10 dark:bg-slate-800/60">
|
||||
<ChatBubbleLeftEllipsisIcon className="h-8 w-8 text-blue-500 dark:text-sky-500" />
|
||||
<p className="mt-4">
|
||||
"By updating to the latest Lerna version and enabling Nx caching, we
|
||||
were able to reduce CI build times by ~35% - a great time saving for
|
||||
a fast-moving company like Sentry with an extremely active
|
||||
repository."
|
||||
</p>
|
||||
<div className="mt-8 font-semibold">Francesco Novy</div>
|
||||
<div className="mt-0.5 text-sm">
|
||||
Senior Software Engineer at Sentry
|
||||
</div>
|
||||
</div>
|
||||
<div className="rounded-xl bg-slate-50 p-10 dark:bg-slate-800/60">
|
||||
<ChatBubbleLeftEllipsisIcon className="h-8 w-8 text-blue-500 dark:text-sky-500" />
|
||||
<p className="mt-4">
|
||||
"Since we are using NxCloud, we saw our CI times reduced by 83%!
|
||||
That means our teams are not waiting hours for their PR to be merged
|
||||
anymore, we reclaimed our productivity and are pretty happy about
|
||||
it."
|
||||
</p>
|
||||
<div className="mt-8 font-semibold">Laurent Delamare</div>
|
||||
<div className="mt-0.5 text-sm">Senior Engineer at VMware</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
import Link from 'next/link';
|
||||
import { SectionDescription, SectionHeading } from '@nx/nx-dev/ui-common';
|
||||
import { SectionDescription, SectionHeading } from './typography';
|
||||
import {
|
||||
AdobeIcon,
|
||||
AwsIcon,
|
||||
@ -19,7 +19,15 @@ import {
|
||||
VmwareIcon,
|
||||
} from '@nx/nx-dev/ui-icons';
|
||||
|
||||
export function TrustedBy(): JSX.Element {
|
||||
export interface TrustedByProps {
|
||||
utmSource?: string;
|
||||
utmCampaign?: string;
|
||||
}
|
||||
|
||||
export function TrustedBy({
|
||||
utmSource = 'homepage',
|
||||
utmCampaign = 'homepage_links',
|
||||
}: TrustedByProps): JSX.Element {
|
||||
return (
|
||||
<article className="mx-auto max-w-7xl px-6 lg:px-8">
|
||||
<div className="text-center">
|
||||
@ -104,9 +112,10 @@ export function TrustedBy(): JSX.Element {
|
||||
className="h-10 w-10 text-slate-950 dark:text-white"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-8 text-center">
|
||||
<Link
|
||||
href="/customers?utm_source=homepage&utm_medium=website&utm_campaign=homepage_links&utm_content=our_customers"
|
||||
href={`/customers?utm_source=${utmSource}&utm_medium=website&utm_campaign=${utmCampaign}&utm_content=our_customers`}
|
||||
title="Our customers"
|
||||
prefetch={false}
|
||||
className="group font-semibold leading-6 text-slate-950 transition-all duration-200 dark:text-white"
|
||||
@ -3,5 +3,4 @@ export * from './lib/hero';
|
||||
export * from './lib/smarter-tools-for-monorepos';
|
||||
export * from './lib/statistics';
|
||||
export * from './lib/team-and-community';
|
||||
export * from './lib/trusted-by';
|
||||
export * from './lib/work-better-achieve-more-ship-quicker';
|
||||
|
||||
12
nx-dev/ui-pricing/.babelrc
Normal file
12
nx-dev/ui-pricing/.babelrc
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@nx/react/babel",
|
||||
{
|
||||
"runtime": "automatic",
|
||||
"useBuiltIns": "usage"
|
||||
}
|
||||
]
|
||||
],
|
||||
"plugins": []
|
||||
}
|
||||
18
nx-dev/ui-pricing/.eslintrc.json
Normal file
18
nx-dev/ui-pricing/.eslintrc.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"extends": ["plugin:@nx/react", "../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
7
nx-dev/ui-pricing/README.md
Normal file
7
nx-dev/ui-pricing/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# ui-pricing
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `nx test ui-pricing` to execute the unit tests via [Jest](https://jestjs.io).
|
||||
9
nx-dev/ui-pricing/project.json
Normal file
9
nx-dev/ui-pricing/project.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "ui-pricing",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "nx-dev/ui-pricing/src",
|
||||
"projectType": "library",
|
||||
"tags": [],
|
||||
"// targets": "to see all targets run: nx show project ui-pricing --web",
|
||||
"targets": {}
|
||||
}
|
||||
4
nx-dev/ui-pricing/src/index.ts
Normal file
4
nx-dev/ui-pricing/src/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './lib/comparable-plans';
|
||||
export * from './lib/faq';
|
||||
export * from './lib/oss';
|
||||
export * from './lib/standard-plans';
|
||||
40
nx-dev/ui-pricing/src/lib/comparable-plans.tsx
Normal file
40
nx-dev/ui-pricing/src/lib/comparable-plans.tsx
Normal file
@ -0,0 +1,40 @@
|
||||
import { ButtonLink, SectionHeading } from '@nx/nx-dev/ui-common';
|
||||
import { PlanTable } from './plans/plan-table';
|
||||
|
||||
export function ComparablePlans() {
|
||||
return (
|
||||
<section
|
||||
id="plan-details"
|
||||
className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8"
|
||||
>
|
||||
<header>
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<SectionHeading as="h2" variant="title">
|
||||
Plans in detail
|
||||
</SectionHeading>
|
||||
<SectionHeading as="p" variant="subtitle" className="mt-6">
|
||||
Compare plan options and benefits.
|
||||
</SectionHeading>
|
||||
</div>
|
||||
</header>
|
||||
<div className="isolate mx-auto mt-10 max-w-full sm:mt-20">
|
||||
<PlanTable />
|
||||
<p className="mt-2 text-sm opacity-80">
|
||||
Credits are the Nx Cloud currency allowing for usage-based pricing.
|
||||
Prices do not include applicable taxes.
|
||||
</p>
|
||||
<div className="mt-4 flex justify-center">
|
||||
<ButtonLink
|
||||
href="https://cloud.nx.app"
|
||||
aria-describedby="hobby-plan"
|
||||
title="Hobby"
|
||||
size="default"
|
||||
className="my-2"
|
||||
>
|
||||
Get started now for free
|
||||
</ButtonLink>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
150
nx-dev/ui-pricing/src/lib/faq.tsx
Normal file
150
nx-dev/ui-pricing/src/lib/faq.tsx
Normal file
@ -0,0 +1,150 @@
|
||||
'use client';
|
||||
import { Disclosure, Transition } from '@headlessui/react';
|
||||
import { ChevronDownIcon } from '@heroicons/react/24/outline';
|
||||
import { SectionHeading } from '@nx/nx-dev/ui-common';
|
||||
import { cx } from '@nx/nx-dev/ui-primitives';
|
||||
import { FAQPageJsonLd } from 'next-seo';
|
||||
|
||||
export function Faq(): JSX.Element {
|
||||
const faqs = [
|
||||
{
|
||||
question: 'What are credits?',
|
||||
answer:
|
||||
'Credits are the currency of Nx Cloud. A determined number of credits are included in each plan. These credits are used to pay for Nx Cloud platform usage in real time.',
|
||||
},
|
||||
{
|
||||
question: 'Do credits expire?',
|
||||
answer:
|
||||
'Credits expire at the end of the billing cycle and do not roll over.',
|
||||
},
|
||||
{
|
||||
question: 'When does the billing cycle start and end?',
|
||||
answer:
|
||||
'A new billing cycle starts on the first day of every month. If you go over the Hobby plan limit during a cycle your organization will be disabled. You will have to upgrade to our Pro plan or wait for the next billing cycle.',
|
||||
},
|
||||
{
|
||||
question: 'What is a CI Pipeline Execution (CIPE)?',
|
||||
answer:
|
||||
'By default, a CI pipeline execution is a 1:1 match to your CI provider of choice\'s concept of a "workflow".',
|
||||
},
|
||||
{
|
||||
question: 'What is the concurrency connections limit?',
|
||||
answer:
|
||||
'As you scale your usage of Nx Cloud, you may run into concurrency limits. Nx Cloud puts a limit on the number of CI machines in your workspace that are simultaneously connecting to Nx Cloud. This includes any machine running in CI - both the main CI pipeline machine and any agent machines.',
|
||||
},
|
||||
{
|
||||
question: 'What is a contributor?',
|
||||
answer:
|
||||
"A contributor is a person who has committed to your repository. Your organization's contributor count is calculated from anonymized, monthly git histories across all the workspaces in your Nx Cloud organization.",
|
||||
},
|
||||
{
|
||||
question: "What if I exceed my plan's contributor limit?",
|
||||
answer:
|
||||
'If you exceed the contributor limit, your organization will be disabled until you upgrade to a plan that supports the number of contributors you have.',
|
||||
},
|
||||
{
|
||||
question:
|
||||
'What happens if I consume all my credits while on the Hobby plan?',
|
||||
answer:
|
||||
'The Hobby plan allows you to configure and run a small project at no cost. If you consume all the credits, your organization will be disabled until you upgrade to Pro or wait for the next billing cycle.',
|
||||
},
|
||||
{
|
||||
question: 'Can I upgrade my Hobby plan to the Pro plan?',
|
||||
answer:
|
||||
'Yes, you can upgrade your Hobby plan to the Pro plan at any time.',
|
||||
},
|
||||
{
|
||||
question: 'Is there a plan for open source projects?',
|
||||
answer:
|
||||
'Yes, we are happy to collaborate with open source projects. Please complete this form, and we will review your request and get back to you: https://nx.app/pricing/special-offer',
|
||||
},
|
||||
{
|
||||
question: 'What payment methods do you accept?',
|
||||
answer:
|
||||
'We accept Visa, Mastercard, American Express, and Discover from customers worldwide.',
|
||||
},
|
||||
{
|
||||
question: 'Do I need a credit card to create an account?',
|
||||
answer:
|
||||
'No, you can set up a workspace with Nx Cloud completely for free, without entering any billing information.',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<section id="faq">
|
||||
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
<div className="lg:grid lg:grid-cols-3 lg:gap-8">
|
||||
<header>
|
||||
<SectionHeading as="h2" variant="title">
|
||||
Not sure yet? <br /> Have questions?
|
||||
</SectionHeading>
|
||||
<SectionHeading as="p" variant="subtitle" className="mt-6">
|
||||
Here are the most asked question we condensed for your to get you
|
||||
setup quickly.
|
||||
</SectionHeading>
|
||||
|
||||
<p className="text-md mt-4 text-slate-400 dark:text-slate-600">
|
||||
Can’t find the answer you’re looking for? Reach out to our{' '}
|
||||
<a
|
||||
href="mailto:cloud-support@nrwl.io"
|
||||
className="font-medium underline"
|
||||
>
|
||||
customer support
|
||||
</a>{' '}
|
||||
team.
|
||||
</p>
|
||||
</header>
|
||||
<FAQPageJsonLd
|
||||
useAppDir={true}
|
||||
mainEntity={faqs.map((faq) => ({
|
||||
questionName: faq.question,
|
||||
acceptedAnswerText: faq.answer,
|
||||
}))}
|
||||
/>
|
||||
<div className="mt-12 lg:col-span-2 lg:mt-0">
|
||||
<dl className="mt-6 space-y-6 divide-y divide-slate-100 dark:divide-slate-800">
|
||||
{faqs.map((faq) => (
|
||||
<Disclosure as="div" key={faq.question} className="pt-6">
|
||||
{({ open }) => (
|
||||
<>
|
||||
<dt className="text-lg">
|
||||
<Disclosure.Button className="flex w-full items-start justify-between text-left text-slate-400">
|
||||
<span className="font-medium text-slate-800 dark:text-slate-300">
|
||||
{faq.question}
|
||||
</span>
|
||||
<span className="ml-6 flex h-7 items-center">
|
||||
<ChevronDownIcon
|
||||
className={cx(
|
||||
open ? '-rotate-180' : 'rotate-0',
|
||||
'h-6 w-6 transform transition-transform'
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</span>
|
||||
</Disclosure.Button>
|
||||
</dt>
|
||||
<Transition
|
||||
enter="transition duration-100 ease-out"
|
||||
enterFrom="transform -translate-y-6 opacity-0"
|
||||
enterTo="transform translate-y-0 opacity-100"
|
||||
leave="transition duration-75 ease-out"
|
||||
leaveFrom="transform translate-y-0 opacity-100"
|
||||
leaveTo="transform -translate-y-6 opacity-0"
|
||||
>
|
||||
<Disclosure.Panel as="dd" className="mt-2 pr-12">
|
||||
<p className="text-base text-slate-500 dark:text-slate-400">
|
||||
{faq.answer}
|
||||
</p>
|
||||
</Disclosure.Panel>
|
||||
</Transition>
|
||||
</>
|
||||
)}
|
||||
</Disclosure>
|
||||
))}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
52
nx-dev/ui-pricing/src/lib/oss.tsx
Normal file
52
nx-dev/ui-pricing/src/lib/oss.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
import { CheckIcon } from '@heroicons/react/24/outline';
|
||||
import { ButtonLink } from '@nx/nx-dev/ui-common';
|
||||
|
||||
export function Oss(): JSX.Element {
|
||||
return (
|
||||
<section
|
||||
id="oss"
|
||||
className="bg-blue-500 bg-gradient-to-r from-blue-500 to-cyan-500 shadow-inner"
|
||||
>
|
||||
<div className="px-6 py-24 sm:px-6 sm:py-32 lg:px-8">
|
||||
<div className="mx-auto max-w-2xl text-center">
|
||||
<h2 className="text-3xl font-bold tracking-tight text-white sm:text-4xl">
|
||||
Open Source maintainers and authors?
|
||||
</h2>
|
||||
<p className="mx-auto mt-6 max-w-xl text-lg leading-8 text-slate-100">
|
||||
We provide a <span className="font-black">$0 /month</span> plan for
|
||||
open-source projects.
|
||||
</p>
|
||||
<div className="mt-8 flex items-center justify-center">
|
||||
<ButtonLink
|
||||
href="/pricing/special-offer"
|
||||
aria-describedby="oss"
|
||||
title="Free for Open Source"
|
||||
size="default"
|
||||
variant="secondary"
|
||||
>
|
||||
Apply for free access
|
||||
</ButtonLink>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mx-auto mt-8 flex max-w-4xl flex-col gap-8 text-sm text-white md:flex-row md:justify-between">
|
||||
<div className="flex items-center gap-1">
|
||||
<CheckIcon className="h-6 w-5 flex-none" aria-hidden="true" /> Free
|
||||
credits every month
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
<CheckIcon className="h-6 w-5 flex-none" aria-hidden="true" />
|
||||
Max 3 admin users
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
<CheckIcon className="h-6 w-5 flex-none" aria-hidden="true" />{' '}
|
||||
Powerful analytics
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
<CheckIcon className="h-6 w-5 flex-none" aria-hidden="true" /> Basic
|
||||
support
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
70
nx-dev/ui-pricing/src/lib/plans/enterprise-plan.tsx
Normal file
70
nx-dev/ui-pricing/src/lib/plans/enterprise-plan.tsx
Normal file
@ -0,0 +1,70 @@
|
||||
import { CheckIcon } from '@heroicons/react/24/outline';
|
||||
import { ButtonLink } from '@nx/nx-dev/ui-common';
|
||||
|
||||
const features = [
|
||||
'White glove onboarding',
|
||||
'Work hand-in-hand with the Nx team for continual improvement',
|
||||
'Run on the Nx Cloud servers in any region or run fully self-contained, on-prem',
|
||||
'Premium Support and SLAs available',
|
||||
'SSO / SAML Login',
|
||||
];
|
||||
|
||||
export function EnterprisePlan({
|
||||
cta = 'Learn more',
|
||||
url,
|
||||
}: {
|
||||
cta?: string;
|
||||
url: string;
|
||||
}) {
|
||||
return (
|
||||
<article className="relative rounded-b-xl bg-slate-50/60 py-4 ring-1 ring-slate-200 xl:py-6 dark:bg-slate-800/60 dark:ring-slate-800">
|
||||
<h4
|
||||
id="on-prem"
|
||||
className="absolute -top-9 left-0 w-full rounded-t-xl bg-gradient-to-r from-fuchsia-500 to-violet-500 p-2 text-center text-sm font-medium text-white shadow-inner ring-1 ring-slate-200 dark:ring-slate-800"
|
||||
>
|
||||
Available as an on-prem solution
|
||||
</h4>
|
||||
<header className="flex items-center justify-between gap-x-4 px-4 xl:px-6">
|
||||
<h3
|
||||
id="enterprise-plan"
|
||||
className="text-xl font-semibold leading-8 text-slate-900 dark:text-slate-100"
|
||||
>
|
||||
Enterprise
|
||||
</h3>
|
||||
</header>
|
||||
<p className="mt-4 h-12 px-4 text-sm leading-6 xl:px-6">
|
||||
The ultimate Nx toolchain, tailored to your needs of speed.
|
||||
</p>
|
||||
<p className="mt-12 flex items-baseline gap-x-1"> </p>
|
||||
<div className="p-4 xl:p-6">
|
||||
<ButtonLink
|
||||
href={url}
|
||||
aria-describedby="enterprise-plan"
|
||||
title="Enterprise"
|
||||
size="default"
|
||||
variant="secondary"
|
||||
className="w-full"
|
||||
>
|
||||
{cta}
|
||||
</ButtonLink>
|
||||
</div>
|
||||
<p className="border-b border-t border-slate-100 bg-green-50 px-4 py-2 text-sm font-medium text-green-700 xl:px-6 dark:border-slate-800 dark:bg-green-500/10 dark:text-green-400">
|
||||
Volume discounts on credits available.
|
||||
</p>
|
||||
<ul className="space-y-3 px-4 py-6 text-sm leading-6 text-slate-500 xl:px-6 dark:text-slate-400">
|
||||
<li className="text-base font-medium text-slate-700 dark:text-slate-300">
|
||||
The complete Nx toolchain tailored to your needs:
|
||||
</li>
|
||||
{features.map((feature) => (
|
||||
<li key={feature} className="flex gap-x-3">
|
||||
<CheckIcon
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-600"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
{feature}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</article>
|
||||
);
|
||||
}
|
||||
127
nx-dev/ui-pricing/src/lib/plans/hobby-plan.tsx
Normal file
127
nx-dev/ui-pricing/src/lib/plans/hobby-plan.tsx
Normal file
@ -0,0 +1,127 @@
|
||||
import { CheckIcon } from '@heroicons/react/24/outline';
|
||||
import { ButtonLink } from '@nx/nx-dev/ui-common';
|
||||
import Link from 'next/link';
|
||||
|
||||
const features = [
|
||||
'50k credits included',
|
||||
'Max 5 contributors',
|
||||
'Distributed Task Execution (DTE)',
|
||||
'Nx run detailed reports',
|
||||
'Structured log visualization',
|
||||
'GitHub PR with Nx Cloud live status',
|
||||
'Unlimited users per workspace',
|
||||
'Basic support',
|
||||
];
|
||||
|
||||
export function HobbyPlan({
|
||||
cta = 'Get started now',
|
||||
url,
|
||||
}: {
|
||||
cta?: string;
|
||||
url: string;
|
||||
}) {
|
||||
return (
|
||||
<article className="relative rounded-b-xl py-4 ring-1 ring-blue-500 xl:py-6 dark:ring-sky-500">
|
||||
<h4
|
||||
id="no-credit-card-required"
|
||||
className="absolute -top-9 left-0 w-full rounded-t-2xl bg-blue-500 p-2 text-center text-sm font-medium text-white shadow-inner ring-1 ring-blue-500 dark:bg-sky-500 dark:ring-sky-500"
|
||||
>
|
||||
Start here
|
||||
</h4>
|
||||
<header className="flex items-center justify-between gap-x-4 px-4 xl:px-6">
|
||||
<h3
|
||||
id="hobby-plan"
|
||||
className="text-xl font-semibold leading-8 text-slate-900 dark:text-slate-100"
|
||||
>
|
||||
Hobby
|
||||
</h3>
|
||||
</header>
|
||||
<p className="mt-4 h-12 px-4 text-sm leading-6 xl:px-6">
|
||||
Get started quickly, upgrade when ready.
|
||||
</p>
|
||||
<p className="mt-8 flex items-baseline gap-x-1 px-4 xl:px-6">
|
||||
<span className="text-4xl font-bold tracking-tight text-slate-900 dark:text-slate-100">
|
||||
$0
|
||||
</span>
|
||||
<span className="text-base font-normal leading-6">/month</span>
|
||||
</p>
|
||||
<div className="p-4 xl:p-6">
|
||||
<ButtonLink
|
||||
href={url}
|
||||
aria-describedby="hobby-plan"
|
||||
title="Hobby"
|
||||
size="default"
|
||||
className="w-full"
|
||||
>
|
||||
{cta}
|
||||
</ButtonLink>
|
||||
</div>
|
||||
<p className="border-b border-t border-slate-100 bg-green-50 px-4 py-2 text-sm font-medium text-green-700 xl:px-6 dark:border-slate-800 dark:bg-green-500/10 dark:text-green-400">
|
||||
No credit card required.
|
||||
</p>
|
||||
<ul className="space-y-3 px-4 py-8 text-sm leading-6 text-slate-500 xl:px-6 dark:text-slate-400">
|
||||
<li className="flex gap-x-3">
|
||||
<CheckIcon
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-600"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<p>
|
||||
<Link
|
||||
href="/products/replay#content"
|
||||
title="Learn more about Nx Replay"
|
||||
prefetch={false}
|
||||
className="font-medium text-slate-700 underline dark:text-slate-300"
|
||||
>
|
||||
Nx Replay
|
||||
</Link>
|
||||
: remote caching{' '}
|
||||
</p>
|
||||
</li>
|
||||
<li className="flex gap-x-3">
|
||||
<CheckIcon
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-600"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<p>
|
||||
<Link
|
||||
href="/products/agents#content"
|
||||
title="Learn more about Nx Agents"
|
||||
prefetch={false}
|
||||
className="font-medium text-slate-700 underline dark:text-slate-300"
|
||||
>
|
||||
Nx Agents
|
||||
</Link>
|
||||
: native task distribution solution for CI{' '}
|
||||
</p>
|
||||
</li>
|
||||
<li className="flex gap-x-3">
|
||||
<CheckIcon
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-600"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<p>
|
||||
<Link
|
||||
href="https://nx.app/products/workflows#content?utm_source=nx.dev"
|
||||
title="Learn more about Nx Workflows"
|
||||
prefetch={false}
|
||||
className="font-medium text-slate-700 underline dark:text-slate-300"
|
||||
>
|
||||
Nx Workflows
|
||||
</Link>
|
||||
: full CI replacement{' '}
|
||||
<span className="text-xs italic">(Coming Soon)</span>
|
||||
</p>
|
||||
</li>
|
||||
{features.map((feature) => (
|
||||
<li key={feature} className="flex gap-x-3">
|
||||
<CheckIcon
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-600"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
{feature}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</article>
|
||||
);
|
||||
}
|
||||
1203
nx-dev/ui-pricing/src/lib/plans/plan-table.tsx
Normal file
1203
nx-dev/ui-pricing/src/lib/plans/plan-table.tsx
Normal file
File diff suppressed because it is too large
Load Diff
99
nx-dev/ui-pricing/src/lib/plans/pro-plan.tsx
Normal file
99
nx-dev/ui-pricing/src/lib/plans/pro-plan.tsx
Normal file
@ -0,0 +1,99 @@
|
||||
'use client';
|
||||
import { Popover, Transition } from '@headlessui/react';
|
||||
import { CheckIcon, InformationCircleIcon } from '@heroicons/react/24/outline';
|
||||
import { ButtonLink } from '@nx/nx-dev/ui-common';
|
||||
import { Fragment } from 'react';
|
||||
|
||||
const features = [
|
||||
'300k credits included',
|
||||
'Max 1m runs per month',
|
||||
'Max 70 concurrent CI connections',
|
||||
'Max 70 contributors',
|
||||
'Unlimited private workspaces per organization',
|
||||
'High-priority support',
|
||||
];
|
||||
|
||||
export function ProPlan({
|
||||
cta = 'Get started now',
|
||||
url,
|
||||
}: {
|
||||
cta?: string;
|
||||
url: string;
|
||||
}) {
|
||||
return (
|
||||
<article className="rounded-xl py-4 ring-1 ring-slate-200 xl:py-6 dark:ring-slate-800">
|
||||
<header className="flex items-center justify-between gap-x-4">
|
||||
<h3
|
||||
id="pro-plan"
|
||||
className="px-4 text-xl font-semibold leading-8 text-slate-900 xl:px-6 dark:text-slate-100"
|
||||
>
|
||||
Pro
|
||||
</h3>
|
||||
</header>
|
||||
<p className="mt-4 h-12 px-4 text-sm leading-6 xl:px-6">
|
||||
Scales with your needs.
|
||||
</p>
|
||||
<p className="mt-8 flex items-baseline gap-x-1 px-4 xl:px-6">
|
||||
<span className="text-4xl font-bold tracking-tight text-slate-900 dark:text-slate-100">
|
||||
$249
|
||||
</span>
|
||||
<span className="text-base font-normal leading-6">/month</span>
|
||||
</p>
|
||||
<div className="p-4 xl:p-6">
|
||||
<ButtonLink
|
||||
href={url}
|
||||
aria-describedby="pro-plan"
|
||||
title="Pro plan"
|
||||
size="default"
|
||||
variant="secondary"
|
||||
className="w-full"
|
||||
>
|
||||
{cta}
|
||||
</ButtonLink>
|
||||
</div>
|
||||
<Popover className="relative">
|
||||
<Popover.Button
|
||||
as="ul"
|
||||
className="cursor-pointer list-inside list-disc border-b border-t border-slate-100 bg-green-50 px-4 py-2 text-sm font-medium text-green-700 dark:border-slate-800 dark:bg-green-500/10 dark:text-green-400"
|
||||
>
|
||||
<li>14-day free trial</li>
|
||||
<li>
|
||||
No credit card required{' '}
|
||||
<InformationCircleIcon className="inline h-4 w-4 align-top" />
|
||||
</li>
|
||||
</Popover.Button>
|
||||
|
||||
<Transition
|
||||
as={Fragment}
|
||||
enter="transition ease-out duration-300"
|
||||
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-2 w-96 overflow-hidden rounded-md border border-slate-200 bg-white p-4 text-sm shadow dark:border-slate-800 dark:bg-slate-800">
|
||||
<p>
|
||||
Your organization will be deactivated upon reaching any Pro plan
|
||||
limit unless a credit card is set up in your account.
|
||||
</p>
|
||||
</Popover.Panel>
|
||||
</Transition>
|
||||
</Popover>
|
||||
<ul className="space-y-3 px-4 py-6 text-sm leading-6 text-slate-500 xl:px-6 dark:text-slate-400">
|
||||
<li className="text-base font-medium text-slate-700 dark:text-slate-300">
|
||||
Everything from the Hobby plan plus:
|
||||
</li>
|
||||
{features.map((feature) => (
|
||||
<li key={feature} className="flex gap-x-3">
|
||||
<CheckIcon
|
||||
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-600"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
{feature}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</article>
|
||||
);
|
||||
}
|
||||
56
nx-dev/ui-pricing/src/lib/standard-plans.tsx
Normal file
56
nx-dev/ui-pricing/src/lib/standard-plans.tsx
Normal file
@ -0,0 +1,56 @@
|
||||
import { ButtonLink, SectionHeading } from '@nx/nx-dev/ui-common';
|
||||
|
||||
import { EnterprisePlan } from './plans/enterprise-plan';
|
||||
import { HobbyPlan } from './plans/hobby-plan';
|
||||
import { ProPlan } from './plans/pro-plan';
|
||||
|
||||
export function StandardPlans() {
|
||||
return (
|
||||
<section className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
<header className="mx-auto max-w-4xl text-center">
|
||||
<SectionHeading as="h2" variant="display">
|
||||
Start with everything,
|
||||
<br /> scale when you need
|
||||
</SectionHeading>
|
||||
<SectionHeading as="p" variant="subtitle" className="mt-6">
|
||||
Level up your CI with Nx Cloud
|
||||
</SectionHeading>
|
||||
</header>
|
||||
|
||||
<div className="relative mt-32 w-full" />
|
||||
{/* Plans */}
|
||||
<section id="plans">
|
||||
{/* <header>
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<SectionHeading as="h2" variant="title">
|
||||
Start Free, Scale Smart
|
||||
</SectionHeading>
|
||||
<SectionHeading as="p" variant="subtitle" className="mt-6">
|
||||
Kick off with complimentary credits and explore everything Nx
|
||||
Cloud offers. Add your card details when you're ready for more.
|
||||
</SectionHeading>
|
||||
</div>
|
||||
</header> */}
|
||||
<div className="isolate mx-auto mt-10 grid max-w-lg grid-cols-1 items-stretch gap-x-4 gap-y-16 sm:mt-20 md:max-w-3xl md:grid-cols-3 xl:max-w-full xl:grid-cols-3">
|
||||
<HobbyPlan url="https://cloud.nx.app" />
|
||||
<ProPlan url="https://cloud.nx.app" />
|
||||
<EnterprisePlan url="/enterprise" />
|
||||
</div>
|
||||
<p className="mt-2 text-center text-sm opacity-80 xl:text-left">
|
||||
Credits are the Nx Cloud currency allowing for usage based pricing.
|
||||
Prices do not include applicable taxes.
|
||||
</p>
|
||||
</section>
|
||||
<div className="mx-auto my-8 text-center">
|
||||
<ButtonLink
|
||||
href="#plan-details"
|
||||
title="Compare all plans options and benefits"
|
||||
variant="secondary"
|
||||
size="default"
|
||||
>
|
||||
Compare all plans options and benefits
|
||||
</ButtonLink>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
17
nx-dev/ui-pricing/tsconfig.json
Normal file
17
nx-dev/ui-pricing/tsconfig.json
Normal 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"
|
||||
}
|
||||
23
nx-dev/ui-pricing/tsconfig.lib.json
Normal file
23
nx-dev/ui-pricing/tsconfig.lib.json
Normal 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"]
|
||||
}
|
||||
@ -107,6 +107,7 @@
|
||||
"@nx/nx-dev/ui-icons": ["nx-dev/ui-icons/src/index.ts"],
|
||||
"@nx/nx-dev/ui-markdoc": ["nx-dev/ui-markdoc/src/index.ts"],
|
||||
"@nx/nx-dev/ui-member-card": ["nx-dev/ui-member-card/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-references": ["nx-dev/ui-references/src/index.ts"],
|
||||
"@nx/nx-dev/ui-sponsor-card": ["nx-dev/ui-sponsor-card/src/index.ts"],
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user