nx/nx-dev/ui-cloud/src/lib/hero.tsx
2024-07-19 14:53:25 -04:00

203 lines
6.9 KiB
TypeScript

'use client';
import { Dialog, Transition } from '@headlessui/react';
import { cx } from '@nx/nx-dev/ui-primitives';
import { PlayIcon } from '@heroicons/react/24/outline';
import { motion } from 'framer-motion';
import { ComponentProps, Fragment, useState } from 'react';
import { ButtonLink, SectionHeading } from '@nx/nx-dev/ui-common';
import { MovingBorder } from '@nx/nx-dev/ui-animations';
import Image from 'next/image';
export function Hero(): JSX.Element {
const [isOpen, setIsOpen] = useState(false);
return (
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto max-w-3xl text-center">
<SectionHeading as="h1" variant="display">
Fast CI <br /> Built for Monorepos
</SectionHeading>
<SectionHeading
as="p"
variant="subtitle"
className="mx-auto mt-6 max-w-xl"
>
Nx Cloud is the end-to-end solution for smart, efficient and
maintainable CI.
</SectionHeading>
<div className="mt-10 flex items-center justify-center gap-x-6">
<ButtonLink
href="https://cloud.nx.app"
title="Get started"
variant="primary"
size="default"
>
Get started
</ButtonLink>
<ButtonLink
href="/ci/intro/ci-with-nx"
title="Learn More"
variant="secondary"
size="default"
>
Learn More
</ButtonLink>
<a
href="https://staging.nx.app/orgs/62d013d4d26f260059f7765e/workspaces/62d013ea0852fe0a2df74438/overview"
target="_blank"
rel="noreferrer"
title="Live demo"
className="group text-sm font-semibold leading-6 text-slate-950 dark:text-white"
>
Live demo{' '}
<span
aria-hidden="true"
className="inline-block transition group-hover:translate-x-1"
>
</span>
</a>
</div>
</div>
<div className="relative overflow-hidden pt-16">
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="relative mb-6 mt-0 overflow-hidden rounded-xl bg-transparent p-[0.5px] text-xl shadow-lg">
<div className="absolute inset-0">
<MovingBorder duration={4500} rx="5%" ry="5%">
<div className="h-20 w-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>
<picture className="relative flex h-full w-full items-center justify-center overflow-hidden rounded-xl border border-slate-100 bg-slate-50 antialiased backdrop-blur-xl dark:border-slate-900 dark:bg-slate-900/[0.8]">
<Image
src="/images/cloud/nrwl-ocean.avif"
alt="App screenshot: overview"
width={2550}
height={1622}
loading="eager"
priority
/>
</picture>
<div className="absolute inset-0 z-10 grid h-full w-full items-center justify-center">
<PlayButton onClick={() => setIsOpen(true)} />
</div>
</div>
</div>
</div>
{/*MODAL*/}
<Transition appear show={isOpen} as={Fragment}>
<Dialog
as="div"
open={isOpen}
onClose={() => setIsOpen(false)}
className="relative z-10"
>
<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/25 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 text-center">
<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="relative w-auto transform overflow-hidden rounded-2xl border border-slate-600 text-left align-middle shadow-xl transition-all focus:outline-none dark:border-slate-800">
<iframe
width="812"
height="468"
src="https://www.youtube.com/embed/4VI-q943J3o?si=3tR-EkCKLfLvHYzL"
title="YouTube video player"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowFullScreen
className="max-w-full"
/>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition>
</div>
);
}
function PlayButton({
className,
...props
}: ComponentProps<'div'>): JSX.Element {
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="h-20 w-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 h-20 w-20 cursor-pointer items-center justify-center gap-6 rounded-full border border-slate-100 bg-white/[0.6] p-6 text-sm text-slate-950 antialiased backdrop-blur-xl"
>
<PlayIcon
aria-hidden="true"
className="absolute left-6 top-6 h-8 w-8"
/>
<motion.div variants={child} className="absolute left-20 top-4 w-48">
<p className="text-base font-medium">See how Nx Cloud works</p>
<p className="text-slate-700">In under 9 minutes</p>
</motion.div>
</motion.div>
</div>
);
}