Seed: event template (15 files)
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { ArrowRight, Ticket, Users, Calendar, Mic, Layers, Send, Mail, User } from "lucide-react";
|
||||
import { useSaasMutation } from "@/hooks/use-tygarun";
|
||||
import Header from "@/components/Header";
|
||||
import Footer from "@/components/Footer";
|
||||
|
||||
const speakers = [
|
||||
{ initials: "SK", name: "Sarah Kim", role: "VP Eng, Vercel", gradient: "from-indigo-500 to-cyan-500" },
|
||||
{ initials: "AM", name: "Alex Morgan", role: "CTO, Supabase", gradient: "from-purple-500 to-pink-500" },
|
||||
{ initials: "RJ", name: "Raj Joshi", role: "Staff Eng, Google", gradient: "from-cyan-500 to-emerald-500" },
|
||||
{ initials: "LP", name: "Lisa Park", role: "Design Lead, Figma", gradient: "from-amber-500 to-red-500" },
|
||||
{ initials: "TW", name: "Tom Walsh", role: "Creator, Bun", gradient: "from-pink-500 to-violet-500" },
|
||||
{ initials: "DN", name: "Diana Nguyen", role: "SRE Lead, Netflix", gradient: "from-emerald-500 to-indigo-500" },
|
||||
];
|
||||
|
||||
const sponsorTiers = [
|
||||
{ tier: "Platinum", names: ["CloudScale AI", "DevOps Hub"] },
|
||||
{ tier: "Gold", names: ["StackForge", "CodeVault", "DataPipe"] },
|
||||
{ tier: "Silver", names: ["GitSync", "EdgeNode", "APILayer", "DeployFast"] },
|
||||
{ tier: "Community", names: ["ReactConf", "JSNation"] },
|
||||
];
|
||||
|
||||
export default function IndexPage() {
|
||||
const [regName, setRegName] = useState("");
|
||||
const [regEmail, setRegEmail] = useState("");
|
||||
const { mutate: registerInterest, loading: registering } = useSaasMutation("scheduling", "/bookings");
|
||||
const { mutate: purchaseTicket, loading: purchasing } = useSaasMutation("event-ticketing", "/checkout");
|
||||
const [countdown, setCountdown] = useState({ days: 0, hours: 0, minutes: 0, seconds: 0 });
|
||||
useEffect(() => {
|
||||
const target = new Date("2026-06-18T09:00:00").getTime();
|
||||
const tick = () => {
|
||||
const now = Date.now();
|
||||
const diff = Math.max(0, target - now);
|
||||
setCountdown({
|
||||
days: Math.floor(diff / (1000 * 60 * 60 * 24)),
|
||||
hours: Math.floor((diff / (1000 * 60 * 60)) % 24),
|
||||
minutes: Math.floor((diff / (1000 * 60)) % 60),
|
||||
seconds: Math.floor((diff / 1000) % 60),
|
||||
});
|
||||
};
|
||||
tick();
|
||||
const id = setInterval(tick, 1000);
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-slate-950 text-white">
|
||||
<Header />
|
||||
|
||||
{/* Hero */}
|
||||
<section className="relative min-h-screen flex items-center justify-center overflow-hidden">
|
||||
<div className="absolute inset-0">
|
||||
<div className="absolute top-1/4 left-1/4 w-96 h-96 bg-indigo-500/30 rounded-full blur-3xl" />
|
||||
<div className="absolute bottom-1/4 right-1/4 w-80 h-80 bg-cyan-400/20 rounded-full blur-3xl" />
|
||||
<div className="absolute top-1/2 left-1/2 w-72 h-72 bg-purple-500/20 rounded-full blur-3xl -translate-x-1/2 -translate-y-1/2" />
|
||||
</div>
|
||||
<div className="relative z-10 text-center px-6 max-w-5xl mx-auto">
|
||||
<Badge variant="secondary" className="mb-6 bg-indigo-500/10 text-indigo-400 border-indigo-500/20">June 18–20, 2026</Badge>
|
||||
<h1 className="text-7xl font-black tracking-tight mb-6 bg-gradient-to-r from-white via-indigo-200 to-cyan-200 bg-clip-text text-transparent">DevForge 2026</h1>
|
||||
<p className="text-xl text-slate-300 mb-4 max-w-2xl mx-auto">The premier conference for developers, designers, and DevOps engineers building the future of the web.</p>
|
||||
<p className="text-slate-400 mb-8 flex items-center justify-center gap-2"><Calendar className="h-4 w-4" /> June 18–20, 2026 · The Apex Centre, San Francisco</p>
|
||||
|
||||
{/* Countdown */}
|
||||
<p className="text-sm text-slate-400 mb-4 animate-fade-up">Event starts in</p>
|
||||
<div className="grid grid-cols-4 gap-4 max-w-md mx-auto mb-8">
|
||||
{[
|
||||
{ label: "Days", value: countdown.days },
|
||||
{ label: "Hours", value: countdown.hours },
|
||||
{ label: "Minutes", value: countdown.minutes },
|
||||
{ label: "Seconds", value: countdown.seconds },
|
||||
].map((c) => (
|
||||
<div key={c.label} className="ring-1 ring-indigo-500/20 rounded-xl">
|
||||
<div className="animate-scale-in relative bg-gradient-to-b from-slate-800/80 to-slate-900/80 backdrop-blur border border-slate-700/50 rounded-xl p-4 text-center shadow-lg shadow-indigo-500/10 overflow-hidden" style={{ perspective: "300px" }}>
|
||||
<div className="absolute inset-0 bg-indigo-500/5 animate-pulse rounded-xl" />
|
||||
<div className="relative z-10 text-3xl sm:text-4xl font-black tabular-nums transition-all duration-500 text-white" style={{ transform: "rotateX(0deg)" }}>{String(c.value).padStart(2, "0")}</div>
|
||||
<div className="relative z-10 text-xs text-slate-400 uppercase tracking-wider mt-1">{c.label}</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Register Interest */}
|
||||
<form className="flex flex-col sm:flex-row gap-3 max-w-lg mx-auto mb-10" onSubmit={async (e) => { e.preventDefault(); if (!regName || !regEmail) return; try { await registerInterest({ name: regName, email: regEmail, event: "DevForge 2026" }); toast.success("Registered! We'll be in touch."); setRegName(""); setRegEmail(""); } catch { toast.error("Could not register. Please try again."); } }}>
|
||||
<div className="relative flex-1">
|
||||
<User className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-slate-500" />
|
||||
<Input placeholder="Your name" value={regName} onChange={(e) => setRegName(e.target.value)} className="pl-9 bg-slate-800/60 border-slate-700/50 text-white placeholder:text-slate-500 focus:border-indigo-500" />
|
||||
</div>
|
||||
<div className="relative flex-1">
|
||||
<Mail className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-slate-500" />
|
||||
<Input type="email" placeholder="Email address" value={regEmail} onChange={(e) => setRegEmail(e.target.value)} className="pl-9 bg-slate-800/60 border-slate-700/50 text-white placeholder:text-slate-500 focus:border-indigo-500" />
|
||||
</div>
|
||||
<Button type="submit" size="sm" disabled={registering} className="bg-indigo-600 hover:bg-indigo-500 active:scale-[0.98] text-white px-6"><Send className="h-4 w-4 mr-2" />{registering ? "Registering…" : "Register"}</Button>
|
||||
</form>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<Button asChild size="lg" className="bg-indigo-600 hover:bg-indigo-500 active:scale-[0.98] text-white text-lg px-8">
|
||||
<Link to="/#tickets"><Ticket className="h-5 w-5 mr-2" />Get Tickets</Link>
|
||||
</Button>
|
||||
<Button asChild variant="outline" size="lg" className="border-slate-700 text-slate-200 hover:bg-slate-800 active:scale-[0.98] text-lg px-8">
|
||||
<Link to="/schedule">View Schedule<ArrowRight className="h-5 w-5 ml-2" /></Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Stats */}
|
||||
<section className="py-24 border-y border-slate-800">
|
||||
<div className="mx-auto max-w-5xl px-6 grid grid-cols-2 md:grid-cols-4 gap-8 text-center">
|
||||
{[
|
||||
{ icon: Mic, value: "48+", label: "Speakers" },
|
||||
{ icon: Layers, value: "24", label: "Workshops" },
|
||||
{ icon: Users, value: "2,000+", label: "Attendees" },
|
||||
{ icon: Calendar, value: "3", label: "Days" },
|
||||
].map((s, i) => (
|
||||
<div key={i}>
|
||||
<s.icon className="h-6 w-6 text-indigo-400 mx-auto mb-2" />
|
||||
<div className="text-3xl font-black text-white">{s.value}</div>
|
||||
<div className="text-sm text-slate-400">{s.label}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Featured Speakers */}
|
||||
<section className="py-24">
|
||||
<div className="mx-auto max-w-6xl px-6">
|
||||
<div className="text-center mb-16">
|
||||
<h2 className="text-4xl font-black tracking-tight mb-4 animate-fade-up">Featured Speakers</h2>
|
||||
<p className="text-slate-400 max-w-xl mx-auto">Industry leaders and open-source pioneers sharing cutting-edge insights.</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-8 stagger">
|
||||
{speakers.map((sp, i) => (
|
||||
<Link key={i} to="/speakers" className="group text-center hover:-translate-y-1 hover:shadow-xl transition-all duration-300">
|
||||
<div className={`w-24 h-24 mx-auto mb-4 rounded-full bg-gradient-to-br \${sp.gradient} flex items-center justify-center text-xl font-bold text-white ring-2 ring-offset-2 ring-offset-slate-950 ring-indigo-500/50 group-hover:scale-110 transition-transform`}>
|
||||
{sp.initials}
|
||||
</div>
|
||||
<div className="font-semibold text-white group-hover:text-indigo-400 transition-colors">{sp.name}</div>
|
||||
<div className="text-sm text-slate-400">{sp.role}</div>
|
||||
<Badge className="mt-2 text-[10px] bg-indigo-500/20 text-indigo-300 border-0">2 talks</Badge>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
<div className="text-center mt-12">
|
||||
<Button asChild variant="outline" className="border-slate-700 text-slate-200 hover:bg-slate-800 active:scale-[0.98]">
|
||||
<Link to="/speakers">View All Speakers<ArrowRight className="h-4 w-4 ml-2" /></Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Sponsors */}
|
||||
<section className="py-24 bg-slate-900/50">
|
||||
<div className="mx-auto max-w-6xl px-6">
|
||||
<h2 className="text-4xl font-black tracking-tight text-center mb-16 animate-fade-up">Our Sponsors</h2>
|
||||
{sponsorTiers.map((tier) => (
|
||||
<div key={tier.tier} className="mb-12">
|
||||
<h3 className="text-sm font-semibold text-indigo-400 uppercase tracking-wider text-center mb-6">{tier.tier}</h3>
|
||||
<div className="flex flex-wrap justify-center gap-6">
|
||||
{tier.names.map((name, i) => (
|
||||
<div key={i} className={`flex items-center justify-center rounded-lg border border-slate-800 bg-slate-900/50 px-8 py-4 text-slate-400 hover:border-indigo-500 hover:text-white hover:scale-110 transition-all duration-300 grayscale hover:grayscale-0 \${tier.tier === "Platinum" ? "text-lg font-semibold min-w-[200px] hover:drop-shadow-[0_0_8px_rgba(99,102,241,0.3)]" : tier.tier === "Gold" ? "min-w-[160px]" : "min-w-[120px] text-sm"}`}>
|
||||
{name}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<div className="text-center">
|
||||
<Button variant="ghost" className="mt-8 text-slate-400 hover:text-white">Become a Sponsor <ArrowRight className="ml-2 h-4 w-4" /></Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Ticket Pricing */}
|
||||
<section id="tickets" className="py-24">
|
||||
<div className="mx-auto max-w-5xl px-6">
|
||||
<h2 className="text-4xl font-black tracking-tight text-center mb-4 animate-fade-up">Get Your Ticket</h2>
|
||||
<p className="text-slate-400 text-center max-w-xl mx-auto mb-12">Choose the pass that fits your needs. All tickets include 3 days of content.</p>
|
||||
<div className="grid md:grid-cols-3 gap-6 stagger">
|
||||
{[
|
||||
{ name: "Early Bird", price: "$299", features: ["All keynotes & talks", "Coffee & lunch included", "Conference swag bag"], accent: "border-slate-700" },
|
||||
{ name: "Regular", price: "$499", features: ["Everything in Early Bird", "Workshop access", "Networking lounge"], accent: "border-indigo-500 ring-1 ring-indigo-500/30" },
|
||||
{ name: "VIP", price: "$899", features: ["Everything in Regular", "Speaker dinner invite", "Priority front-row seating"], accent: "border-cyan-500" },
|
||||
].map((t, i) => (
|
||||
<Card key={i} className={`backdrop-blur-sm bg-slate-800/80 border-slate-700/50 \${t.accent} hover:-translate-y-1 hover:shadow-xl transition-all duration-300`}>
|
||||
<CardContent className="p-8 text-center">
|
||||
<div className="flex items-center justify-center gap-2 mb-2">
|
||||
<div className="text-sm font-semibold text-indigo-400 uppercase tracking-wider">{t.name}</div>
|
||||
{i === 2 && <Badge className="bg-amber-500/20 text-amber-300 border-0 text-[10px]">Limited</Badge>}
|
||||
</div>
|
||||
<div className="text-4xl font-black text-white mb-6">{t.price}</div>
|
||||
<ul className="text-sm text-slate-400 space-y-2 mb-8">
|
||||
{t.features.map((f, j) => <li key={j}>{f}</li>)}
|
||||
</ul>
|
||||
<Button disabled={purchasing} onClick={async () => { const amount = Math.round((parseFloat(String(t.price).replace(/[^0-9.]/g, "")) || 0) * 100); try { const res = await purchaseTicket({ plan: t.name, amount }); if (res?.url && String(res.url).indexOf("#") !== 0) { window.location.href = res.url; return; } toast.success(`\${t.name} ticket selected`); } catch { toast.error("Checkout unavailable. Please try again."); } }} className="w-full bg-indigo-600 hover:bg-indigo-500 active:scale-[0.98] text-white"><Ticket className="h-4 w-4 mr-2" />{purchasing ? "Processing…" : "Select"}</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
<p className="text-center text-sm text-slate-500 mt-6">Group discount available for 5+ tickets. Contact us for details.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Newsletter CTA */}
|
||||
<section className="py-24">
|
||||
<div className="mx-auto max-w-3xl px-6 text-center">
|
||||
<h2 className="text-4xl font-black tracking-tight mb-4 animate-fade-up">Stay in the Loop</h2>
|
||||
<p className="text-slate-400 mb-8 max-w-lg mx-auto">Subscribe for speaker announcements, schedule updates, and exclusive early-bird pricing.</p>
|
||||
<form onSubmit={(e) => { e.preventDefault(); toast.success("Subscribed! You'll get event updates."); e.currentTarget.reset(); }} className="flex gap-3 max-w-md mx-auto">
|
||||
<Input type="email" required placeholder="your@email.com" className="bg-slate-900 border-slate-700 text-white placeholder:text-slate-500 flex-1" />
|
||||
<Button type="submit" className="bg-indigo-600 hover:bg-indigo-500 active:scale-[0.98] text-white"><Send className="h-4 w-4 mr-2" />Subscribe</Button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user