GRV-Summit-Site/components/home/Hero.tsx
kirukib cb404ec079
Some checks failed
Deploy to Cloudflare Workers (OpenNext) / deploy (push) Has been cancelled
Align site colors with GRV brand book palette.
Centralize primary, secondary, tertiary, and neutral tokens and apply them across theme variables and UI components.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-04 14:45:22 +03:00

141 lines
5.1 KiB
TypeScript

"use client";
import { useCallback, useEffect, useState } from "react";
import Link from "next/link";
import { ArrowRight } from "lucide-react";
import { site } from "@/content/site";
import { HeroGrantLine } from "@/components/home/HeroGrantLine";
import { LastYearWinnersScroll } from "@/components/home/LastYearWinnersScroll";
import { TopoCurvyExtend } from "@/components/brand/TopoCurvyExtend";
import { HeroTopographyBackground } from "@/components/home/HeroTopographyBackground";
import { HeroRiftParticles } from "@/components/home/HeroRiftParticles";
import { TopoProseSurface } from "@/components/layout/TopoProseSurface";
import { TopoSectionProvider } from "@/components/layout/TopoSectionContext";
import { ScrollReveal } from "@/components/motion/ScrollReveal";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
const INTRO_MS = 10000;
export function Hero() {
const [reduceMotion, setReduceMotion] = useState(false);
const [introPhase, setIntroPhase] = useState<"intro" | "settled" | "static">("intro");
const [heroHover, setHeroHover] = useState(false);
const [hoverPoint, setHoverPoint] = useState({ x: 50, y: 50 });
const handleHeroPointerMove = useCallback(
(e: React.MouseEvent<HTMLElement>) => {
const rect = e.currentTarget.getBoundingClientRect();
setHoverPoint({
x: ((e.clientX - rect.left) / rect.width) * 100,
y: ((e.clientY - rect.top) / rect.height) * 100,
});
setHeroHover(true);
},
[]
);
const handleHeroPointerLeave = useCallback(() => {
setHeroHover(false);
}, []);
useEffect(() => {
const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
const apply = () => {
const reduced = mq.matches;
setReduceMotion(reduced);
if (reduced) setIntroPhase("static");
};
apply();
mq.addEventListener("change", apply);
if (!mq.matches) {
const t = window.setTimeout(() => setIntroPhase("settled"), INTRO_MS);
return () => {
clearTimeout(t);
mq.removeEventListener("change", apply);
};
}
return () => mq.removeEventListener("change", apply);
}, []);
return (
<section
id="hero"
data-section-hero
className="section-white relative isolate min-h-[min(100svh,900px)] overflow-x-hidden overflow-y-visible bg-white"
onMouseMove={handleHeroPointerMove}
onMouseLeave={handleHeroPointerLeave}
>
<HeroTopographyBackground
introPhase={introPhase}
hoverActive={heroHover && !reduceMotion}
hoverX={hoverPoint.x}
hoverY={hoverPoint.y}
className="absolute inset-0"
/>
<TopoCurvyExtend />
<HeroRiftParticles
active={!reduceMotion}
className="pointer-events-none absolute inset-0 z-[15]"
/>
<TopoSectionProvider tone="light">
<div className="topo-content-layer topo-content-readable relative z-20 mx-auto flex min-h-[min(100svh,900px)] w-full max-w-6xl flex-col items-center justify-center px-4 py-24 text-center md:px-6">
<TopoProseSurface className="mx-auto flex w-full max-w-4xl flex-col items-center text-center">
<ScrollReveal immediate variant="fade-up" delay={0}>
<p className="text-xs font-semibold uppercase tracking-[0.2em] text-[#37a47a]/80 md:text-sm">
{site.dates.label} · {site.venue.address}
</p>
</ScrollReveal>
<ScrollReveal immediate variant="fade-up" delay={200}>
<h1
className={cn(
"rift-hero-heading rift-hero-title mt-6 font-display text-3xl font-bold leading-[1.05] tracking-tight text-[#30614c] sm:text-4xl md:text-5xl lg:text-6xl"
)}
>
<span className="font-wordmark block uppercase tracking-wide">
Great Rift Valley
</span>
<span className="mt-1 block text-[#37a47a]">Innovation Summit</span>
</h1>
</ScrollReveal>
<ScrollReveal immediate variant="fade-up" delay={400}>
<p className="mx-auto mt-6 max-w-2xl text-lg text-[#37a47a]/80 md:text-xl">
{site.tagline} Presented by {site.presentedBy}.
</p>
</ScrollReveal>
<ScrollReveal immediate variant="fade-up" delay={500}>
<div className="mt-8 flex flex-wrap items-center justify-center gap-3">
<Button
className="rounded-full bg-[#37a47a] px-8 text-[#ffffff] hover:bg-[#37a47a]/90"
asChild
>
<Link href={site.links.pitchApplyUrl}>
Register <ArrowRight className="size-4" />
</Link>
</Button>
<Button
variant="outline"
className="rounded-full border-[#37a47a]/30 bg-white/80 text-[#37a47a] backdrop-blur-sm"
asChild
>
<Link href="/payment">Get tickets</Link>
</Button>
</div>
<p className="mt-4 text-sm text-[#37a47a]/70">
<HeroGrantLine />
</p>
</ScrollReveal>
</TopoProseSurface>
<LastYearWinnersScroll variant="on-light" className="w-full max-w-5xl" />
</div>
</TopoSectionProvider>
</section>
);
}