feat(nx-dev): customer videos on customer page (#29380)

Co-authored-by: Nicholas Cunningham <ndcunningham@gmail.com>
This commit is contained in:
Juri Strumpflohner 2025-01-09 21:30:16 +01:00 committed by GitHub
parent c09e3690b1
commit 9c176d8a44
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 780 additions and 400 deletions

View File

@ -6,7 +6,7 @@ import {
Hero,
OssProjects,
} from '@nx/nx-dev/ui-customers';
import { tryNxCloudForFree } from '../lib/components/headerCtaConfigs';
import { contactButton } from '../lib/components/headerCtaConfigs';
export function Customers(): JSX.Element {
const router = useRouter();
@ -34,7 +34,7 @@ export function Customers(): JSX.Element {
type: 'website',
}}
/>
<DefaultLayout headerCTAConfig={[tryNxCloudForFree]}>
<DefaultLayout headerCTAConfig={[contactButton]}>
<div>
<Hero />
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

View File

@ -63,6 +63,7 @@ module.exports = {
theme: {
extend: {
animation: {
progress: `progress linear forwards`,
marquee: 'marquee var(--duration) linear infinite',
'marquee-vertical': 'marquee-vertical var(--duration) linear infinite',
},
@ -75,6 +76,10 @@ module.exports = {
from: { transform: 'translateY(0)' },
to: { transform: 'translateY(calc(-100% - var(--gap)))' },
},
progress: {
'0%': { width: '0%' },
'100%': { width: '100%' },
},
},
typography: {
DEFAULT: {

View File

@ -0,0 +1,38 @@
import { FC, SVGProps } from 'react';
interface CustomerIcon {
url: string;
icon: FC<SVGProps<SVGSVGElement>>;
height: string;
width: string;
}
interface CustomerIconGridProps {
icons: CustomerIcon[];
}
const CustomerIconGrid: FC<CustomerIconGridProps> = ({ icons }) => {
return (
<div className="grid grid-cols-2 justify-between md:grid-cols-4">
{icons.map((customerIcon, index) => {
return (
<a
key={`customer-icon-${index}`}
href={customerIcon.url}
target="_blank"
rel="noopener noreferrer"
className={`flex items-center justify-center border-slate-200/20 p-12 shadow-[0_0px_1px_0_rgba(226,232,240,0.2)] transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white`}
>
<customerIcon.icon
aria-hidden="true"
className={`${customerIcon.height} ${customerIcon.width}`}
/>
</a>
);
})}
</div>
);
};
export default CustomerIconGrid;
export { CustomerIconGrid, type CustomerIcon };

View File

@ -0,0 +1,423 @@
'use client';
import {
Fragment,
useState,
useEffect,
FC,
SVGProps,
type ReactElement,
} from 'react';
import { Dialog, Transition } from '@headlessui/react';
import {
ChevronLeftIcon,
ChevronRightIcon,
PlayIcon,
} from '@heroicons/react/24/outline';
import {
CasewareIcon,
HetznerCloudIcon,
PayfitIcon,
SiriusxmIcon,
UkgIcon,
VmwareIcon,
} from '@nx/nx-dev/ui-icons';
interface Testimonial {
title: string;
subtitle: string;
metrics?: {
value: string;
label: string;
}[];
quote?: {
text: string;
author: {
name: string;
role: string;
};
};
company: string;
videoId: string;
thumbnail: string;
logo: {
icon: FC<SVGProps<SVGSVGElement>>;
height: string;
width: string;
color?: string;
};
}
const testimonials: Testimonial[] = [
{
title: 'Customer story',
subtitle:
'How Hetzner Cloud solved the Performance Paradox: Faster builds with more features',
metrics: [
{ value: 'Faster tests', label: 'From 20 min -> seconds.' },
{ value: 'Faster builds', label: 'Down from 30 minutes.' },
{ value: 'Speed & scale', label: 'Faster CI with even more features.' },
],
company: 'Hetzner',
videoId: '2BLqiNnBPuU',
thumbnail: '/images/customers/video-story-pavlo-grosse.avif',
logo: {
icon: HetznerCloudIcon,
height: 'h-10',
width: 'w-10',
color: 'text-[#D50C2D]',
},
},
{
title: 'Customer story',
subtitle:
'Scaling 700+ projects: How Nx Enterprise became a no-brainer for Caseware.',
metrics: [
{
value: 'Massive scale',
label: '700+ projects, unifying frontends and backends company wide.',
},
{
value: 'Instant impact',
label: 'Trialing Nx Enterprise cut build times immediately.',
},
{
value: 'Actionable insights',
label:
'Nx Clouds metrics uncovered inefficiencies across 10+ year old codebase.',
},
],
company: 'Caseware',
videoId: 'lvS8HjjFwEM',
thumbnail: '/images/customers/video-story-caseware.avif',
logo: {
icon: CasewareIcon,
height: 'h-12',
width: 'w-12',
color: 'text-[#F56354]',
},
},
{
title: 'Customer story',
subtitle:
'How SiriusXM stays competitive by iterating and getting to market fast.',
metrics: [
{
value: 'Faster releases',
label:
'Nx streamlines feature management, accelerating delivery cycles.',
},
{
value: 'Seamless adoption',
label:
'Nx Cloud integration delivers continuous benefits from day one.',
},
{
value: 'Expert guidance',
label:
'Nx Enterprise support provides quick, informed assistance on demand.',
},
],
company: 'SiriusXM',
videoId: 'Q0ky-8oJcro',
thumbnail: '/images/customers/video-story-siriusxm.avif',
logo: {
icon: SiriusxmIcon,
height: 'h-32',
width: 'w-32',
color: 'text-[#0000EB]',
},
},
{
title: 'Customer story',
subtitle:
'From 5 days to 2 hours: How Payfit improved velocity and offloads complexity.',
metrics: [
{
value: 'From 5 days → 2 hours',
label: 'Nx & Nx Cloud drastically accelerate feature deployment',
},
{
value: 'Eliminated CI Complexity',
label: 'Nx Cloud offloads CI load balancing headaches.',
},
{
value: 'Faster time-to-market',
label:
'Nx boosts velocity, helping teams deliver faster and more reliably.',
},
],
company: 'Payfit',
videoId: 'Vdk-tza4PCs',
thumbnail: '/images/customers/video-story-payfit.avif',
logo: {
icon: PayfitIcon,
height: 'h-16',
width: 'w-16',
color: 'text-[#0F6FDE]',
},
},
{
title: 'Customer story',
subtitle:
'How UKG reduced build times while scaling development across teams.',
metrics: [
{
value: 'From 1 day → instant builds',
label: 'Nx Cloud slashed build wait times, enabling dev productivity.',
},
{
value: 'Eliminated CI Maintenance',
label:
'Nx Cloud frees teams from managing CI, letting devs focus on code.',
},
{
value: 'Reduced duplication',
label:
'Shared libraries cut down redundant code across mobile and web apps.',
},
],
company: 'UKG',
videoId: 'rSC8wihnfP4',
thumbnail: '/images/customers/video-story-ukg.avif',
logo: {
icon: UkgIcon,
height: 'h-20',
width: 'w-20',
color: 'text-[#005151]',
},
},
{
title: 'Customer story',
subtitle: 'How Broadcom stays efficient and nimble with monorepos',
metrics: [
{
value: '2x faster',
label: 'Nx doubles speed, supporting fast, nimble development.',
},
{
value: 'Unmatched DX',
label: 'Nx empowers teams to be more productive than ever.',
},
{
value: 'Always ahead',
label:
'Nxs rapid feature delivery keeps teams at the cutting edge of development.',
},
],
company: 'Broadcom (VMware)',
videoId: 'RWTgYNKqxNc',
thumbnail: '/images/customers/video-story-broadcom.avif',
logo: {
icon: VmwareIcon,
height: 'h-28',
width: 'w-28',
color: 'text-[#607078]',
},
},
];
export function CustomerTestimonialCarousel(): ReactElement {
const [currentIndex, setCurrentIndex] = useState(0);
const [isOpen, setIsOpen] = useState(false);
const currentTestimonial = testimonials[currentIndex];
const slideLogoTimeOut = 12000; // 12 seconds
useEffect(() => {
let timer: NodeJS.Timeout;
if (!isOpen) {
timer = setInterval(() => {
setCurrentIndex((prevIndex) => (prevIndex + 1) % testimonials.length);
}, slideLogoTimeOut);
}
return () => {
clearInterval(timer);
};
}, [currentIndex, setCurrentIndex, isOpen]);
return (
<div className="w-full">
<div className="mx-auto grid max-w-7xl grid-cols-2 gap-2 px-4 lg:grid-cols-5 lg:gap-4">
{/* Left side - Quote or Metrics */}
<div className="col-span-2 hidden lg:block">
<div className="flex h-full flex-col justify-center space-y-8">
{currentTestimonial.metrics?.map((metric, index) => (
<div key={index} className="space-y-2">
<div className="border-l-2 border-blue-900/70 pl-4 text-3xl font-bold text-slate-700 dark:border-sky-300/60 dark:text-slate-200">
{metric.value}
</div>
<div className="text-balance pl-[18px] text-lg text-slate-500 dark:text-slate-400">
{metric.label}
</div>
</div>
))}
</div>
</div>
{/* Right side - Video Card */}
<div className="col-span-2 md:col-span-3">
<div className="flex items-center gap-4">
{/* Prev Button Mobile only */}
<button
disabled={currentIndex === 0}
title={`See ${testimonials[currentIndex - 1]?.company}`}
className="flex h-12 w-12 items-center justify-center rounded-full p-2 transition hover:text-slate-950 disabled:pointer-events-none disabled:opacity-0 md:hidden dark:hover:text-white"
onClick={() => {
setCurrentIndex(
(currentIndex - 1 + testimonials.length) % testimonials.length
);
}}
>
<span className="sr-only">Previous</span>
<ChevronLeftIcon
className="h-8 w-8 flex-shrink-0"
aria-hidden="true"
/>
</button>
<div
className="group relative h-56 w-full cursor-pointer self-stretch overflow-hidden rounded-lg sm:h-80 md:h-[450px] xl:shadow-2xl"
onClick={() => setIsOpen(true)}
>
{/* Thumbnail */}
<img
src={currentTestimonial.thumbnail}
alt={currentTestimonial.title}
className="aspect-video h-full w-full object-cover transition duration-300 group-hover:scale-105"
/>
{/* Gradient Overlay */}
<div className="absolute inset-0 bg-gradient-to-t from-black/80 from-25% via-black/20" />
{/* Content Overlay */}
<div className="absolute bottom-0 left-0 p-4 md:p-8">
<h3 className="text-base font-semibold text-white md:text-2xl lg:text-3xl">
{currentTestimonial.subtitle}
</h3>
<button className="mt-2 inline-flex items-center gap-1 rounded-full bg-white/10 px-4 py-2 text-sm font-medium text-white backdrop-blur-sm transition hover:bg-white/20 md:mt-4 md:gap-2">
<PlayIcon className="size-3 md:size-5" aria-hidden="true" />
Watch video
</button>
</div>
</div>
{/* Next Button - Mobile only */}
<button
className="flex h-12 w-12 items-center justify-center rounded-full p-2 transition hover:text-slate-950 disabled:pointer-events-none disabled:opacity-0 md:hidden dark:hover:text-white"
disabled={currentIndex === testimonials.length - 1}
title={`Next ${testimonials[currentIndex + 1]?.company}`}
onClick={() => {
setCurrentIndex(
(currentIndex + 1 + testimonials.length) % testimonials.length
);
}}
>
<span className="sr-only">Next</span>
<ChevronRightIcon
className="h-8 w-8 flex-shrink-0"
aria-hidden="true"
/>
</button>
</div>
{/* Mobile Navigation display dots */}
<ul className="mt-4 flex justify-center gap-2 md:hidden">
{testimonials.map((_, index) => (
<li
key={index}
className={`h-1.5 rounded-full transition-all duration-300 ${
index === currentIndex
? 'w-12 bg-blue-500'
: 'w-4 bg-slate-200 dark:bg-slate-700'
}`}
/>
))}
</ul>
</div>
</div>
{/* Carosel Navigation - Larger screens */}
<div className="relative mx-auto hidden max-w-7xl grid-cols-6 items-center justify-center px-4 pt-16 md:grid">
{testimonials.map(({ company, logo }, i) => (
<button
onClick={() => setCurrentIndex(i)}
key={`logo-${i}`}
title={company}
className={`relative grid h-full w-full place-items-center border border-slate-200/15 transition-all dark:border-slate-800/20 ${
i !== currentIndex &&
'text-slate-400 hover:text-slate-500 dark:text-slate-700 dark:hover:text-slate-500'
}`}
>
<span className="sr-only">{company} Logo</span>
<logo.icon
key={`logo-icon-${i}`}
className={`${logo.height} ${logo.width} ${
i === currentIndex && logo.color
} transition`}
aria-hidden="true"
/>
{/* Progress Bar */}
{i === currentIndex && !isOpen && (
<div className="absolute left-0 top-0 h-[2px] w-full overflow-hidden bg-gray-300/80 transition-all">
<div
className="animate-progress h-full w-full bg-blue-600/80 dark:bg-sky-600/80"
style={{ animationDuration: `${slideLogoTimeOut}ms` }}
/>
</div>
)}
</button>
))}
</div>
{/* Video Modal */}
<Transition appear show={isOpen} as={Fragment}>
<Dialog
as="div"
open={isOpen}
onClose={() => setIsOpen(false)}
className="relative z-50"
>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-black/70 backdrop-blur-sm" />
</Transition.Child>
<div className="fixed inset-0 overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="w-full max-w-4xl overflow-hidden rounded-2xl bg-black shadow-2xl">
<div className="aspect-video">
<iframe
width="100%"
height="100%"
src={`https://www.youtube.com/embed/${currentTestimonial.videoId}`}
title="Customer Success Story"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
className="h-full w-full"
/>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition>
</div>
);
}

View File

@ -6,7 +6,6 @@ import {
BloombergIcon,
CaisGroupIcon,
CapitalOneIcon,
CasewareIcon,
CaterpillarIcon,
CiscoIcon,
ClickUpIcon,
@ -16,7 +15,6 @@ import {
FedExIcon,
FicoIcon,
HasuraIcon,
HetznerCloudIcon,
HiltonIcon,
IkeaIcon,
IntelIcon,
@ -26,7 +24,6 @@ import {
MillienniumIcon,
ModernaIcon,
ParamountIcon,
PayfitIcon,
PaylocityIcon,
PhilipsIcon,
RedBullIcon,
@ -38,388 +35,273 @@ import {
ThreeKitIcon,
TideIcon,
TMobileIcon,
UkgIcon,
VarianIcon,
VmwareIcon,
VodafoneIcon,
PlexIcon,
ZipariIcon,
} from '@nx/nx-dev/ui-icons';
import { DownloadCaseStudy } from '@nx/nx-dev/ui-enterprise';
import { CustomerTestimonialCarousel } from './customer-testimonial-carousel';
import { CustomerIconGrid, type CustomerIcon } from './customer-icon-grid';
import { type ReactElement } from 'react';
export function EnterpriseCustomers(): JSX.Element {
const firstCustomerIcons: CustomerIcon[] = [
{ url: 'https://man-es.com', icon: ManIcon, height: 'h-20', width: 'w-20' },
{
url: 'https://caterpillar.com',
icon: CaterpillarIcon,
height: 'h-16',
width: 'w-16',
},
{
url: 'https://capitalone.com',
icon: CapitalOneIcon,
height: 'h-32',
width: 'w-32',
},
{
url: 'https://hilton.com',
icon: HiltonIcon,
height: 'h-24',
width: 'w-24',
},
{ url: 'https://myfico.com', icon: FicoIcon, height: 'h-28', width: 'w-28' },
{
url: 'https://7-eleven.com',
icon: SevenElevenIcon,
height: 'h-16',
width: 'w-16',
},
{ url: 'https://cisco.com', icon: CiscoIcon, height: 'h-24', width: 'w-24' },
{
url: 'https://zipari.com',
icon: ZipariIcon,
height: 'h-12',
width: 'w-12',
},
];
const secondCustomerIcons: CustomerIcon[] = [
{
url: 'https://www.fedex.com',
icon: FedExIcon,
height: 'h-28',
width: 'w-28',
},
{
url: 'https://www.aa.com',
icon: AmericanAirlinesIcon,
height: 'h-12',
width: 'w-12',
},
{
url: 'https://www.bill.com',
icon: BillIcon,
height: 'h-16',
width: 'w-16',
},
{
url: 'https://www.adobe.com',
icon: AdobeIcon,
height: 'h-14',
width: 'w-14',
},
{
url: 'https://www.intel.com',
icon: IntelIcon,
height: 'h-16',
width: 'w-16',
},
{
url: 'https://www.adidas.com',
icon: AdidasIcon,
height: 'h-14',
width: 'w-14',
},
{
url: 'https://www.ikea.com',
icon: IkeaIcon,
height: 'h-20',
width: 'w-20',
},
{
url: 'https://www.deloitte.com',
icon: DeloitteIcon,
height: 'h-28',
width: 'w-28',
},
{
url: 'https://www.vodafone.com',
icon: VodafoneIcon,
height: 'h-12',
width: 'w-12',
},
{
url: 'https://mailchimp.com',
icon: MailChimpIcon,
height: 'h-14',
width: 'w-14',
},
{
url: 'https://www.modernatx.com',
icon: ModernaIcon,
height: 'h-32',
width: 'w-32',
},
{
url: 'https://www.paramountplus.com',
icon: ParamountIcon,
height: 'h-14',
width: 'w-14',
},
];
const thirdCustomerIcons: CustomerIcon[] = [
{
url: 'https://clickup.com',
icon: ClickUpIcon,
height: 'h-12',
width: 'w-12',
},
{
url: 'https://global.sharp',
icon: SharpIcon,
height: 'h-28',
width: 'w-28',
},
{
url: 'https://www.redbull.com',
icon: RedBullIcon,
height: 'h-24',
width: 'w-24',
},
{
url: 'https://www.lego.com',
icon: LegoIcon,
height: 'h-24',
width: 'w-24',
},
{
url: 'https://www.philips.ca',
icon: PhilipsIcon,
height: 'h-24',
width: 'w-24',
},
{
url: 'https://www.bloomberg.com',
icon: BloombergIcon,
height: 'h-10',
width: 'w-10',
},
{
url: 'https://www.sainsburys.co.uk',
icon: SainsburysIcon,
height: 'h-32',
width: 'w-36',
},
{
url: 'https://splice.com',
icon: SpliceIcon,
height: 'h-14',
width: 'w-14',
},
{ url: 'https://www.tide.co', icon: TideIcon, height: 'h-20', width: 'w-20' },
{ url: 'https://hasura.io', icon: HasuraIcon, height: 'h-12', width: 'w-12' },
{ url: ' https://www.dnb.no', icon: DnbIcon, height: 'h-16', width: 'w-16' },
{
url: 'https://ghost.org',
icon: RoyalBankOfCanadaIcon,
height: 'h-14',
width: 'w-14',
},
{
url: 'https://www.varian.com',
icon: VarianIcon,
height: 'h-28',
width: 'w-28',
},
{
url: 'https://www.paylocity.com',
icon: PaylocityIcon,
height: 'h-12',
width: 'w-12',
},
{
url: 'https://www.mlp.com',
icon: MillienniumIcon,
height: 'h-24',
width: 'w-40',
},
{
url: 'https://www.threekit.com',
icon: ThreeKitIcon,
height: 'h-12',
width: 'w-12',
},
{
url: 'https://www.caisgroup.com',
icon: CaisGroupIcon,
height: 'h-28',
width: 'w-28',
},
{
url: 'https://www.entaingroup.com',
icon: EntainIcon,
height: 'h-16',
width: 'w-24',
},
{
url: 'https://t-mobile.com',
icon: TMobileIcon,
height: 'h-10',
width: 'w-10',
},
{ url: 'https://plex.tv', icon: PlexIcon, height: 'h-20', width: 'w-20' },
];
export function EnterpriseCustomers(): ReactElement {
return (
<section id="customers">
<div className="mx-auto max-w-7xl">
<div className="mt-8">
<div className="grid grid-cols-2 justify-between md:grid-cols-4">
<a
href="https://www.man-es.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<ManIcon aria-hidden="true" className="h-20 w-20" />
</a>
<a
href="https://www.caterpillar.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-y border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<CaterpillarIcon aria-hidden="true" className="h-16 w-16" />
</a>
<a
href="https://www.capitalone.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<CapitalOneIcon aria-hidden="true" className="h-32 w-32" />
</a>
<a
href="https://www.vmware.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-y border-r border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<VmwareIcon aria-hidden="true" className="h-28 w-28" />
</a>
<a
href="https://www.hilton.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-x border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<HiltonIcon aria-hidden="true" className="h-24 w-24" />
</a>
<a
href="https://www.myfico.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<FicoIcon aria-hidden="true" className="h-28 w-28" />
</a>
<a
href="https://www.7-eleven.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-x border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<SevenElevenIcon aria-hidden="true" className="h-16 w-16" />
</a>
<a
href="https://www.cisco.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-b border-r border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<CiscoIcon aria-hidden="true" className="h-24 w-24" />
</a>
<a
href="https://www.paramountplus.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-x border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<ParamountIcon aria-hidden="true" className="h-14 w-14" />
</a>
<div className="col-span-2 flex items-center justify-center p-6 md:col-span-2">
<DownloadCaseStudy
title="Banking Case Study"
description="$7B European bank cuts CI times by 62% and boosts team productivity."
buttonHref="https://go.nx.dev/banking-case-study"
/>
<div className="mx-auto max-w-7xl">
<CustomerIconGrid icons={firstCustomerIcons} />
</div>
<a
href="https://www.fedex.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-b border-l border-r border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<FedExIcon aria-hidden="true" className="h-28 w-28" />
</a>
<a
href="https://www.aa.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-x border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<AmericanAirlinesIcon aria-hidden="true" className="h-12 w-12" />
</a>
<a
href="https://zipari.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-b border-r border-t border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<ZipariIcon aria-hidden="true" className="h-12 w-12" />
</a>
<a
href="https://www.bill.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-x border-b border-t border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<BillIcon aria-hidden="true" className="h-16 w-16" />
</a>
<a
href="https://www.adobe.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<AdobeIcon aria-hidden="true" className="h-14 w-14" />
</a>
<a
href="https://www.adidas.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-x border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<AdidasIcon aria-hidden="true" className="h-14 w-14" />
</a>
<a
href="https://www.intel.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-b border-r border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white dark:hover:text-white"
>
<IntelIcon aria-hidden="true" className="h-16 w-16" />
</a>
<a
href="https://www.ikea.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-x border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<IkeaIcon aria-hidden="true" className="h-20 w-20" />
</a>
<a
href="https://www.deloitte.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-b border-r border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<DeloitteIcon aria-hidden="true" className="h-28 w-28" />
</a>
<a
href="https://www.vodafone.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-x border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<VodafoneIcon aria-hidden="true" className="h-12 w-12" />
</a>
<div className="col-span-2 flex items-center justify-center p-6 md:col-span-2">
<div className="col-span-2 border-y border-slate-200 bg-slate-50 py-24 sm:py-32 md:col-span-4 dark:border-slate-800 dark:bg-slate-900">
<div className="mx-auto">
<CustomerTestimonialCarousel />
</div>
</div>
<div className="mx-auto max-w-7xl">
<CustomerIconGrid icons={secondCustomerIcons} />
<div className="grid-cols my-8 grid justify-center gap-8 px-2 py-6 md:grid-cols-3">
<DownloadCaseStudy
title="Financial Institution Case Study"
description="$28B Fortune 500 financial institution reduces CI times by 79% with Nx Cloud."
buttonHref="https://go.nx.dev/financial-case-study"
buttonText="Read more"
variant="secondary"
/>
<DownloadCaseStudy
title="Banking Case Study"
description="$7B European bank cuts CI times by 62% and boosts team productivity."
buttonHref="https://go.nx.dev/banking-case-study"
buttonText="Read more"
variant="secondary"
/>
{/* Blog Excerpt */}
<DownloadCaseStudy
title="Improve your architecture and CI speeds"
description="Structure your monorepo the right way to save time, reduce costs, and maximize efficiency."
buttonHref="/blog/improve-architecture-and-ci-times-with-projects"
buttonText="Read more"
buttonCTA="Read more"
variant="secondary"
/>
</div>
<a
href="https://www.t-mobile.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-b border-l border-r border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<TMobileIcon aria-hidden="true" className="h-10 w-10" />
</a>
<a
href="https://mailchimp.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-x border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<MailChimpIcon aria-hidden="true" className="h-14 w-14" />
</a>
<a
href="https://www.modernatx.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-b border-t border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<ModernaIcon aria-hidden="true" className="h-32 w-32" />
</a>
<a
href="https://clickup.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-x border-b border-t border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<ClickUpIcon aria-hidden="true" className="h-12 w-12" />
</a>
<a
href="https://global.sharp"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-b border-r border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<SharpIcon aria-hidden="true" className="h-28 w-28" />
</a>
<a
href="https://www.redbull.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-x border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<RedBullIcon aria-hidden="true" className="h-24 w-24" />
</a>
<a
href="https://www.lego.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<LegoIcon aria-hidden="true" className="h-24 w-24" />
</a>
<a
href="https://www.philips.ca"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-x border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<PhilipsIcon aria-hidden="true" className="h-24 w-24" />
</a>
<a
href="https://www.bloomberg.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-b border-r border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<BloombergIcon aria-hidden="true" className="h-10 w-10" />
</a>
<a
href="https://www.sainsburys.co.uk"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-x border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<SainsburysIcon aria-hidden="true" className="h-32 w-36" />
</a>
<a
href="https://splice.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<SpliceIcon aria-hidden="true" className="h-14 w-14" />
</a>
<a
href="https://www.tide.co"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-x border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<TideIcon aria-hidden="true" className="h-20 w-20" />
</a>
<a
href="https://hasura.io"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-b border-r border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<HasuraIcon aria-hidden="true" className="h-12 w-12" />
</a>
<a
href="https://www.hetzner.com/cloud"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-x border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<HetznerCloudIcon aria-hidden="true" className="h-10 w-10" />
</a>
<a
href=" https://www.dnb.no"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<DnbIcon aria-hidden="true" className="h-16 w-16" />
</a>
<a
href="https://ghost.org"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-x border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<RoyalBankOfCanadaIcon aria-hidden="true" className="h-14 w-14" />
</a>
<a
href="https://www.ukg.ca"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-b border-r border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<UkgIcon aria-hidden="true" className="h-20 w-20" />
</a>
<a
href="https://www.varian.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-x border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<VarianIcon aria-hidden="true" className="h-28 w-28" />
</a>
<a
href="https://www.paylocity.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<PaylocityIcon aria-hidden="true" className="h-12 w-12" />
</a>
<a
href="https://www.mlp.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-x border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<MillienniumIcon aria-hidden="true" className="h-24 w-40" />
</a>
<a
href="https://payfit.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-b border-r border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<PayfitIcon aria-hidden="true" className="h-14 w-14" />
</a>
<a
href="https://www.threekit.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-x border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<ThreeKitIcon aria-hidden="true" className="h-12 w-12" />
</a>
<a
href="https://www.caisgroup.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<CaisGroupIcon aria-hidden="true" className="h-28 w-28" />
</a>
<a
href="https://www.caseware.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-x border-b border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<CasewareIcon aria-hidden="true" className="h-12 w-12" />
</a>
<a
href="https://www.entaingroup.com"
rel="noreferrer"
target="_blank"
className="flex items-center justify-center border-b border-r border-slate-200/20 p-12 transition hover:bg-slate-100/20 hover:text-slate-950 dark:border-slate-800/20 dark:hover:border-slate-600/20 dark:hover:bg-slate-600/10 dark:hover:text-white"
>
<EntainIcon aria-hidden="true" className="h-16 w-24" />
</a>
</div>
<CustomerIconGrid icons={thirdCustomerIcons} />
</div>
</div>
</section>

View File

@ -1,6 +1,8 @@
import { sendCustomEvent } from '@nx/nx-dev/feature-analytics';
import { ButtonLink, SectionHeading } from '@nx/nx-dev/ui-common';
import { type ReactElement } from 'react';
export function Hero(): JSX.Element {
export function Hero(): ReactElement {
return (
<section>
<div className="mx-auto max-w-7xl px-6 lg:px-8">
@ -17,12 +19,15 @@ export function Hero(): JSX.Element {
</SectionHeading>
<div className="mt-16 flex items-center justify-center gap-x-6">
<ButtonLink
href="/contact"
variant="contrast"
href="https://cloud.nx.app/get-started/"
title="Try Nx Cloud for free"
variant="primary"
size="default"
title="Contact us"
onClick={() =>
sendCustomEvent('try-nx-cloud', 'customers-hero', 'customers')
}
>
Contact us
Try Nx Cloud for free
</ButtonLink>
<a

View File

@ -2,6 +2,7 @@
"compilerOptions": {
"jsx": "react-jsx",
"allowJs": false,
"lib": ["dom", "dom.iterable", "esnext"],
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true

View File

@ -6,30 +6,33 @@ export interface DownloadCaseStudyProps {
description: string;
buttonHref: string;
buttonText?: string;
buttonCTA?: 'Download' | 'Read more';
variant?: 'primary' | 'secondary';
}
export function DownloadCaseStudy({
title,
description,
buttonHref,
buttonCTA = 'Download',
buttonText = 'Download (pdf)',
variant = 'primary',
}: DownloadCaseStudyProps): ReactElement {
return (
<div className="border border-slate-100 bg-white shadow-lg sm:rounded-lg dark:border-slate-800/60 dark:bg-slate-950">
<div className="px-4 py-5 sm:p-6">
<div className="flex h-full flex-col border border-slate-100 bg-white shadow sm:rounded-lg dark:border-slate-800/60 dark:bg-slate-950">
<div className="flex flex-1 flex-col px-4 py-5 sm:p-6">
<h3 className="text-base font-semibold leading-6 text-slate-900 dark:text-slate-100">
{title}
</h3>
<div className="mt-2 sm:flex sm:items-start sm:justify-between">
<div className="max-w-xl text-sm">
<div className="mt-2 max-w-xl flex-1 text-sm">
<p>{description}</p>
</div>
<div className="mt-5 sm:ml-6 sm:mt-0 sm:flex sm:flex-shrink-0 sm:items-center">
<div className="mt-auto pt-5">
<ButtonLink
href={buttonHref}
title={`Download ${title}`}
variant="primary"
target="_blank"
title={`${buttonCTA} ${title}`}
variant={variant}
target={buttonCTA === 'Download' ? '_blank' : undefined}
size="small"
>
{buttonText}
@ -37,6 +40,5 @@ export function DownloadCaseStudy({
</div>
</div>
</div>
</div>
);
}

View File

@ -48,6 +48,7 @@ export * from './lib/customers/paramount';
export * from './lib/customers/payfit';
export * from './lib/customers/paylocity';
export * from './lib/customers/philips';
export * from './lib/customers/plex';
export * from './lib/customers/react-query';
export * from './lib/customers/red-bull';
export * from './lib/customers/redwood-js';

View File

@ -1,5 +1,9 @@
import { FC, SVGProps } from 'react';
/**
* Use `#F56354` for a colored version.
*/
export const CasewareIcon: FC<SVGProps<SVGSVGElement>> = (props) => (
<svg
xmlns="http://www.w3.org/2000/svg"

View File

@ -0,0 +1,17 @@
import { FC, SVGProps } from 'react';
/**
* Use `#EBAF00` for a colored version.
*/
export const PlexIcon: FC<SVGProps<SVGSVGElement>> = (props) => (
<svg
role="img"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
{...props}
>
<title>Plex</title>
<path d="M3.987 8.409c-.96 0-1.587.28-2.12.933v-.72H0v8.88s.038.018.127.037c.138.03.821.187 1.331-.249.441-.377.542-.814.542-1.318v-1.283c.533.573 1.147.813 2 .813 1.84 0 3.253-1.493 3.253-3.48 0-2.12-1.36-3.613-3.266-3.613Zm16.748 5.595.406.591c.391.614.894.906 1.492.908.621-.012 1.064-.562 1.226-.755 0 0-.307-.27-.686-.72-.517-.614-1.214-1.755-1.24-1.803l-1.198 1.779Zm-3.205-1.955c0-2.08-1.52-3.64-3.52-3.64s-3.467 1.587-3.467 3.573a3.48 3.48 0 0 0 3.507 3.52c1.413 0 2.626-.84 3.253-2.293h-2.04l-.093.093c-.427.4-.72.533-1.227.533-.787 0-1.373-.506-1.453-1.266h4.986c.04-.214.054-.307.054-.52Zm-7.671-.219c0 .769.11 1.701.868 2.722l.056.069c-.306.526-.742.88-1.248.88-.399 0-.814-.211-1.138-.579a2.177 2.177 0 0 1-.538-1.441V6.409H9.86l-.001 5.421Zm9.283 3.46h-2.39l2.247-3.332-2.247-3.335h2.39l2.248 3.335-2.248 3.332Zm1.593-1.286Zm-17.162-.342c-.933 0-1.68-.773-1.68-1.72s.76-1.666 1.68-1.666c.92 0 1.68.733 1.68 1.68 0 .946-.733 1.706-1.68 1.706Zm18.361-1.974L24 8.622h-2.391l-.87 1.293 1.195 1.773Zm-9.404-.466c.16-.706.72-1.133 1.493-1.133.773 0 1.373.467 1.507 1.133h-3Z" />
</svg>
);

View File

@ -1,5 +1,7 @@
import { FC, SVGProps } from 'react';
/**
* Use `#005151` for a colored version.
*/
export const UkgIcon: FC<SVGProps<SVGSVGElement>> = (props) => (
<svg
xmlns="http://www.w3.org/2000/svg"