Replace sponsor program with $VOICEBOX token

- Remove the sponsor feature (sponsors page, homepage promo, footer
  link, Stripe constants, and the app About-page sponsored-by section)
- Add $VOICEBOX token: navbar pill linking to pump.fun and a footer
  Token column with a copyable Solana contract address
- Drop API and Download from the navbar links
This commit is contained in:
James Pine
2026-06-26 14:06:47 -07:00
parent b35b90961d
commit 45b64e0233
11 changed files with 90 additions and 501 deletions
+38
View File
@@ -0,0 +1,38 @@
'use client';
import { Check, Copy } from 'lucide-react';
import { useState } from 'react';
/** Compact, copyable contract address — short display, full value to clipboard. */
export function CopyAddress({ address }: { address: string }) {
const [copied, setCopied] = useState(false);
const handleCopy = async () => {
try {
await navigator.clipboard.writeText(address);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch {
// Clipboard unavailable (e.g. insecure context) — silently no-op.
}
};
const short = `${address.slice(0, 4)}${address.slice(-4)}`;
return (
<button
type="button"
onClick={handleCopy}
title={address}
aria-label={copied ? 'Contract address copied' : 'Copy contract address'}
className="group inline-flex items-center gap-2 rounded-lg border border-border/60 bg-card/60 px-2.5 py-1.5 font-mono text-xs text-muted-foreground transition-colors hover:border-border hover:text-foreground"
>
<span>{short}</span>
{copied ? (
<Check className="h-3.5 w-3.5 text-accent" />
) : (
<Copy className="h-3.5 w-3.5 opacity-60 transition-opacity group-hover:opacity-100" />
)}
</button>
);
}
+32 -8
View File
@@ -1,13 +1,20 @@
import { Coffee } from 'lucide-react';
import { ArrowUpRight, Coffee, Coins } from 'lucide-react';
import Image from 'next/image';
import Link from 'next/link';
import { DONATE_URL, GITHUB_REPO } from '@/lib/constants';
import { CopyAddress } from '@/components/CopyAddress';
import {
DONATE_URL,
GITHUB_REPO,
TOKEN_CONTRACT_ADDRESS,
TOKEN_PUMP_URL,
TOKEN_TICKER,
} from '@/lib/constants';
export function Footer() {
return (
<footer className="border-t border-border py-12">
<div className="mx-auto max-w-7xl px-6">
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-8 mb-10">
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-5 gap-8 mb-10">
{/* Brand */}
<div className="md:col-span-1">
<div className="flex items-center gap-2.5 mb-4">
@@ -116,11 +123,6 @@ export function Footer() {
Issues
</Link>
</li>
<li>
<a href="/sponsors" className="hover:text-foreground transition-colors">
VIP Sponsor
</a>
</li>
</ul>
</div>
@@ -150,6 +152,28 @@ export function Footer() {
</li>
</ul>
</div>
{/* Token */}
<div>
<h4 className="text-sm font-semibold mb-3">Token</h4>
<div className="space-y-3 text-sm text-muted-foreground">
<div className="flex items-center gap-2">
<Coins className="h-4 w-4 text-accent" />
<span className="font-semibold text-foreground">{TOKEN_TICKER}</span>
<span className="text-xs text-muted-foreground/60">Solana</span>
</div>
<CopyAddress address={TOKEN_CONTRACT_ADDRESS} />
<a
href={TOKEN_PUMP_URL}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1.5 hover:text-foreground transition-colors"
>
Buy on pump.fun
<ArrowUpRight className="h-3.5 w-3.5" />
</a>
</div>
</div>
</div>
<div className="border-t border-border pt-6">
+15 -15
View File
@@ -1,9 +1,9 @@
'use client';
import { Coffee, Github } from 'lucide-react';
import { Coffee, Coins, Github } from 'lucide-react';
import Image from 'next/image';
import { useEffect, useState } from 'react';
import { DONATE_URL, GITHUB_REPO } from '@/lib/constants';
import { DONATE_URL, GITHUB_REPO, TOKEN_PUMP_URL, TOKEN_TICKER } from '@/lib/constants';
function formatStarCount(count: number): string {
if (count >= 1000) {
@@ -74,18 +74,6 @@ export function Navbar() {
>
Models
</a>
<a
href="/#api"
className="rounded-md px-3 py-1.5 text-sm font-medium text-muted-foreground transition-colors hover:text-foreground"
>
API
</a>
<a
href="/download"
className="rounded-md px-3 py-1.5 text-sm font-medium text-muted-foreground transition-colors hover:text-foreground"
>
Download
</a>
<a
href="https://docs.voicebox.sh"
target="_blank"
@@ -96,8 +84,20 @@ export function Navbar() {
</a>
</div>
{/* Donate + GitHub star buttons */}
{/* Token + Donate + GitHub star buttons */}
<div className="flex items-center gap-2 justify-self-end">
<a
href={TOKEN_PUMP_URL}
target="_blank"
rel="noopener noreferrer"
className="hidden sm:flex items-center gap-2 rounded-lg border border-border/60 bg-card/60 px-3 py-1.5 text-sm text-muted-foreground transition-colors hover:text-foreground hover:border-accent/40"
aria-label={`${TOKEN_TICKER} token on pump.fun`}
>
<Coins className="h-4 w-4 text-accent" />
<span className="text-[13px] font-semibold tracking-wide text-foreground">
{TOKEN_TICKER}
</span>
</a>
<a
href={DONATE_URL}
target="_blank"
-94
View File
@@ -1,94 +0,0 @@
import { ArrowRight, Heart } from 'lucide-react';
import { SPONSORS, type Sponsor } from '@/lib/sponsors';
export function SponsorPromo() {
if (SPONSORS.length === 0) {
return <SponsorPromoEmpty />;
}
return <SponsorStrip sponsors={SPONSORS} />;
}
function SponsorPromoEmpty() {
return (
<section className="border-t border-border py-16">
<div className="mx-auto max-w-5xl px-6">
<div className="rounded-2xl border-2 border-accent/40 bg-gradient-to-br from-card/80 to-card/40 backdrop-blur-sm p-8 md:p-10 shadow-[0_8px_40px_hsl(43_60%_50%/0.08)]">
<div className="grid md:grid-cols-[1fr_auto] items-center gap-8">
<div>
<div className="inline-flex items-center gap-2 mb-4 text-[11px] font-semibold uppercase tracking-[0.22em] text-accent">
<Heart className="h-3.5 w-3.5" />
Sponsor Voicebox
</div>
<h3 className="text-2xl md:text-3xl font-semibold tracking-tight text-foreground mb-3">
Get your logo in front of 170k+ monthly visitors.
</h3>
<p className="text-sm md:text-base text-muted-foreground leading-relaxed max-w-2xl">
Voicebox is open-source and used by creators, voice artists, podcasters,
writers, developers, accessibility users, and curious humans all over the world.
Sponsor the project and your logo lands on the homepage, in the app, in the
README, and on the sponsors page in front of every one of them.
</p>
</div>
<div className="flex flex-col items-start md:items-end gap-2">
<a
href="/sponsors"
className="inline-flex items-center gap-2 rounded-full bg-accent px-6 py-3 text-sm font-semibold uppercase tracking-wider text-white shadow-[0_4px_20px_hsl(43_60%_50%/0.3),inset_0_2px_0_rgba(255,255,255,0.2),inset_0_-2px_0_rgba(0,0,0,0.1)] transition-all hover:bg-accent-faint whitespace-nowrap"
>
Become a sponsor
<ArrowRight className="h-4 w-4" />
</a>
<span className="text-xs text-muted-foreground/70">From $500 / month</span>
</div>
</div>
</div>
</div>
</section>
);
}
function SponsorStrip({ sponsors }: { sponsors: Sponsor[] }) {
return (
<section className="border-t border-border py-14">
<div className="mx-auto max-w-6xl px-6">
<div className="text-center mb-8">
<div className="text-[11px] font-semibold uppercase tracking-[0.22em] text-muted-foreground/80">
Sponsored by
</div>
</div>
<div className="flex flex-wrap items-center justify-center gap-5 md:gap-6">
{sponsors.map((sponsor) => (
<a
key={sponsor.name}
href={sponsor.url}
target="_blank"
rel="noopener noreferrer"
aria-label={sponsor.name}
className="group flex h-32 min-w-[260px] items-center justify-center rounded-2xl border border-border bg-card/40 backdrop-blur-sm px-10 transition-all hover:border-accent/40 hover:bg-card"
>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={sponsor.logoSrc}
alt={sponsor.logoAlt ?? sponsor.name}
className={`h-14 w-auto max-w-[220px] object-contain opacity-80 transition-opacity group-hover:opacity-100 ${
sponsor.invert ? 'brightness-0 invert' : ''
}`}
/>
</a>
))}
</div>
<div className="mt-8 text-center">
<a
href="/sponsors"
className="inline-flex items-center gap-1.5 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground"
>
Become a sponsor
<ArrowRight className="h-3.5 w-3.5" />
</a>
</div>
</div>
</section>
);
}