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
@@ -3,7 +3,6 @@ import type { CSSProperties, ReactNode } from 'react';
import { useEffect, useState } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import voiceboxLogo from '@/assets/voicebox-logo.png';
import { SPONSORS } from '@/lib/sponsors';
import { usePlatform } from '@/platform/PlatformContext';
function FadeIn({ delay = 0, children }: { delay?: number; children: ReactNode }) {
@@ -117,36 +116,6 @@ export function AboutPage() {
</div>
</FadeIn>
{SPONSORS.length > 0 && (
<FadeIn delay={400}>
<div className="pt-4 flex flex-col items-center gap-3">
<p className="text-[10px] font-semibold uppercase tracking-[0.22em] text-muted-foreground/60">
Sponsored by
</p>
<div className="flex flex-wrap items-center justify-center gap-3">
{SPONSORS.map((sponsor) => (
<a
key={sponsor.name}
href={sponsor.url}
target="_blank"
rel="noopener noreferrer"
aria-label={sponsor.name}
className="group flex h-12 min-w-[120px] items-center justify-center rounded-lg border border-border/60 bg-card/50 px-4 transition-colors hover:bg-muted/50"
>
<img
src={sponsor.logoSrc}
alt={sponsor.logoAlt ?? sponsor.name}
className={`h-5 w-auto max-w-[100px] object-contain opacity-80 transition-opacity group-hover:opacity-100 ${
sponsor.invertOnDark ? 'dark:brightness-0 dark:invert' : ''
}`}
/>
</a>
))}
</div>
</div>
</FadeIn>
)}
<FadeIn delay={480}>
<p className="text-xs text-muted-foreground/40 pt-4">
<Trans
-10
View File
@@ -1,10 +0,0 @@
export type Sponsor = {
name: string;
url: string;
logoSrc: string;
logoAlt?: string;
/** Set true for solid-black logos that need to flip white in dark mode. */
invertOnDark?: boolean;
};
export const SPONSORS: Sponsor[] = [];
-1
View File
@@ -1 +0,0 @@
<svg viewBox="0 0 1180 320" xmlns="http://www.w3.org/2000/svg"><path d="m367.44 153.84c0 52.32 33.6 88.8 80.16 88.8s80.16-36.48 80.16-88.8-33.6-88.8-80.16-88.8-80.16 36.48-80.16 88.8zm129.6 0c0 37.44-20.4 61.68-49.44 61.68s-49.44-24.24-49.44-61.68 20.4-61.68 49.44-61.68 49.44 24.24 49.44 61.68z"/><path d="m614.27 242.64c35.28 0 55.44-29.76 55.44-65.52s-20.16-65.52-55.44-65.52c-16.32 0-28.32 6.48-36.24 15.84v-13.44h-28.8v169.2h28.8v-56.4c7.92 9.36 19.92 15.84 36.24 15.84zm-36.96-69.12c0-23.76 13.44-36.72 31.2-36.72 20.88 0 32.16 16.32 32.16 40.32s-11.28 40.32-32.16 40.32c-17.76 0-31.2-13.2-31.2-36.48z"/><path d="m747.65 242.64c25.2 0 45.12-13.2 54-35.28l-24.72-9.36c-3.84 12.96-15.12 20.16-29.28 20.16-18.48 0-31.44-13.2-33.6-34.8h88.32v-9.6c0-34.56-19.44-62.16-55.92-62.16s-60 28.56-60 65.52c0 38.88 25.2 65.52 61.2 65.52zm-1.44-106.8c18.24 0 26.88 12 27.12 25.92h-57.84c4.32-17.04 15.84-25.92 30.72-25.92z"/><path d="m823.98 240h28.8v-73.92c0-18 13.2-27.6 26.16-27.6 15.84 0 22.08 11.28 22.08 26.88v74.64h28.8v-83.04c0-27.12-15.84-45.36-42.24-45.36-16.32 0-27.6 7.44-34.8 15.84v-13.44h-28.8z"/><path d="m1014.17 67.68-65.28 172.32h30.48l14.64-39.36h74.4l14.88 39.36h30.96l-65.28-172.32zm16.8 34.08 27.36 72h-54.24z"/><path d="m1163.69 68.18h-30.72v172.32h30.72z"/><path d="m297.06 130.97c7.26-21.79 4.76-45.66-6.85-65.48-17.46-30.4-52.56-46.04-86.84-38.68-15.25-17.18-37.16-26.95-60.13-26.81-35.04-.08-66.13 22.48-76.91 55.82-22.51 4.61-41.94 18.7-53.31 38.67-17.59 30.32-13.58 68.54 9.92 94.54-7.26 21.79-4.76 45.66 6.85 65.48 17.46 30.4 52.56 46.04 86.84 38.68 15.24 17.18 37.16 26.95 60.13 26.8 35.06.09 66.16-22.49 76.94-55.86 22.51-4.61 41.94-18.7 53.31-38.67 17.57-30.32 13.55-68.51-9.94-94.51zm-120.28 168.11c-14.03.02-27.62-4.89-38.39-13.88.49-.26 1.34-.73 1.89-1.07l63.72-36.8c3.26-1.85 5.26-5.32 5.24-9.07v-89.83l26.93 15.55c.29.14.48.42.52.74v74.39c-.04 33.08-26.83 59.9-59.91 59.97zm-128.84-55.03c-7.03-12.14-9.56-26.37-7.15-40.18.47.28 1.3.79 1.89 1.13l63.72 36.8c3.23 1.89 7.23 1.89 10.47 0l77.79-44.92v31.1c.02.32-.13.63-.38.83l-64.41 37.19c-28.69 16.52-65.33 6.7-81.92-21.95zm-16.77-139.09c7-12.16 18.05-21.46 31.21-26.29 0 .55-.03 1.52-.03 2.2v73.61c-.02 3.74 1.98 7.21 5.23 9.06l77.79 44.91-26.93 15.55c-.27.18-.61.21-.91.08l-64.42-37.22c-28.63-16.58-38.45-53.21-21.95-81.89zm221.26 51.49-77.79-44.92 26.93-15.54c.27-.18.61-.21.91-.08l64.42 37.19c28.68 16.57 38.51 53.26 21.94 81.94-7.01 12.14-18.05 21.44-31.2 26.28v-75.81c.03-3.74-1.96-7.2-5.2-9.06zm26.8-40.34c-.47-.29-1.3-.79-1.89-1.13l-63.72-36.8c-3.23-1.89-7.23-1.89-10.47 0l-77.79 44.92v-31.1c-.02-.32.13-.63.38-.83l64.41-37.16c28.69-16.55 65.37-6.7 81.91 22 6.99 12.12 9.52 26.31 7.15 40.1zm-168.51 55.43-26.94-15.55c-.29-.14-.48-.42-.52-.74v-74.39c.02-33.12 26.89-59.96 60.01-59.94 14.01 0 27.57 4.92 38.34 13.88-.49.26-1.33.73-1.89 1.07l-63.72 36.8c-3.26 1.85-5.26 5.31-5.24 9.06l-.04 89.79zm14.63-31.54 34.65-20.01 34.65 20v40.01l-34.65 20-34.65-20z"/></svg>

Before

Width:  |  Height:  |  Size: 2.9 KiB

-4
View File
@@ -11,7 +11,6 @@ import {Footer} from "@/components/Footer";
import {Navbar} from "@/components/Navbar";
import {Personalities} from "@/components/Personalities";
import {AppleIcon, LinuxIcon, WindowsIcon} from "@/components/PlatformIcons";
import {SponsorPromo} from "@/components/SponsorPromo";
import {SupportedModels} from "@/components/SupportedModels";
import {TutorialsSection} from "@/components/TutorialsSection";
import {VoiceCreator} from "@/components/VoiceCreator";
@@ -131,9 +130,6 @@ export default function Home() {
</div>
</section>
{/* ── Sponsor promo ────────────────────────────────────────── */}
<SponsorPromo />
{/* ── Features ─────────────────────────────────────────────── */}
<Features />
-324
View File
@@ -1,324 +0,0 @@
'use client';
import { ArrowRight, Check, Coffee, Mail } from 'lucide-react';
import { useEffect, useState } from 'react';
import { Footer } from '@/components/Footer';
import { Navbar } from '@/components/Navbar';
import {
DONATE_URL,
SPONSOR_CHECKOUT_URL,
SPONSOR_CONTACT_EMAIL,
} from '@/lib/constants';
function formatCount(n: number): string {
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1).replace(/\.0$/, '')}M`;
if (n >= 1_000) return `${(n / 1_000).toFixed(0)}k`;
return n.toLocaleString();
}
export default function SponsorsPage() {
const [downloads, setDownloads] = useState<number | null>(null);
const [stars, setStars] = useState<number | null>(null);
useEffect(() => {
fetch('/api/releases')
.then((res) => (res.ok ? res.json() : null))
.then((data) => {
if (data?.totalDownloads != null) setDownloads(data.totalDownloads);
})
.catch(() => {});
fetch('/api/stars')
.then((res) => (res.ok ? res.json() : null))
.then((data) => {
if (typeof data?.count === 'number') setStars(data.count);
})
.catch(() => {});
}, []);
return (
<>
<Navbar />
{/* ── Hero ─────────────────────────────────────────────────── */}
<section className="relative pt-32 pb-16">
<div className="hero-glow hero-glow-fade pointer-events-none absolute inset-0 -top-32">
<div className="absolute left-1/2 top-0 -translate-x-1/2 w-[900px] h-[500px] rounded-full bg-accent/12 blur-[140px]" />
<div className="absolute left-1/2 top-16 -translate-x-1/2 w-[520px] h-[360px] rounded-full bg-accent/8 blur-[80px]" />
</div>
<div className="relative mx-auto max-w-4xl px-6 text-center">
<div
className="fade-in mb-6 text-[11px] font-semibold uppercase tracking-[0.22em] text-accent"
style={{ animationDelay: '50ms' }}
>
VIP Sponsor
</div>
<h1
className="fade-in text-5xl font-bold tracking-tighter leading-[0.95] text-foreground md:text-6xl lg:text-7xl"
style={{ animationDelay: '100ms' }}
>
Get your brand in front of half a million creators.
</h1>
<p
className="fade-in mx-auto mt-6 max-w-2xl text-lg text-muted-foreground md:text-xl"
style={{ animationDelay: '200ms' }}
>
Voicebox is the open-source AI voice studio used by creators, podcasters, voice
artists, writers, developers, accessibility users, and curious humans all over the
world. Sponsor the project, get your logo in front of all of them.
</p>
<div
className="fade-in mt-10 flex flex-row items-center justify-center gap-3 sm:gap-4"
style={{ animationDelay: '300ms' }}
>
<a
href="#sponsor"
className="rounded-full bg-accent px-8 py-3.5 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 active:shadow-[0_2px_10px_hsl(43_60%_50%/0.3),inset_0_4px_8px_rgba(0,0,0,0.3)]"
>
Become a sponsor
</a>
<a
href={`mailto:${SPONSOR_CONTACT_EMAIL}`}
className="flex items-center gap-2 rounded-full border border-border/60 bg-card/40 backdrop-blur-sm px-6 py-3 text-sm font-medium text-muted-foreground transition-colors hover:text-foreground hover:border-border"
>
<Mail className="h-4 w-4" />
Talk to us
</a>
</div>
</div>
</section>
{/* ── Traction ────────────────────────────────────────────── */}
<section className="border-t border-border py-20">
<div className="mx-auto max-w-5xl px-6">
<div className="text-center mb-12">
<div className="text-[11px] font-semibold uppercase tracking-[0.22em] text-accent mb-4">
Reach
</div>
<h2 className="text-3xl md:text-4xl font-semibold tracking-tight text-foreground">
Real distribution, real attention.
</h2>
</div>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<Stat
value={downloads != null ? formatCount(downloads) : '500k+'}
label="Downloads"
note="Since launch in February 2026"
/>
<Stat
value={stars != null ? formatCount(stars) : '22k+'}
label="GitHub stars"
note="Trending #1 maintainer, #4 repo"
/>
<Stat
value="170k+"
label="Monthly site visitors"
note="voicebox.sh, last 30 days · growing 5×"
/>
<Stat
value="Millions"
label="Social reach"
note="Tutorials, reels, TikToks"
/>
</div>
<p className="text-center text-sm text-muted-foreground mt-10 max-w-2xl mx-auto">
Voicebox users are content creators, podcasters, voice artists, writers, developers,
accessibility users, hobbyists, and AI enthusiasts. They picked a local-first tool
over a cloud subscription they care about owning their software and the brands
behind it.
</p>
</div>
</section>
{/* ── What you get ────────────────────────────────────────── */}
<section className="border-t border-border py-20">
<div className="mx-auto max-w-5xl px-6">
<div className="text-center mb-12">
<div className="text-[11px] font-semibold uppercase tracking-[0.22em] text-accent mb-4">
Placement
</div>
<h2 className="text-3xl md:text-4xl font-semibold tracking-tight text-foreground">
Where your logo shows up.
</h2>
</div>
<div className="rounded-2xl border-2 border-accent/40 bg-card/60 backdrop-blur-sm p-8 mb-4 shadow-[0_8px_40px_hsl(43_60%_50%/0.08)]">
<div className="text-[11px] font-semibold uppercase tracking-[0.22em] text-accent mb-2">
Headline placement
</div>
<h3 className="text-xl md:text-2xl font-semibold tracking-tight text-foreground mb-2">
voicebox.sh directly below the hero.
</h3>
<p className="text-sm md:text-base text-muted-foreground leading-relaxed max-w-2xl mb-8">
Your logo lives in the prime slot on the homepage the first thing every visitor
sees after the hero. Same row as every other VIP Sponsor, linked to your URL
of choice. This is the placement that actually moves the needle.
</p>
{/* Preview of what the placement looks like on the homepage */}
<div className="rounded-xl border border-dashed border-border/80 bg-background/50 p-6 md:p-8">
<div className="text-center mb-6">
<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">
<div className="flex h-32 min-w-[260px] items-center justify-center rounded-2xl border border-border bg-card/40 backdrop-blur-sm px-10">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src="/sponsors/openai.svg"
alt="Example sponsor logo"
className="h-14 w-auto max-w-[220px] object-contain brightness-0 invert opacity-80"
/>
</div>
</div>
<p className="mt-6 text-center text-xs text-muted-foreground/70 italic">
Example only actual sponsor logos appear here once placements are live.
</p>
</div>
</div>
<div className="grid md:grid-cols-3 gap-4">
<Perk
title="GitHub README"
body="Logo in the repo's Sponsors section. The README is one of the most-viewed docs on GitHub for any trending project."
/>
<Perk
title="/sponsors page"
body="Dedicated logo card on this page with your tagline, what your company does, and a direct link out."
/>
<Perk
title="Release notes"
body="One-line acknowledgement in the next major release post — read by the long tail of users who follow Voicebox updates."
/>
</div>
</div>
</section>
{/* ── Pricing ─────────────────────────────────────────────── */}
<section id="sponsor" className="border-t border-border py-20">
<div className="mx-auto max-w-3xl px-6">
<div className="text-center mb-10">
<div className="text-[11px] font-semibold uppercase tracking-[0.22em] text-accent mb-4">
Pricing
</div>
<h2 className="text-3xl md:text-4xl font-semibold tracking-tight text-foreground">
One tier. Month-to-month. Cancel anytime.
</h2>
</div>
<div className="rounded-2xl border-2 border-accent/40 bg-card/60 backdrop-blur-sm p-8 md:p-10 shadow-[0_8px_40px_hsl(43_60%_50%/0.1)]">
<div className="flex items-baseline gap-2 mb-2">
<span className="text-5xl font-bold tracking-tight text-foreground">$500</span>
<span className="text-base text-muted-foreground">/ month</span>
</div>
<p className="text-sm text-muted-foreground mb-8">
Billed monthly via Stripe. Logo goes live within 48 hours of payment.
</p>
<ul className="space-y-3 mb-8">
<PerkRow text="Logo on voicebox.sh — directly below the hero" />
<PerkRow text="Logo in the GitHub README sponsors section" />
<PerkRow text="Featured card on /sponsors with your tagline and link" />
<PerkRow text="Acknowledgement in the next major release post" />
<PerkRow text="Direct line to the team for collaboration" />
</ul>
<a
href={SPONSOR_CHECKOUT_URL}
target="_blank"
rel="noopener noreferrer"
className="flex items-center justify-center gap-2 w-full rounded-full bg-accent px-6 py-3.5 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"
>
Sponsor Voicebox
<ArrowRight className="h-4 w-4" />
</a>
<p className="text-center text-xs text-muted-foreground/70 mt-4">
Need an annual contract, invoicing, or higher placement?{' '}
<a
href={`mailto:${SPONSOR_CONTACT_EMAIL}`}
className="text-foreground/80 underline-offset-4 hover:underline"
>
{SPONSOR_CONTACT_EMAIL}
</a>
</p>
</div>
</div>
</section>
{/* ── Individual / policy ─────────────────────────────────── */}
<section className="border-t border-border py-20">
<div className="mx-auto max-w-4xl px-6 grid md:grid-cols-2 gap-4">
<div className="rounded-xl border border-border bg-card/40 backdrop-blur-sm p-6">
<div className="flex items-center gap-2 mb-3">
<Coffee className="h-5 w-5 text-[#FFDD00]" />
<h3 className="text-[15px] font-semibold text-foreground">Not a company?</h3>
</div>
<p className="text-sm leading-relaxed text-muted-foreground mb-4">
Individual supporters keep Voicebox running too. Drop a tip on Buy Me a Coffee and
your name shows up in the supporters list.
</p>
<a
href={DONATE_URL}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2 text-sm font-medium text-foreground/80 hover:text-foreground transition-colors"
>
Support on Buy Me a Coffee
<ArrowRight className="h-4 w-4" />
</a>
</div>
<div className="rounded-xl border border-border bg-card/40 backdrop-blur-sm p-6">
<h3 className="text-[15px] font-semibold text-foreground mb-3">
Who we accept
</h3>
<p className="text-sm leading-relaxed text-muted-foreground">
Voicebox is local-first and privacy-first. We don't accept sponsorships from
companies whose business model conflicts with that voice-data brokers, ad-tech
built on speech, or surveillance vendors. Everyone else is welcome.
</p>
</div>
</div>
</section>
<Footer />
</>
);
}
function Stat({ value, label, note }: { value: string; label: string; note: string }) {
return (
<div className="rounded-xl border border-border bg-card/40 backdrop-blur-sm p-5 text-center">
<div className="text-3xl md:text-4xl font-bold tracking-tight text-foreground">{value}</div>
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-accent mt-2">
{label}
</div>
<div className="text-xs text-muted-foreground mt-2">{note}</div>
</div>
);
}
function Perk({ title, body }: { title: string; body: string }) {
return (
<div className="rounded-xl border border-border bg-card/40 backdrop-blur-sm p-6">
<h3 className="text-[15px] font-semibold text-foreground mb-2">{title}</h3>
<p className="text-sm leading-relaxed text-muted-foreground">{body}</p>
</div>
);
}
function PerkRow({ text }: { text: string }) {
return (
<li className="flex items-start gap-3 text-sm text-foreground/90">
<Check className="h-5 w-5 shrink-0 text-accent mt-px" />
<span>{text}</span>
</li>
);
}
+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>
);
}
+5 -2
View File
@@ -5,8 +5,11 @@ export const LATEST_VERSION = 'v0.1.0';
export const GITHUB_REPO = 'https://github.com/jamiepine/voicebox';
export const GITHUB_RELEASES_PAGE = `${GITHUB_REPO}/releases`;
export const DONATE_URL = 'https://buymeacoffee.com/jamiepine';
export const SPONSOR_CHECKOUT_URL = 'https://buy.stripe.com/eVqdRad3n16ubcqf201Jm00';
export const SPONSOR_CONTACT_EMAIL = '[email protected]';
// $VOICEBOX — the official community token on Solana
export const TOKEN_TICKER = '$VOICEBOX';
export const TOKEN_CONTRACT_ADDRESS = 'FpzZHtp5tbvz6xndEtoJHoGEWcT7cFEuscdCh9RApump';
export const TOKEN_PUMP_URL = `https://pump.fun/coin/${TOKEN_CONTRACT_ADDRESS}`;
export const DOWNLOAD_LINKS = {
macArm: GITHUB_RELEASES_PAGE,
-12
View File
@@ -1,12 +0,0 @@
export type Sponsor = {
name: string;
url: string;
logoSrc: string;
logoAlt?: string;
tagline?: string;
/** Set true for solid-black logos that need to render white on the dark theme. */
invert?: boolean;
};
export const SPONSORS: Sponsor[] = [
];