first commit

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
root
2026-05-10 19:20:03 +00:00
parent 1050bb39ec
commit a3f08242fe
58 changed files with 5803 additions and 261 deletions

View File

@@ -0,0 +1,84 @@
"use client";
import { motion, useSpring, useTransform } from "framer-motion";
import { useEffect, useState } from "react";
type Stats = {
raisedUsd: number;
goalUsd: number;
donationCount: number;
uniqueDonors: number;
};
export function ProgressSection() {
const [stats, setStats] = useState<Stats | null>(null);
useEffect(() => {
let alive = true;
const load = async () => {
const res = await fetch("/api/public/stats", { cache: "no-store" });
if (!res.ok) return;
const data = await res.json();
if (alive) setStats(data);
};
load();
const id = setInterval(load, 30000);
return () => {
alive = false;
clearInterval(id);
};
}, []);
const goal = stats?.goalUsd ?? 250000;
const pct = stats ? Math.min(100, Math.round((stats.raisedUsd / goal) * 100)) : 0;
const spring = useSpring(pct, { stiffness: 120, damping: 20 });
const width = useTransform(spring, (v) => `${v}%`);
useEffect(() => {
spring.set(pct);
}, [pct, spring]);
return (
<section className="border-b border-white/10 bg-gradient-to-b from-[#030712] to-[#050b1f] py-16">
<div className="mx-auto max-w-6xl px-4 sm:px-6">
<div className="flex flex-col gap-8 lg:flex-row lg:items-end lg:justify-between">
<div>
<p className="text-xs uppercase tracking-[0.32em] text-slate-400">Grassroots meter</p>
<h2 className="mt-3 text-3xl font-semibold text-white sm:text-4xl">Momentum you can see</h2>
<p className="mt-3 max-w-xl text-slate-400">
Every dollar is a choice about whose voice counts. We publish aggregate totals so supporters can
feel the collective liftwithout gamifying human dignity.
</p>
</div>
<div className="grid grid-cols-2 gap-4 text-sm text-slate-200 sm:grid-cols-3">
<div className="rounded-2xl border border-white/10 bg-white/5 p-4">
<p className="text-xs uppercase tracking-wide text-slate-400">Raised</p>
<p className="mt-2 text-2xl font-semibold text-white">
{stats ? `$${stats.raisedUsd.toLocaleString(undefined, { maximumFractionDigits: 0 })}` : "—"}
</p>
</div>
<div className="rounded-2xl border border-white/10 bg-white/5 p-4">
<p className="text-xs uppercase tracking-wide text-slate-400">Donations</p>
<p className="mt-2 text-2xl font-semibold text-white">{stats?.donationCount ?? "—"}</p>
</div>
<div className="rounded-2xl border border-white/10 bg-white/5 p-4">
<p className="text-xs uppercase tracking-wide text-slate-400">Supporters</p>
<p className="mt-2 text-2xl font-semibold text-white">{stats?.uniqueDonors ?? "—"}</p>
</div>
</div>
</div>
<div className="mt-10">
<div className="flex items-center justify-between text-xs text-slate-400">
<span>$0</span>
<span>
Goal ${stats?.goalUsd?.toLocaleString() ?? "—"} (demo target via PUBLIC_CAMPAIGN_GOAL_USD)
</span>
</div>
<div className="mt-3 h-4 overflow-hidden rounded-full border border-white/10 bg-black/40">
<motion.div style={{ width }} className="h-full rounded-full bg-gradient-to-r from-sky-400 via-indigo-400 to-fuchsia-400" />
</div>
</div>
</div>
</section>
);
}