Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1984797ad3 | ||
|
|
1582df0ed5 | ||
|
|
1683abc2e9 | ||
|
|
12a5c15121 | ||
|
|
8bc27bb8a1 | ||
|
|
89391279bb | ||
|
|
7f716397a0 | ||
|
|
4586f1c22c | ||
|
|
b6471f9430 | ||
|
|
380c23e469 | ||
|
|
0b67a1142f | ||
|
|
be28585294 | ||
|
|
1462844e95 | ||
|
|
9916810d18 | ||
|
|
7b81bbc791 | ||
|
|
f92b41384e | ||
|
|
5cd75c27f9 | ||
|
|
5679f7a639 | ||
|
|
25db9d0eee | ||
|
|
0178f89f2b | ||
|
|
b6dc762984 | ||
|
|
1fe10adb1e | ||
|
|
84cb273941 | ||
|
|
071eb4d58a | ||
|
|
bc1798b31b | ||
|
|
fc2aef0c3d | ||
|
|
89f94c1a6e | ||
|
|
f5abe33c09 | ||
|
|
f96e7dd2f1 | ||
|
|
0cf6df5942 | ||
|
|
5c72416ae8 | ||
|
|
197e13c0ef | ||
|
|
0608e2b6f6 | ||
|
|
cb376f8497 | ||
|
|
eac56b7974 | ||
|
|
be4c2f17fe | ||
|
|
6cc9285bad | ||
|
|
ab35767374 | ||
|
|
c551d2f7a8 | ||
|
|
a4fd63695a | ||
|
|
91621693a6 | ||
|
|
79f0bd9223 | ||
|
|
7585e6cb31 | ||
|
|
c8de98c8de | ||
|
|
72a092b3c9 | ||
|
|
752ad20fed | ||
|
|
0280a81777 | ||
|
|
69e5f2c45c | ||
|
|
45c7cf047e | ||
|
|
a4baf6d215 | ||
|
|
455ed0f7cb | ||
|
|
7c3cf656b5 | ||
|
|
23d06a3db5 | ||
|
|
3accc753d0 | ||
|
|
b04ed1d3aa | ||
|
|
9808dd3033 | ||
|
|
b248f962a1 | ||
|
|
61581b67a7 | ||
|
|
eb0c981d3c | ||
|
|
37305201bd | ||
|
|
4471ef10aa | ||
|
|
397a09e814 | ||
|
|
9e68184750 | ||
|
|
439664a97d | ||
|
|
cc5633c37a | ||
|
|
6a0559e608 | ||
|
|
25a729959f | ||
|
|
af5ab9cf6b | ||
|
|
884a984e50 | ||
|
|
ead8ad02e8 | ||
|
|
4b159cb4d9 | ||
|
|
3903423d06 | ||
|
|
a46e29d998 | ||
|
|
922d76e21f | ||
|
|
909ae67320 | ||
|
|
482a845f37 | ||
|
|
647a803b96 | ||
|
|
e36afdd1a5 | ||
|
|
ef6e280524 | ||
|
|
cf733062f8 | ||
|
|
421b41cade | ||
|
|
deeda40c9d | ||
|
|
90df5bc784 | ||
|
|
0334e03c3c | ||
|
|
ecb32d2e85 | ||
|
|
d5fb350652 | ||
|
|
bcffe9684f | ||
|
|
0db339254d | ||
|
|
684ea2ae97 | ||
|
|
0f433c5708 | ||
|
|
48dd450a15 | ||
|
|
ddc6d3c7bf | ||
|
|
fd333159f6 | ||
|
|
0bcda5a791 | ||
|
|
c89cc8b779 | ||
|
|
ec67ddf852 | ||
|
|
086f1dd8aa | ||
|
|
b61c3df473 | ||
|
|
cb70a84dd5 | ||
|
|
dc01d09f09 | ||
|
|
84d86c45b5 | ||
|
|
4d45e20cb1 | ||
|
|
e72679d1b6 | ||
|
|
91d5d272d2 | ||
|
|
0352cb2003 | ||
|
|
8a8ce24479 | ||
|
|
7d76afe102 | ||
|
|
8c1f3a1b7b | ||
|
|
3624c19d2d | ||
|
|
5988d02373 | ||
|
|
17fb83087f | ||
|
|
489adb0eeb | ||
|
|
d8de0a18e5 | ||
|
|
c20d6bffe8 | ||
|
|
01bcc057fa | ||
|
|
8bd82a0e8a | ||
|
|
5506afa758 | ||
|
|
88f1b08675 | ||
|
|
336f478f8b | ||
|
|
03b8f85e06 | ||
|
|
0ff8005df2 | ||
|
|
0ae3334d98 | ||
|
|
ec20eb996b |
@@ -0,0 +1,20 @@
|
|||||||
|
NEXT_PUBLIC_SITE_URL=https://prabhupadasays.org
|
||||||
|
|
||||||
|
# BFF API Server (server-side fetches)
|
||||||
|
BFF_URL=http://localhost:8080
|
||||||
|
|
||||||
|
# BFF API Server (browser-side fetches; must be publicly reachable in prod)
|
||||||
|
NEXT_PUBLIC_BFF_URL=http://localhost:8080
|
||||||
|
|
||||||
|
# RTF Viewer (development only)
|
||||||
|
ALLOW_RTF=true
|
||||||
|
NEXT_PUBLIC_OAUTH_ENABLED=true
|
||||||
|
|
||||||
|
# SOKETI
|
||||||
|
NEXT_PUBLIC_SOKETI_KEY=spsays
|
||||||
|
NEXT_PUBLIC_SOKETI_HOST=ws.prabhupadasays.org
|
||||||
|
NEXT_PUBLIC_SOKETI_PORT=443
|
||||||
|
NEXT_PUBLIC_SOKETI_FORCE_TLS=true
|
||||||
|
|
||||||
|
# Analytics
|
||||||
|
NEXT_PUBLIC_RYBBIT_HOST=https://analytics.krispire.cloud
|
||||||
+1
-1
@@ -31,7 +31,7 @@ yarn-error.log*
|
|||||||
.pnpm-debug.log*
|
.pnpm-debug.log*
|
||||||
|
|
||||||
# env files (can opt-in for committing if needed)
|
# env files (can opt-in for committing if needed)
|
||||||
.env*
|
.env
|
||||||
|
|
||||||
# vercel
|
# vercel
|
||||||
.vercel
|
.vercel
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shared layout for the auth pages (login, signup, forgot-password,
|
||||||
|
* reset-password). Provides the centered card frame so each page only
|
||||||
|
* has to render its own form.
|
||||||
|
*
|
||||||
|
* Also gates the routes: a signed-in user landing on any /login, /signup,
|
||||||
|
* etc. URL is bounced to /u/me (or the `next` query param if present).
|
||||||
|
* The check happens client-side because auth state lives in
|
||||||
|
* AuthProvider — there's no server-side cookie inspection here yet, and
|
||||||
|
* the redirect is purely cosmetic (logged-in users don't gain anything
|
||||||
|
* from re-seeing these forms, and signing in over an existing session
|
||||||
|
* would just no-op).
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Suspense, useEffect } from "react";
|
||||||
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
|
import { useAuth } from "@/components/auth/auth-provider";
|
||||||
|
|
||||||
|
export default function AuthLayout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
// useSearchParams forces a CSR bailout during prerender, so Next.js
|
||||||
|
// requires a Suspense boundary anywhere it's read. The gate is the
|
||||||
|
// only consumer here — isolate it so the rest of the layout can still
|
||||||
|
// SSR normally.
|
||||||
|
return (
|
||||||
|
<main className="flex items-center justify-center px-4 py-12 min-h-[90vh]">
|
||||||
|
<Suspense fallback={<AuthShell>{children}</AuthShell>}>
|
||||||
|
<AuthGate>{children}</AuthGate>
|
||||||
|
</Suspense>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function AuthShell({ children }: { children: React.ReactNode }) {
|
||||||
|
return <div className="w-full max-w-md">{children}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function AuthGate({ children }: { children: React.ReactNode }) {
|
||||||
|
const { user, loading } = useAuth();
|
||||||
|
const router = useRouter();
|
||||||
|
const params = useSearchParams();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (loading || !user) return;
|
||||||
|
const next = params.get("next");
|
||||||
|
router.replace(next && next.startsWith("/") ? next : "/u/me");
|
||||||
|
}, [loading, user, router, params]);
|
||||||
|
|
||||||
|
// Don't flash the form for an instant before the redirect fires.
|
||||||
|
if (!loading && user) {
|
||||||
|
return <p className="text-sm text-muted-foreground">Redirecting…</p>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <AuthShell>{children}</AuthShell>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { Suspense } from "react";
|
||||||
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
|
import { AuthCard, AuthFooterLink } from "@/components/auth/auth-card";
|
||||||
|
import { LoginForm } from "@/components/auth/login-form";
|
||||||
|
|
||||||
|
function LoginContent() {
|
||||||
|
const router = useRouter();
|
||||||
|
const params = useSearchParams();
|
||||||
|
const next = params.get("next") ?? "/u/me";
|
||||||
|
const oauthError = params.get("oauth_error");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AuthCard
|
||||||
|
title="Welcome back"
|
||||||
|
description="Log in to access your bookmarks, notes, and collections."
|
||||||
|
footer={
|
||||||
|
<AuthFooterLink prefix="No account?" href="/signup" label="Create one" />
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{oauthError ? (
|
||||||
|
<p className="text-sm text-destructive">
|
||||||
|
{oauthErrorMessage(oauthError)}
|
||||||
|
</p>
|
||||||
|
) : null}
|
||||||
|
<LoginForm
|
||||||
|
oauthNext={next}
|
||||||
|
onSuccess={() => {
|
||||||
|
router.push(next);
|
||||||
|
router.refresh();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</AuthCard>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function oauthErrorMessage(code: string): string {
|
||||||
|
switch (code) {
|
||||||
|
case "invalid_state":
|
||||||
|
case "missing_state":
|
||||||
|
return "Your sign-in link expired. Please try again.";
|
||||||
|
case "exchange_failed":
|
||||||
|
case "profile_failed":
|
||||||
|
return "Sign-in failed while talking to the provider. Please try again.";
|
||||||
|
case "unknown_provider":
|
||||||
|
return "That sign-in provider isn't configured. Please use email or another method.";
|
||||||
|
case "unavailable":
|
||||||
|
return "Social sign-in is temporarily unavailable. Please use email/password.";
|
||||||
|
case "server":
|
||||||
|
return "Something went wrong on our side. Please try again in a moment.";
|
||||||
|
default:
|
||||||
|
return "Sign-in failed. Please try again.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function LoginPage() {
|
||||||
|
return (
|
||||||
|
<Suspense fallback={null}>
|
||||||
|
<LoginContent />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ export default function SignUpPage() {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<SignUpForm
|
<SignUpForm
|
||||||
|
oauthNext="/u/me"
|
||||||
onSuccess={() => {
|
onSuccess={() => {
|
||||||
router.push("/u/me");
|
router.push("/u/me");
|
||||||
router.refresh();
|
router.refresh();
|
||||||
@@ -12,12 +12,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -70,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"
|
||||||
@@ -77,12 +81,15 @@ export default async function BbdChapterPage({
|
|||||||
>
|
>
|
||||||
← Beyond Birth and Death
|
← Beyond Birth and Death
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -100,7 +107,7 @@ export default async function BbdChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
+10
-6
@@ -1,10 +1,11 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/layout/page-header";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { getBookMeta, getSingleVerse, getChapterVerseIndex } from "@/lib/api";
|
import { getBookMeta, getSingleVerse, getChapterVerseIndex } from "@/lib/api";
|
||||||
import { ChapterViewer } from "@/app/books/chapter-viewer";
|
import { ChapterViewer } from "@/app/(app)/(reader)/books/chapter-viewer";
|
||||||
import type { MobileNavGroup } from "@/components/mobile-nav";
|
import type { MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
import { ogForVerse, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
|
import { ogForVerse, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
@@ -101,9 +102,12 @@ export default async function VersePage({
|
|||||||
>
|
>
|
||||||
← Bhagavad-gītā
|
← Bhagavad-gītā
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-2 text-2xl font-bold text-foreground">
|
<div className="mt-2 flex items-start justify-between gap-3">
|
||||||
Chapter {chapter}: {title}
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
</h1>
|
Chapter {chapter}: {title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
import type { Metadata } from "next";
|
||||||
|
import { redirect } from "next/navigation";
|
||||||
|
import { notFound } from "next/navigation";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { getChapterVerseIndex, getProseChapter } from "@/lib/api";
|
||||||
|
import { buildOgMeta } from "@/lib/og";
|
||||||
|
import { BOOK_NAMES } from "@/lib/constants";
|
||||||
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
|
import { PageHeader } from "@/components/layout/page-header";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
|
export async function generateMetadata({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ chapter: string }>;
|
||||||
|
}): Promise<Metadata> {
|
||||||
|
const { chapter } = await params;
|
||||||
|
// Non-numeric segments are front matter (dedication, foreword, …).
|
||||||
|
if (isNaN(parseInt(chapter))) {
|
||||||
|
const segment = await getProseChapter("bg", 0, chapter);
|
||||||
|
return buildOgMeta({
|
||||||
|
title: BOOK_NAMES["bg"],
|
||||||
|
detail: segment?.title ?? "Front Matter",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return buildOgMeta({ title: BOOK_NAMES["bg"], detail: `Chapter ${chapter}` });
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function ChapterPage({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ chapter: string }>;
|
||||||
|
}) {
|
||||||
|
const { chapter } = await params;
|
||||||
|
|
||||||
|
// Front matter — non-numeric slugs (dedication, foreword, preface,
|
||||||
|
// introduction, disciplic-succession) resolve to prose intro-segments.
|
||||||
|
if (isNaN(parseInt(chapter))) {
|
||||||
|
const segment = await getProseChapter("bg", 0, chapter);
|
||||||
|
if (!segment) notFound();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-background">
|
||||||
|
<PageHeader sticky>
|
||||||
|
<Link
|
||||||
|
href="/books/bg"
|
||||||
|
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
||||||
|
>
|
||||||
|
← {BOOK_NAMES["bg"]}
|
||||||
|
</Link>
|
||||||
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
|
{segment.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
|
</PageHeader>
|
||||||
|
|
||||||
|
<main className="max-w-5xl mx-auto px-6 py-8">
|
||||||
|
<Card id="book-content">
|
||||||
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
|
<div className="space-y-4">
|
||||||
|
{segment.paragraphs.map((paragraph, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className="text-base text-foreground leading-relaxed"
|
||||||
|
dangerouslySetInnerHTML={{ __html: paragraph }}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Numeric chapters — redirect to the first verse.
|
||||||
|
const verseIndex = await getChapterVerseIndex("bg", null, parseInt(chapter));
|
||||||
|
if (verseIndex.length === 0) {
|
||||||
|
notFound();
|
||||||
|
}
|
||||||
|
redirect(`/books/bg/${chapter}/${verseIndex[0].verse}`);
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { notFound } from "next/navigation";
|
||||||
|
import { getBookMeta, getProseChapters } from "@/lib/api";
|
||||||
|
import { ogForBook } from "@/lib/og";
|
||||||
|
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 { ExtractedVerseCount } from "../extracted-verse-count";
|
||||||
|
|
||||||
|
export function generateMetadata(): Metadata {
|
||||||
|
return ogForBook("bg");
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChapterInfo = {
|
||||||
|
number: number;
|
||||||
|
title: string;
|
||||||
|
totalVerses: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function BgPage() {
|
||||||
|
const [meta, introSegments] = await Promise.all([
|
||||||
|
getBookMeta("bg"),
|
||||||
|
getProseChapters("bg", 0, "intro-segment"),
|
||||||
|
]);
|
||||||
|
if (!meta) notFound();
|
||||||
|
|
||||||
|
const intro = meta as unknown as {
|
||||||
|
book: string;
|
||||||
|
title: string;
|
||||||
|
author: string;
|
||||||
|
totalChapters: number;
|
||||||
|
chapters: ChapterInfo[];
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-background">
|
||||||
|
<JsonLd data={bookJsonLd({ path: "/books/bg", name: "Bhagavad-gītā As It Is" })} />
|
||||||
|
<PageHeader>
|
||||||
|
<Link
|
||||||
|
href="/books"
|
||||||
|
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
||||||
|
>
|
||||||
|
← Books
|
||||||
|
</Link>
|
||||||
|
<h1 className="mt-3 text-3xl font-bold text-foreground">
|
||||||
|
{intro.title}
|
||||||
|
</h1>
|
||||||
|
<p className="mt-1 text-muted-foreground">{intro.author}</p>
|
||||||
|
</PageHeader>
|
||||||
|
<main className="max-w-5xl mx-auto px-6 py-8 space-y-8">
|
||||||
|
{/* Front Matter */}
|
||||||
|
{introSegments.length > 0 && (
|
||||||
|
<div>
|
||||||
|
<h2 className="text-sm font-bold uppercase tracking-wider text-muted-foreground mb-3">
|
||||||
|
Front Matter
|
||||||
|
</h2>
|
||||||
|
<Card className="divide-y divide-border py-0">
|
||||||
|
<CardContent className="p-0">
|
||||||
|
<ul className="divide-y divide-border">
|
||||||
|
{introSegments.map((seg) => (
|
||||||
|
<li key={seg.slug}>
|
||||||
|
<Link
|
||||||
|
href={`/books/bg/${seg.slug}`}
|
||||||
|
className="flex px-5 py-4 hover:bg-muted transition-colors"
|
||||||
|
>
|
||||||
|
<p className="font-medium text-foreground">
|
||||||
|
{seg.title}
|
||||||
|
</p>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Chapters */}
|
||||||
|
<div>
|
||||||
|
<h2 className="text-sm font-bold uppercase tracking-wider text-muted-foreground mb-3">
|
||||||
|
Chapters
|
||||||
|
</h2>
|
||||||
|
<Card className="divide-y divide-border py-0">
|
||||||
|
<CardContent className="p-0">
|
||||||
|
<ul className="divide-y divide-border">
|
||||||
|
{intro.chapters.map((ch) => (
|
||||||
|
<li key={ch.number}>
|
||||||
|
<Link
|
||||||
|
href={`/books/bg/${ch.number}`}
|
||||||
|
className="flex flex-col sm:flex-row sm:items-center sm:justify-between px-5 py-4 gap-1 sm:gap-0 hover:bg-muted transition-colors"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<span className="text-sm text-primary font-medium">
|
||||||
|
Chapter {ch.number}
|
||||||
|
</span>
|
||||||
|
<p className="font-medium text-foreground">
|
||||||
|
{ch.title}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<span className="text-sm text-muted-foreground sm:shrink-0 sm:ml-4">
|
||||||
|
<ExtractedVerseCount count={ch.totalVerses} />
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -10,12 +10,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
@@ -62,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"
|
||||||
@@ -69,12 +73,15 @@ export default async function BkChapterPage({
|
|||||||
>
|
>
|
||||||
← Bhagavāner Kathā
|
← Bhagavāner Kathā
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -92,7 +99,7 @@ export default async function BkChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -72,11 +72,16 @@ export function BooksGrid({ books }: { books: BookInfo[] }) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const filtered = useMemo(() => {
|
const filtered = useMemo(() => {
|
||||||
if (!query.trim()) return books;
|
const base = query.trim()
|
||||||
const q = normalize(query.trim());
|
? normalizedBooks
|
||||||
return normalizedBooks
|
.filter((entry) =>
|
||||||
.filter((entry) => entry.searchText.includes(q))
|
entry.searchText.includes(normalize(query.trim())),
|
||||||
.map((entry) => entry.book);
|
)
|
||||||
|
.map((entry) => entry.book)
|
||||||
|
: books;
|
||||||
|
return [...base].sort((a, b) =>
|
||||||
|
normalize(a.title).localeCompare(normalize(b.title)),
|
||||||
|
);
|
||||||
}, [books, normalizedBooks, query]);
|
}, [books, normalizedBooks, query]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
+10
-6
@@ -2,7 +2,8 @@ import type { Metadata } from "next";
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/layout/page-header";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import {
|
import {
|
||||||
getBookMeta,
|
getBookMeta,
|
||||||
@@ -11,8 +12,8 @@ import {
|
|||||||
type VerseIndexEntry,
|
type VerseIndexEntry,
|
||||||
type VerseRecord,
|
type VerseRecord,
|
||||||
} from "@/lib/api";
|
} from "@/lib/api";
|
||||||
import { ChapterViewer } from "@/app/books/chapter-viewer";
|
import { ChapterViewer } from "@/app/(app)/(reader)/books/chapter-viewer";
|
||||||
import type { MobileNavGroup } from "@/components/mobile-nav";
|
import type { MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
import { ogForVerse, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
|
import { ogForVerse, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
@@ -187,9 +188,12 @@ export default async function VersePage({
|
|||||||
>
|
>
|
||||||
← Śrī Brahma-saṁhitā
|
← Śrī Brahma-saṁhitā
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-2 text-2xl font-bold text-foreground">
|
<div className="mt-2 flex items-start justify-between gap-3">
|
||||||
Chapter {chapter}: {title}
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
</h1>
|
Chapter {chapter}: {title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -7,7 +7,8 @@ import { getChapterVerseIndex } from "@/lib/api";
|
|||||||
import { buildOgMeta } from "@/lib/og";
|
import { buildOgMeta } from "@/lib/og";
|
||||||
import { BOOK_NAMES } from "@/lib/constants";
|
import { BOOK_NAMES } from "@/lib/constants";
|
||||||
import { Card, CardContent } from "@/components/ui/card";
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/layout/page-header";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
@@ -59,13 +60,16 @@ export default async function BsChapterPage({
|
|||||||
>
|
>
|
||||||
← Śrī Brahma-saṁhitā
|
← Śrī Brahma-saṁhitā
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{segment.title}
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
</h1>
|
{segment.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<main className="max-w-5xl mx-auto px-6 py-8">
|
<main className="max-w-5xl mx-auto px-6 py-8">
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{segment.paragraphs.map((paragraph: string, i: number) => (
|
{segment.paragraphs.map((paragraph: string, i: number) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
+16
-9
@@ -10,12 +10,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
@@ -62,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"
|
||||||
@@ -69,12 +73,15 @@ export default async function CbhcChapterPage({
|
|||||||
>
|
>
|
||||||
← Śrī Caitanya-bhāgavata Commentary
|
← Śrī Caitanya-bhāgavata Commentary
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -92,7 +99,7 @@ export default async function CbhcChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
+10
-6
@@ -2,11 +2,12 @@ export const dynamic = "force-dynamic";
|
|||||||
|
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/layout/page-header";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { getBookMeta, getSingleVerse, getChapterVerseIndex } from "@/lib/api";
|
import { getBookMeta, getSingleVerse, getChapterVerseIndex } from "@/lib/api";
|
||||||
import { ChapterViewer } from "@/app/books/chapter-viewer";
|
import { ChapterViewer } from "@/app/(app)/(reader)/books/chapter-viewer";
|
||||||
import type { MobileNavGroup } from "@/components/mobile-nav";
|
import type { MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
import { ogForVerse, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
|
import { ogForVerse, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
|
||||||
|
|
||||||
type ChapterInfo = {
|
type ChapterInfo = {
|
||||||
@@ -111,9 +112,12 @@ export default async function CcVersePage({
|
|||||||
>
|
>
|
||||||
← {lilaInfo.name}
|
← {lilaInfo.name}
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-2 text-2xl font-bold text-foreground">
|
<div className="mt-2 flex items-start justify-between gap-3">
|
||||||
Chapter {chapter}: {chapterInfo.title}
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
</h1>
|
Chapter {chapter}: {chapterInfo.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -0,0 +1,227 @@
|
|||||||
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
import type { Metadata } from "next";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { redirect, notFound } from "next/navigation";
|
||||||
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
|
import { getBookMeta, getProseChapter, getChapterVerseIndex } from "@/lib/api";
|
||||||
|
import { CC_LILAS } from "@/lib/constants";
|
||||||
|
import { buildOgMeta } from "@/lib/og";
|
||||||
|
import { PageHeader } from "@/components/layout/page-header";
|
||||||
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
type ChapterInfo = { number: number; title: string; totalVerses: number };
|
||||||
|
type LilaInfo = {
|
||||||
|
key: string;
|
||||||
|
name: string;
|
||||||
|
totalChapters: number;
|
||||||
|
totalVerses: number;
|
||||||
|
chapters: ChapterInfo[];
|
||||||
|
};
|
||||||
|
type VerseEntry = { verse: number; verseEnd?: number | null; reference: string };
|
||||||
|
|
||||||
|
export async function generateMetadata({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ lila: string; chapter: string }>;
|
||||||
|
}): Promise<Metadata> {
|
||||||
|
const { lila, chapter } = await params;
|
||||||
|
const lilaName = CC_LILAS[lila] || lila;
|
||||||
|
return buildOgMeta({
|
||||||
|
title: "Śrī Caitanya-caritāmṛta",
|
||||||
|
detail: `${lilaName}, Chapter ${chapter}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function verseLabel(v: VerseEntry): string {
|
||||||
|
return v.verseEnd ? `${v.verse}–${v.verseEnd}` : String(v.verse);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Top/bottom navigation — mirrors the verse pages' VerseNav: a Contents
|
||||||
|
// toggle (mobile) listing this chapter's verses, Previous/Next (chapter), and
|
||||||
|
// a "Chapter X of N" label.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
function ChapterNav({
|
||||||
|
lila,
|
||||||
|
chapters,
|
||||||
|
current,
|
||||||
|
chapterTitle,
|
||||||
|
verseIndex,
|
||||||
|
}: {
|
||||||
|
lila: string;
|
||||||
|
chapters: ChapterInfo[];
|
||||||
|
current: number;
|
||||||
|
chapterTitle: string;
|
||||||
|
verseIndex: VerseEntry[];
|
||||||
|
}) {
|
||||||
|
const idx = chapters.findIndex((c) => c.number === current);
|
||||||
|
const prev = idx > 0 ? chapters[idx - 1] : null;
|
||||||
|
const next = idx < chapters.length - 1 ? chapters[idx + 1] : null;
|
||||||
|
|
||||||
|
// The contents drawer lists the active chapter's verses (same as the
|
||||||
|
// verse-page sidebar) so the reader can jump straight in.
|
||||||
|
const groups: MobileNavGroup[] = [
|
||||||
|
{
|
||||||
|
title: "Verses",
|
||||||
|
items: verseIndex.map((v) => ({
|
||||||
|
slug: String(v.verse),
|
||||||
|
label: `Verse ${verseLabel(v)}`,
|
||||||
|
href: `/books/cc/${lila}/${current}/${v.verse}`,
|
||||||
|
type: "verse",
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-between gap-3">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<MobileNav
|
||||||
|
groups={groups}
|
||||||
|
currentSlug=""
|
||||||
|
bookTitle={`Chapter ${current}: ${chapterTitle}`}
|
||||||
|
/>
|
||||||
|
{prev ? (
|
||||||
|
<Link
|
||||||
|
href={`/books/cc/${lila}/${prev.number}`}
|
||||||
|
className={cn(buttonVariants({ variant: "outline", size: "sm" }), "gap-1.5")}
|
||||||
|
>
|
||||||
|
<ChevronLeft className="size-4" />
|
||||||
|
<span className="hidden sm:inline">Previous</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div className="hidden lg:block" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span className="text-sm text-muted-foreground">
|
||||||
|
Chapter {current} of {chapters.length}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{next ? (
|
||||||
|
<Link
|
||||||
|
href={`/books/cc/${lila}/${next.number}`}
|
||||||
|
className={cn(buttonVariants({ variant: "outline", size: "sm" }), "gap-1.5")}
|
||||||
|
>
|
||||||
|
<span className="hidden sm:inline">Next</span>
|
||||||
|
<ChevronRight className="size-4" />
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function CcChapterPage({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ lila: string; chapter: string }>;
|
||||||
|
}) {
|
||||||
|
const { lila, chapter } = await params;
|
||||||
|
const chapterNum = parseInt(chapter);
|
||||||
|
|
||||||
|
const [meta, summary, verseIndex] = await Promise.all([
|
||||||
|
getBookMeta("cc"),
|
||||||
|
getProseChapter("cc", 0, `${lila}-${chapterNum}`),
|
||||||
|
getChapterVerseIndex("cc", lila, chapterNum),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!meta) notFound();
|
||||||
|
const lilaInfo = (meta.lilas as LilaInfo[] | undefined)?.find(
|
||||||
|
(l) => l.key === lila,
|
||||||
|
);
|
||||||
|
if (!lilaInfo) notFound();
|
||||||
|
const chapterInfo = lilaInfo.chapters.find((ch) => ch.number === chapterNum);
|
||||||
|
if (!chapterInfo) notFound();
|
||||||
|
if (verseIndex.length === 0) notFound();
|
||||||
|
|
||||||
|
const firstVerse = verseIndex[0].verse;
|
||||||
|
|
||||||
|
// Chapters without a summary (e.g. Ādi 7) go straight to the verses.
|
||||||
|
if (!summary || summary.paragraphs.length === 0) {
|
||||||
|
redirect(`/books/cc/${lila}/${chapterNum}/${firstVerse}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-background">
|
||||||
|
<PageHeader sticky>
|
||||||
|
<Link
|
||||||
|
href={`/books/cc/${lila}`}
|
||||||
|
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
||||||
|
>
|
||||||
|
← {lilaInfo.name}
|
||||||
|
</Link>
|
||||||
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
|
Chapter {chapterNum}: {chapterInfo.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
|
</PageHeader>
|
||||||
|
|
||||||
|
<div className="max-w-5xl mx-auto flex">
|
||||||
|
{/* Desktop sidebar — verses of the active chapter (matches the
|
||||||
|
verse-page sidebar) so the reader can jump to any verse. */}
|
||||||
|
<aside className="hidden lg:block w-64 shrink-0 sticky top-[89px] self-start max-h-[calc(100vh-165px)] overflow-y-auto py-8 pr-4">
|
||||||
|
<h2 className="text-sm font-bold uppercase tracking-wider text-muted-foreground mb-3 px-2">
|
||||||
|
Verses
|
||||||
|
</h2>
|
||||||
|
<nav className="grid grid-cols-3 gap-1">
|
||||||
|
{verseIndex.map((v) => (
|
||||||
|
<Link
|
||||||
|
key={v.verse}
|
||||||
|
href={`/books/cc/${lila}/${chapterNum}/${v.verse}`}
|
||||||
|
className="px-2 py-1 rounded-md text-sm tabular-nums text-muted-foreground hover:bg-muted hover:text-foreground transition-colors"
|
||||||
|
>
|
||||||
|
{verseLabel(v)}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</nav>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
{/* Main — chapter summary */}
|
||||||
|
<main className="flex-1 min-w-0 px-6 py-8 space-y-6">
|
||||||
|
{/* Top navigation */}
|
||||||
|
<ChapterNav
|
||||||
|
lila={lila}
|
||||||
|
chapters={lilaInfo.chapters}
|
||||||
|
current={chapterNum}
|
||||||
|
chapterTitle={chapterInfo.title}
|
||||||
|
verseIndex={verseIndex}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<p className="text-sm font-bold uppercase tracking-wider text-muted-foreground">
|
||||||
|
Chapter Summary
|
||||||
|
</p>
|
||||||
|
<Card id="book-content">
|
||||||
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
|
<div className="space-y-4">
|
||||||
|
{summary.paragraphs.map((paragraph, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className="text-base text-foreground leading-relaxed"
|
||||||
|
dangerouslySetInnerHTML={{ __html: paragraph }}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* Bottom navigation */}
|
||||||
|
<ChapterNav
|
||||||
|
lila={lila}
|
||||||
|
chapters={lilaInfo.chapters}
|
||||||
|
current={chapterNum}
|
||||||
|
chapterTitle={chapterInfo.title}
|
||||||
|
verseIndex={verseIndex}
|
||||||
|
/>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/layout/page-header";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { Card, CardContent } from "@/components/ui/card";
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
import { ExtractedVerseCount } from "../../extracted-verse-count";
|
import { ExtractedVerseCount } from "../../extracted-verse-count";
|
||||||
import { getBookMeta } from "@/lib/api";
|
import { getBookMeta, getProseChapter } from "@/lib/api";
|
||||||
import { buildOgMeta } from "@/lib/og";
|
import { buildOgMeta } from "@/lib/og";
|
||||||
import { BOOK_NAMES, CC_LILAS } from "@/lib/constants";
|
import { BOOK_NAMES, CC_LILAS } from "@/lib/constants";
|
||||||
|
|
||||||
@@ -14,12 +15,15 @@ export async function generateMetadata({
|
|||||||
params: Promise<{ lila: string }>;
|
params: Promise<{ lila: string }>;
|
||||||
}): Promise<Metadata> {
|
}): Promise<Metadata> {
|
||||||
const { lila } = await params;
|
const { lila } = await params;
|
||||||
const lilaName = CC_LILAS[lila] || lila;
|
|
||||||
const bookTitle = BOOK_NAMES["cc"] || "Śrī Caitanya-caritāmṛta";
|
const bookTitle = BOOK_NAMES["cc"] || "Śrī Caitanya-caritāmṛta";
|
||||||
return buildOgMeta({
|
// A non-līlā segment (front-flap, preface, introduction) is front matter.
|
||||||
title: bookTitle,
|
if (!CC_LILAS[lila]) {
|
||||||
detail: lilaName,
|
const segment = await getProseChapter("cc", 0, lila);
|
||||||
});
|
if (segment) {
|
||||||
|
return buildOgMeta({ title: bookTitle, detail: segment.title });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buildOgMeta({ title: bookTitle, detail: CC_LILAS[lila] || lila });
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChapterInfo = {
|
type ChapterInfo = {
|
||||||
@@ -47,7 +51,48 @@ export default async function LilaPage({
|
|||||||
|
|
||||||
const lilas = meta.lilas as LilaInfo[];
|
const lilas = meta.lilas as LilaInfo[];
|
||||||
const lilaInfo = lilas.find((l) => l.key === lila);
|
const lilaInfo = lilas.find((l) => l.key === lila);
|
||||||
if (!lilaInfo) notFound();
|
|
||||||
|
// Front matter — the param is not a līlā key, so resolve it as a prose
|
||||||
|
// intro-segment (front-flap, preface, introduction).
|
||||||
|
if (!lilaInfo) {
|
||||||
|
const segment = await getProseChapter("cc", 0, lila);
|
||||||
|
if (!segment) notFound();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-background">
|
||||||
|
<PageHeader sticky>
|
||||||
|
<Link
|
||||||
|
href="/books/cc"
|
||||||
|
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
||||||
|
>
|
||||||
|
← Śrī Caitanya-caritāmṛta
|
||||||
|
</Link>
|
||||||
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
|
{segment.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
|
</PageHeader>
|
||||||
|
|
||||||
|
<main className="max-w-5xl mx-auto px-6 py-8">
|
||||||
|
<Card id="book-content">
|
||||||
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
|
<div className="space-y-4">
|
||||||
|
{segment.paragraphs.map((paragraph, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className="text-base text-foreground leading-relaxed"
|
||||||
|
dangerouslySetInnerHTML={{ __html: paragraph }}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const totalVerses = lilaInfo.chapters.reduce(
|
const totalVerses = lilaInfo.chapters.reduce(
|
||||||
(sum, ch) => sum + ch.totalVerses,
|
(sum, ch) => sum + ch.totalVerses,
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { getBookMeta } from "@/lib/api";
|
import { getBookMeta, getProseChapters } from "@/lib/api";
|
||||||
import { ogForBook } from "@/lib/og";
|
import { ogForBook } from "@/lib/og";
|
||||||
import { PageHeader } from "@/components/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";
|
||||||
@@ -26,7 +28,10 @@ export function generateMetadata(): Metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default async function CcPage() {
|
export default async function CcPage() {
|
||||||
const meta = await getBookMeta("cc");
|
const [meta, introSegments] = await Promise.all([
|
||||||
|
getBookMeta("cc"),
|
||||||
|
getProseChapters("cc", 0, "intro-segment"),
|
||||||
|
]);
|
||||||
if (!meta) {
|
if (!meta) {
|
||||||
return (
|
return (
|
||||||
<div className="p-8 text-center text-muted-foreground">
|
<div className="p-8 text-center text-muted-foreground">
|
||||||
@@ -41,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"
|
||||||
@@ -51,7 +57,33 @@ export default async function CcPage() {
|
|||||||
<h1 className="mt-3 text-3xl font-bold text-foreground">{title}</h1>
|
<h1 className="mt-3 text-3xl font-bold text-foreground">{title}</h1>
|
||||||
<p className="mt-1 text-muted-foreground">{author}</p>
|
<p className="mt-1 text-muted-foreground">{author}</p>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<main className="max-w-5xl mx-auto px-6 py-8">
|
<main className="max-w-5xl mx-auto px-6 py-8 space-y-8">
|
||||||
|
{introSegments.length > 0 && (
|
||||||
|
<div>
|
||||||
|
<h2 className="text-sm font-bold uppercase tracking-wider text-muted-foreground mb-3">
|
||||||
|
Front Matter
|
||||||
|
</h2>
|
||||||
|
<Card className="divide-y divide-border py-0">
|
||||||
|
<CardContent className="p-0">
|
||||||
|
<ul className="divide-y divide-border">
|
||||||
|
{introSegments.map((seg) => (
|
||||||
|
<li key={seg.slug}>
|
||||||
|
<Link
|
||||||
|
href={`/books/cc/${seg.slug}`}
|
||||||
|
className="flex px-5 py-4 hover:bg-muted transition-colors"
|
||||||
|
>
|
||||||
|
<p className="font-medium text-foreground">
|
||||||
|
{seg.title}
|
||||||
|
</p>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<Card className="divide-y divide-border">
|
<Card className="divide-y divide-border">
|
||||||
<CardContent className="p-0">
|
<CardContent className="p-0">
|
||||||
<ul className="divide-y divide-border">
|
<ul className="divide-y divide-border">
|
||||||
@@ -6,7 +6,10 @@ import { Card, CardHeader, CardContent } from "@/components/ui/card";
|
|||||||
import { Badge } from "@/components/ui/badge";
|
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/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
|
||||||
@@ -216,9 +219,17 @@ function VerseCard({
|
|||||||
Purport
|
Purport
|
||||||
</h3>
|
</h3>
|
||||||
<div className="text-base text-foreground leading-relaxed space-y-3">
|
<div className="text-base text-foreground leading-relaxed space-y-3">
|
||||||
{verse.purport.map((p, i) => (
|
{verse.purport.map((p, i) =>
|
||||||
<p key={i} dangerouslySetInnerHTML={{ __html: p }} />
|
// Cited ślokas come wrapped in <blockquote class="shloka"> — a
|
||||||
))}
|
// block element that can't live inside a <p>, so render those
|
||||||
|
// in a <div> (styled centered + accent via globals.css); plain
|
||||||
|
// prose paragraphs stay as <p>.
|
||||||
|
/^\s*<blockquote/i.test(p) ? (
|
||||||
|
<div key={i} dangerouslySetInnerHTML={{ __html: p }} />
|
||||||
|
) : (
|
||||||
|
<p key={i} dangerouslySetInnerHTML={{ __html: p }} />
|
||||||
|
),
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -389,6 +400,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
|
||||||
@@ -440,7 +464,8 @@ export function ChapterViewer({
|
|||||||
mobileNavBookTitle={mobileNavBookTitle}
|
mobileNavBookTitle={mobileNavBookTitle}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Verse content */}
|
{/* Verse content — id targeted by each page header's FindInPage. */}
|
||||||
|
<div id="book-content">
|
||||||
{loading && !currentVerse ? (
|
{loading && !currentVerse ? (
|
||||||
<div className="flex items-center justify-center py-24 text-muted-foreground gap-2">
|
<div className="flex items-center justify-center py-24 text-muted-foreground gap-2">
|
||||||
<Loader2 className="size-5 animate-spin" />
|
<Loader2 className="size-5 animate-spin" />
|
||||||
@@ -453,6 +478,7 @@ export function ChapterViewer({
|
|||||||
Verse not found.
|
Verse not found.
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Bottom navigation */}
|
{/* Bottom navigation */}
|
||||||
<VerseNav
|
<VerseNav
|
||||||
@@ -12,12 +12,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -76,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"
|
||||||
@@ -83,12 +87,15 @@ export default async function DsChapterPage({
|
|||||||
>
|
>
|
||||||
← Dialectic Spiritualism
|
← Dialectic Spiritualism
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{parentChapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {parentChapterNum}: </span>
|
{parentChapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {parentChapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -106,7 +113,7 @@ export default async function DsChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -12,12 +12,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -70,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"
|
||||||
@@ -77,12 +81,15 @@ export default async function EjChapterPage({
|
|||||||
>
|
>
|
||||||
← Easy Journey to Other Planets
|
← Easy Journey to Other Planets
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -100,7 +107,7 @@ export default async function EjChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -12,12 +12,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -70,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"
|
||||||
@@ -77,12 +81,15 @@ export default async function EkChapterPage({
|
|||||||
>
|
>
|
||||||
← Elevation to Kṛṣṇa Consciousness
|
← Elevation to Kṛṣṇa Consciousness
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -100,7 +107,7 @@ export default async function EkChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -10,12 +10,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
@@ -66,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"
|
||||||
@@ -73,12 +77,15 @@ export default async function GgChapterPage({
|
|||||||
>
|
>
|
||||||
← Gītār Gān
|
← Gītār Gān
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -96,7 +103,7 @@ export default async function GgChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -12,12 +12,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -70,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"
|
||||||
@@ -77,12 +81,15 @@ export default async function HkhChapterPage({
|
|||||||
>
|
>
|
||||||
← The Kṛṣṇa Consciousness Handbook
|
← The Kṛṣṇa Consciousness Handbook
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -100,7 +107,7 @@ export default async function HkhChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -11,12 +11,15 @@ import {
|
|||||||
type IsoSidebarItem,
|
type IsoSidebarItem,
|
||||||
} from "@/lib/iso";
|
} from "@/lib/iso";
|
||||||
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
|
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
|
||||||
import { PageHeader } from "@/components/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Type guards
|
// Type guards
|
||||||
@@ -102,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"
|
||||||
@@ -109,15 +113,18 @@ export default async function IsoMantraPage({
|
|||||||
>
|
>
|
||||||
← Śrī Īśopaniṣad
|
← Śrī Īśopaniṣad
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{verse && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<>
|
{verse && (
|
||||||
<span className="text-primary">{verse.reference}: </span>
|
<>
|
||||||
{verse.bookTitle}
|
<span className="text-primary">{verse.reference}: </span>
|
||||||
</>
|
{verse.bookTitle}
|
||||||
)}
|
</>
|
||||||
{intro && intro.title}
|
)}
|
||||||
</h1>
|
{intro && intro.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -157,7 +164,7 @@ export default async function IsoMantraPage({
|
|||||||
|
|
||||||
function VerseContent({ verse }: { verse: IsoVerse }) {
|
function VerseContent({ verse }: { verse: IsoVerse }) {
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8 space-y-8">
|
<CardContent className="py-8 px-6 sm:px-8 space-y-8">
|
||||||
{/* Devanagari */}
|
{/* Devanagari */}
|
||||||
<section>
|
<section>
|
||||||
@@ -233,7 +240,7 @@ function VerseContent({ verse }: { verse: IsoVerse }) {
|
|||||||
|
|
||||||
function IntroContent({ intro }: { intro: IsoIntroSegment }) {
|
function IntroContent({ intro }: { intro: IsoIntroSegment }) {
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{intro.paragraphs.map((paragraph, i) => (
|
{intro.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
+16
-9
@@ -6,12 +6,15 @@ import { notFound } from "next/navigation";
|
|||||||
import { getProseChapter, getProseChapters } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
export async function generateMetadata({
|
export async function generateMetadata({
|
||||||
params,
|
params,
|
||||||
@@ -65,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}`}
|
||||||
@@ -72,12 +76,15 @@ export default async function KbChapterPage({
|
|||||||
>
|
>
|
||||||
← Volume {vol}
|
← Volume {vol}
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterLabel && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">{chapterLabel}: </span>
|
{chapterLabel && (
|
||||||
)}
|
<span className="text-primary">{chapterLabel}: </span>
|
||||||
{chapter.title}
|
)}
|
||||||
</h1>
|
{chapter.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -100,7 +107,7 @@ export default async function KbChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Chapter content */}
|
{/* Chapter content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{chapter.paragraphs.map((paragraph, i) => (
|
{chapter.paragraphs.map((paragraph, i) => (
|
||||||
@@ -4,7 +4,7 @@ import { notFound } from "next/navigation";
|
|||||||
import { getBookMeta, getProseChapters } from "@/lib/api";
|
import { getBookMeta, getProseChapters } from "@/lib/api";
|
||||||
import { buildOgMeta } from "@/lib/og";
|
import { buildOgMeta } from "@/lib/og";
|
||||||
import { BOOK_NAMES } from "@/lib/constants";
|
import { BOOK_NAMES } from "@/lib/constants";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/layout/page-header";
|
||||||
import { Card, CardContent } from "@/components/ui/card";
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
|
|
||||||
export async function generateMetadata({
|
export async function generateMetadata({
|
||||||
@@ -3,7 +3,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -12,12 +12,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -70,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"
|
||||||
@@ -77,12 +81,15 @@ export default async function LclChapterPage({
|
|||||||
>
|
>
|
||||||
← Life Comes from Life
|
← Life Comes from Life
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -100,7 +107,7 @@ export default async function LclChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -12,12 +12,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
export async function generateMetadata({
|
export async function generateMetadata({
|
||||||
params,
|
params,
|
||||||
@@ -66,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"
|
||||||
@@ -73,12 +77,15 @@ export default async function LobChapterPage({
|
|||||||
>
|
>
|
||||||
← Light of the Bhāgavata
|
← Light of the Bhāgavata
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Text {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Text {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -96,7 +103,7 @@ export default async function LobChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) =>
|
{content.paragraphs.map((paragraph, i) =>
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -12,12 +12,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
export async function generateMetadata({
|
export async function generateMetadata({
|
||||||
params,
|
params,
|
||||||
@@ -66,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"
|
||||||
@@ -73,12 +77,15 @@ export default async function MgChapterPage({
|
|||||||
>
|
>
|
||||||
← Kṛṣṇa Consciousness: The Matchless Gift
|
← Kṛṣṇa Consciousness: The Matchless Gift
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -96,7 +103,7 @@ export default async function MgChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
+10
-6
@@ -1,7 +1,8 @@
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/layout/page-header";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import {
|
import {
|
||||||
getBookMeta,
|
getBookMeta,
|
||||||
@@ -10,8 +11,8 @@ import {
|
|||||||
type VerseIndexEntry,
|
type VerseIndexEntry,
|
||||||
type VerseRecord,
|
type VerseRecord,
|
||||||
} from "@/lib/api";
|
} from "@/lib/api";
|
||||||
import { ChapterViewer } from "@/app/books/chapter-viewer";
|
import { ChapterViewer } from "@/app/(app)/(reader)/books/chapter-viewer";
|
||||||
import type { MobileNavGroup } from "@/components/mobile-nav";
|
import type { MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { ogForVerse, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
|
import { ogForVerse, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
|
||||||
|
|
||||||
@@ -187,9 +188,12 @@ export default async function VersePage({
|
|||||||
>
|
>
|
||||||
← Mukunda-mālā-stotra
|
← Mukunda-mālā-stotra
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-2 text-2xl font-bold text-foreground">
|
<div className="mt-2 flex items-start justify-between gap-3">
|
||||||
Chapter {chapter}: {title}
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
</h1>
|
Chapter {chapter}: {title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -7,7 +7,8 @@ import { getChapterVerseIndex } from "@/lib/api";
|
|||||||
import { buildOgMeta } from "@/lib/og";
|
import { buildOgMeta } from "@/lib/og";
|
||||||
import { BOOK_NAMES } from "@/lib/constants";
|
import { BOOK_NAMES } from "@/lib/constants";
|
||||||
import { Card, CardContent } from "@/components/ui/card";
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/layout/page-header";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
@@ -59,13 +60,16 @@ export default async function MmChapterPage({
|
|||||||
>
|
>
|
||||||
← Mukunda-mālā-stotra
|
← Mukunda-mālā-stotra
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{segment.title}
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
</h1>
|
{segment.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<main className="max-w-5xl mx-auto px-6 py-8">
|
<main className="max-w-5xl mx-auto px-6 py-8">
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{segment.paragraphs.map((paragraph: string, i: number) => (
|
{segment.paragraphs.map((paragraph: string, i: number) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -12,12 +12,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -70,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"
|
||||||
@@ -77,12 +81,15 @@ export default async function MogChapterPage({
|
|||||||
>
|
>
|
||||||
← Message of Godhead
|
← Message of Godhead
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -100,7 +107,7 @@ export default async function MogChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
+10
-6
@@ -4,7 +4,8 @@ import type { Metadata } from "next";
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/layout/page-header";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import {
|
import {
|
||||||
getBookMeta,
|
getBookMeta,
|
||||||
@@ -14,8 +15,8 @@ import {
|
|||||||
type VerseRecord,
|
type VerseRecord,
|
||||||
} from "@/lib/api";
|
} from "@/lib/api";
|
||||||
import { ogForVerse, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
|
import { ogForVerse, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
|
||||||
import { ChapterViewer } from "@/app/books/chapter-viewer";
|
import { ChapterViewer } from "@/app/(app)/(reader)/books/chapter-viewer";
|
||||||
import type { MobileNavGroup } from "@/components/mobile-nav";
|
import type { MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
|
||||||
type NbsMeta = {
|
type NbsMeta = {
|
||||||
book: string;
|
book: string;
|
||||||
@@ -192,9 +193,12 @@ export default async function VersePage({
|
|||||||
>
|
>
|
||||||
← Nārada-bhakti-sūtra
|
← Nārada-bhakti-sūtra
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-2 text-2xl font-bold text-foreground">
|
<div className="mt-2 flex items-start justify-between gap-3">
|
||||||
Chapter {chapter}: {title}
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
</h1>
|
Chapter {chapter}: {title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -7,7 +7,8 @@ import { getChapterVerseIndex } from "@/lib/api";
|
|||||||
import { buildOgMeta } from "@/lib/og";
|
import { buildOgMeta } from "@/lib/og";
|
||||||
import { BOOK_NAMES } from "@/lib/constants";
|
import { BOOK_NAMES } from "@/lib/constants";
|
||||||
import { Card, CardContent } from "@/components/ui/card";
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/layout/page-header";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
@@ -62,13 +63,16 @@ export default async function NbsChapterPage({
|
|||||||
>
|
>
|
||||||
← Nārada-bhakti-sūtra
|
← Nārada-bhakti-sūtra
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{segment.title}
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
</h1>
|
{segment.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<main className="max-w-5xl mx-auto px-6 py-8">
|
<main className="max-w-5xl mx-auto px-6 py-8">
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{segment.paragraphs.map((paragraph: string, i: number) => (
|
{segment.paragraphs.map((paragraph: string, i: number) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -12,12 +12,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -70,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"
|
||||||
@@ -77,12 +81,15 @@ export default async function NodChapterPage({
|
|||||||
>
|
>
|
||||||
← The Nectar of Devotion
|
← The Nectar of Devotion
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -100,7 +107,7 @@ export default async function NodChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -11,12 +11,15 @@ import {
|
|||||||
type NoiSidebarItem,
|
type NoiSidebarItem,
|
||||||
} from "@/lib/noi";
|
} from "@/lib/noi";
|
||||||
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
|
import { ogForChapter, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
|
||||||
import { PageHeader } from "@/components/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Type guards
|
// Type guards
|
||||||
@@ -93,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"
|
||||||
@@ -100,15 +104,18 @@ export default async function NoiTextPage({
|
|||||||
>
|
>
|
||||||
← The Nectar of Instruction
|
← The Nectar of Instruction
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{verse && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<>
|
{verse && (
|
||||||
<span className="text-primary">Text {verse.text}: </span>
|
<>
|
||||||
{verse.title}
|
<span className="text-primary">Text {verse.text}: </span>
|
||||||
</>
|
{verse.title}
|
||||||
)}
|
</>
|
||||||
{intro && intro.title}
|
)}
|
||||||
</h1>
|
{intro && intro.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -148,7 +155,7 @@ export default async function NoiTextPage({
|
|||||||
|
|
||||||
function VerseContent({ verse }: { verse: NoiVerse }) {
|
function VerseContent({ verse }: { verse: NoiVerse }) {
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8 space-y-8">
|
<CardContent className="py-8 px-6 sm:px-8 space-y-8">
|
||||||
{/* Devanagari */}
|
{/* Devanagari */}
|
||||||
<section>
|
<section>
|
||||||
@@ -224,7 +231,7 @@ function VerseContent({ verse }: { verse: NoiVerse }) {
|
|||||||
|
|
||||||
function IntroContent({ intro }: { intro: NoiIntroSegment }) {
|
function IntroContent({ intro }: { intro: NoiIntroSegment }) {
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{intro.paragraphs.map((paragraph, i) => (
|
{intro.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
+16
-9
@@ -12,12 +12,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -70,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"
|
||||||
@@ -77,12 +81,15 @@ export default async function OchkmChapterPage({
|
|||||||
>
|
>
|
||||||
← On Chanting the Hare Kṛṣṇa Mantra
|
← On Chanting the Hare Kṛṣṇa Mantra
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -100,7 +107,7 @@ export default async function OchkmChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -12,12 +12,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -70,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"
|
||||||
@@ -77,12 +81,15 @@ export default async function OwkChapterPage({
|
|||||||
>
|
>
|
||||||
← On the Way to Kṛṣṇa
|
← On the Way to Kṛṣṇa
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -100,7 +107,7 @@ export default async function OwkChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/layout/page-header";
|
||||||
import { getAllBooks, type BookMeta } from "@/lib/api";
|
import { getAllBooks, type BookMeta } from "@/lib/api";
|
||||||
import { buildOgMeta } from "@/lib/og";
|
import { buildOgMeta } from "@/lib/og";
|
||||||
import { BooksGrid, type BookInfo } from "./books-grid";
|
import { BooksGrid, type BookInfo } from "./books-grid";
|
||||||
@@ -12,12 +12,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -65,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"
|
||||||
@@ -72,12 +76,15 @@ export default async function PkChapterPage({
|
|||||||
>
|
>
|
||||||
← Prayers of King Kulaśekhara
|
← Prayers of King Kulaśekhara
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Verse {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Verse {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -95,7 +102,7 @@ export default async function PkChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -12,12 +12,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -70,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"
|
||||||
@@ -77,12 +81,15 @@ export default async function PoyChapterPage({
|
|||||||
>
|
>
|
||||||
← The Perfection of Yoga
|
← The Perfection of Yoga
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -100,7 +107,7 @@ export default async function PoyChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
+16
-9
@@ -12,12 +12,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -70,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"
|
||||||
@@ -77,12 +81,15 @@ export default async function PqpaChapterPage({
|
|||||||
>
|
>
|
||||||
← Perfect Questions Perfect Answers
|
← Perfect Questions Perfect Answers
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -100,7 +107,7 @@ export default async function PqpaChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -12,12 +12,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -70,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"
|
||||||
@@ -77,12 +81,15 @@ export default async function RvChapterPage({
|
|||||||
>
|
>
|
||||||
← Rāja-vidyā: The King of Knowledge
|
← Rāja-vidyā: The King of Knowledge
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -100,7 +107,7 @@ export default async function RvChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
+10
-6
@@ -2,11 +2,12 @@ export const dynamic = "force-dynamic";
|
|||||||
|
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/layout/page-header";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { getBookMeta, getSingleVerse, getChapterVerseIndex } from "@/lib/api";
|
import { getBookMeta, getSingleVerse, getChapterVerseIndex } from "@/lib/api";
|
||||||
import { ChapterViewer } from "@/app/books/chapter-viewer";
|
import { ChapterViewer } from "@/app/(app)/(reader)/books/chapter-viewer";
|
||||||
import type { MobileNavGroup } from "@/components/mobile-nav";
|
import type { MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
import { ogForVerse, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
|
import { ogForVerse, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
|
||||||
|
|
||||||
type ChapterInfo = {
|
type ChapterInfo = {
|
||||||
@@ -107,9 +108,12 @@ export default async function SbVersePage({
|
|||||||
>
|
>
|
||||||
← Canto {cantoInfo.number}: {cantoInfo.title}
|
← Canto {cantoInfo.number}: {cantoInfo.title}
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-2 text-2xl font-bold text-foreground">
|
<div className="mt-2 flex items-start justify-between gap-3">
|
||||||
Chapter {chapter}: {chapterInfo.title}
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
</h1>
|
Chapter {chapter}: {chapterInfo.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/layout/page-header";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { Card, CardContent } from "@/components/ui/card";
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
import { ExtractedVerseCount } from "../../extracted-verse-count";
|
import { ExtractedVerseCount } from "../../extracted-verse-count";
|
||||||
import { getBookMeta } from "@/lib/api";
|
import { getBookMeta, getProseChapter } from "@/lib/api";
|
||||||
import { buildOgMeta } from "@/lib/og";
|
import { buildOgMeta } from "@/lib/og";
|
||||||
import { BOOK_NAMES } from "@/lib/constants";
|
import { BOOK_NAMES } from "@/lib/constants";
|
||||||
|
|
||||||
@@ -15,6 +16,11 @@ export async function generateMetadata({
|
|||||||
}): Promise<Metadata> {
|
}): Promise<Metadata> {
|
||||||
const { canto } = await params;
|
const { canto } = await params;
|
||||||
const title = BOOK_NAMES["sb"] || "Śrīmad-Bhāgavatam";
|
const title = BOOK_NAMES["sb"] || "Śrīmad-Bhāgavatam";
|
||||||
|
// A non-numeric segment (preface, introduction) is front matter.
|
||||||
|
if (isNaN(parseInt(canto))) {
|
||||||
|
const segment = await getProseChapter("sb", 0, canto);
|
||||||
|
if (segment) return buildOgMeta({ title, detail: segment.title });
|
||||||
|
}
|
||||||
return buildOgMeta({ title, detail: `Canto ${canto}` });
|
return buildOgMeta({ title, detail: `Canto ${canto}` });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,6 +44,49 @@ export default async function CantoPage({
|
|||||||
}) {
|
}) {
|
||||||
const { canto } = await params;
|
const { canto } = await params;
|
||||||
const cantoNum = parseInt(canto);
|
const cantoNum = parseInt(canto);
|
||||||
|
|
||||||
|
// Front matter — a non-numeric param (preface, introduction) resolves to a
|
||||||
|
// prose intro-segment.
|
||||||
|
if (isNaN(cantoNum)) {
|
||||||
|
const segment = await getProseChapter("sb", 0, canto);
|
||||||
|
if (!segment) notFound();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-background">
|
||||||
|
<PageHeader sticky>
|
||||||
|
<Link
|
||||||
|
href="/books/sb"
|
||||||
|
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
||||||
|
>
|
||||||
|
← Śrīmad-Bhāgavatam
|
||||||
|
</Link>
|
||||||
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
|
{segment.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
|
</PageHeader>
|
||||||
|
|
||||||
|
<main className="max-w-5xl mx-auto px-6 py-8">
|
||||||
|
<Card id="book-content">
|
||||||
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
|
<div className="space-y-4">
|
||||||
|
{segment.paragraphs.map((paragraph, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className="text-base text-foreground leading-relaxed"
|
||||||
|
dangerouslySetInnerHTML={{ __html: paragraph }}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const meta = await getBookMeta("sb");
|
const meta = await getBookMeta("sb");
|
||||||
if (!meta) notFound();
|
if (!meta) notFound();
|
||||||
|
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/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";
|
||||||
import { getBookMeta } from "@/lib/api";
|
import { getBookMeta, getProseChapters } from "@/lib/api";
|
||||||
import { ogForBook } from "@/lib/og";
|
import { ogForBook } from "@/lib/og";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
|
|
||||||
@@ -26,7 +28,10 @@ type CantoInfo = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function SbPage() {
|
export default async function SbPage() {
|
||||||
const meta = await getBookMeta("sb");
|
const [meta, introSegments] = await Promise.all([
|
||||||
|
getBookMeta("sb"),
|
||||||
|
getProseChapters("sb", 0, "intro-segment"),
|
||||||
|
]);
|
||||||
if (!meta) notFound();
|
if (!meta) notFound();
|
||||||
|
|
||||||
const intro = meta as {
|
const intro = meta as {
|
||||||
@@ -39,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"
|
||||||
@@ -51,7 +57,33 @@ export default async function SbPage() {
|
|||||||
</h1>
|
</h1>
|
||||||
<p className="mt-1 text-muted-foreground">{intro.author}</p>
|
<p className="mt-1 text-muted-foreground">{intro.author}</p>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<main className="max-w-5xl mx-auto px-6 py-8">
|
<main className="max-w-5xl mx-auto px-6 py-8 space-y-8">
|
||||||
|
{introSegments.length > 0 && (
|
||||||
|
<div>
|
||||||
|
<h2 className="text-sm font-bold uppercase tracking-wider text-muted-foreground mb-3">
|
||||||
|
Front Matter
|
||||||
|
</h2>
|
||||||
|
<Card className="divide-y divide-border py-0">
|
||||||
|
<CardContent className="p-0">
|
||||||
|
<ul className="divide-y divide-border">
|
||||||
|
{introSegments.map((seg) => (
|
||||||
|
<li key={seg.slug}>
|
||||||
|
<Link
|
||||||
|
href={`/books/sb/${seg.slug}`}
|
||||||
|
className="flex px-5 py-4 hover:bg-muted transition-colors"
|
||||||
|
>
|
||||||
|
<p className="font-medium text-foreground">
|
||||||
|
{seg.title}
|
||||||
|
</p>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<Card className="divide-y divide-border">
|
<Card className="divide-y divide-border">
|
||||||
<CardContent className="p-0">
|
<CardContent className="p-0">
|
||||||
<ul className="divide-y divide-border">
|
<ul className="divide-y divide-border">
|
||||||
+10
-6
@@ -1,10 +1,11 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/layout/page-header";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { getBookMeta, getSingleVerse, getChapterVerseIndex } from "@/lib/api";
|
import { getBookMeta, getSingleVerse, getChapterVerseIndex } from "@/lib/api";
|
||||||
import { ChapterViewer } from "@/app/books/chapter-viewer";
|
import { ChapterViewer } from "@/app/(app)/(reader)/books/chapter-viewer";
|
||||||
import type { MobileNavGroup } from "@/components/mobile-nav";
|
import type { MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
import { ogForVerse, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
|
import { ogForVerse, extractQuoteFromHl, buildOgMeta } from "@/lib/og";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
@@ -104,9 +105,12 @@ export default async function VersePage({
|
|||||||
>
|
>
|
||||||
← Śrīmad-Bhāgavatam (1962)
|
← Śrīmad-Bhāgavatam (1962)
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-2 text-2xl font-bold text-foreground">
|
<div className="mt-2 flex items-start justify-between gap-3">
|
||||||
Chapter {chapter}: {title}
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
</h1>
|
Chapter {chapter}: {title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -3,7 +3,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -12,12 +12,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -76,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"
|
||||||
@@ -83,12 +87,15 @@ export default async function SsrChapterPage({
|
|||||||
>
|
>
|
||||||
← The Science of Self-Realization
|
← The Science of Self-Realization
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{parentChapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {parentChapterNum}: </span>
|
{parentChapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {parentChapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -106,7 +113,7 @@ export default async function SsrChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -13,12 +13,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -77,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"
|
||||||
@@ -84,12 +88,15 @@ export default async function SvaChapterPage({
|
|||||||
>
|
>
|
||||||
← Songs of the Vaiṣṇava Ācāryas
|
← Songs of the Vaiṣṇava Ācāryas
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{parentChapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Part {parentChapterNum}: </span>
|
{parentChapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Part {parentChapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -107,7 +114,7 @@ export default async function SvaChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -12,12 +12,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -70,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"
|
||||||
@@ -77,12 +81,15 @@ export default async function TlcChapterPage({
|
|||||||
>
|
>
|
||||||
← Teachings of Lord Caitanya
|
← Teachings of Lord Caitanya
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -100,7 +107,7 @@ export default async function TlcChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -12,12 +12,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -70,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"
|
||||||
@@ -77,12 +81,15 @@ export default async function TlkChapterPage({
|
|||||||
>
|
>
|
||||||
← Teachings of Lord Kapila
|
← Teachings of Lord Kapila
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -100,7 +107,7 @@ export default async function TlkChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -12,12 +12,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -70,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"
|
||||||
@@ -77,12 +81,15 @@ export default async function TqkChapterPage({
|
|||||||
>
|
>
|
||||||
← Teachings of Queen Kuntī
|
← Teachings of Queen Kuntī
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -100,7 +107,7 @@ export default async function TqkChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -12,12 +12,15 @@ import {
|
|||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -70,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"
|
||||||
@@ -77,12 +81,15 @@ export default async function TtpChapterPage({
|
|||||||
>
|
>
|
||||||
← Transcendental Teachings of Prahlāda Mahārāja
|
← Transcendental Teachings of Prahlāda Mahārāja
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{chapterNum != null && (
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
<span className="text-primary">Chapter {chapterNum}: </span>
|
{chapterNum != null && (
|
||||||
)}
|
<span className="text-primary">Chapter {chapterNum}: </span>
|
||||||
{content.title}
|
)}
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -100,7 +107,7 @@ export default async function TtpChapterPage({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -6,18 +6,20 @@ import { notFound } from "next/navigation";
|
|||||||
import {
|
import {
|
||||||
getVaContent,
|
getVaContent,
|
||||||
getVaSidebarItems,
|
getVaSidebarItems,
|
||||||
type VaChapter,
|
|
||||||
type VaSidebarItem,
|
type VaSidebarItem,
|
||||||
} from "@/lib/va";
|
} from "@/lib/va";
|
||||||
import { getProseChapter } from "@/lib/api";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
|
import { FindInPage } from "@/components/layout/find-in-page";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -61,10 +63,9 @@ export default async function VaChapterPage({
|
|||||||
const next =
|
const next =
|
||||||
currentIdx < sidebarItems.length - 1 ? sidebarItems[currentIdx + 1] : null;
|
currentIdx < sidebarItems.length - 1 ? sidebarItems[currentIdx + 1] : null;
|
||||||
|
|
||||||
const chapterNum = (content as VaChapter).chapter;
|
|
||||||
|
|
||||||
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"
|
||||||
@@ -72,9 +73,12 @@ export default async function VaChapterPage({
|
|||||||
>
|
>
|
||||||
← Vaiśiṣṭyāṣṭakam
|
← Vaiśiṣṭyāṣṭakam
|
||||||
</Link>
|
</Link>
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<div className="mt-3 flex items-start justify-between gap-3">
|
||||||
{content.title}
|
<h1 className="text-2xl font-bold text-foreground">
|
||||||
</h1>
|
{content.title}
|
||||||
|
</h1>
|
||||||
|
<FindInPage targetId="book-content" className="shrink-0 mt-0.5" />
|
||||||
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<div className="max-w-5xl mx-auto flex">
|
<div className="max-w-5xl mx-auto flex">
|
||||||
@@ -88,7 +92,7 @@ export default async function VaChapterPage({
|
|||||||
currentSlug={slug}
|
currentSlug={slug}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Card>
|
<Card id="book-content">
|
||||||
<CardContent className="py-8 px-6 sm:px-8">
|
<CardContent className="py-8 px-6 sm:px-8">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{content.paragraphs.map((paragraph, i) => (
|
{content.paragraphs.map((paragraph, i) => (
|
||||||
@@ -5,7 +5,9 @@ import Link from "next/link";
|
|||||||
import { notFound } from "next/navigation";
|
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/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"
|
||||||
@@ -2,7 +2,7 @@ export const dynamic = "force-dynamic";
|
|||||||
|
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/layout/page-header";
|
||||||
import { ogForDisciples } from "@/lib/og";
|
import { ogForDisciples } from "@/lib/og";
|
||||||
import {
|
import {
|
||||||
getTotalDiscipleCount,
|
getTotalDiscipleCount,
|
||||||
@@ -4,12 +4,14 @@ import type { Metadata } from "next";
|
|||||||
import Link from "next/link";
|
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/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";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
import { MobileNav, type MobileNavGroup } from "@/components/layout/mobile-nav";
|
||||||
import { bff, bffList } from "@/lib/bff";
|
import { bff, bffList } from "@/lib/bff";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -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"
|
||||||
@@ -2,7 +2,7 @@ export const dynamic = "force-dynamic";
|
|||||||
|
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { PageHeader } from "@/components/page-header";
|
import { PageHeader } from "@/components/layout/page-header";
|
||||||
import { buildOgMeta } from "@/lib/og";
|
import { buildOgMeta } from "@/lib/og";
|
||||||
import { bffList } from "@/lib/bff";
|
import { bffList } from "@/lib/bff";
|
||||||
import { EssaysGrid } from "./essays-grid";
|
import { EssaysGrid } from "./essays-grid";
|
||||||
@@ -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
-19
@@ -1,14 +1,13 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useMemo, useRef, useEffect, useCallback } from "react";
|
import { useState, useMemo, useRef, useEffect, useCallback } from "react";
|
||||||
import { useRouter, useSearchParams } from "next/navigation";
|
import { useSearchParams } from "next/navigation";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { Search, X, Menu, ChevronLeft, ChevronRight } from "lucide-react";
|
import { Search, X, Menu, ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Card, CardContent } from "@/components/ui/card";
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { Button, buttonVariants } from "@/components/ui/button";
|
import { Button, buttonVariants } from "@/components/ui/button";
|
||||||
import { ReadingSettings } from "@/components/reading-settings";
|
|
||||||
import {
|
import {
|
||||||
Drawer,
|
Drawer,
|
||||||
DrawerClose,
|
DrawerClose,
|
||||||
@@ -290,7 +289,6 @@ export function GlossaryClient({
|
|||||||
letters,
|
letters,
|
||||||
letterCounts,
|
letterCounts,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const router = useRouter();
|
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
|
|
||||||
@@ -389,22 +387,17 @@ export function GlossaryClient({
|
|||||||
<>
|
<>
|
||||||
{/* Sticky header */}
|
{/* Sticky header */}
|
||||||
<header className="border-b border-border bg-card px-6 py-4 sticky top-0 z-20">
|
<header className="border-b border-border bg-card px-6 py-4 sticky top-0 z-20">
|
||||||
<div className="max-w-5xl mx-auto flex items-start justify-between gap-4">
|
<div className="max-w-5xl mx-auto">
|
||||||
<div className="flex-1 min-w-0">
|
<Link
|
||||||
<Link
|
href="/"
|
||||||
href="/"
|
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
||||||
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
>
|
||||||
>
|
← Home
|
||||||
← Home
|
</Link>
|
||||||
</Link>
|
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
||||||
<h1 className="mt-3 text-2xl font-bold text-foreground">
|
<span className="text-primary">Glossary: </span>
|
||||||
<span className="text-primary">Glossary: </span>
|
{activeEntry?.term || activeLetter}
|
||||||
{activeEntry?.term || activeLetter}
|
</h1>
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
<div className="shrink-0 pt-1">
|
|
||||||
<ReadingSettings />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user