95 lines
4.1 KiB
TypeScript
95 lines
4.1 KiB
TypeScript
import Link from "next/link";
|
|
import type { Plan } from "@/lib/pricing";
|
|
|
|
export default function Pricing({ plans }: { plans: Plan[] }) {
|
|
return (
|
|
<section
|
|
aria-labelledby="pricing-heading"
|
|
className="relative py-24 border-t border-neutral-200 dark:border-neutral-800 bg-gradient-to-b from-white via-neutral-50 to-white dark:from-neutral-950 dark:via-neutral-900 dark:to-neutral-950"
|
|
>
|
|
<div className="container mx-auto max-w-6xl px-4 text-center">
|
|
<h2
|
|
id="pricing-heading"
|
|
className="text-3xl sm:text-4xl font-bold tracking-tight bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent"
|
|
>
|
|
Simple plans with real SLAs
|
|
</h2>
|
|
<p className="mt-4 text-neutral-700 dark:text-neutral-300 max-w-2xl mx-auto">
|
|
Pick the care level that matches your traffic and risk. Month-to-month, 30-day cancel.
|
|
</p>
|
|
|
|
<div className="mt-12 grid gap-8 sm:grid-cols-3">
|
|
{plans.map((p, i) => (
|
|
<article
|
|
key={p.id}
|
|
aria-label={`${p.name} plan`}
|
|
className={[
|
|
"relative rounded-2xl border border-neutral-200 dark:border-neutral-800",
|
|
p.popular
|
|
? "bg-white shadow-lg ring-2 ring-blue-600/20 dark:bg-neutral-900/80"
|
|
: "bg-white/70 dark:bg-neutral-900/70 shadow-sm",
|
|
"p-8 hover:shadow-lg transition backdrop-blur animate-[fadeInUp_0.6s_ease_forwards]",
|
|
].join(" ")}
|
|
style={{ animationDelay: `${i * 100}ms` }}
|
|
>
|
|
{p.popular && (
|
|
<div
|
|
aria-hidden="true"
|
|
className="absolute -top-3 right-6 rounded-full bg-gradient-to-r from-blue-600 to-purple-600 px-3 py-1 text-xs text-white"
|
|
>
|
|
Most popular
|
|
</div>
|
|
)}
|
|
|
|
<div className="text-xl font-semibold text-neutral-900 dark:text-white">{p.name}</div>
|
|
|
|
<div className="mt-3 flex items-baseline justify-center gap-1">
|
|
<div className="text-4xl font-bold text-neutral-900 dark:text-white">{p.price}</div>
|
|
{p.periodicity && (
|
|
<div className="text-sm text-neutral-500 dark:text-neutral-400">{p.periodicity}</div>
|
|
)}
|
|
</div>
|
|
|
|
{p.description && (
|
|
<p className="mt-3 text-sm text-neutral-600 dark:text-neutral-300">{p.description}</p>
|
|
)}
|
|
|
|
<ul className="mt-5 space-y-2 text-sm text-neutral-700 dark:text-neutral-300 text-left">
|
|
{p.features.map((f, idx) => (
|
|
<li key={idx} className="flex items-start gap-2">
|
|
<span className="mt-1.5 inline-block h-1.5 w-1.5 rounded-full bg-gradient-to-r from-blue-600 to-purple-600" />
|
|
<span>{f}</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
|
|
<Link
|
|
href={p.cta.href}
|
|
aria-label={p.cta.label}
|
|
className={[
|
|
"mt-8 inline-block w-full rounded-lg py-3 text-sm font-medium transition",
|
|
p.popular
|
|
? "bg-gradient-to-r from-blue-600 to-purple-600 text-white hover:opacity-90"
|
|
: "border border-neutral-300 dark:border-neutral-700 text-neutral-900 dark:text-white hover:bg-neutral-50 dark:hover:bg-neutral-800",
|
|
].join(" ")}
|
|
>
|
|
{p.cta.label}
|
|
</Link>
|
|
|
|
<p className="mt-3 text-xs text-neutral-500 dark:text-neutral-400">
|
|
Includes DNS/email monitoring, automated backups with restore verification, uptime & SSL watch.
|
|
</p>
|
|
</article>
|
|
))}
|
|
</div>
|
|
|
|
<div className="mt-10 text-center">
|
|
<p className="text-sm text-neutral-600 dark:text-neutral-400">
|
|
Need 24/7 paging and 1-hour first response? Choose <span className="font-medium">Mission-Critical</span>.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|