Files
Kordant/web/src/components/landing/HowItWorksSection.tsx
2026-05-25 16:31:39 -04:00

198 lines
4.8 KiB
TypeScript

import { For } from "solid-js";
import type { JSX } from "solid-js";
import { cn } from "~/lib/utils";
import PageContainer from "~/components/layout/PageContainer";
interface Step {
number: number;
title: string;
description: string;
icon: () => JSX.Element;
}
function EnrollIcon() {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
class="w-8 h-8 text-white"
>
<path
d="M12 4a4 4 0 100 8 4 4 0 000-8zM6 21v-2a4 4 0 014-4h4a4 4 0 014 4v2"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
/>
<path
d="M17 8l2 2 4-4"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
);
}
function MonitorIcon() {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
class="w-8 h-8 text-white"
>
<path
d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
stroke="currentColor"
stroke-width="1.5"
/>
<path
d="M12 8v4l3 3"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M3 12h3m15 0h3M12 3v3m0 15v3"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
opacity="0.5"
/>
</svg>
);
}
function AlertIcon() {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
class="w-8 h-8 text-white"
>
<path
d="M18 8A6 6 0 006 8c0 7-3 9-3 9h18s-3-2-3-9"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M12 22a2 2 0 01-2-2h4a2 2 0 01-2 2z"
fill="currentColor"
/>
<path
d="M12 11v3m0-6v1"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
/>
</svg>
);
}
const steps: Step[] = [
{
number: 1,
title: "Enroll Your Identity",
description:
"Sign up and add your emails, phone numbers, and family members to create your protection profile.",
icon: EnrollIcon,
},
{
number: 2,
title: "We Monitor 24/7",
description:
"Our system runs continuous dark web scans, voiceprint detection, and spam filtering to catch threats early.",
icon: MonitorIcon,
},
{
number: 3,
title: "Get Instant Alerts",
description:
"Receive real-time notifications the moment a threat is detected, with clear guidance on what to do next.",
icon: AlertIcon,
},
];
interface StepBlockProps {
step: Step;
index: number;
}
function StepBlock(props: StepBlockProps) {
const isEven = props.index % 2 === 0;
const Icon = props.step.icon;
return (
<div
class={cn(
"flex gap-8 md:flex-row flex-col",
isEven ? "" : "md:flex-row-reverse",
)}
>
<div class="flex-1">
<div class="flex items-start gap-5">
<div class="w-14 h-14 rounded-full gradient-primary shadow-glow-primary flex items-center justify-center shrink-0">
<Icon />
</div>
<div>
<div class="inline-flex items-center gap-2 mb-1.5">
<span class="text-sm font-semibold text-[var(--color-brand-primary)]">
Step {props.step.number}
</span>
</div>
<h3 class="text-xl md:text-2xl font-bold text-[var(--color-text-primary)] mb-2">
{props.step.title}
</h3>
<p class="text-base text-[var(--color-text-secondary)] leading-relaxed">
{props.step.description}
</p>
</div>
</div>
</div>
<div class="flex-1 hidden md:block" />
</div>
);
}
interface HowItWorksSectionProps {
class?: string;
}
export default function HowItWorksSection(props: HowItWorksSectionProps) {
return (
<section
id="how-it-works"
class={cn("py-20 md:py-28 scroll-mt-16", props.class)}
>
<PageContainer py="py-8">
<div class="text-center mb-16">
<h2 class="text-3xl md:text-4xl lg:text-5xl font-bold text-[var(--color-text-primary)] mb-4">
How It Works
</h2>
<p class="text-lg text-[var(--color-text-secondary)] max-w-2xl mx-auto">
Three simple steps to full identity protection
</p>
</div>
<div class="flex flex-col gap-12 md:gap-16">
<For each={steps}>
{(step, index) => <StepBlock step={step} index={index()} />}
</For>
</div>
</PageContainer>
</section>
);
}