feat(about): add static public about page

This commit is contained in:
2026-06-06 23:32:55 +03:30
parent ef3eaf1206
commit 870d198cc8
3 changed files with 468 additions and 0 deletions

323
src/pages/About.tsx Normal file
View File

@@ -0,0 +1,323 @@
import { Link, useNavigate } from "react-router-dom"
import {
ArrowLeft,
ArrowRight,
BarChart3,
CheckCircle2,
Command,
FileText,
Globe2,
Layers3,
LockKeyhole,
Moon,
ShieldCheck,
Sparkles,
Sun,
TimerReset,
Users,
Waypoints,
} from "lucide-react"
import { Button } from "../components/ui/button"
import { useTheme } from "../components/ThemeProvider"
import { useTranslation } from "../hooks/useTranslation"
import aboutContent from "../content/about.json"
import { cn } from "../lib/utils"
type AboutContent = typeof aboutContent.en
const sectionIcons = [Sparkles, ShieldCheck, Layers3]
const principleIcons = [TimerReset, Waypoints, BarChart3]
const capabilityIcons = [TimerReset, Users, FileText, LockKeyhole]
export default function About() {
const navigate = useNavigate()
const { t, lang, setLanguage } = useTranslation()
const { theme, setTheme } = useTheme()
const content = aboutContent[lang] as AboutContent
const isAuthenticated = typeof window !== "undefined" && !!localStorage.getItem("accessToken")
const isDarkMode =
theme === "dark" ||
(theme === "system" && document.documentElement.classList.contains("dark"))
const ctaTarget = isAuthenticated ? "/timesheet" : "/auth"
return (
<div className="scroll-smooth min-h-screen overflow-x-hidden bg-[radial-gradient(circle_at_top,#e0f2fe_0%,#f8fafc_36%,#eef2ff_100%)] text-slate-950 dark:bg-[radial-gradient(circle_at_top,#082f49_0%,#020617_40%,#020617_100%)] dark:text-slate-50">
<div className="landing-aurora pointer-events-none fixed inset-0 opacity-80" />
<div className="landing-hero-grid pointer-events-none fixed inset-0 opacity-70 dark:opacity-40" />
<div className="pointer-events-none fixed left-[-12rem] top-20 h-80 w-80 rounded-full bg-cyan-400/20 blur-3xl dark:bg-cyan-500/10" />
<div className="pointer-events-none fixed right-[-10rem] top-52 h-72 w-72 rounded-full bg-emerald-300/20 blur-3xl dark:bg-emerald-400/10" />
<div className="relative mx-auto flex min-h-screen max-w-7xl flex-col px-4 pb-14 pt-5 sm:px-6 lg:px-8">
<header className="animate-landing-rise flex items-center justify-between rounded-full border border-white/70 bg-white/75 px-4 py-3 shadow-[0_20px_60px_-36px_rgba(15,23,42,0.45)] backdrop-blur-xl dark:border-white/10 dark:bg-slate-950/55">
<button
type="button"
onClick={() => navigate("/")}
className="inline-flex items-center gap-3 rounded-full px-2 py-1 text-left"
>
<span className="flex h-10 w-10 items-center justify-center rounded-2xl bg-slate-950 text-white shadow-lg shadow-cyan-500/20 dark:bg-white dark:text-slate-950">
<Command className="h-5 w-5" />
</span>
<span className="hidden sm:block">
<span className="block text-lg font-semibold">{t.title}</span>
</span>
</button>
<nav className="hidden items-center gap-2 md:flex">
<Link
to="/"
className="rounded-full px-4 py-2 text-sm font-medium text-slate-600 transition hover:bg-slate-100 hover:text-slate-950 dark:text-slate-300 dark:hover:bg-slate-900 dark:hover:text-white"
>
{lang === "fa" ? "خانه" : "Home"}
</Link>
<Link
to="/about"
className="rounded-full bg-slate-950 px-4 py-2 text-sm font-medium text-white shadow-sm dark:bg-white dark:text-slate-950"
>
{lang === "fa" ? "درباره ما" : "About us"}
</Link>
</nav>
<div className="flex items-center gap-2">
<button
type="button"
onClick={() => setLanguage(lang === "fa" ? "en" : "fa")}
className="inline-flex h-11 items-center gap-2 rounded-full border border-slate-200/80 bg-white/80 px-4 text-sm font-medium text-slate-700 transition hover:bg-slate-50 dark:border-slate-800 dark:bg-slate-950/80 dark:text-slate-200 dark:hover:bg-slate-900"
>
<Globe2 className="h-4 w-4" />
{lang === "fa" ? t.landing.actions.switchToEnglish : t.landing.actions.switchToPersian}
</button>
<button
type="button"
onClick={() => setTheme(isDarkMode ? "light" : "dark")}
className="inline-flex h-11 w-11 items-center justify-center rounded-full border border-slate-200/80 bg-white/80 text-slate-700 transition hover:bg-slate-50 dark:border-slate-800 dark:bg-slate-950/80 dark:text-slate-200 dark:hover:bg-slate-900"
aria-label={isDarkMode ? t.lightMode : t.darkMode}
>
{isDarkMode ? <Sun className="h-4 w-4" /> : <Moon className="h-4 w-4" />}
</button>
</div>
</header>
<main className="flex-1">
<section className="grid items-center gap-10 py-12 lg:grid-cols-[1.05fr_0.95fr] lg:py-20">
<div className="space-y-7">
<div className="animate-landing-rise">
<div className="mb-5 inline-flex items-center gap-2 rounded-full border border-cyan-200/70 bg-white/75 px-4 py-2 text-sm font-medium text-cyan-900 shadow-sm backdrop-blur dark:border-cyan-500/20 dark:bg-cyan-500/10 dark:text-cyan-100">
<Sparkles className="h-4 w-4" />
{content.eyebrow}
</div>
<h1 className="max-w-4xl text-4xl font-semibold leading-[1.08] text-slate-950 sm:text-5xl lg:text-6xl dark:text-white">
{content.hero.title}
<span className="landing-shimmer mt-4 block bg-[linear-gradient(120deg,#0f172a_15%,#0891b2_48%,#0f766e_78%,#0f172a_100%)] bg-clip-text pb-4 text-transparent dark:bg-[linear-gradient(120deg,#ffffff_18%,#67e8f9_48%,#2dd4bf_78%,#ffffff_100%)]">
{content.hero.accent}
</span>
</h1>
<p className="mt-6 max-w-2xl text-lg leading-8 text-slate-600 dark:text-slate-300 sm:text-xl">
{content.hero.description}
</p>
</div>
<div className="animate-landing-rise flex flex-col gap-3 sm:flex-row [animation-delay:140ms]">
<Button
asChild
className="h-14 rounded-full bg-slate-950 px-7 text-base text-white shadow-[0_30px_80px_-28px_rgba(8,145,178,0.45)] hover:bg-slate-800 dark:bg-cyan-400 dark:text-slate-950 dark:hover:bg-cyan-300"
>
<Link to={ctaTarget}>
{content.cta.button}
<ArrowRight className={cn("ms-2 h-4 w-4", lang === "fa" && "rotate-180")} />
</Link>
</Button>
<Button
asChild
variant="outline"
className="h-14 rounded-full border-slate-200 bg-white/85 px-7 text-base text-slate-800 shadow-sm backdrop-blur hover:bg-white dark:border-slate-800 dark:bg-slate-950/70 dark:text-slate-100 dark:hover:bg-slate-900"
>
<Link to="/">
{lang === "fa" ? "بازگشت به صفحه اصلی" : "Back to home"}
{lang === "fa" ? <ArrowLeft className="ms-2 h-4 w-4" /> : <ArrowRight className="ms-2 h-4 w-4" />}
</Link>
</Button>
</div>
</div>
<div className="animate-landing-rise [animation-delay:180ms]">
<div className="relative overflow-hidden rounded-[2rem] border border-white/70 bg-white/80 p-5 shadow-[0_45px_110px_-48px_rgba(15,23,42,0.6)] backdrop-blur-2xl dark:border-white/10 dark:bg-slate-950/70 sm:p-6">
<div className="absolute inset-x-0 top-0 h-24 bg-[linear-gradient(90deg,rgba(34,211,238,0.16),rgba(16,185,129,0.12),rgba(245,158,11,0.12))]" />
<div className="relative">
<div className="mb-6 flex items-center justify-between">
<div>
<div className="text-xs uppercase tracking-[0.22em] text-slate-400 dark:text-slate-500">
{lang === "fa" ? "مدل محصول" : "Product model"}
</div>
<div className="mt-2 text-2xl font-semibold tracking-[-0.04em] text-slate-950 dark:text-white">
{lang === "fa" ? "از ثبت تا تصمیم" : "From capture to decision"}
</div>
</div>
<div className="rounded-full border border-emerald-200 bg-emerald-50 px-4 py-2 text-sm font-semibold text-emerald-700 dark:border-emerald-500/20 dark:bg-emerald-500/10 dark:text-emerald-200">
{lang === "fa" ? "شفاف" : "Clear"}
</div>
</div>
<div className="space-y-3">
{content.sections.map((section, index) => {
const Icon = sectionIcons[index] ?? Sparkles
return (
<div
key={section.title}
className="rounded-[1.5rem] border border-slate-200/80 bg-white/80 p-4 shadow-sm backdrop-blur dark:border-slate-800 dark:bg-slate-900/80"
>
<div className="flex items-start gap-4">
<div className="flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl bg-slate-950 text-white dark:bg-cyan-400 dark:text-slate-950">
<Icon className="h-5 w-5" />
</div>
<div>
<h2 className="text-lg font-semibold tracking-[-0.03em] text-slate-950 dark:text-white">
{section.title}
</h2>
<p className="mt-2 text-sm leading-7 text-slate-600 dark:text-slate-300">
{section.description}
</p>
</div>
</div>
</div>
)
})}
</div>
</div>
</div>
</div>
</section>
<section className="grid gap-4 py-8 md:grid-cols-3">
{content.principles.map((principle, index) => {
const Icon = principleIcons[index] ?? CheckCircle2
return (
<article
key={principle.title}
className="animate-landing-rise rounded-[2rem] border border-white/70 bg-white/80 p-6 shadow-[0_30px_80px_-50px_rgba(15,23,42,0.6)] backdrop-blur-xl dark:border-white/10 dark:bg-slate-950/65"
style={{ animationDelay: `${index * 120}ms` }}
>
<div className="flex h-12 w-12 items-center justify-center rounded-2xl bg-slate-950 text-white dark:bg-cyan-400 dark:text-slate-950">
<Icon className="h-5 w-5" />
</div>
<h2 className="mt-5 text-2xl font-semibold tracking-[-0.04em] text-slate-950 dark:text-white">
{principle.title}
</h2>
<p className="mt-3 text-base leading-7 text-slate-600 dark:text-slate-300">
{principle.description}
</p>
</article>
)
})}
</section>
<section className="grid gap-6 py-8 lg:grid-cols-[0.9fr_1.1fr]">
<div className="animate-landing-rise rounded-[2rem] border border-white/70 bg-white/80 p-7 shadow-[0_30px_80px_-50px_rgba(15,23,42,0.6)] backdrop-blur-xl dark:border-white/10 dark:bg-slate-950/65">
<div className="text-sm font-semibold uppercase tracking-[0.2em] text-cyan-700 dark:text-cyan-300">
{lang === "fa" ? "برای چه تیم‌هایی" : "Who it serves"}
</div>
<h2 className="mt-4 text-4xl font-semibold tracking-[-0.05em] text-slate-950 dark:text-white">
{lang === "fa" ? "برای تیم‌هایی که زمان را بخشی از عملیات می‌دانند." : "For teams that treat time as part of operations."}
</h2>
<div className="mt-6 flex flex-wrap gap-3">
{content.audience.map((item) => (
<span
key={item}
className="rounded-full border border-cyan-200/70 bg-cyan-50/70 px-4 py-2 text-sm font-medium text-cyan-900 backdrop-blur dark:border-cyan-500/20 dark:bg-cyan-500/10 dark:text-cyan-100"
>
{item}
</span>
))}
</div>
</div>
<div className="grid gap-4 sm:grid-cols-2">
{content.capabilities.map((capability, index) => {
const Icon = capabilityIcons[index] ?? Waypoints
return (
<article
key={capability.title}
className="animate-landing-rise rounded-[2rem] border border-white/70 bg-gradient-to-br from-white/95 to-slate-50/80 p-6 shadow-[0_26px_70px_-48px_rgba(15,23,42,0.65)] backdrop-blur-xl dark:border-white/10 dark:from-slate-950/80 dark:to-slate-900/55"
style={{ animationDelay: `${index * 90}ms` }}
>
<div className="flex items-center gap-3">
<div className="flex h-11 w-11 items-center justify-center rounded-2xl bg-slate-950 text-white dark:bg-white dark:text-slate-950">
<Icon className="h-5 w-5" />
</div>
<h3 className="text-xl font-semibold tracking-[-0.04em] text-slate-950 dark:text-white">
{capability.title}
</h3>
</div>
<p className="mt-4 text-sm leading-7 text-slate-600 dark:text-slate-300">
{capability.description}
</p>
</article>
)
})}
</div>
</section>
<section className="py-8">
<div className="rounded-[2rem] border border-white/70 bg-white/80 p-7 shadow-[0_30px_80px_-50px_rgba(15,23,42,0.6)] backdrop-blur-xl dark:border-white/10 dark:bg-slate-950/65">
<div className="mb-6 flex flex-col gap-2 sm:flex-row sm:items-end sm:justify-between">
<div>
<div className="text-sm font-semibold uppercase tracking-[0.2em] text-cyan-700 dark:text-cyan-300">
{lang === "fa" ? "اعتماد و کنترل" : "Trust and control"}
</div>
<h2 className="mt-3 text-3xl font-semibold tracking-[-0.05em] text-slate-950 dark:text-white">
{lang === "fa" ? "جزئیات مهم باید قابل بررسی بمانند." : "Important details should remain reviewable."}
</h2>
</div>
</div>
<div className="grid gap-3 md:grid-cols-3">
{content.trust.map((item, index) => (
<div
key={item}
className="rounded-[1.5rem] border border-slate-200/80 bg-white/80 p-4 text-sm leading-7 text-slate-600 shadow-sm backdrop-blur dark:border-slate-800 dark:bg-slate-900/80 dark:text-slate-300"
>
<CheckCircle2 className="mb-4 h-5 w-5 text-emerald-500" />
{item}
<div className="mt-5 text-xs font-semibold uppercase tracking-[0.2em] text-slate-400 dark:text-slate-500">
{lang === "fa" ? `نکته ${new Intl.NumberFormat("fa-IR").format(index + 1)}` : `Note ${index + 1}`}
</div>
</div>
))}
</div>
</div>
</section>
<section className="py-8">
<div className="relative overflow-hidden rounded-[2.5rem] border border-slate-950/5 bg-slate-950 px-6 py-10 text-white shadow-[0_40px_100px_-40px_rgba(15,23,42,0.8)] dark:border-white/10 sm:px-10">
<div className="pointer-events-none absolute inset-y-0 right-0 w-[45%] bg-[radial-gradient(circle_at_top_right,rgba(34,211,238,0.35),transparent_55%),radial-gradient(circle_at_bottom_right,rgba(16,185,129,0.24),transparent_45%)]" />
<div className="relative flex flex-col gap-6 lg:flex-row lg:items-end lg:justify-between">
<div className="max-w-3xl">
<div className="text-sm font-semibold uppercase tracking-[0.2em] text-cyan-300">
{lang === "fa" ? "شروع ساده" : "Simple start"}
</div>
<h2 className="mt-4 text-4xl font-semibold leading-[1.1] tracking-[-0.05em] sm:text-5xl">
{content.cta.title}
</h2>
<p className="mt-4 text-lg leading-8 text-slate-300">{content.cta.description}</p>
</div>
<Button
asChild
className="h-14 rounded-full bg-white px-7 text-base font-semibold text-slate-950 hover:bg-slate-100"
>
<Link to={ctaTarget}>
{content.cta.button}
<ArrowRight className={cn("ms-2 h-4 w-4", lang === "fa" && "rotate-180")} />
</Link>
</Button>
</div>
</div>
</section>
</main>
</div>
</div>
)
}