Files
spsays-training/app/api/og/route.tsx
T
2026-05-06 01:19:06 +05:30

222 lines
6.0 KiB
TypeScript

import { ImageResponse } from "next/og";
import { readFile } from "node:fs/promises";
import { join } from "node:path";
export const runtime = "nodejs";
// Cache the font data at module level so it's only loaded once
let geistBoldData: ArrayBuffer | null = null;
let geistRegularData: ArrayBuffer | null = null;
async function loadFonts() {
if (!geistBoldData) {
// Fetch Geist Bold from Google Fonts CDN
const boldRes = await fetch(
"https://cdn.jsdelivr.net/fontsource/fonts/geist-sans@latest/latin-700-normal.woff",
);
geistBoldData = await boldRes.arrayBuffer();
}
if (!geistRegularData) {
const regularRes = await fetch(
"https://cdn.jsdelivr.net/fontsource/fonts/geist-sans@latest/latin-400-normal.woff",
);
geistRegularData = await regularRes.arrayBuffer();
}
return { bold: geistBoldData, regular: geistRegularData };
}
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
const title = searchParams.get("title") || "Prabhupāda Says";
const detail = searchParams.get("detail") || "";
const rawQuote = searchParams.get("quote") || "";
// Fallback: if no quote provided, generate one from context
const quote =
rawQuote ||
(title === "Prabhupāda Says"
? "Browse the original, unedited books, letters, and teachings of His Divine Grace A.C. Bhaktivedanta Swami Prabhupāda — presented as they are."
: `Read ${title}${detail ? ` — ${detail}` : ""} by His Divine Grace A.C. Bhaktivedanta Swami Prabhupāda`);
// Truncate for readability and to prevent overflow
const displayTitle = title.length > 60 ? title.slice(0, 57) + "..." : title;
const displayDetail =
detail.length > 80 ? detail.slice(0, 77) + "..." : detail;
const displayQuote =
quote.length > 220 ? quote.slice(0, 217) + "..." : quote;
// Load fonts and image
const fonts = await loadFonts();
const imgData = await readFile(
join(process.cwd(), "public/images/og-left-prabhupada-reading.png"),
"base64",
);
const imgSrc = `data:image/png;base64,${imgData}`;
return new ImageResponse(
<div
style={{
width: 1200,
height: 630,
display: "flex",
flexDirection: "row",
backgroundColor: "#faf5f0",
fontFamily: "Geist, sans-serif",
overflow: "hidden",
position: "relative",
}}
>
{/* Left side — image + branding */}
<div
style={{
width: 460,
height: 630,
display: "flex",
alignItems: "center",
justifyContent: "center",
flexShrink: 0,
padding: 20,
}}
>
{/* Prabhupāda image — already contains quote mark and branding */}
<img
src={imgSrc}
width={420}
height={590}
style={{
objectFit: "contain",
objectPosition: "center",
}}
/>
</div>
{/* Right side — content */}
<div
style={{
flex: 1,
display: "flex",
flexDirection: "column",
justifyContent: "center",
paddingTop: 50,
paddingRight: 60,
paddingBottom: 50,
paddingLeft: 60,
gap: 16,
}}
>
{/* Title */}
<div
style={{
fontSize: 36,
fontWeight: 700,
color: "#2d2418",
lineHeight: 1.15,
display: "flex",
overflow: "hidden",
maxHeight: 84,
}}
>
{displayTitle}
</div>
{/* Detail (chapter, verse, etc.) */}
{displayDetail ? (
<div
style={{
fontSize: 22,
fontWeight: 600,
color: "#5a4a3a",
lineHeight: 1.3,
display: "flex",
overflow: "hidden",
maxHeight: 30,
}}
>
{displayDetail}
</div>
) : null}
{/* Quote text */}
{displayQuote ? (
<div
style={{
display: "flex",
flexDirection: "column",
marginTop: 16,
overflow: "hidden",
maxHeight: 180,
}}
>
<div
style={{
fontSize: 24,
color: "#3d3228",
lineHeight: 1.5,
display: "flex",
overflow: "hidden",
}}
>
{displayQuote}
</div>
</div>
) : null}
{/* Read more */}
<div
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
gap: 6,
marginTop: 16,
}}
>
<span
style={{
fontSize: 18,
fontWeight: 700,
color: "#5a4a3a",
}}
>
Read more at
</span>
<span
style={{
fontSize: 18,
fontWeight: 700,
color: "#c47a5a",
}}
>
prabhupadasays.org
</span>
</div>
</div>
</div>,
{
width: 1200,
height: 630,
fonts: [
{
name: "Geist",
data: fonts.regular,
style: "normal" as const,
weight: 400,
},
{
name: "Geist",
data: fonts.bold,
style: "normal" as const,
weight: 700,
},
],
},
);
} catch (e) {
console.error("OG image generation failed:", e);
return new Response("Failed to generate OG image", { status: 500 });
}
}