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="/privacy" element={<PrivacyPage />} />
<Route path="/supporters" element={<SupportersPage />} />
{/* Friendly alias: people naturally type /support. */}
<Route path="/support" element={<Navigate to="/supporters" replace />} />
<Route path="/donate" element={<DonatePage />} />
{/* Marketplace */}
<Route path="/marketplace-listings" element={<MarketplacePage />} />

View file

@ -1,11 +1,20 @@
import { useTranslation } from '@/contexts/language';
import { cn } from '@/lib/utils';
/**
* "Ways to support" — three purpose-first cards; each scrolls to its rail by id
* (#support-lightning / #support-silent / #support-angor), so it works anywhere
* 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 ways = [
{ 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') },
];
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) => (
<button
key={w.id}
onClick={() => document.getElementById(w.id)?.scrollIntoView({ behavior: 'smooth', block: 'start' })}
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"
type="button"
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>
<p className="mt-2 text-sm font-black uppercase text-white">{w.title}</p>
<p className="mt-1 text-xs text-gray-400">{w.desc}</p>
<span className="text-xl">{w.emoji}</span>
<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-0.5 hidden text-[10px] leading-snug text-gray-400 sm:block">{w.desc}</p>
</button>
))}
</div>

View file

@ -20,6 +20,7 @@ import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea';
import { Label } from '@/components/ui/label';
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).
@ -27,7 +28,7 @@ import { Button } from '@/components/ui/button';
// platform zap is already ≥ 2026-01, so this doesn't currently trim the list —
// the visible cap below is what keeps it short.
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). */
function npubToHex(npub?: string): string | undefined {
@ -261,15 +262,15 @@ function SectionHeader({
color?: string;
}) {
return (
<div className="mb-6 md:mb-8">
<div className="flex items-center gap-3 mb-2">
<Icon className="h-5 w-5 flex-shrink-0" style={{ color }} />
<h2 className="text-2xl md:text-3xl font-black uppercase tracking-wide" style={{ color }}>
<div className="mb-3 md:mb-4">
<div className="mb-1.5 flex items-center gap-2.5">
<Icon className="h-4 w-4 flex-shrink-0" style={{ color }} />
<h2 className="text-lg font-black uppercase tracking-wide md:text-xl" style={{ color }}>
{title}
</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>
{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>
);
}
@ -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 ────────────────────────────────────────────────────────────────
export default function SupportersPage() {
@ -571,6 +559,8 @@ export default function SupportersPage() {
const totalUsd = useSatsToUsd(allSats);
const { data: stats } = useGrowthStats();
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.
const supporters = useMemo<SupporterEntry[]>(() => {
@ -652,97 +642,106 @@ export default function SupportersPage() {
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 ── */}
<div className="text-center">
<div className="text-6xl mb-4">⚡</div>
<h1 className="text-5xl md:text-6xl font-black uppercase mb-3 leading-none">
<h1 className="text-4xl font-black uppercase leading-none md:text-5xl">
<span className="neon-red">{t('walletUi.supporters.our')}</span>{' '}
<span className="neon-lime">{t('walletUi.supporters.community')}</span>
</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')}
</p>
<div className="mt-5 flex flex-wrap items-center justify-center gap-2">
<a
href={ANGOR_PROJECT_URL}
target="_blank"
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" />
{t('walletUi.supporters.backAngor')}
<ExternalLink className="h-3.5 w-3.5 opacity-70" />
<ExternalLink className="h-3 w-3 opacity-70" />
</a>
<Link
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')} →
</Link>
</div>
{/* ── 1. Support ── */}
<section>
<SectionHeader
icon={Zap}
title={t('walletUi.supporters.support')}
subtitle={t('walletUi.supporters.supportDesc')}
color="#f7931a"
/>
<WaysToSupport className="mb-4" />
{/* 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 className="mt-4 flex flex-wrap items-center justify-center gap-x-3 gap-y-1 text-[11px] text-gray-500">
<span>{supporters.length.toLocaleString()} {t('walletUi.supporters.backers')}</span>
<span aria-hidden="true">·</span>
<span>{allSats.toLocaleString()} sats</span>
{typeof totalUsd === 'number' && (
<>
<span aria-hidden="true">·</span>
<span>≈ ${totalUsd.toFixed(2)}</span>
</>
)}
</div>
</div>
{/* Silent payments — private on-chain (and Lightning) via a BIP-353 name. */}
<div id="support-silent" className="scroll-mt-24">
<SilentPaymentsCard className="mt-4" />
</div>
<div id="support-angor" className="scroll-mt-24">
<AngorProjectCard count={supporters.length} className="mt-4" />
</div>
</section>
{/* ── Compact navigation ── */}
<Tabs
value={tab}
onValueChange={(value) => setTab(value as 'support' | 'backers' | 'community' | 'grants')}
>
<TabsList className="grid h-auto w-full grid-cols-4 gap-1 rounded-2xl border border-white/10 bg-black/70 p-1">
{[
{ 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 ── */}
<section>
<SectionHeader
icon={Handshake}
title={t('walletUi.supporters.grantsSection')}
subtitle={t('walletUi.supporters.grantsSectionDesc')}
color="#f7931a"
/>
<GrantmakerForm />
</section>
{/* ── Support rails ── */}
<TabsContent value="support" className="space-y-4 pt-4">
<div>
<h2 className="text-xl font-black uppercase text-white">{t('walletUi.supporters.support')}</h2>
<p className="mt-0.5 text-sm text-gray-400">{t('walletUi.supporters.donateDesc')}</p>
</div>
<WaysToSupport active={rail} onSelect={(id) => setRail(id as typeof rail)} />
<div id={rail} className="scroll-mt-24">
{rail === 'support-lightning' && <SupportSkateSpots />}
{rail === 'support-silent' && <SilentPaymentsCard />}
{rail === 'support-angor' && <AngorProjectCard count={supporters.length} />}
</div>
{/* ── 3. What your support pays for (words only) ── */}
<section>
<section className="pt-1">
<SectionHeader
icon={Heart}
title={t('walletUi.supporters.paysFor')}
subtitle={t('walletUi.supporters.paysForDesc')}
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 }) => (
<div
key={key}
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 key={key} className="flex items-start gap-2 rounded-xl border border-white/10 bg-black/60 px-3 py-2">
<Icon className="mt-0.5 h-3.5 w-3.5 flex-shrink-0 text-[#22d3ee]" />
<div className="min-w-0">
<span className="text-sm font-medium text-white">{t(key)}</span>
<p className="text-[11px] text-gray-500">{t(desc)}</p>
<span className="text-xs font-medium text-white">{t(key)}</span>
<p className="text-[10px] leading-snug text-gray-500">{t(desc)}</p>
</div>
</div>
))}
</div>
</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 && (
<section>
<SectionHeader
@ -751,16 +750,16 @@ export default function SupportersPage() {
subtitle={t('walletUi.supporters.impactDesc')}
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 }) => (
<div key={key} className="rounded-xl border border-white/10 bg-black/60 px-4 py-3 text-center">
<div className="text-2xl font-black text-[#ccff00]">{value.toLocaleString()}</div>
<div className="text-xs text-gray-400">{t(key)}</div>
<div key={key} className="rounded-xl border border-white/10 bg-black/60 px-2 py-2.5 text-center">
<div className="text-lg font-black text-[#ccff00]">{value.toLocaleString()}</div>
<div className="truncate text-[10px] text-gray-400">{t(key)}</div>
</div>
))}
</div>
<p className="mt-4 text-center text-xs text-gray-500">
<Link to="/stats" className="text-[#ccff00]/70 underline transition-colors hover:text-[#ccff00]">
<p className="mt-2 text-center text-[11px] text-gray-500">
<Link to="/stats" className="text-[#ccff00]/70 underline underline-offset-2 hover:text-[#ccff00]">
{t('walletUi.supporters.impactSeeStats')}
</Link>
{' · '}
@ -769,7 +768,6 @@ export default function SupportersPage() {
</section>
)}
{/* ── 4. Supporters (Angor + Lightning zaps) ── */}
<section>
<SectionHeader
icon={Zap}
@ -777,19 +775,19 @@ export default function SupportersPage() {
subtitle={t('walletUi.supporters.backersDesc')}
color="#22d3ee"
/>
{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) => (
<SupporterRow key={entry.key} rank={i + 1} entry={entry} />
))}
</div>
{supporters.length > VISIBLE_LIMIT && (
<div className="mt-3 text-center">
<div className="mt-2 text-center">
<button
type="button"
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
? t('walletUi.supporters.showLess')
@ -797,47 +795,62 @@ export default function SupportersPage() {
</button>
</div>
)}
<p className="mt-4 text-center text-sm text-gray-400">
<p className="mt-3 text-center text-xs text-gray-400">
{t('walletUi.supporters.supportersTotals', {
count: supporters.length,
angor: BACKERS_TOTAL_SATS.toLocaleString(),
zap: zapTotal.toLocaleString(),
})}
{typeof totalUsd === 'number' && (
<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')}
{typeof totalUsd === 'number' && <span className="text-gray-500"> · ≈ ${totalUsd.toFixed(2)}</span>}
</p>
<p className="mt-1 text-center text-[11px] text-gray-600">{t('walletUi.supporters.quietNote')}</p>
{latestAt > 0 && (
<p className="mt-1 text-center text-[11px] text-gray-600">
{t('walletUi.supporters.updatedAt', {
when: formatDistanceToNow(new Date(latestAt * 1000), { addSuffix: true }),
})}
<p className="mt-0.5 text-center text-[10px] text-gray-600">
{t('walletUi.supporters.updatedAt', { when: formatDistanceToNow(new Date(latestAt * 1000), { addSuffix: true }) })}
</p>
)}
<TierLadder supporters={supporters} />
</>
) : (
<div className="rounded-xl border border-dashed border-[#22d3ee]/20 p-8 text-center">
<Zap className="h-10 w-10 mx-auto mb-3 text-[#22d3ee]/30" />
<p className="text-gray-500 text-sm mb-1">{t('walletUi.supporters.beFirstBacker')}</p>
<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] transition-colors"
>
<ExternalLink className="h-3 w-3" />
{t('walletUi.supporters.backAngor')}
<div className="rounded-xl border border-dashed border-[#22d3ee]/20 p-6 text-center">
<Zap className="mx-auto mb-2 h-8 w-8 text-[#22d3ee]/30" />
<p className="mb-1 text-sm text-gray-500">{t('walletUi.supporters.beFirstBacker')}</p>
<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]">
<ExternalLink className="h-3 w-3" /> {t('walletUi.supporters.backAngor')}
</a>
</div>
)}
</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>
<SectionHeader
icon={Users}
@ -845,124 +858,68 @@ export default function SupportersPage() {
subtitle={t('walletUi.supporters.collaboratorsDesc')}
color="#ff0040"
/>
{COLLABORATORS.length > 0 ? (
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
{COLLABORATORS.map((c) => (
<CollaboratorCard key={c.name} collab={c} />
))}
<div className="grid grid-cols-1 gap-2 sm:grid-cols-2">
{COLLABORATORS.map((c) => <CollaboratorCard key={c.name} collab={c} />)}
</div>
) : (
<div className="rounded-xl border border-dashed border-[#ff0040]/20 p-8 text-center">
<Users className="h-10 w-10 mx-auto mb-3 text-[#ff0040]/30" />
<p className="text-gray-500 text-sm mb-1">{t('walletUi.supporters.wantCollaborate')}</p>
<p className="text-xs text-gray-600 mb-4">{t('walletUi.supporters.wantCollaborateDesc')}</p>
<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] transition-colors"
>
<ExternalLink className="h-3 w-3" />
{t('walletUi.supporters.viewNostrHub')}
<div className="rounded-xl border border-dashed border-[#ff0040]/20 p-5 text-center">
<Users className="mx-auto mb-2 h-8 w-8 text-[#ff0040]/30" />
<p className="mb-1 text-sm text-gray-500">{t('walletUi.supporters.wantCollaborate')}</p>
<p className="mb-3 text-xs text-gray-600">{t('walletUi.supporters.wantCollaborateDesc')}</p>
<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]">
<ExternalLink className="h-3 w-3" /> {t('walletUi.supporters.viewNostrHub')}
</a>
</div>
)}
</section>
{/* ── 7. Partners ── */}
<section>
<SectionHeader
icon={Handshake}
title={t('walletUi.supporters.partners')}
subtitle={t('walletUi.supporters.partnersDesc')}
color="#ff6600"
/>
<SectionHeader icon={Handshake} title={t('walletUi.supporters.partners')} subtitle={t('walletUi.supporters.partnersDesc')} color="#ff6600" />
{PARTNERS.length > 0 ? (
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
{PARTNERS.map((p) => (
<PartnerCard key={p.name} partner={p} />
))}
<div className="grid grid-cols-1 gap-2 sm:grid-cols-2">
{PARTNERS.map((p) => <PartnerCard key={p.name} partner={p} />)}
</div>
) : (
<>
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-3 mb-4">
{Array.from({ length: 4 }).map((_, i) => (
<PlaceholderCard key={i} label={t('walletUi.supporters.comingSoon')} />
))}
<div className="rounded-xl border border-dashed border-[#ff6600]/20 p-5 text-center text-sm text-gray-500">
{t('walletUi.supporters.wantPartner')}
</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>
{/* ── 8. Friends ── */}
<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
icon={Star}
title={t('walletUi.supporters.friends')}
subtitle={t('walletUi.supporters.friendsDesc')}
color="#ccff00"
icon={Handshake}
title={t('walletUi.supporters.grantsSection')}
subtitle={t('walletUi.supporters.grantsSectionDesc')}
color="#f7931a"
/>
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-3">
{FRIENDS.map((f) => (
<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>
<GrantmakerForm />
</TabsContent>
</Tabs>
{/* ── 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>
<Link to="/license" className="text-[#ccff00]/70 hover:text-[#ccff00] transition-colors underline">{t('walletUi.supporters.license')}</Link>
<p className="mt-1.5">
<Link to="/license" className="text-[#ccff00]/70 underline transition-colors hover:text-[#ccff00]">{t('walletUi.supporters.license')}</Link>
{' '}&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;{' '}
<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>
</div>