122 lines
3.5 KiB
TypeScript
122 lines
3.5 KiB
TypeScript
export const dynamic = "force-dynamic";
|
|
|
|
import type { Metadata } from "next";
|
|
import { redirect } from "next/navigation";
|
|
import { notFound } from "next/navigation";
|
|
import { getChapterVerseIndex } 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";
|
|
import Link from "next/link";
|
|
import fs from "fs";
|
|
import path from "path";
|
|
|
|
const BS_JSON_DIR = path.join(process.cwd(), "lib", "jsons", "books", "bs");
|
|
|
|
type IntroSegment = {
|
|
slug: string;
|
|
title: string;
|
|
paragraphs: string[];
|
|
};
|
|
|
|
export async function generateMetadata({
|
|
params,
|
|
}: {
|
|
params: Promise<{ chapter: string }>;
|
|
}): Promise<Metadata> {
|
|
const { chapter } = await params;
|
|
return buildOgMeta({ title: BOOK_NAMES["bs"], detail: `Chapter ${chapter}` });
|
|
}
|
|
|
|
export default async function BsChapterPage({
|
|
params,
|
|
}: {
|
|
params: Promise<{ chapter: string }>;
|
|
}) {
|
|
const { chapter } = await params;
|
|
|
|
// Handle intro segments (intro-introduction, intro-foreword)
|
|
if (chapter.startsWith("intro-")) {
|
|
const rawSlug = chapter.replace(/^intro-/, "");
|
|
const filePath = path.join(BS_JSON_DIR, "intro", `${rawSlug}.json`);
|
|
|
|
if (!fs.existsSync(filePath)) notFound();
|
|
|
|
let segment: IntroSegment;
|
|
try {
|
|
segment = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
} catch {
|
|
notFound();
|
|
}
|
|
|
|
return (
|
|
<div className="min-h-screen bg-background">
|
|
<PageHeader sticky>
|
|
<Link
|
|
href="/books/bs"
|
|
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
|
>
|
|
← Śrī Brahma-saṁhitā
|
|
</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: string, i: number) => (
|
|
<div
|
|
key={i}
|
|
className="text-base text-foreground leading-relaxed"
|
|
dangerouslySetInnerHTML={{ __html: paragraph }}
|
|
/>
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Handle numeric chapters — redirect to first verse
|
|
const chapterNum = parseInt(chapter);
|
|
if (isNaN(chapterNum)) notFound();
|
|
|
|
// Try DB first
|
|
const verseIndex = await getChapterVerseIndex("bs", null, chapterNum);
|
|
|
|
// Fallback to local JSON
|
|
if (verseIndex.length === 0) {
|
|
const versesDir = path.join(
|
|
BS_JSON_DIR,
|
|
"chapters",
|
|
String(chapterNum).padStart(2, "0"),
|
|
"verses",
|
|
);
|
|
if (fs.existsSync(versesDir)) {
|
|
const files = fs
|
|
.readdirSync(versesDir)
|
|
.filter((f: string) => f.endsWith(".json"))
|
|
.sort();
|
|
if (files.length > 0) {
|
|
const first = JSON.parse(
|
|
fs.readFileSync(path.join(versesDir, files[0]), "utf-8"),
|
|
);
|
|
redirect(`/books/bs/${chapter}/${first.verse}`);
|
|
}
|
|
}
|
|
notFound();
|
|
}
|
|
|
|
redirect(`/books/bs/${chapter}/${verseIndex[0].verse}`);
|
|
}
|