add pricing page and extract CTA into its own component
This commit is contained in:
parent
42bcf81ee5
commit
8c5cffad7a
3 changed files with 244 additions and 44 deletions
63
src/components/CTA.tsx
Normal file
63
src/components/CTA.tsx
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
import { useAtom } from "jotai/index";
|
||||||
|
import recordVideoModalOpen from "~/atoms/recordVideoModalOpen";
|
||||||
|
import { usePostHog } from "posthog-js/react";
|
||||||
|
|
||||||
|
export default function CTA() {
|
||||||
|
const [, setRecordOpen] = useAtom(recordVideoModalOpen);
|
||||||
|
const posthog = usePostHog();
|
||||||
|
|
||||||
|
const openRecordModal = () => {
|
||||||
|
setRecordOpen(true);
|
||||||
|
|
||||||
|
posthog?.capture("open record video modal", {
|
||||||
|
cta: "cta section",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-white">
|
||||||
|
<div className="mx-auto max-w-7xl py-12 sm:px-6 sm:py-16 lg:px-8">
|
||||||
|
<div className="relative isolate overflow-hidden bg-gray-900 px-6 py-24 text-center shadow-2xl sm:rounded-3xl sm:px-16">
|
||||||
|
<h2 className="mx-auto max-w-2xl text-4xl font-bold tracking-tight text-white">
|
||||||
|
Ready to improve how your team communicates?
|
||||||
|
</h2>
|
||||||
|
<div className="mt-10 flex items-center justify-center gap-x-6">
|
||||||
|
<button
|
||||||
|
onClick={openRecordModal}
|
||||||
|
className="inline-flex max-h-[40px] items-center rounded-md border border-transparent bg-red-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2"
|
||||||
|
>
|
||||||
|
Record a video
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 1024 1024"
|
||||||
|
className="absolute left-1/2 top-1/2 -z-10 h-[64rem] w-[64rem] -translate-x-1/2"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<circle
|
||||||
|
cx={512}
|
||||||
|
cy={512}
|
||||||
|
r={512}
|
||||||
|
fill="url(#827591b1-ce8c-4110-b064-7cb85a0b1217)"
|
||||||
|
fillOpacity="0.7"
|
||||||
|
/>
|
||||||
|
<defs>
|
||||||
|
<radialGradient
|
||||||
|
id="827591b1-ce8c-4110-b064-7cb85a0b1217"
|
||||||
|
cx={0}
|
||||||
|
cy={0}
|
||||||
|
r={1}
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(512 512) rotate(90) scale(512)"
|
||||||
|
>
|
||||||
|
<stop stopColor="#7775D6" />
|
||||||
|
<stop offset={1} stopColor="#E935C1" stopOpacity={0} />
|
||||||
|
</radialGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -10,6 +10,7 @@ import { CheckIcon } from "@heroicons/react/20/solid";
|
||||||
import { CheckCircleIcon } from "@heroicons/react/24/outline";
|
import { CheckCircleIcon } from "@heroicons/react/24/outline";
|
||||||
import Footer from "~/components/Footer";
|
import Footer from "~/components/Footer";
|
||||||
import Header from "~/components/Header";
|
import Header from "~/components/Header";
|
||||||
|
import CTA from "~/components/CTA";
|
||||||
|
|
||||||
const navigation = [
|
const navigation = [
|
||||||
{ name: "Features", href: "#features" },
|
{ name: "Features", href: "#features" },
|
||||||
|
|
@ -291,50 +292,7 @@ const Home: NextPage = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="bg-white">
|
<CTA />
|
||||||
<div className="mx-auto max-w-7xl py-12 sm:px-6 sm:py-16 lg:px-8">
|
|
||||||
<div className="relative isolate overflow-hidden bg-gray-900 px-6 py-24 text-center shadow-2xl sm:rounded-3xl sm:px-16">
|
|
||||||
<h2 className="mx-auto max-w-2xl text-4xl font-bold tracking-tight text-white">
|
|
||||||
Ready to improve how your team communicates?
|
|
||||||
</h2>
|
|
||||||
<div className="mt-10 flex items-center justify-center gap-x-6">
|
|
||||||
<button
|
|
||||||
onClick={openRecordModal}
|
|
||||||
className="inline-flex max-h-[40px] items-center rounded-md border border-transparent bg-red-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2"
|
|
||||||
>
|
|
||||||
Record a video
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 1024 1024"
|
|
||||||
className="absolute left-1/2 top-1/2 -z-10 h-[64rem] w-[64rem] -translate-x-1/2"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<circle
|
|
||||||
cx={512}
|
|
||||||
cy={512}
|
|
||||||
r={512}
|
|
||||||
fill="url(#827591b1-ce8c-4110-b064-7cb85a0b1217)"
|
|
||||||
fillOpacity="0.7"
|
|
||||||
/>
|
|
||||||
<defs>
|
|
||||||
<radialGradient
|
|
||||||
id="827591b1-ce8c-4110-b064-7cb85a0b1217"
|
|
||||||
cx={0}
|
|
||||||
cy={0}
|
|
||||||
r={1}
|
|
||||||
gradientUnits="userSpaceOnUse"
|
|
||||||
gradientTransform="translate(512 512) rotate(90) scale(512)"
|
|
||||||
>
|
|
||||||
<stop stopColor="#7775D6" />
|
|
||||||
<stop offset={1} stopColor="#E935C1" stopOpacity={0} />
|
|
||||||
</radialGradient>
|
|
||||||
</defs>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
179
src/pages/pricing.tsx
Normal file
179
src/pages/pricing.tsx
Normal file
|
|
@ -0,0 +1,179 @@
|
||||||
|
import Footer from "~/components/Footer";
|
||||||
|
import Header from "~/components/Header";
|
||||||
|
import Head from "next/head";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { CheckIcon } from "@heroicons/react/20/solid";
|
||||||
|
import Tooltip from "~/components/Tooltip";
|
||||||
|
import { Disclosure, Transition } from "@headlessui/react";
|
||||||
|
import { ChevronUpIcon } from "@heroicons/react/20/solid";
|
||||||
|
import CTA from "~/components/CTA";
|
||||||
|
import VideoRecordModal from "~/components/VideoRecordModal";
|
||||||
|
|
||||||
|
export default function Pricing() {
|
||||||
|
const [billedAnnually, setBilledAnnually] = useState<boolean>(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Head>
|
||||||
|
<title>{"Snapify | Pricing"}</title>
|
||||||
|
<meta name="description" content="Generated by create-t3-app" />
|
||||||
|
<link rel="icon" href="/favicon.ico" />
|
||||||
|
</Head>
|
||||||
|
<Header />
|
||||||
|
<div className="m-20 flex h-40 items-center justify-center">
|
||||||
|
<span className="text-center text-7xl font-bold">
|
||||||
|
Choose the plan that fits your needs.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mx-4 mb-20 flex flex-row gap-4 lg:mx-16 lg:gap-16">
|
||||||
|
{[
|
||||||
|
{
|
||||||
|
name: "Free",
|
||||||
|
price: { monthly: 0, annual: 0 },
|
||||||
|
features: [
|
||||||
|
{
|
||||||
|
feature: "Unlimited video recording",
|
||||||
|
description: "Record and share unlimited videos",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
feature: "10 video uploads",
|
||||||
|
description: "Upload external videos to your Library",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
feature: "Remove branding",
|
||||||
|
description: "Remove Snapify branding from your videos",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Pro",
|
||||||
|
price: { monthly: 5, annual: 4 },
|
||||||
|
features: [
|
||||||
|
{
|
||||||
|
feature: "Unlimited videos",
|
||||||
|
description: "Record and share unlimited videos",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
feature: "Video uploads",
|
||||||
|
description: "Upload external videos to your Library",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
feature: "Remove branding",
|
||||||
|
description: "Remove Snapify branding from your videos",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
].map(({ name, price, features }) => (
|
||||||
|
<div
|
||||||
|
key={name}
|
||||||
|
className="flex-1 rounded-3xl border bg-white shadow-sm"
|
||||||
|
>
|
||||||
|
<div className="hero relative flex flex-col items-start rounded-3xl px-6 py-6 shadow-sm">
|
||||||
|
<div className="rounded-lg bg-white/20 px-2 font-medium">
|
||||||
|
{name}
|
||||||
|
</div>
|
||||||
|
<div className="mb-2 mt-4 flex items-end text-5xl font-extrabold tracking-tight">
|
||||||
|
{billedAnnually ? price.annual : price.monthly}
|
||||||
|
<span className="mb-1 text-sm opacity-80">/ mo.</span>
|
||||||
|
</div>
|
||||||
|
<div className="mt-2 text-sm">
|
||||||
|
{billedAnnually ? "billed annually" : "billed monthly"}
|
||||||
|
</div>
|
||||||
|
<div className="mt-2 flex-grow" />
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="btn mt-4 block w-full appearance-none rounded-lg bg-black px-4 py-2.5 text-center text-sm font-medium text-white shadow-lg shadow-black/50 duration-100 focus:outline-transparent disabled:opacity-80"
|
||||||
|
>
|
||||||
|
Get started
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="mt-4 flex flex-col gap-2 pb-8">
|
||||||
|
{features.map(({ feature, description }) => (
|
||||||
|
<div
|
||||||
|
key={feature}
|
||||||
|
className="flex items-center gap-2 text-gray-500"
|
||||||
|
>
|
||||||
|
<div className="ml-6 h-5 w-5 flex-none">
|
||||||
|
<CheckIcon />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Tooltip title={description}>
|
||||||
|
<div className="text-base text-gray-500 underline decoration-gray-400 decoration-dashed underline-offset-4">
|
||||||
|
{feature}
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col items-center justify-center border-y border-[#eaeaea] pb-8">
|
||||||
|
<div className="mb-12 mt-8">
|
||||||
|
<span className="text-5xl font-bold">FAQs</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-1 border-collapse flex-col justify-center px-6">
|
||||||
|
{[
|
||||||
|
{
|
||||||
|
question: "What is your refund policy?",
|
||||||
|
answer:
|
||||||
|
"If you're unhappy with your purchase for any reason, email us within 90 days and we'll refund you in full, no questions asked.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Do you offer technical support?",
|
||||||
|
answer: "No",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Which payment formats and currencies do you accept?",
|
||||||
|
answer:
|
||||||
|
"All payments on our standard plans are via credit card and PayPal.\n" +
|
||||||
|
"\n" +
|
||||||
|
"We use Paddle, the leading Merchant of Record for SaaS companies.\n" +
|
||||||
|
"\n" +
|
||||||
|
"Contact us if you need an alternative payment method.",
|
||||||
|
},
|
||||||
|
].map(({ answer, question }) => (
|
||||||
|
<Disclosure
|
||||||
|
key={question}
|
||||||
|
as="div"
|
||||||
|
className="w-[600px] max-w-[600px]"
|
||||||
|
>
|
||||||
|
{({ open }) => (
|
||||||
|
<>
|
||||||
|
<Disclosure.Button className="flex h-12 w-full items-center justify-between border-t border-[#eaeaea] px-4 py-8 text-left text-sm font-medium">
|
||||||
|
<span>{question}</span>
|
||||||
|
<ChevronUpIcon
|
||||||
|
className={`transition-transform ${
|
||||||
|
open ? "rotate-180" : ""
|
||||||
|
} h-5 w-5`}
|
||||||
|
/>
|
||||||
|
</Disclosure.Button>
|
||||||
|
<Transition
|
||||||
|
enter="transition duration-100 ease-out"
|
||||||
|
enterFrom="transform scale-95 opacity-0"
|
||||||
|
enterTo="transform scale-100 opacity-100"
|
||||||
|
leave="transition duration-75 ease-out"
|
||||||
|
leaveFrom="transform scale-100 opacity-100"
|
||||||
|
leaveTo="transform scale-95 opacity-0"
|
||||||
|
>
|
||||||
|
<Disclosure.Panel className="px-4 pb-2 pt-0 text-sm text-gray-500">
|
||||||
|
{answer}
|
||||||
|
</Disclosure.Panel>
|
||||||
|
</Transition>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Disclosure>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<CTA />
|
||||||
|
|
||||||
|
<Footer />
|
||||||
|
|
||||||
|
<VideoRecordModal />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue