clear old assets, new ci/cd flow
This commit is contained in:
297
web/src/routes/pricing.tsx
Normal file
297
web/src/routes/pricing.tsx
Normal file
@@ -0,0 +1,297 @@
|
||||
import { createSignal, For, Show } from "solid-js";
|
||||
import { Title } from "@solidjs/meta";
|
||||
import { A, useSearchParams } from "@solidjs/router";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { Badge, Button, Card } from "~/components/ui";
|
||||
import PageContainer from "~/components/layout/PageContainer";
|
||||
|
||||
interface Plan {
|
||||
name: string;
|
||||
price: string;
|
||||
period: string;
|
||||
description: string;
|
||||
features: string[];
|
||||
cta: string;
|
||||
popular: boolean;
|
||||
}
|
||||
|
||||
interface FAQ {
|
||||
q: string;
|
||||
a: string;
|
||||
}
|
||||
|
||||
const plans: Plan[] = [
|
||||
{
|
||||
name: "Basic",
|
||||
price: "$9",
|
||||
period: "/month",
|
||||
description: "Essential identity protection for individuals",
|
||||
features: ["Dark web monitoring", "Email breach alerts", "Basic scam call blocking", "Monthly reports"],
|
||||
cta: "Start Free Trial",
|
||||
popular: false,
|
||||
},
|
||||
{
|
||||
name: "Plus",
|
||||
price: "$19",
|
||||
period: "/month",
|
||||
description: "Advanced protection for you and your family",
|
||||
features: ["Everything in Basic", "VoicePrint AI detection", "HomeTitle fraud alerts", "RemoveBrokers automation", "Family sharing (up to 5)"],
|
||||
cta: "Start Free Trial",
|
||||
popular: true,
|
||||
},
|
||||
{
|
||||
name: "Premium",
|
||||
price: "$39",
|
||||
period: "/month",
|
||||
description: "Maximum security for the whole household",
|
||||
features: ["Everything in Plus", "Unlimited family members", "Priority support 24/7", "Real-time alert correlation", "Advanced analytics dashboard", "Data broker suppression"],
|
||||
cta: "Start Free Trial",
|
||||
popular: false,
|
||||
},
|
||||
];
|
||||
|
||||
const faqs: FAQ[] = [
|
||||
{
|
||||
q: "How does Kordant detect voice clones?",
|
||||
a: "VoicePrint analyzes over 200 acoustic features in real-time, including micro-tremors and breathing patterns that AI clones can't replicate accurately.",
|
||||
},
|
||||
{
|
||||
q: "Is my data encrypted?",
|
||||
a: "Yes. All data is encrypted at rest using AES-256 and in transit using TLS 1.3. We never share or sell your personal information.",
|
||||
},
|
||||
{
|
||||
q: "Can I protect my whole family?",
|
||||
a: "Absolutely. Plus and Premium plans include family sharing with centralized monitoring and alert management for all household members.",
|
||||
},
|
||||
{
|
||||
q: "How does dark web monitoring work?",
|
||||
a: "DarkWatch continuously scans dark web forums, marketplaces, and data dumps for your email addresses, phone numbers, and other personal data.",
|
||||
},
|
||||
{
|
||||
q: "What happens after my free trial?",
|
||||
a: "Your trial includes full access to your selected plan for 14 days. You can cancel anytime before the trial ends with no charge.",
|
||||
},
|
||||
{
|
||||
q: "Can I remove my data from brokers?",
|
||||
a: "Yes. RemoveBrokers automates opt-out requests to over 200 data broker sites and verifies removal on your behalf.",
|
||||
},
|
||||
];
|
||||
|
||||
const comparisonFeatures = [
|
||||
{ feature: "Dark web monitoring", basic: true, plus: true, premium: true },
|
||||
{ feature: "Email breach alerts", basic: true, plus: true, premium: true },
|
||||
{ feature: "Basic scam call blocking", basic: true, plus: true, premium: true },
|
||||
{ feature: "Monthly reports", basic: true, plus: true, premium: true },
|
||||
{ feature: "VoicePrint AI detection", basic: false, plus: true, premium: true },
|
||||
{ feature: "HomeTitle fraud alerts", basic: false, plus: true, premium: true },
|
||||
{ feature: "RemoveBrokers automation", basic: false, plus: true, premium: true },
|
||||
{ feature: "Family sharing", basic: false, plus: "Up to 5", premium: "Unlimited" },
|
||||
{ feature: "Priority support 24/7", basic: false, plus: false, premium: true },
|
||||
{ feature: "Real-time alert correlation", basic: false, plus: false, premium: true },
|
||||
{ feature: "Advanced analytics", basic: false, plus: false, premium: true },
|
||||
{ feature: "Data broker suppression", basic: false, plus: false, premium: true },
|
||||
];
|
||||
|
||||
function CheckIcon() {
|
||||
return (
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" class="flex-shrink-0">
|
||||
<path d="M6.5 11.5L3 8l1.1-1.1L6.5 9.3l5.9-5.9L13.5 4.5l-7 7z" fill="var(--color-success)"/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
function XIcon() {
|
||||
return (
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" class="flex-shrink-0">
|
||||
<path d="M4 4l8 8M12 4l-8 8" stroke="var(--color-text-muted)" stroke-width="1.5" stroke-linecap="round"/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default function PricingPage() {
|
||||
const [searchParams] = useSearchParams();
|
||||
const [openFaq, setOpenFaq] = createSignal<string | null>(null);
|
||||
|
||||
const signupUrl = () => `/signup${searchParams.utm_source ? `?utm_source=${searchParams.utm_source}&utm_medium=${searchParams.utm_medium || ""}&utm_campaign=${searchParams.utm_campaign || ""}` : ""}`;
|
||||
|
||||
return (
|
||||
<main>
|
||||
<Title>Kordant Pricing — AI-Powered Identity Protection Plans</Title>
|
||||
|
||||
<section class="relative py-20 md:py-28 overflow-hidden">
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-[var(--color-brand-primary)]/5 to-transparent" />
|
||||
<PageContainer class="relative z-10">
|
||||
<div class="text-center max-w-3xl mx-auto">
|
||||
<Badge variant="info" class="mb-4">Simple Pricing</Badge>
|
||||
<h1 class="text-4xl md:text-5xl lg:text-6xl font-bold text-[var(--color-text-primary)] mb-6">
|
||||
Protection That Fits{" "}
|
||||
<span class="text-gradient-primary">Your Budget</span>
|
||||
</h1>
|
||||
<p class="text-xl text-[var(--color-text-secondary)] mb-8 max-w-2xl mx-auto">
|
||||
Start with a 14-day free trial. No credit card required. Cancel anytime.
|
||||
</p>
|
||||
<div class="flex flex-wrap items-center justify-center gap-x-6 gap-y-2 text-sm text-[var(--color-text-tertiary)]">
|
||||
<span class="flex items-center gap-1.5">
|
||||
<CheckIcon />14-day free trial
|
||||
</span>
|
||||
<span class="flex items-center gap-1.5">
|
||||
<CheckIcon />No credit card required
|
||||
</span>
|
||||
<span class="flex items-center gap-1.5">
|
||||
<CheckIcon />Cancel anytime
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</PageContainer>
|
||||
</section>
|
||||
|
||||
<section class="py-20 md:py-28">
|
||||
<PageContainer>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 max-w-5xl mx-auto">
|
||||
<For each={plans}>
|
||||
{(plan) => (
|
||||
<Card
|
||||
class={cn(
|
||||
"relative flex flex-col",
|
||||
plan.popular && "ring-2 ring-[var(--color-brand-primary)] shadow-glow-primary",
|
||||
)}
|
||||
>
|
||||
<Show when={plan.popular}>
|
||||
<div class="absolute -top-3 left-1/2 -translate-x-1/2">
|
||||
<Badge variant="info">Most Popular</Badge>
|
||||
</div>
|
||||
</Show>
|
||||
<div class="mb-6">
|
||||
<h3 class="text-lg font-semibold text-[var(--color-text-primary)] mb-1">{plan.name}</h3>
|
||||
<p class="text-sm text-[var(--color-text-secondary)] mb-4">{plan.description}</p>
|
||||
<div class="flex items-baseline gap-0.5">
|
||||
<span class="text-4xl font-bold text-[var(--color-text-primary)]">{plan.price}</span>
|
||||
<span class="text-sm text-[var(--color-text-tertiary)]">{plan.period}</span>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="space-y-3 mb-8 flex-1">
|
||||
<For each={plan.features}>
|
||||
{(feature) => (
|
||||
<li class="flex items-start gap-2 text-sm text-[var(--color-text-secondary)]">
|
||||
<CheckIcon />
|
||||
{feature}
|
||||
</li>
|
||||
)}
|
||||
</For>
|
||||
</ul>
|
||||
<A href={signupUrl()}>
|
||||
<Button variant={plan.popular ? "primary" : "secondary"} class="w-full">
|
||||
{plan.cta}
|
||||
</Button>
|
||||
</A>
|
||||
</Card>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</PageContainer>
|
||||
</section>
|
||||
|
||||
<section class="py-16 bg-[var(--color-bg-secondary)]">
|
||||
<PageContainer>
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-[var(--color-text-primary)] mb-4">
|
||||
Compare Plans
|
||||
</h2>
|
||||
</div>
|
||||
<div class="max-w-4xl mx-auto overflow-x-auto">
|
||||
<table class="w-full">
|
||||
<thead>
|
||||
<tr class="border-b-2 border-[var(--color-border)]">
|
||||
<th class="text-left px-4 py-3 text-sm font-medium text-[var(--color-text-secondary)]">Feature</th>
|
||||
<th class="text-center px-4 py-3 text-sm font-medium text-[var(--color-text-secondary)]">Basic</th>
|
||||
<th class="text-center px-4 py-3 text-sm font-semibold text-[var(--color-brand-primary)]">Plus</th>
|
||||
<th class="text-center px-4 py-3 text-sm font-medium text-[var(--color-text-secondary)]">Premium</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<For each={comparisonFeatures}>
|
||||
{(row) => (
|
||||
<tr class="border-b border-[var(--color-border)]">
|
||||
<td class="px-4 py-3 text-sm text-[var(--color-text-primary)]">{row.feature}</td>
|
||||
<td class="text-center px-4 py-3">
|
||||
{row.basic === true ? <CheckIcon /> : row.basic === false ? <XIcon /> : <span class="text-xs text-[var(--color-text-secondary)]">{row.basic}</span>}
|
||||
</td>
|
||||
<td class="text-center px-4 py-3">
|
||||
{row.plus === true ? <CheckIcon /> : row.plus === false ? <XIcon /> : <span class="text-xs text-[var(--color-text-secondary)]">{row.plus}</span>}
|
||||
</td>
|
||||
<td class="text-center px-4 py-3">
|
||||
{row.premium === true ? <CheckIcon /> : row.premium === false ? <XIcon /> : <span class="text-xs text-[var(--color-text-secondary)]">{row.premium}</span>}
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</For>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</PageContainer>
|
||||
</section>
|
||||
|
||||
<section class="py-20 md:py-28">
|
||||
<PageContainer>
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<div class="text-center mb-12">
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-[var(--color-text-primary)] mb-4">
|
||||
Frequently Asked Questions
|
||||
</h2>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<For each={faqs}>
|
||||
{(faq) => {
|
||||
const isOpen = () => openFaq() === faq.q;
|
||||
return (
|
||||
<div class="border border-[var(--color-border)] rounded-xl overflow-hidden">
|
||||
<button
|
||||
type="button"
|
||||
class="w-full flex items-center justify-between px-5 py-4 text-left text-sm font-medium text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] transition-colors"
|
||||
onClick={() => setOpenFaq(isOpen() ? null : faq.q)}
|
||||
>
|
||||
{faq.q}
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
class={cn("transition-transform duration-200", isOpen() && "rotate-180")}
|
||||
>
|
||||
<path d="M4 6l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</button>
|
||||
<Show when={isOpen()}>
|
||||
<div class="px-5 pb-4 text-sm text-[var(--color-text-secondary)] leading-relaxed">
|
||||
{faq.a}
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</For>
|
||||
</div>
|
||||
</div>
|
||||
</PageContainer>
|
||||
</section>
|
||||
|
||||
<section class="py-16 bg-[var(--color-brand-primary)]">
|
||||
<PageContainer>
|
||||
<div class="text-center">
|
||||
<h2 class="text-3xl md:text-4xl font-bold text-white mb-4">
|
||||
Ready to protect your identity?
|
||||
</h2>
|
||||
<p class="text-lg text-white/80 mb-8 max-w-2xl mx-auto">
|
||||
Join 50,000+ users who trust Kordant for AI-powered identity protection.
|
||||
</p>
|
||||
<A href={signupUrl()}>
|
||||
<Button variant="primary" size="lg" class="bg-white text-[var(--color-brand-primary)] hover:bg-white/90 shadow-lg">
|
||||
Get Started Free
|
||||
</Button>
|
||||
</A>
|
||||
</div>
|
||||
</PageContainer>
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user