feat(seo): add sitemap generator

This commit is contained in:
gosangam
2026-06-15 13:52:12 +05:30
parent 6cc9285bad
commit be4c2f17fe
83 changed files with 633 additions and 8 deletions
+2
View File
@@ -1,3 +1,5 @@
NEXT_PUBLIC_SITE_URL=https://prabhupadasays.org
# BFF API Server (server-side fetches) # BFF API Server (server-side fetches)
BFF_URL=http://localhost:8080 BFF_URL=http://localhost:8080
+3
View File
@@ -13,6 +13,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -71,6 +73,7 @@ export default async function BbdChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/bbd/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "Beyond Birth and Death" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/bbd" href="/books/bbd"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getBbdMeta, getBbdIntroSegments } from "@/lib/bbd"; import { getBbdMeta, getBbdIntroSegments } from "@/lib/bbd";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -20,6 +22,7 @@ export default async function BbdPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/bbd", name: "Beyond Birth and Death" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -4,6 +4,8 @@ import { notFound } from "next/navigation";
import { getBookMeta, getProseChapters } from "@/lib/api"; import { getBookMeta, getProseChapters } from "@/lib/api";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { ExtractedVerseCount } from "../extracted-verse-count"; import { ExtractedVerseCount } from "../extracted-verse-count";
@@ -34,6 +36,7 @@ export default async function BgPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/bg", name: "Bhagavad-gītā As It Is" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -11,6 +11,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -63,6 +65,7 @@ export default async function BkChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/bk/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "Bhagavāner Kathā" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/bk" href="/books/bk"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getBkMeta } from "@/lib/bk"; import { getBkMeta } from "@/lib/bk";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -18,6 +20,7 @@ export default async function BkPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/bk", name: "Bhagavāner Kathā" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getBookMeta } from "@/lib/api"; import { getBookMeta } from "@/lib/api";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { ExtractedVerseCount } from "../extracted-verse-count"; import { ExtractedVerseCount } from "../extracted-verse-count";
import fs from "fs"; import fs from "fs";
@@ -80,6 +82,7 @@ export default async function BsPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/bs", name: "Śrī Brahma-saṁhitā" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -11,6 +11,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -63,6 +65,7 @@ export default async function CbhcChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/cbhc/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "Śrī Caitanya-bhāgavata Commentary" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/cbhc" href="/books/cbhc"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getCbhcMeta } from "@/lib/cbhc"; import { getCbhcMeta } from "@/lib/cbhc";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -18,6 +20,7 @@ export default async function CbhcPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/cbhc", name: "Śrī Caitanya-bhāgavata Commentary" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -3,6 +3,8 @@ import Link from "next/link";
import { getBookMeta, getProseChapters } from "@/lib/api"; import { getBookMeta, getProseChapters } from "@/lib/api";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { ExtractedVerseCount } from "../extracted-verse-count"; import { ExtractedVerseCount } from "../extracted-verse-count";
@@ -44,6 +46,7 @@ export default async function CcPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/cc", name: "Śrī Caitanya-caritāmṛta" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+16
View File
@@ -7,6 +7,9 @@ import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { ChevronLeft, ChevronRight, Loader2 } from "lucide-react"; import { ChevronLeft, ChevronRight, Loader2 } from "lucide-react";
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav"; import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { BOOK_NAMES } from "@/lib/constants";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Types // Types
@@ -389,6 +392,19 @@ export function ChapterViewer({
return ( return (
<> <>
{/* Structured data for the currently-shown verse (SSR'd for the initial
verse, updates on client navigation). */}
{currentVerse ? (
<JsonLd
data={articleJsonLd({
path: `${basePath}/${currentVerseNum}`,
headline: `${BOOK_NAMES[book] ?? book} ${currentVerse.reference}`,
description: currentVerse.translation,
isPartOf: BOOK_NAMES[book] ?? book,
})}
/>
) : null}
{/* ---- Sidebar: Verse Index ---- */} {/* ---- Sidebar: Verse Index ---- */}
{/* Sticky sidebar. The max-h leaves 76px at the viewport bottom for {/* Sticky sidebar. The max-h leaves 76px at the viewport bottom for
the site footer so the sidebar doesn't slide behind it when the the site footer so the sidebar doesn't slide behind it when the
+3
View File
@@ -13,6 +13,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -77,6 +79,7 @@ export default async function DsChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/ds/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "Dialectic Spiritualism" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/ds" href="/books/ds"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getDsMeta, getDsIntroSegments } from "@/lib/ds"; import { getDsMeta, getDsIntroSegments } from "@/lib/ds";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -20,6 +22,7 @@ export default async function DsPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/ds", name: "Dialectic Spiritualism" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -13,6 +13,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -71,6 +73,7 @@ export default async function EjChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/ej/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "Easy Journey to Other Planets" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/ej" href="/books/ej"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getEjMeta, getEjIntroSegments } from "@/lib/ej"; import { getEjMeta, getEjIntroSegments } from "@/lib/ej";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -20,6 +22,7 @@ export default async function EjPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/ej", name: "Easy Journey to Other Planets" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -13,6 +13,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -71,6 +73,7 @@ export default async function EkChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/ek/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "Elevation to Kṛṣṇa Consciousness" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/ek" href="/books/ek"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getEkMeta, getEkIntroSegments } from "@/lib/ek"; import { getEkMeta, getEkIntroSegments } from "@/lib/ek";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -20,6 +22,7 @@ export default async function EkPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/ek", name: "Elevation to Kṛṣṇa Consciousness" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -11,6 +11,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -67,6 +69,7 @@ export default async function GgChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/gg/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "Gītār Gān" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/gg" href="/books/gg"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getGgMeta, getGgIntroSegments } from "@/lib/gg"; import { getGgMeta, getGgIntroSegments } from "@/lib/gg";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -24,6 +26,7 @@ export default async function GgPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/gg", name: "Gītār Gān" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -13,6 +13,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -71,6 +73,7 @@ export default async function HkhChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/hkh/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "The Kṛṣṇa Consciousness Handbook" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/hkh" href="/books/hkh"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getHkhMeta, getHkhIntroSegments } from "@/lib/hkh"; import { getHkhMeta, getHkhIntroSegments } from "@/lib/hkh";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -20,6 +22,7 @@ export default async function HkhPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/hkh", name: "The Kṛṣṇa Consciousness Handbook" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -12,6 +12,8 @@ import {
} from "@/lib/iso"; } from "@/lib/iso";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -103,6 +105,7 @@ export default async function IsoMantraPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/iso/${slug}`, headline: content.title ?? "Śrī Īśopaniṣad", isPartOf: "Śrī Īśopaniṣad" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/iso" href="/books/iso"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getIsoMeta, getIsoIntroSegments } from "@/lib/iso"; import { getIsoMeta, getIsoIntroSegments } from "@/lib/iso";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -28,6 +30,7 @@ export default async function IsoPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/iso", name: "Śrī Īśopaniṣad" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
@@ -7,6 +7,8 @@ import { getProseChapter, getProseChapters } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -66,6 +68,7 @@ export default async function KbChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/kb/${vol}/${slug}`, headline: chapter.title, description: chapter.paragraphs?.[0], isPartOf: "Kṛṣṇa, The Supreme Personality of Godhead" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href={`/books/kb/${vol}`} href={`/books/kb/${vol}`}
+3
View File
@@ -4,6 +4,8 @@ import { notFound } from "next/navigation";
import { getBookMeta } from "@/lib/api"; import { getBookMeta } from "@/lib/api";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
@@ -27,6 +29,7 @@ export default async function KbPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/kb", name: "Kṛṣṇa, The Supreme Personality of Godhead" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -13,6 +13,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -71,6 +73,7 @@ export default async function LclChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/lcl/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "Life Comes from Life" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/lcl" href="/books/lcl"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getLclMeta, getLclIntroSegments } from "@/lib/lcl"; import { getLclMeta, getLclIntroSegments } from "@/lib/lcl";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -24,6 +26,7 @@ export default async function LclPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/lcl", name: "Life Comes from Life" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -13,6 +13,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -67,6 +69,7 @@ export default async function LobChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/lob/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "Light of the Bhāgavata" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/lob" href="/books/lob"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getLobMeta, getLobIntroSegments } from "@/lib/lob"; import { getLobMeta, getLobIntroSegments } from "@/lib/lob";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -20,6 +22,7 @@ export default async function LobPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/lob", name: "Light of the Bhāgavata" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -13,6 +13,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -67,6 +69,7 @@ export default async function MgChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/mg/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "Kṛṣṇa Consciousness: The Matchless Gift" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/mg" href="/books/mg"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getMgMeta, getMgIntroSegments } from "@/lib/mg"; import { getMgMeta, getMgIntroSegments } from "@/lib/mg";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -20,6 +22,7 @@ export default async function MgPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/mg", name: "Kṛṣṇa Consciousness: The Matchless Gift" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getBookMeta } from "@/lib/api"; import { getBookMeta } from "@/lib/api";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { ExtractedVerseCount } from "../extracted-verse-count"; import { ExtractedVerseCount } from "../extracted-verse-count";
import fs from "fs"; import fs from "fs";
@@ -79,6 +81,7 @@ export default async function MmPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/mm", name: "Mukunda-mālā-stotra" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -13,6 +13,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -71,6 +73,7 @@ export default async function MogChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/mog/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "Message of Godhead" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/mog" href="/books/mog"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getMogMeta, getMogIntroSegments } from "@/lib/mog"; import { getMogMeta, getMogIntroSegments } from "@/lib/mog";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -20,6 +22,7 @@ export default async function MogPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/mog", name: "Message of Godhead" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getBookMeta } from "@/lib/api"; import { getBookMeta } from "@/lib/api";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { ExtractedVerseCount } from "../extracted-verse-count"; import { ExtractedVerseCount } from "../extracted-verse-count";
import fs from "fs"; import fs from "fs";
@@ -79,6 +81,7 @@ export default async function NbsPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/nbs", name: "Nārada-bhakti-sūtra" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -13,6 +13,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -71,6 +73,7 @@ export default async function NodChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/nod/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "The Nectar of Devotion" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/nod" href="/books/nod"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getNodMeta, getNodIntroSegments } from "@/lib/nod"; import { getNodMeta, getNodIntroSegments } from "@/lib/nod";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -27,6 +29,7 @@ export default async function NodPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/nod", name: "The Nectar of Devotion" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -12,6 +12,8 @@ import {
} from "@/lib/noi"; } from "@/lib/noi";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -94,6 +96,7 @@ export default async function NoiTextPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/noi/${slug}`, headline: content.title ?? "The Nectar of Instruction", isPartOf: "The Nectar of Instruction" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/noi" href="/books/noi"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getNoiMeta, getNoiIntroSegments } from "@/lib/noi"; import { getNoiMeta, getNoiIntroSegments } from "@/lib/noi";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -24,6 +26,7 @@ export default async function NoiPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/noi", name: "The Nectar of Instruction" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -13,6 +13,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -71,6 +73,7 @@ export default async function OchkmChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/ochkm/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "On Chanting Hare Kṛṣṇa" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/ochkm" href="/books/ochkm"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getOchkmMeta, getOchkmIntroSegments } from "@/lib/ochkm"; import { getOchkmMeta, getOchkmIntroSegments } from "@/lib/ochkm";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -20,6 +22,7 @@ export default async function OchkmPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/ochkm", name: "On Chanting Hare Kṛṣṇa" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -13,6 +13,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -71,6 +73,7 @@ export default async function OwkChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/owk/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "On the Way to Kṛṣṇa" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/owk" href="/books/owk"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getOwkMeta, getOwkIntroSegments } from "@/lib/owk"; import { getOwkMeta, getOwkIntroSegments } from "@/lib/owk";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -20,6 +22,7 @@ export default async function OwkPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/owk", name: "On the Way to Kṛṣṇa" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -13,6 +13,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -66,6 +68,7 @@ export default async function PkChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/pk/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "Prabhupāda-Kṛpā" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/pk" href="/books/pk"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getPkMeta } from "@/lib/pk"; import { getPkMeta } from "@/lib/pk";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -18,6 +20,7 @@ export default async function PkPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/pk", name: "Prabhupāda-Kṛpā" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -13,6 +13,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -71,6 +73,7 @@ export default async function PoyChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/poy/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "The Perfection of Yoga" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/poy" href="/books/poy"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getPoyMeta, getPoyIntroSegments } from "@/lib/poy"; import { getPoyMeta, getPoyIntroSegments } from "@/lib/poy";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -20,6 +22,7 @@ export default async function PoyPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/poy", name: "The Perfection of Yoga" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -13,6 +13,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -71,6 +73,7 @@ export default async function PqpaChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/pqpa/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "Perfect Questions, Perfect Answers" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/pqpa" href="/books/pqpa"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getPqpaMeta, getPqpaIntroSegments } from "@/lib/pqpa"; import { getPqpaMeta, getPqpaIntroSegments } from "@/lib/pqpa";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -24,6 +26,7 @@ export default async function PqpaPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/pqpa", name: "Perfect Questions, Perfect Answers" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -13,6 +13,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -71,6 +73,7 @@ export default async function RvChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/rv/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "Rāja-vidyā: The King of Knowledge" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/rv" href="/books/rv"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getRvMeta, getRvIntroSegments } from "@/lib/rv"; import { getRvMeta, getRvIntroSegments } from "@/lib/rv";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -20,6 +22,7 @@ export default async function RvPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/rv", name: "Rāja-vidyā: The King of Knowledge" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -1,6 +1,8 @@
import type { Metadata } from "next"; import type { Metadata } from "next";
import Link from "next/link"; import Link from "next/link";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { ExtractedVerseCount } from "../extracted-verse-count"; import { ExtractedVerseCount } from "../extracted-verse-count";
@@ -42,6 +44,7 @@ export default async function SbPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/sb", name: "Śrīmad-Bhāgavatam" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -4,6 +4,8 @@ import { notFound } from "next/navigation";
import { getBookMeta } from "@/lib/api"; import { getBookMeta } from "@/lib/api";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { ExtractedVerseCount } from "../extracted-verse-count"; import { ExtractedVerseCount } from "../extracted-verse-count";
@@ -32,6 +34,7 @@ export default async function Sb1962Page() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/sb1962", name: "Śrīmad-Bhāgavatam (1962 Edition)" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -13,6 +13,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -77,6 +79,7 @@ export default async function SsrChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/ssr/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "The Science of Self-Realization" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/ssr" href="/books/ssr"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getSsrMeta, getSsrIntroSegments } from "@/lib/ssr"; import { getSsrMeta, getSsrIntroSegments } from "@/lib/ssr";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -24,6 +26,7 @@ export default async function SsrPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/ssr", name: "The Science of Self-Realization" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -14,6 +14,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -78,6 +80,7 @@ export default async function SvaChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/sva/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "Songs of the Vaiṣṇava Ācāryas" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/sva" href="/books/sva"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getSvaMeta, getSvaIntroSegments } from "@/lib/sva"; import { getSvaMeta, getSvaIntroSegments } from "@/lib/sva";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -24,6 +26,7 @@ export default async function SvaPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/sva", name: "Songs of the Vaiṣṇava Ācāryas" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -13,6 +13,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -71,6 +73,7 @@ export default async function TlcChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/tlc/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "Teachings of Lord Caitanya" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/tlc" href="/books/tlc"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getTlcMeta, getTlcIntroSegments } from "@/lib/tlc"; import { getTlcMeta, getTlcIntroSegments } from "@/lib/tlc";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -25,6 +27,7 @@ export default async function TlcPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/tlc", name: "Teachings of Lord Caitanya" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -13,6 +13,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -71,6 +73,7 @@ export default async function TlkChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/tlk/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "Teachings of Lord Kapila" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/tlk" href="/books/tlk"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getTlkMeta, getTlkIntroSegments } from "@/lib/tlk"; import { getTlkMeta, getTlkIntroSegments } from "@/lib/tlk";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -24,6 +26,7 @@ export default async function TlkPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/tlk", name: "Teachings of Lord Kapila" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -13,6 +13,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -71,6 +73,7 @@ export default async function TqkChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/tqk/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "Teachings of Queen Kuntī" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/tqk" href="/books/tqk"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getTqkMeta, getTqkIntroSegments } from "@/lib/tqk"; import { getTqkMeta, getTqkIntroSegments } from "@/lib/tqk";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -24,6 +26,7 @@ export default async function TqkPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/tqk", name: "Teachings of Queen Kuntī" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -13,6 +13,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -71,6 +73,7 @@ export default async function TtpChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/ttp/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "Teachings of Lord Kapila" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/ttp" href="/books/ttp"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getTtpMeta } from "@/lib/ttp"; import { getTtpMeta } from "@/lib/ttp";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -18,6 +20,7 @@ export default async function TtpPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/ttp", name: "Teachings of Lord Kapila" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -12,6 +12,8 @@ import { getProseChapter } from "@/lib/api";
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { BOOK_NAMES } from "@/lib/constants"; import { BOOK_NAMES } from "@/lib/constants";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -63,6 +65,7 @@ export default async function VaChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/books/va/${slug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: "Vedānta-sūtra Transcript" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/books/va" href="/books/va"
+3
View File
@@ -6,6 +6,8 @@ import { notFound } from "next/navigation";
import { getVaMeta } from "@/lib/va"; import { getVaMeta } from "@/lib/va";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { bookJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
export function generateMetadata(): Metadata { export function generateMetadata(): Metadata {
@@ -18,6 +20,7 @@ export default async function VaPage() {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={bookJsonLd({ path: "/books/va", name: "Vedānta-sūtra Transcript" })} />
<PageHeader> <PageHeader>
<Link <Link
href="/books" href="/books"
+3
View File
@@ -5,6 +5,8 @@ import Link from "next/link";
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
import { ogForEssay, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForEssay, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -119,6 +121,7 @@ export default async function EssayPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/essays/${slug}`, headline: essay.title, description: essay.paragraphs?.[0], isPartOf: "Essays & Talks" })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href="/essays" href="/essays"
+9
View File
@@ -5,6 +5,8 @@ import { notFound } from "next/navigation";
import { getAllGlossaryEntries } from "@/lib/api"; import { getAllGlossaryEntries } from "@/lib/api";
import { buildOgMeta, extractQuoteFromHl } from "@/lib/og"; import { buildOgMeta, extractQuoteFromHl } from "@/lib/og";
import { GlossaryClient } from "../glossary-client"; import { GlossaryClient } from "../glossary-client";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Diacritic → base letter mapping // Diacritic → base letter mapping
@@ -145,6 +147,13 @@ export default async function GlossaryLetterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd
data={articleJsonLd({
path: `/glossary/${rawLetter}`,
headline: `Glossary — ${activeLetter}`,
isPartOf: "Glossary of Sanskrit & Vedic Terms",
})}
/>
<GlossaryClient <GlossaryClient
entries={clientEntries} entries={clientEntries}
activeLetter={activeLetter} activeLetter={activeLetter}
@@ -12,6 +12,8 @@ import {
} from "@/lib/journals"; } from "@/lib/journals";
import { ogForJournal, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForJournal, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -74,6 +76,7 @@ export default async function JournalChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/journals/${slug}/${chapterSlug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: meta.title })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href={`/journals/${slug}`} href={`/journals/${slug}`}
+11
View File
@@ -10,6 +10,8 @@ import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
export async function generateMetadata({ export async function generateMetadata({
params, params,
@@ -54,6 +56,15 @@ export default async function LetterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd
data={articleJsonLd({
path: `/letters/${slug}`,
headline: `Letter to ${letter.recipientDisplay}`,
description: letter.paragraphs[0],
datePublished: letter.year ? String(letter.year) : undefined,
isPartOf: "Letters of Śrīla Prabhupāda",
})}
/>
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href={backHref} href={backHref}
@@ -12,6 +12,8 @@ import {
} from "@/lib/magazines"; } from "@/lib/magazines";
import { ogForMagazine, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForMagazine, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -72,6 +74,7 @@ export default async function MagazineIssuePage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/magazines/${slug}/${issueSlug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: meta.title })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href={`/magazines/${slug}`} href={`/magazines/${slug}`}
@@ -12,6 +12,8 @@ import {
} from "@/lib/other-documents"; } from "@/lib/other-documents";
import { ogForOtherDocument, extractQuoteFromHl, buildOgMeta } from "@/lib/og"; import { ogForOtherDocument, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { buttonVariants } from "@/components/ui/button"; import { buttonVariants } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react"; import { ChevronLeft, ChevronRight } from "lucide-react";
@@ -79,6 +81,7 @@ export default async function OtherDocumentChapterPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd data={articleJsonLd({ path: `/other-documents/${slug}/${chapterSlug}`, headline: content.title, description: content.paragraphs?.[0], isPartOf: meta.title })} />
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href={`/other-documents/${slug}`} href={`/other-documents/${slug}`}
+11
View File
@@ -16,6 +16,8 @@ import { cn } from "@/lib/utils";
import { ChevronLeft, ChevronRight, Clock, MapPin, Users } from "lucide-react"; import { ChevronLeft, ChevronRight, Clock, MapPin, Users } from "lucide-react";
import { PlayAudioButton } from "./play-audio-button"; import { PlayAudioButton } from "./play-audio-button";
import { FindInPage } from "@/components/layout/find-in-page"; import { FindInPage } from "@/components/layout/find-in-page";
import { JsonLd } from "@/components/seo/json-ld";
import { articleJsonLd } from "@/lib/jsonld";
export async function generateMetadata({ export async function generateMetadata({
params, params,
@@ -82,6 +84,15 @@ export default async function TranscriptionPage({
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<JsonLd
data={articleJsonLd({
path: `/transcriptions/${slug}`,
headline: t.name,
description: t.content[0]?.text,
datePublished: t.year ? String(t.year) : undefined,
isPartOf: "Lectures & Conversations of Śrīla Prabhupāda",
})}
/>
<PageHeader sticky> <PageHeader sticky>
<Link <Link
href={backHref} href={backHref}
+37 -6
View File
@@ -1,18 +1,23 @@
/** /**
* /u/[handle] — public profile, Posts tab (default). * /u/[handle] — public profile, Posts tab (default).
* *
* Server shell that exists for two reasons: * Server shell that exists for three reasons:
* *
* 1. Export `generateMetadata` so direct shares of this URL * 1. Export `generateMetadata` so direct shares of this URL
* (https://prabhupadasays.org/u/<handle>) get a rich OG card * (https://prabhupadasays.org/u/<handle>) get a rich OG card
* pointing at /api/og/profile/<handle>. The layout and the body * pointing at /api/og/profile/<handle>. The layout and the body
* below are client components; only this file is server. * below are client components; only this file is server.
* 2. Mount the client tree (<PostsGrid />), which reads the * 2. Emit server-rendered ProfilePage/Person JSON-LD so crawlers + LLMs
* ProfileContext provided by the parent layout for the post-grid * can resolve the profile (the layout is a client component and
* hrefs and renders the feed. * fetches the profile after hydration, too late for crawlers).
* 3. Mount the client tree (<PostsGrid />), which reads the
* ProfileContext provided by the parent layout.
*/ */
import type { Metadata } from "next"; import type { Metadata } from "next";
import { bff } from "@/lib/bff";
import { JsonLd } from "@/components/seo/json-ld";
import { profileJsonLd } from "@/lib/jsonld";
import { PostsGrid } from "./posts-grid"; import { PostsGrid } from "./posts-grid";
import { metadataForHandle } from "./profile-og"; import { metadataForHandle } from "./profile-og";
@@ -23,6 +28,32 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
return metadataForHandle(handle); return metadataForHandle(handle);
} }
export default function PublicProfilePage({ params }: Props) { export default async function PublicProfilePage({ params }: Props) {
return <PostsGrid params={params} />; const { handle } = await params;
let person: object | null = null;
try {
const profile = await bff<{
handle: string;
name: string;
avatar_url?: string | null;
}>(`/u/${encodeURIComponent(handle)}`, { revalidate: 60 });
if (profile) {
person = profileJsonLd({
path: `/u/${profile.handle}`,
name: profile.name,
handle: profile.handle,
image: profile.avatar_url ?? null,
});
}
} catch {
// Profile unavailable — skip JSON-LD rather than fail the page.
}
return (
<>
{person ? <JsonLd data={person} /> : null}
<PostsGrid params={params} />
</>
);
} }
+28
View File
@@ -0,0 +1,28 @@
import { revalidateTag } from "next/cache";
import type { NextRequest } from "next/server";
/**
* On-demand cache revalidation. The BFF pings this (fire-and-forget) when
* sitemap-relevant data changes — a new signup, or a content re-seed/reindex —
* so /sitemap.xml refreshes within seconds instead of waiting out the 24h ISR
* window. Secret-gated; lives under /api/ which robots.txt disallows.
*
* POST /api/revalidate?tag=sitemap&secret=…
*/
export const runtime = "nodejs";
export async function POST(req: NextRequest) {
const expected = process.env.REVALIDATE_SECRET;
const secret = req.nextUrl.searchParams.get("secret");
if (!expected || secret !== expected) {
return Response.json(
{ revalidated: false, error: "unauthorized" },
{ status: 401 },
);
}
const tag = req.nextUrl.searchParams.get("tag") || "sitemap";
// Next 16 requires a cache-life profile as the 2nd arg; "max" fully purges
// the tagged entries so the next request re-fetches from the BFF.
revalidateTag(tag, "max");
return Response.json({ revalidated: true, tag });
}
+6
View File
@@ -43,6 +43,12 @@ const bricolage = Bricolage_Grotesque({
}); });
export const metadata: Metadata = { export const metadata: Metadata = {
// Resolves all relative OG/Twitter image URLs and canonical links to
// absolute URLs (required for correct social previews + SEO; Next warns
// without it).
metadataBase: new URL(
process.env.NEXT_PUBLIC_SITE_URL || "https://prabhupadasays.org",
),
title: "Prabhupāda Says", title: "Prabhupāda Says",
description: description:
"Browse the books and teachings of His Divine Grace A.C. Bhaktivedanta Swami Prabhupāda", "Browse the books and teachings of His Divine Grace A.C. Bhaktivedanta Swami Prabhupāda",
+45
View File
@@ -0,0 +1,45 @@
import type { MetadataRoute } from "next";
const SITE_URL =
process.env.NEXT_PUBLIC_SITE_URL || "https://prabhupadasays.org";
/**
* robots.txt (generated).
*
* Open the whole site to crawlers — search engines AND AI/LLM crawlers
* (GPTBot, ClaudeBot, PerplexityBot, Google-Extended, etc. all honour the
* `*` rule, and we deliberately don't block them so the corpus is
* discoverable). Only private / non-content surfaces are disallowed:
*
* • /api/ — JSON endpoints, never a destination page
* • /settings — auth-only account settings
* • /notifications — auth-only
* • /verify-email — transactional
* • /chat — interactive tool, not indexable content
* • /u/me, /u/me/* — the signed-in user's own private library
* ($ anchors the bare path so public handles like
* /u/meera aren't caught by the prefix)
*
* Public content (books, verses, prose, letters, transcriptions, essays,
* disciples, magazines, journals, glossary, public profiles, collections)
* stays crawlable and is enumerated in the sitemap index.
*/
export default function robots(): MetadataRoute.Robots {
return {
rules: {
userAgent: "*",
allow: "/",
disallow: [
"/api/",
"/settings",
"/notifications",
"/verify-email",
"/chat",
"/u/me$",
"/u/me/",
],
},
sitemap: `${SITE_URL}/sitemap.xml`,
host: SITE_URL,
};
}
+97
View File
@@ -0,0 +1,97 @@
import type { MetadataRoute } from "next";
import { bff } from "@/lib/bff";
/**
* Sitemap (index + sharded children) for the whole public corpus.
*
* How this stays cheap on the BFF:
* • One projection-only BFF call (`/sitemap/content`) returns every content
* leaf path in a single sweep — no per-document fan-out.
* • That fetch is cached for 24h (revalidate below) AND the rendered XML is
* ISR-cached, so crawlers hit Next's cache, not the BFF. The BFF sees
* ~one query/day regardless of crawl volume (tag "sitemap" allows
* on-demand revalidation after a re-seed).
* • generateSitemaps() shards into ≤40k-URL files (under the 50k/50MB
* limits) and Next serves a sitemap index at /sitemap.xml automatically.
*/
export const revalidate = 86400; // 24h
const SITE_URL =
process.env.NEXT_PUBLIC_SITE_URL || "https://prabhupadasays.org";
const PER_SITEMAP = 40000;
// Top-level hubs that aren't content leaves but should be indexed.
const STATIC_PATHS = [
"/",
"/about",
"/books",
"/letters",
"/transcriptions",
"/disciples",
"/glossary",
"/essays",
"/magazines",
"/journals",
"/other-documents",
];
/**
* All indexable paths: static hubs + book/division landing pages (derived
* from the content leaves) + every content leaf from the BFF. Resilient — if
* the BFF call fails we still emit the static hubs so /sitemap.xml never 500s.
*/
async function fetchUrls(path: string): Promise<string[]> {
try {
const res = await bff<{ urls: string[] }>(path, {
revalidate,
tags: ["sitemap"],
});
return res?.urls ?? [];
} catch {
return [];
}
}
async function allPaths(): Promise<string[]> {
// Content (Mongo) and public profiles (Postgres) come from separate
// projection-only endpoints. New signups appear automatically on the next
// daily revalidation.
const [content, users] = await Promise.all([
fetchUrls("/sitemap/content"),
fetchUrls("/sitemap/users"),
]);
// Derive non-redirecting hub pages from the content leaves: every book's
// landing page, and the SB canto / CC līlā division pages.
const hubs = new Set<string>();
for (const p of content) {
const book = p.match(/^\/books\/([^/]+)/);
if (book) hubs.add(`/books/${book[1]}`);
const division = p.match(/^\/books\/(sb|cc)\/([^/]+)\/\d+\/\d+$/);
if (division) hubs.add(`/books/${division[1]}/${division[2]}`);
}
// Dedupe across static + hubs + content + profiles.
return [...new Set([...STATIC_PATHS, ...hubs, ...content, ...users])];
}
export async function generateSitemaps(): Promise<{ id: number }[]> {
const paths = await allPaths();
const count = Math.max(1, Math.ceil(paths.length / PER_SITEMAP));
return Array.from({ length: count }, (_, id) => ({ id }));
}
export default async function sitemap({
id,
}: {
id: number;
}): Promise<MetadataRoute.Sitemap> {
const paths = await allPaths();
const slice = paths.slice(id * PER_SITEMAP, (id + 1) * PER_SITEMAP);
return slice.map((path) => ({
url: `${SITE_URL}${path}`,
changeFrequency: "weekly",
priority: path === "/" ? 1 : STATIC_PATHS.includes(path) ? 0.8 : 0.7,
}));
}
+14
View File
@@ -0,0 +1,14 @@
/**
* Renders a schema.org JSON-LD <script>. Safe in server or client components.
* The `<` escape prevents the JSON from breaking out of the <script> element.
*/
export function JsonLd({ data }: { data: object | object[] }) {
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(data).replace(/</g, "\\u003c"),
}}
/>
);
}
+121
View File
@@ -0,0 +1,121 @@
/**
* schema.org JSON-LD builders for content pages.
*
* Emitting structured data gives Google rich-result eligibility and gives
* LLMs clean, linked facts (who authored it, which work it belongs to, when).
* Every page renders one of these via the <JsonLd> component
* (components/seo/json-ld.tsx).
*
* The author entity carries `sameAs` links to Wikipedia/Wikidata so search
* engines and LLMs can resolve it to the canonical Śrīla Prabhupāda entity.
*/
const SITE_URL =
process.env.NEXT_PUBLIC_SITE_URL || "https://prabhupadasays.org";
const AUTHOR = {
"@type": "Person",
name: "His Divine Grace A.C. Bhaktivedanta Swami Prabhupāda",
alternateName: "A.C. Bhaktivedanta Swami Prabhupāda",
sameAs: [
"https://en.wikipedia.org/wiki/A._C._Bhaktivedanta_Swami_Prabhupada",
"https://www.wikidata.org/wiki/Q318439",
],
} as const;
const PUBLISHER = {
"@type": "Organization",
name: "Prabhupāda Says",
url: SITE_URL,
} as const;
function abs(path: string): string {
return path.startsWith("http") ? path : `${SITE_URL}${path}`;
}
/** Trim a (possibly HTML) string to a clean plain-text description. */
function clean(text: string | undefined, max = 300): string | undefined {
if (!text) return undefined;
const plain = text
.replace(/<[^>]+>/g, "")
.replace(/\s+/g, " ")
.trim();
if (!plain) return undefined;
return plain.length > max ? plain.slice(0, max - 1).trimEnd() + "…" : plain;
}
/**
* An Article — used for every leaf content page (verses, letters, transcripts,
* prose chapters, essays, magazine/journal pages). `isPartOf` names the parent
* work (book/magazine); `datePublished` must be ISO 8601 (omit otherwise).
*/
export function articleJsonLd(params: {
path: string;
headline: string;
description?: string;
datePublished?: string;
isPartOf?: string;
}) {
const url = abs(params.path);
const obj: Record<string, unknown> = {
"@context": "https://schema.org",
"@type": "Article",
headline: params.headline,
author: AUTHOR,
publisher: PUBLISHER,
inLanguage: "en",
isAccessibleForFree: true,
url,
mainEntityOfPage: url,
};
const desc = clean(params.description);
if (desc) obj.description = desc;
if (params.datePublished) obj.datePublished = params.datePublished;
if (params.isPartOf) {
obj.isPartOf = { "@type": "Book", name: params.isPartOf, author: AUTHOR };
}
return obj;
}
/** A public profile page → ProfilePage wrapping the Person. */
export function profileJsonLd(params: {
path: string;
name: string;
handle: string;
image?: string | null;
}) {
const url = abs(params.path);
const person: Record<string, unknown> = {
"@type": "Person",
name: params.name,
alternateName: `@${params.handle}`,
url,
};
if (params.image) person.image = params.image;
return {
"@context": "https://schema.org",
"@type": "ProfilePage",
url,
mainEntity: person,
};
}
/** A Book — used for book landing pages. */
export function bookJsonLd(params: {
path: string;
name: string;
description?: string;
}) {
const obj: Record<string, unknown> = {
"@context": "https://schema.org",
"@type": "Book",
name: params.name,
author: AUTHOR,
publisher: PUBLISHER,
inLanguage: "en",
url: abs(params.path),
};
const desc = clean(params.description);
if (desc) obj.description = desc;
return obj;
}
+29
View File
@@ -0,0 +1,29 @@
# Prabhupāda Says
> The complete teachings of His Divine Grace A.C. Bhaktivedanta Swami Prabhupāda — the books, lectures, conversations, and letters of the Founder-Ācārya of the International Society for Krishna Consciousness (ISKCON) — as structured, searchable, Unicode text (Devanāgarī + IAST transliteration).
All content is server-rendered and crawlable. The full URL list (tens of thousands of pages) is in the sitemap index.
## Sitemap
- [Sitemap index](https://prabhupadasays.org/sitemap.xml): every book, chapter, verse, prose chapter, letter, transcript, essay, magazine, and journal page
## Scriptures (books)
- [All books](https://prabhupadasays.org/books): Bhagavad-gītā As It Is, Śrīmad-Bhāgavatam, Śrī Caitanya-caritāmṛta, Nectar of Devotion, Kṛṣṇa Book, and 30+ more — browsable by chapter and verse (Devanāgarī, transliteration, synonyms, translation, and purport)
## Lectures & conversations
- [Transcriptions](https://prabhupadasays.org/transcriptions): ~3,800 lectures, morning walks, room conversations, and interviews (1966–1977), browsable by year, place, and type
## Letters
- [Letters](https://prabhupadasays.org/letters): ~6,900 letters (1947–1977), browsable by year, recipient, and location
## Reference
- [Glossary](https://prabhupadasays.org/glossary): ~2,750 Sanskrit/Vedic terms
- [Essays & other documents](https://prabhupadasays.org/essays)
- [Magazines (Back to Godhead)](https://prabhupadasays.org/magazines)
- [Journals](https://prabhupadasays.org/journals)
- [Disciples](https://prabhupadasays.org/disciples)
-2
View File
@@ -1,2 +0,0 @@
User-agent: *
Disallow: /