fix: og image generation
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/page-header";
|
||||||
|
import { buildOgMeta } from "@/lib/og";
|
||||||
import {
|
import {
|
||||||
BookOpen,
|
BookOpen,
|
||||||
BrainCircuit,
|
BrainCircuit,
|
||||||
@@ -45,6 +47,14 @@ const PHASES = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export function generateMetadata(): Metadata {
|
||||||
|
return buildOgMeta({
|
||||||
|
title: "About — Prabhupāda Says",
|
||||||
|
quote:
|
||||||
|
"Built by a small team of Prabhupādānugas — preserving and presenting the teachings of Śrīla Prabhupāda exactly as he gave them, without alteration.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export default function AboutPage() {
|
export default function AboutPage() {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-background">
|
<div className="min-h-screen bg-background">
|
||||||
|
|||||||
+93
-90
@@ -4,20 +4,52 @@ import { join } from "node:path";
|
|||||||
|
|
||||||
export const runtime = "nodejs";
|
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) {
|
export async function GET(request: Request) {
|
||||||
|
try {
|
||||||
const { searchParams } = new URL(request.url);
|
const { searchParams } = new URL(request.url);
|
||||||
|
|
||||||
const title = searchParams.get("title") || "Prabhupāda Says";
|
const title = searchParams.get("title") || "Prabhupāda Says";
|
||||||
const detail = searchParams.get("detail") || "";
|
const detail = searchParams.get("detail") || "";
|
||||||
const quote = searchParams.get("quote") || "";
|
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
|
// Truncate for readability and to prevent overflow
|
||||||
const displayTitle = title.length > 60 ? title.slice(0, 57) + "..." : title;
|
const displayTitle = title.length > 60 ? title.slice(0, 57) + "..." : title;
|
||||||
const displayDetail =
|
const displayDetail =
|
||||||
detail.length > 80 ? detail.slice(0, 77) + "..." : detail;
|
detail.length > 80 ? detail.slice(0, 77) + "..." : detail;
|
||||||
const displayQuote = quote.length > 220 ? quote.slice(0, 217) + "..." : quote;
|
const displayQuote =
|
||||||
|
quote.length > 220 ? quote.slice(0, 217) + "..." : quote;
|
||||||
|
|
||||||
|
// Load fonts and image
|
||||||
|
const fonts = await loadFonts();
|
||||||
|
|
||||||
// Load the Prabhupāda image as base64
|
|
||||||
const imgData = await readFile(
|
const imgData = await readFile(
|
||||||
join(process.cwd(), "public/images/og-left-prabhupada-reading.png"),
|
join(process.cwd(), "public/images/og-left-prabhupada-reading.png"),
|
||||||
"base64",
|
"base64",
|
||||||
@@ -27,12 +59,12 @@ export async function GET(request: Request) {
|
|||||||
return new ImageResponse(
|
return new ImageResponse(
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
width: "1200",
|
width: 1200,
|
||||||
height: "630",
|
height: 630,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
backgroundColor: "#faf5f0",
|
backgroundColor: "#faf5f0",
|
||||||
fontFamily: "sans-serif",
|
fontFamily: "Geist, sans-serif",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
position: "relative",
|
position: "relative",
|
||||||
}}
|
}}
|
||||||
@@ -40,137 +72,89 @@ export async function GET(request: Request) {
|
|||||||
{/* Left side — image + branding */}
|
{/* Left side — image + branding */}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
width: "460",
|
width: 460,
|
||||||
height: "630",
|
height: 630,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "flex-end",
|
justifyContent: "center",
|
||||||
position: "relative",
|
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
|
padding: 20,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Decorative quote mark */}
|
{/* Prabhupāda image — already contains quote mark and branding */}
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "absolute",
|
|
||||||
top: "30",
|
|
||||||
left: "30",
|
|
||||||
fontSize: "180",
|
|
||||||
fontWeight: "900",
|
|
||||||
color: "#e8b4b8",
|
|
||||||
lineHeight: "1",
|
|
||||||
display: "flex",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
“
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Prabhupāda image */}
|
|
||||||
<img
|
<img
|
||||||
src={imgSrc}
|
src={imgSrc}
|
||||||
width="420"
|
width={420}
|
||||||
height="500"
|
height={590}
|
||||||
style={{
|
style={{
|
||||||
objectFit: "contain",
|
objectFit: "contain",
|
||||||
objectPosition: "bottom",
|
objectPosition: "center",
|
||||||
marginBottom: "0",
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Branding at the bottom */}
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
alignItems: "center",
|
|
||||||
paddingBottom: "24",
|
|
||||||
marginTop: "-10",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
fontSize: "36",
|
|
||||||
color: "#d4929a",
|
|
||||||
fontStyle: "italic",
|
|
||||||
fontWeight: "600",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Prabhupāda
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
fontSize: "20",
|
|
||||||
color: "#d4929a",
|
|
||||||
fontWeight: "700",
|
|
||||||
letterSpacing: "2",
|
|
||||||
marginTop: "-2",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
says
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right side — content */}
|
{/* Right side — content */}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
flex: "1",
|
flex: 1,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
padding: "50 60 50 30",
|
paddingTop: 50,
|
||||||
gap: "16",
|
paddingRight: 60,
|
||||||
|
paddingBottom: 50,
|
||||||
|
paddingLeft: 60,
|
||||||
|
gap: 16,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Title */}
|
{/* Title */}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
fontSize: "44",
|
fontSize: 36,
|
||||||
fontWeight: "800",
|
fontWeight: 700,
|
||||||
color: "#2d2418",
|
color: "#2d2418",
|
||||||
lineHeight: "1.15",
|
lineHeight: 1.15,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
maxHeight: "102",
|
maxHeight: 84,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{displayTitle}
|
{displayTitle}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Detail (chapter, verse, etc.) */}
|
{/* Detail (chapter, verse, etc.) */}
|
||||||
{displayDetail && (
|
{displayDetail ? (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
fontSize: "22",
|
fontSize: 22,
|
||||||
fontWeight: "600",
|
fontWeight: 600,
|
||||||
color: "#5a4a3a",
|
color: "#5a4a3a",
|
||||||
lineHeight: "1.3",
|
lineHeight: 1.3,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
maxHeight: "30",
|
maxHeight: 30,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{displayDetail}
|
{displayDetail}
|
||||||
</div>
|
</div>
|
||||||
)}
|
) : null}
|
||||||
|
|
||||||
{/* Quote text */}
|
{/* Quote text */}
|
||||||
{displayQuote && (
|
{displayQuote ? (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
marginTop: "16",
|
marginTop: 16,
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
maxHeight: "180",
|
maxHeight: 180,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
fontSize: "24",
|
fontSize: 24,
|
||||||
color: "#3d3228",
|
color: "#3d3228",
|
||||||
lineHeight: "1.5",
|
lineHeight: 1.5,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
}}
|
}}
|
||||||
@@ -178,21 +162,22 @@ export async function GET(request: Request) {
|
|||||||
{displayQuote}
|
{displayQuote}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
) : null}
|
||||||
|
|
||||||
{/* Read more */}
|
{/* Read more */}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
gap: "6",
|
gap: 6,
|
||||||
marginTop: "16",
|
marginTop: 16,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fontSize: "18",
|
fontSize: 18,
|
||||||
fontWeight: "700",
|
fontWeight: 700,
|
||||||
color: "#5a4a3a",
|
color: "#5a4a3a",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -200,8 +185,8 @@ export async function GET(request: Request) {
|
|||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fontSize: "18",
|
fontSize: 18,
|
||||||
fontWeight: "700",
|
fontWeight: 700,
|
||||||
color: "#c47a5a",
|
color: "#c47a5a",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -213,6 +198,24 @@ export async function GET(request: Request) {
|
|||||||
{
|
{
|
||||||
width: 1200,
|
width: 1200,
|
||||||
height: 630,
|
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 });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
import type { Metadata } from "next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/page-header";
|
||||||
|
import { ogForDisciples } from "@/lib/og";
|
||||||
import {
|
import {
|
||||||
getTotalDiscipleCount,
|
getTotalDiscipleCount,
|
||||||
getFilteredDisciples,
|
getFilteredDisciples,
|
||||||
@@ -14,6 +16,10 @@ import {
|
|||||||
import type { SuffixFilter } from "@/lib/disciples";
|
import type { SuffixFilter } from "@/lib/disciples";
|
||||||
import { DisciplesBrowser } from "./disciples-browser";
|
import { DisciplesBrowser } from "./disciples-browser";
|
||||||
|
|
||||||
|
export async function generateMetadata(): Promise<Metadata> {
|
||||||
|
return ogForDisciples();
|
||||||
|
}
|
||||||
|
|
||||||
const VALID_SUFFIXES: SuffixFilter[] = ["all", "Dasa", "Devi Dasi"];
|
const VALID_SUFFIXES: SuffixFilter[] = ["all", "Dasa", "Devi Dasi"];
|
||||||
|
|
||||||
function parseSuffix(raw: string | undefined): SuffixFilter {
|
function parseSuffix(raw: string | undefined): SuffixFilter {
|
||||||
|
|||||||
@@ -1,10 +1,21 @@
|
|||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
import type { Metadata } from "next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/page-header";
|
||||||
|
import { buildOgMeta } from "@/lib/og";
|
||||||
import { prisma } from "@/lib/db";
|
import { prisma } from "@/lib/db";
|
||||||
import { EssaysGrid } from "./essays-grid";
|
import { EssaysGrid } from "./essays-grid";
|
||||||
|
|
||||||
|
export function generateMetadata(): Metadata {
|
||||||
|
return buildOgMeta({
|
||||||
|
title: "Essays",
|
||||||
|
detail: "Standalone essays by Śrīla Prabhupāda",
|
||||||
|
quote:
|
||||||
|
"Foundational essays on the science of Kṛṣṇa consciousness by His Divine Grace A.C. Bhaktivedanta Swami Prabhupāda.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function getAllEssays() {
|
async function getAllEssays() {
|
||||||
return prisma.essay.findMany({
|
return prisma.essay.findMany({
|
||||||
orderBy: [{ group: "asc" }, { order: "asc" }],
|
orderBy: [{ group: "asc" }, { order: "asc" }],
|
||||||
|
|||||||
@@ -1,7 +1,18 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/page-header";
|
||||||
import { GlossaryClient } from "./glossary-client";
|
import { GlossaryClient } from "./glossary-client";
|
||||||
import { getAllGlossaryEntries } from "@/lib/api";
|
import { getAllGlossaryEntries } from "@/lib/api";
|
||||||
|
import { buildOgMeta } from "@/lib/og";
|
||||||
|
|
||||||
|
export function generateMetadata(): Metadata {
|
||||||
|
return buildOgMeta({
|
||||||
|
title: "Glossary",
|
||||||
|
detail: "2,700+ Sanskrit & Vedic terms",
|
||||||
|
quote:
|
||||||
|
"A comprehensive glossary of Sanskrit and Vedic terms from the books of Śrīla Prabhupāda.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export default async function GlossaryPage() {
|
export default async function GlossaryPage() {
|
||||||
const entries = await getAllGlossaryEntries();
|
const entries = await getAllGlossaryEntries();
|
||||||
|
|||||||
+40
-7
@@ -1,18 +1,38 @@
|
|||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
import type { Metadata } from "next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/page-header";
|
||||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@/components/ui/card";
|
import { buildOgMeta } from "@/lib/og";
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
CardDescription,
|
||||||
|
CardContent,
|
||||||
|
} from "@/components/ui/card";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { getAllJournals, bookCodeToSlug } from "@/lib/journals";
|
import { getAllJournals, bookCodeToSlug } from "@/lib/journals";
|
||||||
|
|
||||||
|
export function generateMetadata(): Metadata {
|
||||||
|
return buildOgMeta({
|
||||||
|
title: "Journals",
|
||||||
|
detail: "Personal diaries and journals of Śrīla Prabhupāda",
|
||||||
|
quote:
|
||||||
|
"From the personal journals of Śrīla Prabhupāda — a window into the daily life and mission of the Founder-Ācārya of ISKCON.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export default async function JournalsPage() {
|
export default async function JournalsPage() {
|
||||||
const journals = await getAllJournals();
|
const journals = await getAllJournals();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-background">
|
<div className="min-h-screen bg-background">
|
||||||
<PageHeader>
|
<PageHeader>
|
||||||
<Link href="/" className="text-sm text-muted-foreground hover:text-foreground transition-colors">
|
<Link
|
||||||
|
href="/"
|
||||||
|
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
||||||
|
>
|
||||||
← Home
|
← Home
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-3xl font-bold text-foreground">Journals</h1>
|
<h1 className="mt-3 text-3xl font-bold text-foreground">Journals</h1>
|
||||||
@@ -24,20 +44,33 @@ export default async function JournalsPage() {
|
|||||||
<main className="max-w-5xl mx-auto px-6 py-8">
|
<main className="max-w-5xl mx-auto px-6 py-8">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
{journals.map((journal) => (
|
{journals.map((journal) => (
|
||||||
<Link key={journal.book} href={`/journals/${bookCodeToSlug(journal.book)}`} className="block h-full">
|
<Link
|
||||||
|
key={journal.book}
|
||||||
|
href={`/journals/${bookCodeToSlug(journal.book)}`}
|
||||||
|
className="block h-full"
|
||||||
|
>
|
||||||
<Card className="h-full transition-all hover:shadow-md hover:ring-foreground/20">
|
<Card className="h-full transition-all hover:shadow-md hover:ring-foreground/20">
|
||||||
<CardHeader className="pb-2">
|
<CardHeader className="pb-2">
|
||||||
<CardTitle className="text-base font-bold leading-snug">{journal.title}</CardTitle>
|
<CardTitle className="text-base font-bold leading-snug">
|
||||||
|
{journal.title}
|
||||||
|
</CardTitle>
|
||||||
{journal.description && (
|
{journal.description && (
|
||||||
<CardDescription className="text-xs line-clamp-2">{journal.description}</CardDescription>
|
<CardDescription className="text-xs line-clamp-2">
|
||||||
|
{journal.description}
|
||||||
|
</CardDescription>
|
||||||
)}
|
)}
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="pt-0">
|
<CardContent className="pt-0">
|
||||||
<div className="flex flex-wrap items-center gap-2 text-sm">
|
<div className="flex flex-wrap items-center gap-2 text-sm">
|
||||||
{journal.year && <Badge variant="secondary" className="text-xs">{journal.year}</Badge>}
|
{journal.year && (
|
||||||
|
<Badge variant="secondary" className="text-xs">
|
||||||
|
{journal.year}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
{journal.totalChapters > 0 && (
|
{journal.totalChapters > 0 && (
|
||||||
<span className="text-muted-foreground text-xs">
|
<span className="text-muted-foreground text-xs">
|
||||||
{journal.totalChapters} {journal.totalChapters === 1 ? "chapter" : "chapters"}
|
{journal.totalChapters}{" "}
|
||||||
|
{journal.totalChapters === 1 ? "chapter" : "chapters"}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,23 @@
|
|||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
import type { Metadata } from "next";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { getLettersByLocation } from "@/lib/letters";
|
import { getLettersByLocation } from "@/lib/letters";
|
||||||
|
import { ogForLettersByLocation } from "@/lib/og";
|
||||||
import { FilterYearBrowser } from "../../filter-year-browser";
|
import { FilterYearBrowser } from "../../filter-year-browser";
|
||||||
|
|
||||||
|
export async function generateMetadata({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ name: string }>;
|
||||||
|
}): Promise<Metadata> {
|
||||||
|
const { name: encodedName } = await params;
|
||||||
|
const name = decodeURIComponent(encodedName);
|
||||||
|
const letters = await getLettersByLocation(name);
|
||||||
|
if (letters.length === 0) return {};
|
||||||
|
return ogForLettersByLocation(name, letters.length);
|
||||||
|
}
|
||||||
|
|
||||||
export default async function LettersByLocationPage({
|
export default async function LettersByLocationPage({
|
||||||
params,
|
params,
|
||||||
}: {
|
}: {
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
import type { Metadata } from "next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/page-header";
|
||||||
|
import { buildOgMeta } from "@/lib/og";
|
||||||
import {
|
import {
|
||||||
getLetterYears,
|
getLetterYears,
|
||||||
getLetterRecipients,
|
getLetterRecipients,
|
||||||
@@ -11,6 +13,15 @@ import {
|
|||||||
import { LettersNav } from "./letters-nav";
|
import { LettersNav } from "./letters-nav";
|
||||||
import { LettersBrowser } from "./letters-browser";
|
import { LettersBrowser } from "./letters-browser";
|
||||||
|
|
||||||
|
export function generateMetadata(): Metadata {
|
||||||
|
return buildOgMeta({
|
||||||
|
title: "Letters",
|
||||||
|
detail: "6,800+ letters (1947–1977)",
|
||||||
|
quote:
|
||||||
|
"Personal correspondence by Śrīla Prabhupāda — guiding disciples, Godbrothers, and well-wishers in the science of Kṛṣṇa consciousness.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export default async function LettersPage({
|
export default async function LettersPage({
|
||||||
searchParams,
|
searchParams,
|
||||||
}: {
|
}: {
|
||||||
|
|||||||
@@ -1,9 +1,23 @@
|
|||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
import type { Metadata } from "next";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { getLettersByRecipient } from "@/lib/letters";
|
import { getLettersByRecipient } from "@/lib/letters";
|
||||||
|
import { ogForLettersByRecipient } from "@/lib/og";
|
||||||
import { FilterYearBrowser } from "../../filter-year-browser";
|
import { FilterYearBrowser } from "../../filter-year-browser";
|
||||||
|
|
||||||
|
export async function generateMetadata({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ name: string }>;
|
||||||
|
}): Promise<Metadata> {
|
||||||
|
const { name: encodedName } = await params;
|
||||||
|
const name = decodeURIComponent(encodedName);
|
||||||
|
const letters = await getLettersByRecipient(name);
|
||||||
|
if (letters.length === 0) return {};
|
||||||
|
return ogForLettersByRecipient(name, letters.length);
|
||||||
|
}
|
||||||
|
|
||||||
export default async function LettersByRecipientPage({
|
export default async function LettersByRecipientPage({
|
||||||
params,
|
params,
|
||||||
}: {
|
}: {
|
||||||
|
|||||||
@@ -1,9 +1,23 @@
|
|||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
import type { Metadata } from "next";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { getLettersByYear } from "@/lib/letters";
|
import { getLettersByYear } from "@/lib/letters";
|
||||||
|
import { ogForLettersByYear } from "@/lib/og";
|
||||||
import { YearMonthBrowser } from "./year-month-browser";
|
import { YearMonthBrowser } from "./year-month-browser";
|
||||||
|
|
||||||
|
export async function generateMetadata({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ year: string }>;
|
||||||
|
}): Promise<Metadata> {
|
||||||
|
const { year: yearStr } = await params;
|
||||||
|
const year = parseInt(yearStr, 10);
|
||||||
|
if (isNaN(year)) return {};
|
||||||
|
const letters = await getLettersByYear(year);
|
||||||
|
return ogForLettersByYear(year, letters.length);
|
||||||
|
}
|
||||||
|
|
||||||
export default async function LettersByYearPage({
|
export default async function LettersByYearPage({
|
||||||
params,
|
params,
|
||||||
}: {
|
}: {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
import type { Metadata } from "next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/page-header";
|
||||||
import {
|
import {
|
||||||
@@ -11,6 +12,16 @@ import {
|
|||||||
} from "@/components/ui/card";
|
} from "@/components/ui/card";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { getAllMagazines, bookCodeToSlug } from "@/lib/magazines";
|
import { getAllMagazines, bookCodeToSlug } from "@/lib/magazines";
|
||||||
|
import { buildOgMeta } from "@/lib/og";
|
||||||
|
|
||||||
|
export function generateMetadata(): Metadata {
|
||||||
|
return buildOgMeta({
|
||||||
|
title: "Magazines",
|
||||||
|
detail: "Back to Godhead & other periodicals",
|
||||||
|
quote:
|
||||||
|
"Back to Godhead — the magazine founded by Śrīla Prabhupāda in 1944 to present the timeless science of Kṛṣṇa consciousness.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export default async function MagazinesPage() {
|
export default async function MagazinesPage() {
|
||||||
const magazines = await getAllMagazines();
|
const magazines = await getAllMagazines();
|
||||||
|
|||||||
@@ -1,9 +1,20 @@
|
|||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
import type { Metadata } from "next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/page-header";
|
||||||
import { getAllOtherDocuments, bookCodeToSlug } from "@/lib/other-documents";
|
import { getAllOtherDocuments, bookCodeToSlug } from "@/lib/other-documents";
|
||||||
import { OtherDocumentsGrid } from "./other-documents-grid";
|
import { OtherDocumentsGrid } from "./other-documents-grid";
|
||||||
|
import { buildOgMeta } from "@/lib/og";
|
||||||
|
|
||||||
|
export function generateMetadata(): Metadata {
|
||||||
|
return buildOgMeta({
|
||||||
|
title: "Other Documents",
|
||||||
|
detail: "Miscellaneous analyses & writings",
|
||||||
|
quote:
|
||||||
|
"Writings and analyses by His Divine Grace A.C. Bhaktivedanta Swami Prabhupāda.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export default async function OtherDocumentsPage() {
|
export default async function OtherDocumentsPage() {
|
||||||
const documents = await getAllOtherDocuments();
|
const documents = await getAllOtherDocuments();
|
||||||
|
|||||||
@@ -20,6 +20,91 @@ export type OgParams = {
|
|||||||
quote?: string;
|
quote?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Fallback descriptions — used when no quote/description is provided
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const SITE_DESCRIPTION =
|
||||||
|
"Browse the original, unedited books, letters, and teachings of His Divine Grace A.C. Bhaktivedanta Swami Prabhupāda — presented as they are.";
|
||||||
|
|
||||||
|
const BOOK_DESCRIPTIONS: Record<string, string> = {
|
||||||
|
bg: "The definitive guide to the science of self-realization, spoken by Lord Śrī Kṛṣṇa to His devotee Arjuna on the Battlefield of Kurukṣetra.",
|
||||||
|
sb: "The ripened fruit of the tree of Vedic literature — 18,000 verses describing the pastimes of the Supreme Lord and His devotees.",
|
||||||
|
cc: "The life and teachings of Śrī Caitanya Mahāprabhu, the most munificent incarnation of Godhead who distributed love of God freely to all.",
|
||||||
|
sb1962:
|
||||||
|
"The original 1962 edition of Śrīmad-Bhāgavatam — Śrīla Prabhupāda's first major literary contribution in English.",
|
||||||
|
iso: "Eighteen mantras revealing the essential teachings of the Vedas — the relationship between God, the living entity, and the material world.",
|
||||||
|
noi: "Eleven verses by Śrīla Rūpa Gosvāmī providing essential instructions for serious practitioners of devotional service.",
|
||||||
|
nod: "A comprehensive guide to the science of bhakti-yoga, summarizing Śrīla Rūpa Gosvāmī's Bhakti-rasāmṛta-sindhu.",
|
||||||
|
bs: "The prayers of Lord Brahmā glorifying the Supreme Lord Govinda — with translation and commentary by Śrīla Prabhupāda.",
|
||||||
|
mm: "Devotional prayers of King Kulaśekhara expressing the purest sentiments of surrender to Lord Kṛṣṇa.",
|
||||||
|
nbs: "The eternal principles of devotional service as taught by the great sage Nārada Muni.",
|
||||||
|
kb: "The enchanting pastimes of Lord Śrī Kṛṣṇa in Vṛndāvana and Dvārakā — the Supreme Personality of Godhead in His original form.",
|
||||||
|
tlc: "The sublime teachings of Lord Śrī Caitanya Mahāprabhu to Śrīla Sanātana Gosvāmī, Śrīla Rūpa Gosvāmī, and others.",
|
||||||
|
ej: "A scientific presentation of the anti-material world and how the soul can travel there.",
|
||||||
|
ek: "How to elevate consciousness from the material to the spiritual platform through the practice of Kṛṣṇa consciousness.",
|
||||||
|
mg: "An introduction to the unmatched gift of Kṛṣṇa consciousness — the path to eternal happiness and self-realization.",
|
||||||
|
bbd: "A concise exploration of the soul's journey through repeated birth and death, and the path to liberation.",
|
||||||
|
owk: "Practical guidance on the journey toward Kṛṣṇa — developing love of God through devotional service.",
|
||||||
|
rv: "The king of knowledge — understanding the supreme science of devotional service as taught in the Bhagavad-gītā.",
|
||||||
|
poy: "The perfection of the yoga system — how bhakti-yoga surpasses all other forms of yoga and meditation.",
|
||||||
|
pqpa: "Conversations between Śrīla Prabhupāda and Bob Cohen — answering life's most fundamental questions.",
|
||||||
|
ttp: "The teachings of Lord Kapila to His mother Devahūti on the science of God realization and devotional service.",
|
||||||
|
ochkm:
|
||||||
|
"The transcendental vibration of the Hare Kṛṣṇa mahā-mantra — its meaning, potency, and practice.",
|
||||||
|
hkh: "A practical handbook for understanding and practicing Kṛṣṇa consciousness in daily life.",
|
||||||
|
lcl: "Morning walks with Śrīla Prabhupāda — challenging the fundamental assumptions of modern science.",
|
||||||
|
lob: "Meditations on the beauty of nature as a reflection of the Supreme Lord's transcendental opulence.",
|
||||||
|
tlk: "Lord Kapila's instructions on Sāṅkhya philosophy and the path of devotional service.",
|
||||||
|
tqk: "The prayers and teachings of Queen Kuntī — exemplifying pure devotion in the face of adversity.",
|
||||||
|
gg: "Bengali poetic renderings of the Bhagavad-gītā by Śrīla Prabhupāda.",
|
||||||
|
mog: "Śrīla Prabhupāda's message of Godhead — presenting the Absolute Truth for the modern world.",
|
||||||
|
cbhc: "Commentary on the Śrī Caitanya-bhāgavata — the pastimes of Lord Caitanya by Vṛndāvana dāsa Ṭhākura.",
|
||||||
|
bk: "Bhagavāner Kathā — Bengali narration of the pastimes of the Supreme Lord.",
|
||||||
|
pk: "Prabhupāda-Kṛpā — the mercy of Śrīla Prabhupāda preserved in his writings.",
|
||||||
|
ssr: "Conversations and essays illuminating the timeless science of self-realization for the modern reader.",
|
||||||
|
ds: "Śrīla Prabhupāda's critique of Western philosophy from Socrates to Sartre — in light of Vedic wisdom.",
|
||||||
|
sva: "Sacred songs of the great Vaiṣṇava ācāryas — prayers and bhajanas with translations and purports.",
|
||||||
|
va: "Śrīla Prabhupāda's commentary on the Vedānta-sūtra — the conclusion of all Vedic knowledge.",
|
||||||
|
};
|
||||||
|
|
||||||
|
const CONTENT_TYPE_DESCRIPTIONS: Record<string, string> = {
|
||||||
|
letters:
|
||||||
|
"Personal correspondence by Śrīla Prabhupāda — guiding disciples, Godbrothers, and well-wishers in the science of Kṛṣṇa consciousness.",
|
||||||
|
essays:
|
||||||
|
"Foundational essays on the science of Kṛṣṇa consciousness by His Divine Grace A.C. Bhaktivedanta Swami Prabhupāda.",
|
||||||
|
glossary:
|
||||||
|
"A comprehensive glossary of Sanskrit and Vedic terms from the books of Śrīla Prabhupāda.",
|
||||||
|
disciples:
|
||||||
|
"A directory of disciples initiated by Śrīla Prabhupāda between 1966 and 1977.",
|
||||||
|
journals:
|
||||||
|
"From the personal journals of Śrīla Prabhupāda — a window into the daily life and mission of the Founder-Ācārya of ISKCON.",
|
||||||
|
magazines:
|
||||||
|
"Back to Godhead — the magazine founded by Śrīla Prabhupāda in 1944 to present the timeless science of Kṛṣṇa consciousness.",
|
||||||
|
"other-documents":
|
||||||
|
"Writings and analyses by His Divine Grace A.C. Bhaktivedanta Swami Prabhupāda.",
|
||||||
|
};
|
||||||
|
|
||||||
|
function getFallbackQuote(title: string, code?: string): string {
|
||||||
|
// Book-specific description
|
||||||
|
if (code && BOOK_DESCRIPTIONS[code]) {
|
||||||
|
return BOOK_DESCRIPTIONS[code];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Content-type descriptions
|
||||||
|
if (title.startsWith("Letter to")) {
|
||||||
|
return CONTENT_TYPE_DESCRIPTIONS.letters;
|
||||||
|
}
|
||||||
|
for (const [key, desc] of Object.entries(CONTENT_TYPE_DESCRIPTIONS)) {
|
||||||
|
if (title.toLowerCase().includes(key)) {
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generic fallback
|
||||||
|
return SITE_DESCRIPTION;
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Build the /api/og image URL
|
// Build the /api/og image URL
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -92,7 +177,10 @@ export function buildOgMeta(params: OgParams & { description?: string }) {
|
|||||||
/** OG metadata for a book page. */
|
/** OG metadata for a book page. */
|
||||||
export function ogForBook(code: string) {
|
export function ogForBook(code: string) {
|
||||||
const title = BOOK_NAMES[code] || code.toUpperCase();
|
const title = BOOK_NAMES[code] || code.toUpperCase();
|
||||||
return buildOgMeta({ title });
|
return buildOgMeta({
|
||||||
|
title,
|
||||||
|
quote: getFallbackQuote(title, code),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** OG metadata for a verse page. */
|
/** OG metadata for a verse page. */
|
||||||
@@ -112,13 +200,21 @@ export function ogForVerse(
|
|||||||
detail = `Chapter ${parts.chapter}, Verse ${parts.verse}`;
|
detail = `Chapter ${parts.chapter}, Verse ${parts.verse}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildOgMeta({ title, detail });
|
return buildOgMeta({
|
||||||
|
title,
|
||||||
|
detail,
|
||||||
|
quote: getFallbackQuote(title, code),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** OG metadata for a prose chapter. */
|
/** OG metadata for a prose chapter. */
|
||||||
export function ogForChapter(code: string, chapterTitle: string) {
|
export function ogForChapter(code: string, chapterTitle: string) {
|
||||||
const bookTitle = BOOK_NAMES[code] || code.toUpperCase();
|
const bookTitle = BOOK_NAMES[code] || code.toUpperCase();
|
||||||
return buildOgMeta({ title: bookTitle, detail: chapterTitle });
|
return buildOgMeta({
|
||||||
|
title: bookTitle,
|
||||||
|
detail: chapterTitle,
|
||||||
|
quote: getFallbackQuote(bookTitle, code),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** OG metadata for an essay. */
|
/** OG metadata for an essay. */
|
||||||
@@ -126,6 +222,7 @@ export function ogForEssay(title: string) {
|
|||||||
return buildOgMeta({
|
return buildOgMeta({
|
||||||
title,
|
title,
|
||||||
detail: "Essay by Śrīla Prabhupāda",
|
detail: "Essay by Śrīla Prabhupāda",
|
||||||
|
quote: CONTENT_TYPE_DESCRIPTIONS.essays,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,6 +231,7 @@ export function ogForLetter(recipient: string, meta?: string) {
|
|||||||
return buildOgMeta({
|
return buildOgMeta({
|
||||||
title: `Letter to ${recipient}`,
|
title: `Letter to ${recipient}`,
|
||||||
detail: meta || undefined,
|
detail: meta || undefined,
|
||||||
|
quote: CONTENT_TYPE_DESCRIPTIONS.letters,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,6 +240,7 @@ export function ogForJournal(journalTitle: string, entryTitle?: string) {
|
|||||||
return buildOgMeta({
|
return buildOgMeta({
|
||||||
title: journalTitle,
|
title: journalTitle,
|
||||||
detail: entryTitle || undefined,
|
detail: entryTitle || undefined,
|
||||||
|
quote: CONTENT_TYPE_DESCRIPTIONS.journals,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,6 +249,7 @@ export function ogForMagazine(magazineTitle: string, issueTitle?: string) {
|
|||||||
return buildOgMeta({
|
return buildOgMeta({
|
||||||
title: magazineTitle,
|
title: magazineTitle,
|
||||||
detail: issueTitle || undefined,
|
detail: issueTitle || undefined,
|
||||||
|
quote: CONTENT_TYPE_DESCRIPTIONS.magazines,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,6 +258,42 @@ export function ogForOtherDocument(docTitle: string, chapterTitle?: string) {
|
|||||||
return buildOgMeta({
|
return buildOgMeta({
|
||||||
title: docTitle,
|
title: docTitle,
|
||||||
detail: chapterTitle || undefined,
|
detail: chapterTitle || undefined,
|
||||||
|
quote: CONTENT_TYPE_DESCRIPTIONS["other-documents"],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** OG metadata for the disciples directory. */
|
||||||
|
export function ogForDisciples() {
|
||||||
|
return buildOgMeta({
|
||||||
|
title: "Disciples of Śrīla Prabhupāda",
|
||||||
|
quote: CONTENT_TYPE_DESCRIPTIONS.disciples,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** OG metadata for letters filtered by year. */
|
||||||
|
export function ogForLettersByYear(year: number, count: number) {
|
||||||
|
return buildOgMeta({
|
||||||
|
title: `Letters from ${year}`,
|
||||||
|
detail: `${count} ${count === 1 ? "letter" : "letters"}`,
|
||||||
|
quote: `Śrīla Prabhupāda's correspondence from ${year} — personal letters guiding disciples and well-wishers in the science of Kṛṣṇa consciousness.`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** OG metadata for letters filtered by recipient. */
|
||||||
|
export function ogForLettersByRecipient(name: string, count: number) {
|
||||||
|
return buildOgMeta({
|
||||||
|
title: `Letters to ${name}`,
|
||||||
|
detail: `${count} ${count === 1 ? "letter" : "letters"}`,
|
||||||
|
quote: `Śrīla Prabhupāda's personal correspondence to ${name} — instructions, blessings, and guidance in devotional service.`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** OG metadata for letters filtered by location. */
|
||||||
|
export function ogForLettersByLocation(location: string, count: number) {
|
||||||
|
return buildOgMeta({
|
||||||
|
title: `Letters from ${location}`,
|
||||||
|
detail: `${count} ${count === 1 ? "letter" : "letters"}`,
|
||||||
|
quote: `Śrīla Prabhupāda's letters written from ${location} — chronicling the worldwide mission of the Hare Kṛṣṇa movement.`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +301,7 @@ export function ogForOtherDocument(docTitle: string, chapterTitle?: string) {
|
|||||||
export function ogDefault() {
|
export function ogDefault() {
|
||||||
return buildOgMeta({
|
return buildOgMeta({
|
||||||
title: "Prabhupāda Says",
|
title: "Prabhupāda Says",
|
||||||
description:
|
description: SITE_DESCRIPTION,
|
||||||
"Browse the books and teachings of His Divine Grace A.C. Bhaktivedanta Swami Prabhupāda",
|
quote: SITE_DESCRIPTION,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user