123 lines
4.9 KiB
TypeScript
123 lines
4.9 KiB
TypeScript
"use client";
|
|
|
|
import { ArrowRight, ArrowLeft, ShieldCheck, UserCircle2 } from "lucide-react";
|
|
import Link from "next/link";
|
|
import { useLanguage } from "@/components/language-provider";
|
|
import { Button, buttonVariants } from "@/components/ui/button";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import { PRODUCTS } from "@/lib/content";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
export function Hero() {
|
|
const { t, lang, dir } = useLanguage();
|
|
const Arrow = lang === "fa" ? ArrowLeft : ArrowRight;
|
|
|
|
return (
|
|
<section id="top" className="relative overflow-hidden bg-white dark:bg-ink">
|
|
<div className="pointer-events-none absolute inset-0 bg-grid-faint opacity-[0.03] dark:opacity-100 [mask-image:radial-gradient(ellipse_at_top,black,transparent_70%)]" />
|
|
<div className="pointer-events-none absolute -top-40 left-1/2 h-[36rem] w-[36rem] -translate-x-1/2 rounded-full bg-brand-600/10 dark:bg-brand-600/20 blur-3xl" />
|
|
|
|
<div className="container-x relative grid items-center gap-16 py-24 lg:grid-cols-2 lg:py-32">
|
|
<div className="animate-fade-up">
|
|
<Badge>
|
|
<ShieldCheck className="h-3.5 w-3.5" />
|
|
{t.hero.badge}
|
|
</Badge>
|
|
<h1 className="mt-6 text-4xl font-bold leading-[1.1] tracking-tight text-slate-900 dark:text-white sm:text-5xl lg:text-6xl">
|
|
<span className="gradient-text">{t.hero.title}</span>
|
|
</h1>
|
|
<p className="mt-6 max-w-xl text-lg leading-relaxed text-slate-600 dark:text-slate-400">
|
|
{t.hero.subtitle}
|
|
</p>
|
|
<div className="mt-9 flex flex-wrap gap-3">
|
|
<Link href="/login" className={cn(buttonVariants({ size: "lg" }))}>
|
|
{t.hero.ctaPrimary}
|
|
<Arrow className="h-5 w-5 rtl:rotate-180" />
|
|
</Link>
|
|
<Link href="/account" className={cn(buttonVariants({ size: "lg", variant: "secondary" }))}>
|
|
<UserCircle2 className="h-5 w-5" />
|
|
{t.hero.ctaSecondary}
|
|
</Link>
|
|
</div>
|
|
<p className="mt-6 text-sm text-slate-500 dark:text-slate-500">{t.hero.note}</p>
|
|
</div>
|
|
|
|
<div className="relative flex items-center justify-center">
|
|
<HubVisual />
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|
|
|
|
function HubVisual() {
|
|
const { lang } = useLanguage();
|
|
return (
|
|
<div className="relative h-80 w-full max-w-md" dir="ltr">
|
|
<div className="absolute left-1/2 top-1/2 h-28 w-28 -translate-x-1/2 -translate-y-1/2 rounded-3xl bg-brand-gradient shadow-2xl shadow-brand-900/50 ring-4 ring-white/10">
|
|
<div className="flex h-full w-full flex-col items-center justify-center text-white">
|
|
<ShieldCheck className="h-8 w-8" />
|
|
<span className="mt-1 text-xs font-semibold">
|
|
{lang === "fa" ? "هاب مرکزی" : "Central Hub"}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
{PRODUCTS.map((p, i) => {
|
|
const angle = (Math.PI * 2 * i) / PRODUCTS.length - Math.PI / 2;
|
|
const radius = 130;
|
|
const x = 50 + (Math.cos(angle) * radius) / 3.2;
|
|
const y = 50 + (Math.sin(angle) * radius) / 3.2;
|
|
return (
|
|
<div
|
|
key={p.key}
|
|
className="absolute h-20 w-20 -translate-x-1/2 -translate-y-1/2 rounded-2xl border border-slate-200 bg-white p-3 text-center shadow-sm backdrop-blur dark:border-white/10 dark:bg-white/[0.04] dark:shadow-none"
|
|
style={{ left: `${x}%`, top: `${y}%` }}
|
|
>
|
|
<div className="flex h-full flex-col items-center justify-center gap-1">
|
|
<span className="text-sm font-semibold text-slate-900 dark:text-white">{p.name}</span>
|
|
<span
|
|
className={
|
|
"rounded-full px-2 py-0.5 text-[10px] " +
|
|
(p.status === "connected"
|
|
? "bg-emerald-500/15 text-emerald-700 dark:text-emerald-300"
|
|
: "bg-slate-100 text-slate-500 dark:bg-white/10 dark:text-slate-400")
|
|
}
|
|
>
|
|
{p.status === "connected"
|
|
? lang === "fa"
|
|
? "متصل"
|
|
: "Live"
|
|
: lang === "fa"
|
|
? "آینده"
|
|
: "Soon"}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
|
|
<svg className="absolute inset-0 h-full w-full" viewBox="0 0 100 100" preserveAspectRatio="none">
|
|
{PRODUCTS.map((_, i) => {
|
|
const angle = (Math.PI * 2 * i) / PRODUCTS.length - Math.PI / 2;
|
|
const radius = 130;
|
|
const x = 50 + (Math.cos(angle) * radius) / 3.2;
|
|
const y = 50 + (Math.sin(angle) * radius) / 3.2;
|
|
return (
|
|
<line
|
|
key={i}
|
|
x1="50"
|
|
y1="50"
|
|
x2={x}
|
|
y2={y}
|
|
stroke="rgba(129,140,248,0.35)"
|
|
strokeWidth="0.4"
|
|
strokeDasharray="2 2"
|
|
/>
|
|
);
|
|
})}
|
|
</svg>
|
|
</div>
|
|
);
|
|
}
|