diff --git a/src/app/[user]/opengraph-image.tsx b/src/app/[user]/opengraph-image.tsx new file mode 100644 index 0000000..2e2d2fa --- /dev/null +++ b/src/app/[user]/opengraph-image.tsx @@ -0,0 +1,124 @@ +import { ImageResponse } from "next/og"; + +export const runtime = "edge"; +export const alt = "TwelveCash user profile"; +export const size = { + width: 1200, + height: 630, +}; +export const contentType = "image/png"; + +const DEFAULT_DOMAIN = "twelve.cash"; + +function parseUserParam(userParam: string) { + const decoded = decodeURIComponent(userParam); + const [user, domain = DEFAULT_DOMAIN] = decoded.split("@"); + return { user, domain }; +} + +export default async function Image({ + params, +}: { + params: Promise<{ user: string }>; +}) { + const { user: userParam } = await params; + const { user, domain } = parseUserParam(userParam); + const displayName = `${user}@${domain}`; + + return new ImageResponse( + ( +
+
+
TwelveCash
+
Simple Bitcoin Usernames
+
+ +
+
+ Pay me in bitcoin +
+
+ {displayName} +
+
+ +
+
+
BOLT 12 offers • Silent payments • more
+
twelve.cash
+
+
+ ₿ +
+
+
+ ), + { + ...size, + }, + ); +} diff --git a/src/app/[user]/page.tsx b/src/app/[user]/page.tsx index eb5d47d..564487f 100644 --- a/src/app/[user]/page.tsx +++ b/src/app/[user]/page.tsx @@ -1,15 +1,52 @@ -import Bip353Box from "../components/Bip353Box"; -import CopyUserLinkButton from "../features/CopyUserLinkButton"; -import CopyBip353Button from "../features/CopyBip353Button"; -import PaymentDetail from "../components/PaymentDetail"; +import type { Metadata } from "next"; import Button from "../components/Button"; import { ArrowLeftIcon } from "@bitcoin-design/bitcoin-icons-react/filled"; import UserDetails from "../features/UserDetails"; +const DEFAULT_DOMAIN = "twelve.cash"; + +function parseUserParam(userParam: string) { + const decoded = decodeURIComponent(userParam); + const [user, domain = DEFAULT_DOMAIN] = decoded.split("@"); + return { user, domain }; +} + +export async function generateMetadata({ + params, +}: { + params: Promise<{ user: string }>; +}): Promise { + const { user: userParam } = await params; + const { user, domain } = parseUserParam(userParam); + const displayName = `${user}@${domain}`; + const description = `Send bitcoin to ${displayName} with TwelveCash.`; + + return { + title: `${displayName} | TwelveCash`, + description, + openGraph: { + title: `${displayName} | TwelveCash`, + description, + images: [{ url: `/${encodeURIComponent(displayName)}/opengraph-image` }], + }, + twitter: { + card: "summary_large_image", + title: `${displayName} | TwelveCash`, + description, + images: [`/${encodeURIComponent(displayName)}/opengraph-image`], + }, + alternates: { + canonical: `/${encodeURIComponent(displayName)}`, + }, + other: { + "og:image:alt": `${displayName} on TwelveCash`, + }, + }; +} + export default async function User({ params }: { params: Promise<{ user: string }> }) { const { user: userParam } = await params; - const decoded = decodeURIComponent(userParam); - const [user, domain] = decoded.split("@"); + const { user, domain } = parseUserParam(userParam); return (
diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 959fbe7..4db34de 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -9,26 +9,29 @@ import Header from "./components/Header"; const urbanist = Urbanist({ subsets: ["latin"] }); -const title = "TwelveCash | Simple Bitcoin Usernames" -const description = "Get your own TwelveCash address. Supports BOLT 12 offers, Silent payments, and more!" -const poster = "https://twelve.cash/twelve-cash-poster.png" +const title = "TwelveCash | Simple Bitcoin Usernames"; +const description = + "Get your own TwelveCash address. Supports BOLT 12 offers, Silent payments, and more!"; +const poster = "/twelve-cash-poster.png"; export const metadata: Metadata = { - title: title, - description: description, - icons: [{ url: '/favicon.ico', rel: 'icon' }], + metadataBase: new URL(process.env.NEXT_PUBLIC_URL || "https://twelve.cash"), + title, + description, + icons: [{ url: "/favicon.ico", rel: "icon" }], openGraph: { - title: title, - description: description, - images: [{ url: poster }], + title, + description, + images: [{ url: poster }], }, twitter: { - site: "TwelveCash", - description: description, - title: title, - images: poster - } -} + card: "summary_large_image", + site: "@twelvecash", + title, + description, + images: [poster], + }, +}; export default function RootLayout({ children,