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 (