ui(support): compact tabbed support page with friendlier /support alias

This commit is contained in:
SkateSpots 2026-10-30 17:13:25 +07:00
parent a1b069da13
commit f2787d79cf
3 changed files with 289 additions and 308 deletions

View file

@ -194,6 +194,8 @@ export function AppRouter() {
<Route path="/license" element={<LicensePage />} /> <Route path="/license" element={<LicensePage />} />
<Route path="/privacy" element={<PrivacyPage />} /> <Route path="/privacy" element={<PrivacyPage />} />
<Route path="/supporters" element={<SupportersPage />} /> <Route path="/supporters" element={<SupportersPage />} />
{/* Friendly alias: people naturally type /support. */}
<Route path="/support" element={<Navigate to="/supporters" replace />} />
<Route path="/donate" element={<DonatePage />} /> <Route path="/donate" element={<DonatePage />} />
{/* Marketplace */} {/* Marketplace */}
<Route path="/marketplace-listings" element={<MarketplacePage />} /> <Route path="/marketplace-listings" element={<MarketplacePage />} />

View file

@ -1,11 +1,20 @@
import { useTranslation } from '@/contexts/language'; import { useTranslation } from '@/contexts/language';
import { cn } from '@/lib/utils';
/** /**
* "Ways to support" — three purpose-first cards; each scrolls to its rail by id * "Ways to support" — three purpose-first cards; each scrolls to its rail by id
* (#support-lightning / #support-silent / #support-angor), so it works anywhere * (#support-lightning / #support-silent / #support-angor), so it works anywhere
* those anchors exist (/supporters and /donate). * those anchors exist (/supporters and /donate).
*/ */
export function WaysToSupport({ className }: { className?: string }) { export function WaysToSupport({
className,
active,
onSelect,
}: {
className?: string;
active?: string;
onSelect?: (id: string) => void;
}) {
const { t } = useTranslation(); const { t } = useTranslation();
const ways = [ const ways = [
{ id: 'support-lightning', emoji: '⚡', title: t('walletUi.supporters.wayLightningTitle'), desc: t('walletUi.supporters.wayLightningDesc') }, { id: 'support-lightning', emoji: '⚡', title: t('walletUi.supporters.wayLightningTitle'), desc: t('walletUi.supporters.wayLightningDesc') },
@ -13,16 +22,29 @@ export function WaysToSupport({ className }: { className?: string }) {
{ id: 'support-angor', emoji: '⛓', title: t('walletUi.supporters.wayAngorTitle'), desc: t('walletUi.supporters.wayAngorDesc') }, { id: 'support-angor', emoji: '⛓', title: t('walletUi.supporters.wayAngorTitle'), desc: t('walletUi.supporters.wayAngorDesc') },
]; ];
return ( return (
<div className={`grid grid-cols-1 gap-3 sm:grid-cols-3 ${className ?? ''}`}> <div className={`grid grid-cols-3 gap-2 ${className ?? ''}`}>
{ways.map((w) => ( {ways.map((w) => (
<button <button
key={w.id} key={w.id}
onClick={() => document.getElementById(w.id)?.scrollIntoView({ behavior: 'smooth', block: 'start' })} type="button"
className="min-h-0 min-w-0 rounded-xl border border-white/10 bg-black/60 p-4 text-left transition-colors hover:border-[#ccff00]/40 hover:bg-white/5" aria-pressed={active === w.id}
onClick={() => {
if (onSelect) {
onSelect(w.id);
return;
}
document.getElementById(w.id)?.scrollIntoView({ behavior: 'smooth', block: 'start' });
}}
className={cn(
'min-h-0 min-w-0 rounded-xl border p-2.5 text-left transition-colors sm:p-3',
active === w.id
? 'border-[#ccff00]/60 bg-[#ccff00]/10'
: 'border-white/10 bg-black/60 hover:border-[#ccff00]/40 hover:bg-white/5',
)}
> >
<span className="text-2xl">{w.emoji}</span> <span className="text-xl">{w.emoji}</span>
<p className="mt-2 text-sm font-black uppercase text-white">{w.title}</p> <p className="mt-1 text-[10px] font-black uppercase leading-tight text-white sm:mt-2 sm:text-xs">{w.title}</p>
<p className="mt-1 text-xs text-gray-400">{w.desc}</p> <p className="mt-0.5 hidden text-[10px] leading-snug text-gray-400 sm:block">{w.desc}</p>
</button> </button>
))} ))}
</div> </div>

View file

@ -20,6 +20,7 @@ import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea'; import { Textarea } from '@/components/ui/textarea';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
// Only count support received from this point (the project's public launch era). // Only count support received from this point (the project's public launch era).
@ -27,7 +28,7 @@ import { Button } from '@/components/ui/button';
// platform zap is already ≥ 2026-01, so this doesn't currently trim the list — // platform zap is already ≥ 2026-01, so this doesn't currently trim the list —
// the visible cap below is what keeps it short. // the visible cap below is what keeps it short.
const SUPPORTERS_SINCE = Math.floor(Date.UTC(2025, 11, 1) / 1000); // 2025-12-01 const SUPPORTERS_SINCE = Math.floor(Date.UTC(2025, 11, 1) / 1000); // 2025-12-01
const VISIBLE_LIMIT = 21; const VISIBLE_LIMIT = 12;
/** npub → hex pubkey (useAuthor queries relays by HEX authors). */ /** npub → hex pubkey (useAuthor queries relays by HEX authors). */
function npubToHex(npub?: string): string | undefined { function npubToHex(npub?: string): string | undefined {
@ -261,15 +262,15 @@ function SectionHeader({
color?: string; color?: string;
}) { }) {
return ( return (
<div className="mb-6 md:mb-8"> <div className="mb-3 md:mb-4">
<div className="flex items-center gap-3 mb-2"> <div className="mb-1.5 flex items-center gap-2.5">
<Icon className="h-5 w-5 flex-shrink-0" style={{ color }} /> <Icon className="h-4 w-4 flex-shrink-0" style={{ color }} />
<h2 className="text-2xl md:text-3xl font-black uppercase tracking-wide" style={{ color }}> <h2 className="text-lg font-black uppercase tracking-wide md:text-xl" style={{ color }}>
{title} {title}
</h2> </h2>
<div className="flex-1 h-px" style={{ background: `linear-gradient(to right, ${color}40, transparent)` }} /> <div className="h-px flex-1" style={{ background: `linear-gradient(to right, ${color}40, transparent)` }} />
</div> </div>
{subtitle && <p className="text-gray-400 text-sm ml-8">{subtitle}</p>} {subtitle && <p className="ml-7 text-xs text-gray-400">{subtitle}</p>}
</div> </div>
); );
} }
@ -547,19 +548,6 @@ function SupporterRow({ rank, entry }: { rank: number; entry: SupporterEntry })
); );
} }
// ─── Placeholder card (empty slot) ───────────────────────────────────────────
function PlaceholderCard({ label }: { label: string }) {
return (
<div className="flex flex-col items-center gap-3 p-5 rounded-xl border border-dashed border-white/10 text-center opacity-40">
<div className="w-16 h-16 rounded-2xl border border-dashed border-white/20 flex items-center justify-center">
<span className="text-2xl">?</span>
</div>
<p className="text-xs text-gray-600 font-medium">{label}</p>
</div>
);
}
// ─── Main page ──────────────────────────────────────────────────────────────── // ─── Main page ────────────────────────────────────────────────────────────────
export default function SupportersPage() { export default function SupportersPage() {
@ -571,6 +559,8 @@ export default function SupportersPage() {
const totalUsd = useSatsToUsd(allSats); const totalUsd = useSatsToUsd(allSats);
const { data: stats } = useGrowthStats(); const { data: stats } = useGrowthStats();
const [showAll, setShowAll] = useState(false); const [showAll, setShowAll] = useState(false);
const [tab, setTab] = useState<'support' | 'backers' | 'community' | 'grants'>('support');
const [rail, setRail] = useState<'support-lightning' | 'support-silent' | 'support-angor'>('support-lightning');
// One ranked wall: Angor backers + Lightning zaps to the project, merged by npub. // One ranked wall: Angor backers + Lightning zaps to the project, merged by npub.
const supporters = useMemo<SupporterEntry[]>(() => { const supporters = useMemo<SupporterEntry[]>(() => {
@ -652,97 +642,106 @@ export default function SupportersPage() {
return ( return (
<> <>
<div className="container max-w-4xl px-4 py-12 md:py-16 space-y-16"> <div className="container max-w-4xl space-y-6 px-4 py-8 md:py-10">
{/* ── Hero ── */} {/* ── Hero ── */}
<div className="text-center"> <div className="text-center">
<div className="text-6xl mb-4">⚡</div> <h1 className="text-4xl font-black uppercase leading-none md:text-5xl">
<h1 className="text-5xl md:text-6xl font-black uppercase mb-3 leading-none">
<span className="neon-red">{t('walletUi.supporters.our')}</span>{' '} <span className="neon-red">{t('walletUi.supporters.our')}</span>{' '}
<span className="neon-lime">{t('walletUi.supporters.community')}</span> <span className="neon-lime">{t('walletUi.supporters.community')}</span>
</h1> </h1>
<p className="text-gray-400 max-w-lg mx-auto text-base mb-8"> <p className="mx-auto mt-2 max-w-xl text-sm text-gray-400">
{t('walletUi.supporters.heroDesc')} {t('walletUi.supporters.heroDesc')}
</p> </p>
<div className="mt-5 flex flex-wrap items-center justify-center gap-2">
<a <a
href={ANGOR_PROJECT_URL} href={ANGOR_PROJECT_URL}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="inline-flex items-center gap-2 px-6 py-3 rounded-full bg-gradient-to-r from-[#ff0040] to-[#ff6600] text-white font-black uppercase text-sm hover:opacity-90 transition-all shadow-lg shadow-[#ff0040]/30" className="inline-flex items-center gap-2 rounded-full bg-gradient-to-r from-[#ff0040] to-[#ff6600] px-5 py-2.5 text-xs font-black uppercase text-white shadow-lg shadow-[#ff0040]/25 transition-opacity hover:opacity-90"
> >
<Zap className="h-4 w-4" /> <Zap className="h-4 w-4" />
{t('walletUi.supporters.backAngor')} {t('walletUi.supporters.backAngor')}
<ExternalLink className="h-3.5 w-3.5 opacity-70" /> <ExternalLink className="h-3 w-3 opacity-70" />
</a> </a>
<Link <Link
to="/donate" to="/donate"
className="mt-5 inline-flex items-center gap-1.5 text-xs font-bold text-[#ccff00]/80 transition-colors hover:text-[#ccff00]" className="inline-flex items-center gap-1.5 rounded-full border border-white/15 px-4 py-2.5 text-xs font-bold text-[#ccff00]/80 transition-colors hover:border-[#ccff00]/40 hover:text-[#ccff00]"
> >
{t('walletUi.supporters.donatePageLink')} → {t('walletUi.supporters.donatePageLink')} →
</Link> </Link>
</div> </div>
<div className="mt-4 flex flex-wrap items-center justify-center gap-x-3 gap-y-1 text-[11px] text-gray-500">
{/* ── 1. Support ── */} <span>{supporters.length.toLocaleString()} {t('walletUi.supporters.backers')}</span>
<section> <span aria-hidden="true">·</span>
<SectionHeader <span>{allSats.toLocaleString()} sats</span>
icon={Zap} {typeof totalUsd === 'number' && (
title={t('walletUi.supporters.support')} <>
subtitle={t('walletUi.supporters.supportDesc')} <span aria-hidden="true">·</span>
color="#f7931a" <span>≈ ${totalUsd.toFixed(2)}</span>
/> </>
)}
<WaysToSupport className="mb-4" /> </div>
{/* Lightning rail — the in-app way to chip in (zap publicly or pay quietly). */}
<div id="support-lightning" className="scroll-mt-24">
<SupportSkateSpots className="mt-4" />
</div> </div>
{/* Silent payments — private on-chain (and Lightning) via a BIP-353 name. */} {/* ── Compact navigation ── */}
<div id="support-silent" className="scroll-mt-24"> <Tabs
<SilentPaymentsCard className="mt-4" /> value={tab}
</div> onValueChange={(value) => setTab(value as 'support' | 'backers' | 'community' | 'grants')}
<div id="support-angor" className="scroll-mt-24"> >
<AngorProjectCard count={supporters.length} className="mt-4" /> <TabsList className="grid h-auto w-full grid-cols-4 gap-1 rounded-2xl border border-white/10 bg-black/70 p-1">
</div> {[
</section> { value: 'support', label: t('walletUi.supporters.support') },
{ value: 'backers', label: t('walletUi.supporters.backers') },
{ value: 'community', label: t('walletUi.supporters.community') },
{ value: 'grants', label: t('walletUi.supporters.grantsSection') },
].map((item) => (
<TabsTrigger
key={item.value}
value={item.value}
className="h-auto min-h-10 whitespace-normal rounded-xl px-1.5 py-2 text-center text-[9px] font-black uppercase leading-tight tracking-wide data-[state=active]:bg-[#ccff00] data-[state=active]:text-black data-[state=active]:shadow-none sm:px-2 sm:text-[11px]"
>
{item.label}
</TabsTrigger>
))}
</TabsList>
{/* ── 2. Bitcoin grantmakers ── */} {/* ── Support rails ── */}
<section> <TabsContent value="support" className="space-y-4 pt-4">
<SectionHeader <div>
icon={Handshake} <h2 className="text-xl font-black uppercase text-white">{t('walletUi.supporters.support')}</h2>
title={t('walletUi.supporters.grantsSection')} <p className="mt-0.5 text-sm text-gray-400">{t('walletUi.supporters.donateDesc')}</p>
subtitle={t('walletUi.supporters.grantsSectionDesc')} </div>
color="#f7931a" <WaysToSupport active={rail} onSelect={(id) => setRail(id as typeof rail)} />
/> <div id={rail} className="scroll-mt-24">
<GrantmakerForm /> {rail === 'support-lightning' && <SupportSkateSpots />}
</section> {rail === 'support-silent' && <SilentPaymentsCard />}
{rail === 'support-angor' && <AngorProjectCard count={supporters.length} />}
</div>
{/* ── 3. What your support pays for (words only) ── */} <section className="pt-1">
<section>
<SectionHeader <SectionHeader
icon={Heart} icon={Heart}
title={t('walletUi.supporters.paysFor')} title={t('walletUi.supporters.paysFor')}
subtitle={t('walletUi.supporters.paysForDesc')} subtitle={t('walletUi.supporters.paysForDesc')}
color="#22d3ee" color="#22d3ee"
/> />
<div className="grid grid-cols-2 sm:grid-cols-3 gap-3"> <div className="grid grid-cols-2 gap-2 sm:grid-cols-3">
{PAYS_FOR.map(({ icon: Icon, key, desc }) => ( {PAYS_FOR.map(({ icon: Icon, key, desc }) => (
<div <div key={key} className="flex items-start gap-2 rounded-xl border border-white/10 bg-black/60 px-3 py-2">
key={key} <Icon className="mt-0.5 h-3.5 w-3.5 flex-shrink-0 text-[#22d3ee]" />
className="flex items-start gap-3 rounded-xl border border-white/10 bg-black/60 px-4 py-3"
>
<Icon className="mt-0.5 h-4 w-4 flex-shrink-0 text-[#22d3ee]" />
<div className="min-w-0"> <div className="min-w-0">
<span className="text-sm font-medium text-white">{t(key)}</span> <span className="text-xs font-medium text-white">{t(key)}</span>
<p className="text-[11px] text-gray-500">{t(desc)}</p> <p className="text-[10px] leading-snug text-gray-500">{t(desc)}</p>
</div> </div>
</div> </div>
))} ))}
</div> </div>
</section> </section>
</TabsContent>
{/* ── 3. Impact so far (what the community built) ── */} {/* ── Backers, impact and tiers ── */}
<TabsContent value="backers" className="space-y-5 pt-4">
{impact.length > 0 && ( {impact.length > 0 && (
<section> <section>
<SectionHeader <SectionHeader
@ -751,16 +750,16 @@ export default function SupportersPage() {
subtitle={t('walletUi.supporters.impactDesc')} subtitle={t('walletUi.supporters.impactDesc')}
color="#ccff00" color="#ccff00"
/> />
<div className="grid grid-cols-2 sm:grid-cols-3 gap-3"> <div className="grid grid-cols-3 gap-2 sm:grid-cols-6">
{impact.map(({ key, value }) => ( {impact.map(({ key, value }) => (
<div key={key} className="rounded-xl border border-white/10 bg-black/60 px-4 py-3 text-center"> <div key={key} className="rounded-xl border border-white/10 bg-black/60 px-2 py-2.5 text-center">
<div className="text-2xl font-black text-[#ccff00]">{value.toLocaleString()}</div> <div className="text-lg font-black text-[#ccff00]">{value.toLocaleString()}</div>
<div className="text-xs text-gray-400">{t(key)}</div> <div className="truncate text-[10px] text-gray-400">{t(key)}</div>
</div> </div>
))} ))}
</div> </div>
<p className="mt-4 text-center text-xs text-gray-500"> <p className="mt-2 text-center text-[11px] text-gray-500">
<Link to="/stats" className="text-[#ccff00]/70 underline transition-colors hover:text-[#ccff00]"> <Link to="/stats" className="text-[#ccff00]/70 underline underline-offset-2 hover:text-[#ccff00]">
{t('walletUi.supporters.impactSeeStats')} {t('walletUi.supporters.impactSeeStats')}
</Link> </Link>
{' · '} {' · '}
@ -769,7 +768,6 @@ export default function SupportersPage() {
</section> </section>
)} )}
{/* ── 4. Supporters (Angor + Lightning zaps) ── */}
<section> <section>
<SectionHeader <SectionHeader
icon={Zap} icon={Zap}
@ -777,19 +775,19 @@ export default function SupportersPage() {
subtitle={t('walletUi.supporters.backersDesc')} subtitle={t('walletUi.supporters.backersDesc')}
color="#22d3ee" color="#22d3ee"
/> />
{supporters.length > 0 ? ( {supporters.length > 0 ? (
<> <>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-1.5">
{(showAll ? supporters : supporters.slice(0, VISIBLE_LIMIT)).map((entry, i) => ( {(showAll ? supporters : supporters.slice(0, VISIBLE_LIMIT)).map((entry, i) => (
<SupporterRow key={entry.key} rank={i + 1} entry={entry} /> <SupporterRow key={entry.key} rank={i + 1} entry={entry} />
))} ))}
</div> </div>
{supporters.length > VISIBLE_LIMIT && ( {supporters.length > VISIBLE_LIMIT && (
<div className="mt-3 text-center"> <div className="mt-2 text-center">
<button <button
type="button"
onClick={() => setShowAll((v) => !v)} onClick={() => setShowAll((v) => !v)}
className="min-h-0 min-w-0 text-xs font-bold uppercase tracking-wide text-[#22d3ee]/80 transition-colors hover:text-[#22d3ee]" className="min-h-0 min-w-0 text-[11px] font-bold uppercase tracking-wide text-[#22d3ee]/80 transition-colors hover:text-[#22d3ee]"
> >
{showAll {showAll
? t('walletUi.supporters.showLess') ? t('walletUi.supporters.showLess')
@ -797,47 +795,62 @@ export default function SupportersPage() {
</button> </button>
</div> </div>
)} )}
<p className="mt-3 text-center text-xs text-gray-400">
<p className="mt-4 text-center text-sm text-gray-400">
{t('walletUi.supporters.supportersTotals', { {t('walletUi.supporters.supportersTotals', {
count: supporters.length, count: supporters.length,
angor: BACKERS_TOTAL_SATS.toLocaleString(), angor: BACKERS_TOTAL_SATS.toLocaleString(),
zap: zapTotal.toLocaleString(), zap: zapTotal.toLocaleString(),
})} })}
{typeof totalUsd === 'number' && ( {typeof totalUsd === 'number' && <span className="text-gray-500"> · ≈ ${totalUsd.toFixed(2)}</span>}
<span className="text-gray-500"> · ≈ ${totalUsd.toFixed(2)}</span>
)}
</p>
<p className="mt-2 text-center text-xs text-gray-600">
{t('walletUi.supporters.quietNote')}
</p> </p>
<p className="mt-1 text-center text-[11px] text-gray-600">{t('walletUi.supporters.quietNote')}</p>
{latestAt > 0 && ( {latestAt > 0 && (
<p className="mt-1 text-center text-[11px] text-gray-600"> <p className="mt-0.5 text-center text-[10px] text-gray-600">
{t('walletUi.supporters.updatedAt', { {t('walletUi.supporters.updatedAt', { when: formatDistanceToNow(new Date(latestAt * 1000), { addSuffix: true }) })}
when: formatDistanceToNow(new Date(latestAt * 1000), { addSuffix: true }),
})}
</p> </p>
)} )}
<TierLadder supporters={supporters} /> <TierLadder supporters={supporters} />
</> </>
) : ( ) : (
<div className="rounded-xl border border-dashed border-[#22d3ee]/20 p-8 text-center"> <div className="rounded-xl border border-dashed border-[#22d3ee]/20 p-6 text-center">
<Zap className="h-10 w-10 mx-auto mb-3 text-[#22d3ee]/30" /> <Zap className="mx-auto mb-2 h-8 w-8 text-[#22d3ee]/30" />
<p className="text-gray-500 text-sm mb-1">{t('walletUi.supporters.beFirstBacker')}</p> <p className="mb-1 text-sm text-gray-500">{t('walletUi.supporters.beFirstBacker')}</p>
<a <a href={ANGOR_PROJECT_URL} target="_blank" rel="noopener noreferrer" className="inline-flex items-center gap-1.5 text-xs font-bold text-[#22d3ee]/80 hover:text-[#22d3ee]">
href={ANGOR_PROJECT_URL} <ExternalLink className="h-3 w-3" /> {t('walletUi.supporters.backAngor')}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1.5 text-xs font-bold text-[#22d3ee]/80 hover:text-[#22d3ee] transition-colors"
>
<ExternalLink className="h-3 w-3" />
{t('walletUi.supporters.backAngor')}
</a> </a>
</div> </div>
)} )}
</section> </section>
</TabsContent>
{/* ── Community, mission, collaborators, partners, friends ── */}
<TabsContent value="community" className="space-y-6 pt-4">
<section className="rounded-2xl border border-[#ff0040]/25 bg-black/70 p-5">
<div className="flex items-center justify-center gap-2">
<Heart className="h-5 w-5 text-[#ff0040]" />
<h2 className="text-center text-lg font-black uppercase text-white">
{t('walletUi.supporters.whyTitle1')}{' '}
<span className="neon-red">{t('walletUi.supporters.whyTitle2')}</span>
</h2>
</div>
<p className="mx-auto mt-2 max-w-2xl text-center text-xs leading-relaxed text-gray-400">
{t('walletUi.supporters.whyDesc')}
</p>
<div className="mt-4 grid grid-cols-1 gap-2 sm:grid-cols-3">
{[
{ emoji: '🛹', title: t('walletUi.supporters.why1Title'), desc: t('walletUi.supporters.why1Desc') },
{ emoji: '⚡', title: t('walletUi.supporters.why2Title'), desc: t('walletUi.supporters.why2Desc') },
{ emoji: '🌍', title: t('walletUi.supporters.why3Title'), desc: t('walletUi.supporters.why3Desc') },
].map(({ emoji, title, desc }) => (
<div key={title} className="rounded-xl border border-white/10 bg-white/[0.03] p-3 text-center">
<div className="text-2xl">{emoji}</div>
<p className="mt-1 text-xs font-bold">{title}</p>
<p className="mt-0.5 text-[11px] text-gray-500">{desc}</p>
</div>
))}
</div>
</section>
{/* ── 6. Collaborators ── */}
<section> <section>
<SectionHeader <SectionHeader
icon={Users} icon={Users}
@ -845,124 +858,68 @@ export default function SupportersPage() {
subtitle={t('walletUi.supporters.collaboratorsDesc')} subtitle={t('walletUi.supporters.collaboratorsDesc')}
color="#ff0040" color="#ff0040"
/> />
{COLLABORATORS.length > 0 ? ( {COLLABORATORS.length > 0 ? (
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3"> <div className="grid grid-cols-1 gap-2 sm:grid-cols-2">
{COLLABORATORS.map((c) => ( {COLLABORATORS.map((c) => <CollaboratorCard key={c.name} collab={c} />)}
<CollaboratorCard key={c.name} collab={c} />
))}
</div> </div>
) : ( ) : (
<div className="rounded-xl border border-dashed border-[#ff0040]/20 p-8 text-center"> <div className="rounded-xl border border-dashed border-[#ff0040]/20 p-5 text-center">
<Users className="h-10 w-10 mx-auto mb-3 text-[#ff0040]/30" /> <Users className="mx-auto mb-2 h-8 w-8 text-[#ff0040]/30" />
<p className="text-gray-500 text-sm mb-1">{t('walletUi.supporters.wantCollaborate')}</p> <p className="mb-1 text-sm text-gray-500">{t('walletUi.supporters.wantCollaborate')}</p>
<p className="text-xs text-gray-600 mb-4">{t('walletUi.supporters.wantCollaborateDesc')}</p> <p className="mb-3 text-xs text-gray-600">{t('walletUi.supporters.wantCollaborateDesc')}</p>
<a <a href="https://nostrhub.io/naddr1qvzqqqrhnypzqg88e9f588nx7wyz4wt0ura23w3yd4hmztqrkr95utwyvgachjepqyd8wumn8ghj7emfwsh8x6rpddjhxur9v9ex2tnyd9uj7qq22d4kzar92dcx7arnhyhdwn" target="_blank" rel="noopener noreferrer" className="inline-flex items-center gap-1.5 text-xs font-bold text-[#ff0040]/70 hover:text-[#ff0040]">
href="https://nostrhub.io/naddr1qvzqqqrhnypzqg88e9f588nx7wyz4wt0ura23w3yd4hmztqrkr95utwyvgachjepqyd8wumn8ghj7emfwsh8x6rpddjhxur9v9ex2tnyd9uj7qq22d4kzar92dcx7arnhyhdwn" <ExternalLink className="h-3 w-3" /> {t('walletUi.supporters.viewNostrHub')}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1.5 text-xs font-bold text-[#ff0040]/70 hover:text-[#ff0040] transition-colors"
>
<ExternalLink className="h-3 w-3" />
{t('walletUi.supporters.viewNostrHub')}
</a> </a>
</div> </div>
)} )}
</section> </section>
{/* ── 7. Partners ── */}
<section> <section>
<SectionHeader <SectionHeader icon={Handshake} title={t('walletUi.supporters.partners')} subtitle={t('walletUi.supporters.partnersDesc')} color="#ff6600" />
icon={Handshake}
title={t('walletUi.supporters.partners')}
subtitle={t('walletUi.supporters.partnersDesc')}
color="#ff6600"
/>
{PARTNERS.length > 0 ? ( {PARTNERS.length > 0 ? (
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3"> <div className="grid grid-cols-1 gap-2 sm:grid-cols-2">
{PARTNERS.map((p) => ( {PARTNERS.map((p) => <PartnerCard key={p.name} partner={p} />)}
<PartnerCard key={p.name} partner={p} />
))}
</div> </div>
) : ( ) : (
<> <div className="rounded-xl border border-dashed border-[#ff6600]/20 p-5 text-center text-sm text-gray-500">
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-3 mb-4"> {t('walletUi.supporters.wantPartner')}
{Array.from({ length: 4 }).map((_, i) => (
<PlaceholderCard key={i} label={t('walletUi.supporters.comingSoon')} />
))}
</div> </div>
<div className="rounded-xl border border-dashed border-[#ff6600]/20 p-6 text-center">
<p className="text-gray-500 text-sm">{t('walletUi.supporters.wantPartner')}</p>
</div>
</>
)} )}
</section> </section>
{/* ── 8. Friends ── */}
<section> <section>
<SectionHeader icon={Star} title={t('walletUi.supporters.friends')} subtitle={t('walletUi.supporters.friendsDesc')} color="#ccff00" />
<div className="grid grid-cols-2 gap-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5">
{FRIENDS.map((f) => <FriendCard key={f.name} friend={f} />)}
</div>
<div className="mt-3 rounded-xl border border-dashed border-[#ccff00]/20 p-4 text-center">
<p className="text-xs text-gray-500">{t('walletUi.supporters.wantListed')}</p>
<p className="mt-0.5 text-[11px] text-gray-600">{t('walletUi.supporters.wantListedDesc')}</p>
</div>
</section>
</TabsContent>
{/* ── Grantmakers ── */}
<TabsContent value="grants" className="space-y-4 pt-4">
<SectionHeader <SectionHeader
icon={Star} icon={Handshake}
title={t('walletUi.supporters.friends')} title={t('walletUi.supporters.grantsSection')}
subtitle={t('walletUi.supporters.friendsDesc')} subtitle={t('walletUi.supporters.grantsSectionDesc')}
color="#ccff00" color="#f7931a"
/> />
<GrantmakerForm />
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-3"> </TabsContent>
{FRIENDS.map((f) => ( </Tabs>
<FriendCard key={f.name} friend={f} />
))}
{/* Fill remaining slots up to 5 with placeholders */}
{FRIENDS.length < 5 && Array.from({ length: 5 - FRIENDS.length }).map((_, i) => (
<PlaceholderCard key={`ph-${i}`} label={t('walletUi.supporters.comingSoon')} />
))}
</div>
<div className="mt-4 rounded-xl border border-dashed border-[#ccff00]/20 p-5 text-center">
<p className="text-gray-500 text-sm mb-1">{t('walletUi.supporters.wantListed')}</p>
<p className="text-xs text-gray-600">
{t('walletUi.supporters.wantListedDesc')}
</p>
</div>
</section>
{/* ── Mission ── */}
<section>
<div className="relative rounded-2xl overflow-hidden border-2 border-[#ff0040]/30 bg-black/80 p-8 md:p-10">
<div className="absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-[#ff0040] via-[#ff6600] to-[#ccff00]" />
<div className="flex justify-center mb-5">
<Heart className="h-10 w-10 text-[#ff0040]" />
</div>
<h2 className="text-2xl font-black uppercase text-center mb-3">
{t('walletUi.supporters.whyTitle1')} <span className="neon-red">{t('walletUi.supporters.whyTitle2')}</span>
</h2>
<p className="text-gray-400 text-sm text-center max-w-2xl mx-auto mb-6 leading-relaxed">
{t('walletUi.supporters.whyDesc')}
</p>
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
{[
{ emoji: '🛹', title: t('walletUi.supporters.why1Title'), desc: t('walletUi.supporters.why1Desc') },
{ emoji: '⚡', title: t('walletUi.supporters.why2Title'), desc: t('walletUi.supporters.why2Desc') },
{ emoji: '🌍', title: t('walletUi.supporters.why3Title'), desc: t('walletUi.supporters.why3Desc') },
].map(({ emoji, title, desc }) => (
<div key={title} className="p-4 rounded-xl bg-white/5 border border-white/10 text-center">
<div className="text-3xl mb-2">{emoji}</div>
<p className="font-bold text-sm mb-1">{title}</p>
<p className="text-xs text-gray-500">{desc}</p>
</div>
))}
</div>
</div>
</section>
{/* ── Footer ── */} {/* ── Footer ── */}
<div className="border-t border-gray-800 pt-8 text-center space-y-2 text-sm text-gray-500"> <div className="border-t border-gray-800 pt-5 text-center text-xs text-gray-500">
<p>{t('walletUi.supporters.thankYou')}</p> <p>{t('walletUi.supporters.thankYou')}</p>
<p> <p className="mt-1.5">
<Link to="/license" className="text-[#ccff00]/70 hover:text-[#ccff00] transition-colors underline">{t('walletUi.supporters.license')}</Link> <Link to="/license" className="text-[#ccff00]/70 underline transition-colors hover:text-[#ccff00]">{t('walletUi.supporters.license')}</Link>
{' '}&middot;{' '} {' '}&middot;{' '}
<Link to="/about" className="text-[#ccff00]/70 hover:text-[#ccff00] transition-colors underline">{t('nav.about')}</Link> <Link to="/about" className="text-[#ccff00]/70 underline transition-colors hover:text-[#ccff00]">{t('nav.about')}</Link>
{' '}&middot;{' '} {' '}&middot;{' '}
<Link to="/faq" className="text-[#ccff00]/70 hover:text-[#ccff00] transition-colors underline">{t('walletUi.supporters.faq')}</Link> <Link to="/faq" className="text-[#ccff00]/70 underline transition-colors hover:text-[#ccff00]">{t('walletUi.supporters.faq')}</Link>
</p> </p>
</div> </div>