add rebrand landing page (#211)

This commit is contained in:
KM Koushik
2025-09-05 22:32:56 +10:00
committed by GitHub
parent 1c8bb550d9
commit 3e6d4d12df
24 changed files with 1508 additions and 513 deletions

View File

@@ -1,27 +1,532 @@
import Image from "next/image";
import Link from "next/link";
import { GitHubStarsButton } from "~/components/GitHubStarsButton";
import { Button } from "@usesend/ui/src/button";
import { TopNav } from "~/components/TopNav";
import { FeatureCard } from "~/components/FeatureCard";
import { FeatureCardPlain } from "~/components/FeatureCardPlain";
import { CodeBlock } from "@usesend/ui/src/code-block";
const REPO = "unsend-dev/unsend";
const REPO_URL = `https://github.com/${REPO}`;
const APP_URL = "https://app.usesend.com";
export default function Page() {
return (
<main className="min-h-screen flex items-center justify-center p-6">
<div className="max-w-2xl text-center space-y-4">
<div className="flex justify-center">
<Image
src="/logo-squircle.png"
alt="useSend logo"
width={64}
height={64}
priority
/>
</div>
<h1 className="text-xl font-mono font-medium text-blue">useSend</h1>
<p className="text-muted-foreground">
Open source email platform for everyone
</p>
<div className="mt-6 flex items-center justify-center gap-3">
<GitHubStarsButton />
</div>
</div>
<main className="min-h-screen bg-sidebar-background text-foreground">
<TopNav />
<Hero />
<TrustedBy />
<Features />
<CodeExample />
<Pricing />
<About />
<Footer />
</main>
);
}
// (Removed unused SectionHeading component)
function Hero() {
return (
<section>
<div className="mx-auto max-w-6xl px-6 py-16 sm:py-24">
<h1 className="mt-6 text-center text-2xl sm:text-4xl font-semibold text-primary font-sans">
The open source email platform for everyone
</h1>
<p className="mt-4 text-center text-base sm:text-lg font-sans max-w-2xl mx-auto">
Send product, transactional and marketing emails.{" "}
<span className="text-primary font-normal">
Pay only for what you send
</span>{" "}
and not for storing contacts. Open source and self-hostable.
</p>
<div className="mt-8 flex flex-col sm:flex-row items-center justify-center gap-3">
<Button size="lg" className="px-6">
<a href={APP_URL} target="_blank" rel="noopener noreferrer">
Get started
</a>
</Button>
<GitHubStarsButton />
</div>
<p className="mt-3 text-center text-xs text-muted-foreground">
Open source Self-host in minutes Free tier
</p>
<div className=" mt-32 mx-auto max-w-5xl">
<div className="rounded-[18px] bg-primary/10 p-1 sm:p-1 ">
<div className="rounded-2xl bg-primary/20 p-1 sm:p-1 ">
<Image
src="/hero-light.png"
alt="useSend product hero"
width={3456}
height={1914}
className="w-full h-auto rounded-xl block dark:hidden"
sizes="(min-width: 1024px) 900px, 100vw"
loading="eager"
priority={false}
/>
<Image
src="/hero-dark.png"
alt="useSend product hero"
width={3456}
height={1914}
className="w-full h-auto rounded-xl hidden dark:block"
sizes="(min-width: 1024px) 900px, 100vw"
loading="eager"
priority={false}
/>
</div>
</div>
</div>
</div>
</section>
);
}
// TopNav moved to a dedicated client component in ~/components/TopNav
function TrustedBy() {
const featured = [
{
quote:
"Transitioned recently to open source email sender useSend for our 30k and growing newsletter. It's such a great product and amazing oss experience.",
author: "Marc Seitz",
company: "papermark.com",
image:
"https://pbs.twimg.com/profile_images/1176854646343852032/iYnUXJ-m_400x400.jpg",
},
{
quote:
"useSend was extremely easy to set up, and I love that it's open source. Koushik has been an absolute awesome person to deal with and helps us with any issues or feedback.",
author: "Tommerty",
company: "doras.to",
image:
"https://cdn.doras.to/doras/user/83bda65b-8d42-4011-9bf0-ab23402776f2-0.890688178917765.webp",
},
];
const quick = [
{
quote: "don't sleep on useSend",
author: "shellscape",
company: "jsx.email",
image:
"https://pbs.twimg.com/profile_images/1698447401781022720/b0DZSc_D_400x400.jpg",
},
{
quote: "Thank you for making useSend!",
author: "Andras Bacsai",
company: "coolify.io",
image:
"https://pbs.twimg.com/profile_images/1884210412524027905/jW4NB4rx_400x400.jpg",
},
{
quote: "I KNOW WHAT TO DO",
author: "VicVijayakumar",
company: "onetimefax.com",
image:
"https://pbs.twimg.com/profile_images/1665351804685524995/W4BpDx5Z_400x400.jpg",
},
];
return (
<section className="py-10 sm:py-20 ">
<div className="mx-auto max-w-6xl px-6">
<div className="text-center tracking-wider text-muted-foreground">
<span className="">Builders and open source teams love </span>
<span className="text-primary font-bold">useSend</span>
</div>
{/* Top: 2 larger testimonials */}
<div className="mt-6 grid grid-cols-1 sm:grid-cols-2 gap-4">
{featured.map((t) => (
<figure
key={t.author + t.company}
className="rounded-xl border border-primary/30 p-5 h-full"
>
<blockquote className="text-sm sm:text-base font-light font-sans ">
{t.quote}
</blockquote>
<div className="mt-5 flex items-center gap-3">
<Image
src={t.image}
alt={`${t.author} avatar`}
width={32}
height={32}
className=" rounded-md border-2 border-primary/50"
/>
<figcaption className="text-sm">
<span className="font-medium">{t.author}</span>
<a
href={`https://${t.company}`}
target="_blank"
className="text-muted-foreground hover:text-primary-light"
>
{" "}
{t.company}
</a>{" "}
</figcaption>
</div>
</figure>
))}
</div>
{/* Bottom: 3 multi-line testimonials (same style as top) */}
<div className="mt-4 grid grid-cols-1 sm:grid-cols-3 gap-4">
{quick.map((t) => (
<figure
key={t.author + t.company}
className="rounded-xl border border-primary/30 p-5 h-full"
>
<blockquote className="text-sm sm:text-base font-light font-sans leading-relaxed">
{t.quote}
</blockquote>
<div className="mt-5 flex items-center gap-3">
<Image
src={t.image}
alt={`${t.author} avatar`}
width={32}
height={32}
className=" rounded-md border-2 border-primary/50"
/>
<figcaption className="text-sm">
<span className="font-medium">{t.author}</span>
<a
href={`https://${t.company}`}
target="_blank"
className="text-muted-foreground hover:text-primary-light"
>
{" "}
{t.company}
</a>
</figcaption>
</div>
</figure>
))}
</div>
</div>
</section>
);
}
function Features() {
// Top: 2 cards (with image area) — Analytics, Editor
const top = [
{
key: "feature-analytics",
title: "Analytics",
content:
"Track deliveries, opens, clicks, bounces and unsubscribes in real time with a simple, searchable log. Filter by domain, status, api key and export them. Track which campaigns perform best.",
imageSrc: "", // add an image like "/analytics.png"
},
{
key: "feature-editor",
title: "Marketing Email Editor",
content:
"Design beautiful campaigns without code using a visual, notion like WYSIWYG editor that works in major email clients. Reuse templates and brand styles, and personalize with variables.",
imageSrc: "", // add an image like "/editor.png"
},
];
// Bottom: 3 cards (no images) — Contact Management, Suppression List, SMTP Relay Service
const bottom = [
{
key: "feature-contacts",
title: "Contact Management",
content:
"Manage contacts, lists, and consent in one place. Import and export easily, keep per-list subscription status. Contacts are automatically updated from bounces and complaints.",
},
{
key: "feature-suppression",
title: "Suppression List",
content:
"Prevent accidental sends. Automatically populated from bounces and complaints, and manage via import/export or API. Works with transactional and marketing emails.",
},
{
key: "feature-smtp",
title: "SMTP Relay",
content:
"Drop-in SMTP relay that works with any app or framework. Do not get vendor lock-in. Comes in handy with services like Supabase",
},
];
return (
<section id="features" className="py-16 sm:py-20">
<div className="mx-auto max-w-6xl px-6">
<div className="text-center">
<div className="mb-2 text-sm uppercase tracking-wider text-primary">
Features
</div>
</div>
{/* Top row: 2 side-by-side cards with images */}
<div className="mt-8 grid grid-cols-1 sm:grid-cols-2 gap-6">
{top.map((f) => (
<FeatureCard
key={f.key}
title={f.title}
content={f.content}
imageSrc={f.imageSrc}
/>
))}
</div>
{/* Bottom row: 3 cards without images */}
<div className="mt-6 grid grid-cols-1 sm:grid-cols-3 gap-6">
{bottom.map((f) => (
<FeatureCardPlain key={f.key} title={f.title} content={f.content} />
))}
</div>
</div>
</section>
);
}
function CodeExample() {
const code = `import { Unsend } from "@unsend/sdk";
const unsend = new Unsend({ apiKey: process.env.UNSEND_API_KEY! });
await unsend.emails.send({
from: "hi@example.com",
to: "you@company.com",
subject: "Welcome to useSend",
template: "welcome", // or html/text
data: { name: "Ada" },
});`;
return (
<section className="py-16 sm:py-20">
<div className="mx-auto max-w-6xl px-6">
<div className="text-center">
<div className="mb-2 text-sm uppercase tracking-wider text-primary">
Developers
</div>
<p className="mt-1 text-xs sm:text-sm text-muted-foreground max-w-2xl mx-auto">
Typed SDKs and simple APIs, so you can focus on product not
plumbing.
</p>
</div>
<div className="mt-8 overflow-hidden">
<div className=" py-2 text-xs text-muted-foreground">TypeScript</div>
<div className="rounded-[18px] bg-primary/20 p-1">
<div className="rounded-[14px] bg-primary/20 p-0.5 shadow-sm">
<div className="bg-background rounded-xl overflow-hidden">
<CodeBlock
lang="typescript"
children={code}
className="p-4 rounded-[10px]"
/>
</div>
</div>
</div>
</div>
<div className="mt-6 flex items-center justify-center gap-3">
<Button size="lg" className="px-6">
<a
href="https://docs.usesend.com"
target="_blank"
rel="noopener noreferrer"
>
Read the docs
</a>
</Button>
</div>
</div>
</section>
);
}
function Pricing() {
const freePerks = [
"Send up to 3000 emails per month",
"Send up to 100 emails per day",
"Can have 1 contact book",
"Can have 1 domain",
"Can have 1 team member",
];
const paidPerks = [
"$10 monthly usage credits",
"Send transactional emails at $0.0004 per email",
"Send marketing emails at $0.001 per email",
"Can have unlimited contact books",
"Can have unlimited domains",
"Can have unlimited team members",
];
return (
<section id="pricing" className="py-16 sm:py-20">
<div className="mx-auto max-w-6xl px-6">
<div className="text-center">
<div className="mb-2 text-sm uppercase tracking-wider text-primary">
PRICING
</div>
<p className="mt-1 text-xs sm:text-sm text-muted-foreground max-w-2xl mx-auto">
pay for what you use, not for storing contacts
</p>
</div>
<div className="mt-8 grid grid-cols-1 sm:grid-cols-2 gap-6">
<PricingCard
title="Free"
price="$0"
note="per month"
perks={freePerks}
/>
<PricingCard
title="Paid"
price="$10"
note="minimum usage per month"
perks={paidPerks}
/>
</div>
</div>
</section>
);
}
type PricingCardProps = {
title: string;
price: string;
note: string;
perks: string[];
};
function PricingCard({ title, price, note, perks }: PricingCardProps) {
return (
<div className="rounded-[18px] bg-primary/20 p-1">
<div className="h-full rounded-[14px] bg-primary/20 p-0.5 shadow-sm">
<div className="bg-background rounded-xl h-full flex flex-col p-5">
<h3 className=" font-medium">{title}</h3>
<div className="mt-2 text-4xl text-primary">{price}</div>
<div className="text-xs text-muted-foreground">{note}</div>
<ul className="mt-4 space-y-2 text-sm mb-20">
{perks.map((perk) => (
<li key={perk} className="flex items-start gap-2">
<CheckIcon className="w-4 h-4 mt-0.5 text-primary" />
<span>{perk}</span>
</li>
))}
</ul>
<div className="mt-auto pt-6">
<Button className="">
<a
href="https://app.usesend.com"
target="_blank"
rel="noopener noreferrer"
>
Get started
</a>
</Button>
</div>
</div>
</div>
</div>
);
}
function About() {
return (
<section id="about" className="py-16 sm:py-20">
<div className="mx-auto max-w-6xl px-6">
<div className="text-center">
<div className="mb-2 text-sm uppercase tracking-wider text-primary">
About
</div>
</div>
<div className="mt-8 max-w-3xl mx-auto text-sm sm:text-base space-y-4">
<p>
As most of email products out there, useSend also uses Amazon SES
under the hood to send emails. We provide an open and alternative
way to send emails reliably and cheaply with a great dashboard.
</p>
<p>
useSend is bootstrapped and funded by the cloud offering and
sponsors. If you self host useSend, please consider{" "}
<a
href="https://github.com/sponsors/KMKoushik"
target="_blank"
className="text-primary-light"
>
sponsoring us
</a>
.
</p>
</div>
</div>
</section>
);
}
// FAQ section removed per request
function Footer() {
return (
<footer className="py-10 border-t border-border">
<div className="mx-auto max-w-6xl px-6 flex flex-col sm:flex-row items-center justify-between gap-4 text-sm text-muted-foreground">
<div className="flex items-center gap-2">
<Image
src="/logo-squircle.png"
alt="useSend"
width={24}
height={24}
/>
<span className="text-primary font-mono">useSend</span>
</div>
<div className="flex items-center gap-4">
<Link href="#features" className="hover:text-foreground">
Features
</Link>
<Link href="/privacy" className="hover:text-foreground">
Privacy
</Link>
<Link href="/terms" className="hover:text-foreground">
Terms
</Link>
<a
href={REPO_URL}
target="_blank"
rel="noopener noreferrer"
className="hover:text-foreground"
>
GitHub
</a>
<a
href={APP_URL}
target="_blank"
rel="noopener noreferrer"
className="hover:text-foreground"
>
Get Started
</a>
</div>
</div>
</footer>
);
}
// Minimal inline icons (stroke-based, sleek)
function CheckIcon({ className = "" }: { className?: string }) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
className={className}
aria-hidden="true"
>
<path d="M20 6 9 17l-5-5" strokeLinecap="round" strokeLinejoin="round" />
</svg>
);
}