feat: add bg front matter

This commit is contained in:
gosangam
2026-06-14 13:28:29 +05:30
parent 455ed0f7cb
commit a4baf6d215
2 changed files with 121 additions and 27 deletions
+57 -1
View File
@@ -3,9 +3,13 @@ export const dynamic = "force-dynamic";
import type { Metadata } from "next"; import type { Metadata } from "next";
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
import { getChapterVerseIndex } from "@/lib/api"; import Link from "next/link";
import { getChapterVerseIndex, 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";
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({ export async function generateMetadata({
params, params,
@@ -13,6 +17,14 @@ export async function generateMetadata({
params: Promise<{ chapter: string }>; params: Promise<{ chapter: string }>;
}): Promise<Metadata> { }): Promise<Metadata> {
const { chapter } = await params; 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}` }); return buildOgMeta({ title: BOOK_NAMES["bg"], detail: `Chapter ${chapter}` });
} }
@@ -22,6 +34,50 @@ export default async function ChapterPage({
params: Promise<{ chapter: string }>; params: Promise<{ chapter: string }>;
}) { }) {
const { chapter } = await params; 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"
>
&larr; {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)); const verseIndex = await getChapterVerseIndex("bg", null, parseInt(chapter));
if (verseIndex.length === 0) { if (verseIndex.length === 0) {
notFound(); notFound();
+42 -4
View File
@@ -1,7 +1,7 @@
import type { Metadata } from "next"; 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 { getBookMeta } from "@/lib/api"; import { getBookMeta, getProseChapters } from "@/lib/api";
import { ogForBook } from "@/lib/og"; import { ogForBook } from "@/lib/og";
import { PageHeader } from "@/components/layout/page-header"; import { PageHeader } from "@/components/layout/page-header";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
@@ -18,7 +18,10 @@ type ChapterInfo = {
}; };
export default async function BgPage() { export default async function BgPage() {
const meta = await getBookMeta("bg"); const [meta, introSegments] = await Promise.all([
getBookMeta("bg"),
getProseChapters("bg", 0, "intro-segment"),
]);
if (!meta) notFound(); if (!meta) notFound();
const intro = meta as unknown as { const intro = meta as unknown as {
@@ -43,7 +46,39 @@ export default async function BgPage() {
</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">
{/* 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"> <Card className="divide-y divide-border py-0">
<CardContent className="p-0"> <CardContent className="p-0">
<ul className="divide-y divide-border"> <ul className="divide-y divide-border">
@@ -57,7 +92,9 @@ export default async function BgPage() {
<span className="text-sm text-primary font-medium"> <span className="text-sm text-primary font-medium">
Chapter {ch.number} Chapter {ch.number}
</span> </span>
<p className="font-medium text-foreground">{ch.title}</p> <p className="font-medium text-foreground">
{ch.title}
</p>
</div> </div>
<span className="text-sm text-muted-foreground sm:shrink-0 sm:ml-4"> <span className="text-sm text-muted-foreground sm:shrink-0 sm:ml-4">
<ExtractedVerseCount count={ch.totalVerses} /> <ExtractedVerseCount count={ch.totalVerses} />
@@ -68,6 +105,7 @@ export default async function BgPage() {
</ul> </ul>
</CardContent> </CardContent>
</Card> </Card>
</div>
</main> </main>
</div> </div>
); );