diff --git a/app/books/bbd/[chapter]/page.tsx b/app/books/bbd/[chapter]/page.tsx index 4e03bf45..fd7a4d1c 100644 --- a/app/books/bbd/[chapter]/page.tsx +++ b/app/books/bbd/[chapter]/page.tsx @@ -11,6 +11,7 @@ import { Card, CardContent } from "@/components/ui/card"; import { buttonVariants } from "@/components/ui/button"; import { ChevronLeft, ChevronRight } from "lucide-react"; import { cn } from "@/lib/utils"; +import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav"; // --------------------------------------------------------------------------- // Page @@ -64,7 +65,12 @@ export default async function BbdChapterPage({ {/* Main content */}
{/* Top navigation */} - + {/* Content */} @@ -82,7 +88,12 @@ export default async function BbdChapterPage({ {/* Bottom navigation */} - +
@@ -174,31 +185,68 @@ function SidebarLink({ function BbdNav({ prev, next, + sidebarItems, + currentSlug, }: { prev: BbdSidebarItem | null; next: BbdSidebarItem | null; + sidebarItems: BbdSidebarItem[]; + currentSlug: string; }) { + const mobileNavGroups: MobileNavGroup[] = []; + const introItems = sidebarItems.filter((i) => i.type === "intro-segment"); + if (introItems.length > 0) { + mobileNavGroups.push({ + title: "Front Matter", + items: introItems.map((i) => ({ + slug: i.slug, + label: i.label, + href: `/books/bbd/${i.slug}`, + type: i.type, + })), + }); + } + const chapterItems = sidebarItems.filter((i) => i.type === "chapter"); + if (chapterItems.length > 0) { + mobileNavGroups.push({ + title: "Chapters", + items: chapterItems.map((i) => ({ + slug: i.slug, + label: i.label, + href: `/books/bbd/${i.slug}`, + type: i.type, + })), + }); + } + return (
- {prev ? ( - - - - {prev.type === "chapter" && prev.chapter != null - ? `Ch. ${prev.chapter}` - : prev.label} - - Previous - - ) : ( -
- )} +
+ + {prev ? ( + + + + {prev.type === "chapter" && prev.chapter != null + ? `Ch. ${prev.chapter}` + : prev.label} + + Previous + + ) : ( +
+ )} +
{next ? ( ({ + slug: `${ch.number}`, + label: `${ch.number}. ${ch.title}`, + href: `/books/bg/${ch.number}/1`, + type: "chapter", + })), + }, + ]; + return (
@@ -70,6 +84,8 @@ export default async function VersePage({ chapter={parseInt(chapter)} basePath={`/books/bg/${chapter}`} showBengali={false} + mobileNavGroups={mobileNavGroups} + mobileNavBookTitle="Bhagavad-gītā As It Is" />
diff --git a/app/books/cc/[lila]/[chapter]/[verse]/page.tsx b/app/books/cc/[lila]/[chapter]/[verse]/page.tsx index c9ac0062..8b9d91e1 100644 --- a/app/books/cc/[lila]/[chapter]/[verse]/page.tsx +++ b/app/books/cc/[lila]/[chapter]/[verse]/page.tsx @@ -3,6 +3,7 @@ import { PageHeader } from "@/components/page-header"; import { notFound } from "next/navigation"; import { getBookMeta, getSingleVerse, getChapterVerseIndex } from "@/lib/api"; import { ChapterViewer } from "@/app/books/chapter-viewer"; +import type { MobileNavGroup } from "@/components/mobile-nav"; type ChapterInfo = { number: number; @@ -49,6 +50,23 @@ export default async function CcVersePage({ ); if (!verseData) notFound(); + // Build mobile nav groups from verse index + const mobileNavGroups: MobileNavGroup[] = []; + if (verseIndex.length > 0) { + mobileNavGroups.push({ + title: "Verses", + items: verseIndex.map((v) => { + const label = v.verseEnd ? `${v.reference}` : v.reference; + return { + slug: String(v.verse), + label, + href: `/books/cc/${lila}/${chapter}/${v.verse}`, + type: "verse", + }; + }), + }); + } + return (
@@ -77,6 +95,8 @@ export default async function CcVersePage({ chapter={parseInt(chapter)} showBengali={true} basePath={`/books/cc/${lila}/${chapter}`} + mobileNavGroups={mobileNavGroups} + mobileNavBookTitle={`${lilaInfo.name} — Chapter ${chapter}`} />
diff --git a/app/books/chapter-viewer.tsx b/app/books/chapter-viewer.tsx index 28ad18f1..2e330b44 100644 --- a/app/books/chapter-viewer.tsx +++ b/app/books/chapter-viewer.tsx @@ -6,6 +6,7 @@ import { Card, CardHeader, CardContent } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { ChevronLeft, ChevronRight, Loader2 } from "lucide-react"; +import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav"; // --------------------------------------------------------------------------- // Types @@ -60,6 +61,10 @@ type ChapterViewerProps = { showBengali?: boolean; /** Base path for verse URLs, e.g. "/books/bg/1" — verse number is appended */ basePath: string; + /** Mobile nav groups for the drawer */ + mobileNavGroups?: MobileNavGroup[]; + /** Book title for the mobile nav drawer header */ + mobileNavBookTitle?: string; }; // --------------------------------------------------------------------------- @@ -72,12 +77,18 @@ function VerseNav({ onPrev, onNext, verseIndex, + mobileNavGroups, + currentVerseSlug, + mobileNavBookTitle, }: { currentIdx: number; total: number; onPrev: () => void; onNext: () => void; verseIndex: VerseIndexEntry[]; + mobileNavGroups?: MobileNavGroup[]; + currentVerseSlug?: string; + mobileNavBookTitle?: string; }) { const hasPrev = currentIdx > 0; const hasNext = currentIdx < total - 1; @@ -90,16 +101,25 @@ function VerseNav({ return (
- +
+ {mobileNavGroups && mobileNavGroups.length > 0 && ( + + )} + +
Verse {label} of {total} @@ -220,6 +240,8 @@ export function ChapterViewer({ chapter, showBengali = false, basePath, + mobileNavGroups, + mobileNavBookTitle, }: ChapterViewerProps) { const router = useRouter(); @@ -409,6 +431,9 @@ export function ChapterViewer({ onPrev={goPrev} onNext={goNext} verseIndex={verseIndex} + mobileNavGroups={mobileNavGroups} + currentVerseSlug={String(currentVerseNum)} + mobileNavBookTitle={mobileNavBookTitle} /> {/* Verse content */} @@ -432,6 +457,9 @@ export function ChapterViewer({ onPrev={goPrev} onNext={goNext} verseIndex={verseIndex} + mobileNavGroups={mobileNavGroups} + currentVerseSlug={String(currentVerseNum)} + mobileNavBookTitle={mobileNavBookTitle} /> diff --git a/app/books/ds/[chapter]/page.tsx b/app/books/ds/[chapter]/page.tsx index 95a54b35..4fbc9ea7 100644 --- a/app/books/ds/[chapter]/page.tsx +++ b/app/books/ds/[chapter]/page.tsx @@ -11,6 +11,7 @@ import { Card, CardContent } from "@/components/ui/card"; import { buttonVariants } from "@/components/ui/button"; import { ChevronLeft, ChevronRight } from "lucide-react"; import { cn } from "@/lib/utils"; +import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav"; // --------------------------------------------------------------------------- // Page @@ -70,7 +71,12 @@ export default async function DsChapterPage({ {/* Main content */}
{/* Top navigation */} - + {/* Content */} @@ -88,7 +94,12 @@ export default async function DsChapterPage({ {/* Bottom navigation */} - +
@@ -204,29 +215,72 @@ function SidebarLink({ function DsNav({ prev, next, + sidebarItems, + currentSlug, }: { prev: DsSidebarItem | null; next: DsSidebarItem | null; + sidebarItems: DsSidebarItem[]; + currentSlug: string; }) { + const mobileNavGroups: MobileNavGroup[] = []; + + const introItems = sidebarItems.filter((i) => i.type === "intro-segment"); + if (introItems.length > 0) { + mobileNavGroups.push({ + title: "Front Matter", + items: introItems.map((i) => ({ + slug: i.slug, + label: i.label, + href: `/books/ds/${i.slug}`, + type: i.type, + })), + }); + } + + const chapterItems = sidebarItems.filter( + (i) => i.type === "parent" || i.type === "sub-chapter", + ); + if (chapterItems.length > 0) { + mobileNavGroups.push({ + title: "Chapters", + items: chapterItems.map((i) => ({ + slug: i.slug, + label: i.label, + href: `/books/ds/${i.slug}`, + type: i.type, + parentChapter: i.parentChapter, + isParent: i.type === "parent", + })), + }); + } + return (
- {prev ? ( - - - - {prev.label} - - Previous - - ) : ( -
- )} +
+ + {prev ? ( + + + + {prev.label} + + Previous + + ) : ( +
+ )} +
{next ? ( {/* Top navigation */} - + {/* Content */} @@ -82,7 +88,12 @@ export default async function EjChapterPage({ {/* Bottom navigation */} - +
@@ -174,31 +185,70 @@ function SidebarLink({ function EjNav({ prev, next, + sidebarItems, + currentSlug, }: { prev: EjSidebarItem | null; next: EjSidebarItem | null; + sidebarItems: EjSidebarItem[]; + currentSlug: string; }) { + const mobileNavGroups: MobileNavGroup[] = []; + + const introItems = sidebarItems.filter((i) => i.type === "intro-segment"); + if (introItems.length > 0) { + mobileNavGroups.push({ + title: "Front Matter", + items: introItems.map((i) => ({ + slug: i.slug, + label: i.label, + href: `/books/ej/${i.slug}`, + type: i.type, + })), + }); + } + + const chapterItems = sidebarItems.filter((i) => i.type === "chapter"); + if (chapterItems.length > 0) { + mobileNavGroups.push({ + title: "Chapters", + items: chapterItems.map((i) => ({ + slug: i.slug, + label: i.label, + href: `/books/ej/${i.slug}`, + type: i.type, + })), + }); + } + return (
- {prev ? ( - - - - {prev.type === "chapter" && prev.chapter != null - ? `Ch. ${prev.chapter}` - : prev.label} - - Previous - - ) : ( -
- )} +
+ + {prev ? ( + + + + {prev.type === "chapter" && prev.chapter != null + ? `Ch. ${prev.chapter}` + : prev.label} + + Previous + + ) : ( +
+ )} +
{next ? ( {/* Top navigation */} - + {/* Content */} @@ -82,7 +88,12 @@ export default async function EkChapterPage({ {/* Bottom navigation */} - +
@@ -174,31 +185,70 @@ function SidebarLink({ function EkNav({ prev, next, + sidebarItems, + currentSlug, }: { prev: EkSidebarItem | null; next: EkSidebarItem | null; + sidebarItems: EkSidebarItem[]; + currentSlug: string; }) { + const mobileNavGroups: MobileNavGroup[] = []; + + const introItems = sidebarItems.filter((i) => i.type === "intro-segment"); + if (introItems.length > 0) { + mobileNavGroups.push({ + title: "Front Matter", + items: introItems.map((i) => ({ + slug: i.slug, + label: i.label, + href: `/books/ek/${i.slug}`, + type: i.type, + })), + }); + } + + const chapterItems = sidebarItems.filter((i) => i.type === "chapter"); + if (chapterItems.length > 0) { + mobileNavGroups.push({ + title: "Chapters", + items: chapterItems.map((i) => ({ + slug: i.slug, + label: i.label, + href: `/books/ek/${i.slug}`, + type: i.type, + })), + }); + } + return (
- {prev ? ( - - - - {prev.type === "chapter" && prev.chapter != null - ? `Ch. ${prev.chapter}` - : prev.label} - - Previous - - ) : ( -
- )} +
+ + {prev ? ( + + + + {prev.type === "chapter" && prev.chapter != null + ? `Ch. ${prev.chapter}` + : prev.label} + + Previous + + ) : ( +
+ )} +
{next ? ( {/* Top navigation */} - + {/* Content */} @@ -82,7 +88,12 @@ export default async function HkhChapterPage({ {/* Bottom navigation */} - +
@@ -174,31 +185,70 @@ function SidebarLink({ function HkhNav({ prev, next, + sidebarItems, + currentSlug, }: { prev: HkhSidebarItem | null; next: HkhSidebarItem | null; + sidebarItems: HkhSidebarItem[]; + currentSlug: string; }) { + const mobileNavGroups: MobileNavGroup[] = []; + + const introItems = sidebarItems.filter((i) => i.type === "intro-segment"); + if (introItems.length > 0) { + mobileNavGroups.push({ + title: "Front Matter", + items: introItems.map((i) => ({ + slug: i.slug, + label: i.label, + href: `/books/hkh/${i.slug}`, + type: i.type, + })), + }); + } + + const chapterItems = sidebarItems.filter((i) => i.type === "chapter"); + if (chapterItems.length > 0) { + mobileNavGroups.push({ + title: "Chapters", + items: chapterItems.map((i) => ({ + slug: i.slug, + label: i.label, + href: `/books/hkh/${i.slug}`, + type: i.type, + })), + }); + } + return (
- {prev ? ( - - - - {prev.type === "chapter" && prev.chapter != null - ? `Ch. ${prev.chapter}` - : prev.label} - - Previous - - ) : ( -
- )} +
+ + {prev ? ( + + + + {prev.type === "chapter" && prev.chapter != null + ? `Ch. ${prev.chapter}` + : prev.label} + + Previous + + ) : ( +
+ )} +
{next ? ( {/* Top navigation */} - + {/* Content */} {verse && } {intro && } {/* Bottom navigation */} - +
@@ -295,31 +306,90 @@ function SidebarLink({ function IsoNav({ prev, next, + sidebarItems, + currentSlug, }: { prev: IsoSidebarItem | null; next: IsoSidebarItem | null; + sidebarItems: IsoSidebarItem[]; + currentSlug: string; }) { + const mobileNavGroups: MobileNavGroup[] = []; + + // Front matter (front-pages + introduction) + const frontMatterItems = sidebarItems.filter( + (i) => i.slug === "intro-front-pages" || i.slug === "intro-introduction", + ); + if (frontMatterItems.length > 0) { + mobileNavGroups.push({ + title: "Front Matter", + items: frontMatterItems.map((i) => ({ + slug: i.slug, + label: i.label, + href: `/books/iso/${i.slug}`, + type: i.type, + })), + }); + } + + // Mantras (invocation + 1-18) + const mantraItems = sidebarItems.filter((i) => i.type === "verse"); + if (mantraItems.length > 0) { + mobileNavGroups.push({ + title: "Mantras", + items: mantraItems.map((i) => ({ + slug: i.slug, + label: i.label, + href: `/books/iso/${i.slug}`, + type: i.type, + })), + }); + } + + // Back matter (about-the-author) + const backMatterItems = sidebarItems.filter( + (i) => i.slug === "intro-about-the-author", + ); + if (backMatterItems.length > 0) { + mobileNavGroups.push({ + title: "Back Matter", + items: backMatterItems.map((i) => ({ + slug: i.slug, + label: i.label, + href: `/books/iso/${i.slug}`, + type: i.type, + })), + }); + } + return (
- {prev ? ( - - - - {prev.type === "verse" && prev.mantra != null && prev.mantra > 0 - ? `Mantra ${prev.mantra}` - : prev.label} - - Previous - - ) : ( -
- )} +
+ + {prev ? ( + + + + {prev.type === "verse" && prev.mantra != null && prev.mantra > 0 + ? `Mantra ${prev.mantra}` + : prev.label} + + Previous + + ) : ( +
+ )} +
{next ? ( {/* Top navigation */} - + {/* Chapter content */} @@ -78,7 +85,13 @@ export default async function KbChapterPage({ {/* Bottom navigation */} - +
@@ -154,32 +167,71 @@ function ChapterNav({ prev, next, volume, + chapters, + currentSlug, }: { prev: NavChapter | null; next: NavChapter | null; volume: number; + chapters: SidebarChapter[]; + currentSlug: string; }) { + const mobileNavGroups: MobileNavGroup[] = []; + + const introItems = chapters.filter((i) => i.type !== "chapter"); + if (introItems.length > 0) { + mobileNavGroups.push({ + title: "Front Matter", + items: introItems.map((i) => ({ + slug: i.slug, + label: i.title, + href: `/books/kb/${volume}/${i.slug}`, + type: i.type, + })), + }); + } + + const chapterItems = chapters.filter((i) => i.type === "chapter"); + if (chapterItems.length > 0) { + mobileNavGroups.push({ + title: "Chapters", + items: chapterItems.map((i) => ({ + slug: i.slug, + label: i.chapter != null ? `${i.chapter}. ${i.title}` : i.title, + href: `/books/kb/${volume}/${i.slug}`, + type: i.type, + })), + }); + } + return (
- {prev ? ( - - - - {prev.type === "chapter" && prev.chapter != null - ? `Ch. ${prev.chapter}` - : prev.title} - - Previous - - ) : ( -
- )} +
+ + {prev ? ( + + + + {prev.type === "chapter" && prev.chapter != null + ? `Ch. ${prev.chapter}` + : prev.title} + + Previous + + ) : ( +
+ )} +
{next ? ( {/* Top navigation */} - + {/* Content */} @@ -82,7 +88,12 @@ export default async function MgChapterPage({ {/* Bottom navigation */} - +
@@ -174,31 +185,70 @@ function SidebarLink({ function MgNav({ prev, next, + sidebarItems, + currentSlug, }: { prev: MgSidebarItem | null; next: MgSidebarItem | null; + sidebarItems: MgSidebarItem[]; + currentSlug: string; }) { + const mobileNavGroups: MobileNavGroup[] = []; + + const introItems = sidebarItems.filter((i) => i.type === "intro-segment"); + if (introItems.length > 0) { + mobileNavGroups.push({ + title: "Front Matter", + items: introItems.map((i) => ({ + slug: i.slug, + label: i.label, + href: `/books/mg/${i.slug}`, + type: i.type, + })), + }); + } + + const chapterItems = sidebarItems.filter((i) => i.type === "chapter"); + if (chapterItems.length > 0) { + mobileNavGroups.push({ + title: "Chapters", + items: chapterItems.map((i) => ({ + slug: i.slug, + label: i.label, + href: `/books/mg/${i.slug}`, + type: i.type, + })), + }); + } + return (
- {prev ? ( - - - - {prev.type === "chapter" && prev.chapter != null - ? `Ch. ${prev.chapter}` - : prev.label} - - Previous - - ) : ( -
- )} +
+ + {prev ? ( + + + + {prev.type === "chapter" && prev.chapter != null + ? `Ch. ${prev.chapter}` + : prev.label} + + Previous + + ) : ( +
+ )} +
{next ? ( {/* Top navigation */} - + {/* Content */} @@ -82,7 +88,12 @@ export default async function NodChapterPage({ {/* Bottom navigation */} - +
@@ -197,31 +208,79 @@ function SidebarLink({ function NodNav({ prev, next, + sidebarItems, + currentSlug, }: { prev: NodSidebarItem | null; next: NodSidebarItem | null; + sidebarItems: NodSidebarItem[]; + currentSlug: string; }) { + const mobileNavGroups: MobileNavGroup[] = []; + + const introItems = sidebarItems.filter((i) => i.type === "intro-segment"); + if (introItems.length > 0) { + mobileNavGroups.push({ + title: "Front Matter", + items: introItems.map((i) => ({ + slug: i.slug, + label: i.label, + href: `/books/nod/${i.slug}`, + type: i.type, + })), + }); + } + + const chapterItems = sidebarItems.filter((i) => i.type === "chapter"); + const conclusionItems = sidebarItems.filter((i) => i.type === "conclusion"); + if (chapterItems.length > 0 || conclusionItems.length > 0) { + mobileNavGroups.push({ + title: "Chapters", + items: [ + ...chapterItems.map((i) => ({ + slug: i.slug, + label: i.label, + href: `/books/nod/${i.slug}`, + type: i.type, + })), + ...conclusionItems.map((i) => ({ + slug: i.slug, + label: i.label, + href: `/books/nod/${i.slug}`, + type: i.type, + })), + ], + }); + } + return (
- {prev ? ( - - - - {prev.type === "chapter" && prev.chapter != null - ? `Ch. ${prev.chapter}` - : prev.label} - - Previous - - ) : ( -
- )} +
+ + {prev ? ( + + + + {prev.type === "chapter" && prev.chapter != null + ? `Ch. ${prev.chapter}` + : prev.label} + + Previous + + ) : ( +
+ )} +
{next ? ( {/* Top navigation */} - + {/* Content */} {verse && } {intro && } {/* Bottom navigation */} - +
@@ -210,9 +221,7 @@ function NoiSidebar({ // Texts = 1-11 const textItems = items.filter((item) => item.type === "verse"); // Appendixes comes last - const appendixesItem = items.find( - (item) => item.slug === "intro-appendixes", - ); + const appendixesItem = items.find((item) => item.slug === "intro-appendixes"); return (