feat: add mobile sidebar
This commit is contained in:
@@ -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 */}
|
||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||
{/* Top navigation */}
|
||||
<BbdNav prev={prev} next={next} />
|
||||
<BbdNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<Card>
|
||||
@@ -82,7 +88,12 @@ export default async function BbdChapterPage({
|
||||
</Card>
|
||||
|
||||
{/* Bottom navigation */}
|
||||
<BbdNav prev={prev} next={next} />
|
||||
<BbdNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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 (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/bbd/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<MobileNav
|
||||
groups={mobileNavGroups}
|
||||
currentSlug={currentSlug}
|
||||
bookTitle="Beyond Birth and Death"
|
||||
/>
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/bbd/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="hidden lg:block" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{next ? (
|
||||
<Link
|
||||
|
||||
@@ -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 BgMeta = {
|
||||
book: string;
|
||||
@@ -42,6 +43,19 @@ export default async function VersePage({
|
||||
);
|
||||
if (!verse) notFound();
|
||||
|
||||
// Build mobile nav groups — single flat list of chapters
|
||||
const mobileNavGroups: MobileNavGroup[] = [
|
||||
{
|
||||
title: "Chapters",
|
||||
items: bgMeta.chapters.map((ch) => ({
|
||||
slug: `${ch.number}`,
|
||||
label: `${ch.number}. ${ch.title}`,
|
||||
href: `/books/bg/${ch.number}/1`,
|
||||
type: "chapter",
|
||||
})),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
<PageHeader sticky wide>
|
||||
@@ -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"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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 (
|
||||
<div className="min-h-screen bg-background">
|
||||
<PageHeader sticky wide>
|
||||
@@ -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}`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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 (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={!hasPrev}
|
||||
onClick={onPrev}
|
||||
className="gap-1.5"
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline">Previous</span>
|
||||
</Button>
|
||||
<div className="flex items-center gap-2">
|
||||
{mobileNavGroups && mobileNavGroups.length > 0 && (
|
||||
<MobileNav
|
||||
groups={mobileNavGroups}
|
||||
currentSlug={currentVerseSlug ?? String(current?.verse ?? "")}
|
||||
bookTitle={mobileNavBookTitle}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={!hasPrev}
|
||||
onClick={onPrev}
|
||||
className="gap-1.5"
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline">Previous</span>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<span className="text-sm text-muted-foreground">
|
||||
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}
|
||||
/>
|
||||
</main>
|
||||
</>
|
||||
|
||||
@@ -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 */}
|
||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||
{/* Top navigation */}
|
||||
<DsNav prev={prev} next={next} />
|
||||
<DsNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<Card>
|
||||
@@ -88,7 +94,12 @@ export default async function DsChapterPage({
|
||||
</Card>
|
||||
|
||||
{/* Bottom navigation */}
|
||||
<DsNav prev={prev} next={next} />
|
||||
<DsNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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 (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/ds/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<MobileNav
|
||||
groups={mobileNavGroups}
|
||||
currentSlug={currentSlug}
|
||||
bookTitle="Dialectic Spiritualism"
|
||||
/>
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/ds/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="hidden lg:block" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{next ? (
|
||||
<Link
|
||||
|
||||
@@ -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 EjChapterPage({
|
||||
{/* Main content */}
|
||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||
{/* Top navigation */}
|
||||
<EjNav prev={prev} next={next} />
|
||||
<EjNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<Card>
|
||||
@@ -82,7 +88,12 @@ export default async function EjChapterPage({
|
||||
</Card>
|
||||
|
||||
{/* Bottom navigation */}
|
||||
<EjNav prev={prev} next={next} />
|
||||
<EjNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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 (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/ej/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<MobileNav
|
||||
groups={mobileNavGroups}
|
||||
currentSlug={currentSlug}
|
||||
bookTitle="Easy Journey to Other Planets"
|
||||
/>
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/ej/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="hidden lg:block" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{next ? (
|
||||
<Link
|
||||
|
||||
@@ -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 EkChapterPage({
|
||||
{/* Main content */}
|
||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||
{/* Top navigation */}
|
||||
<EkNav prev={prev} next={next} />
|
||||
<EkNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<Card>
|
||||
@@ -82,7 +88,12 @@ export default async function EkChapterPage({
|
||||
</Card>
|
||||
|
||||
{/* Bottom navigation */}
|
||||
<EkNav prev={prev} next={next} />
|
||||
<EkNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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 (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/ek/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<MobileNav
|
||||
groups={mobileNavGroups}
|
||||
currentSlug={currentSlug}
|
||||
bookTitle="Elevation to Kṛṣṇa Consciousness"
|
||||
/>
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/ek/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="hidden lg:block" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{next ? (
|
||||
<Link
|
||||
|
||||
@@ -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 HkhChapterPage({
|
||||
{/* Main content */}
|
||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||
{/* Top navigation */}
|
||||
<HkhNav prev={prev} next={next} />
|
||||
<HkhNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<Card>
|
||||
@@ -82,7 +88,12 @@ export default async function HkhChapterPage({
|
||||
</Card>
|
||||
|
||||
{/* Bottom navigation */}
|
||||
<HkhNav prev={prev} next={next} />
|
||||
<HkhNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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 (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/hkh/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<MobileNav
|
||||
groups={mobileNavGroups}
|
||||
currentSlug={currentSlug}
|
||||
bookTitle="The Kṛṣṇa Consciousness Handbook"
|
||||
/>
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/hkh/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="hidden lg:block" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{next ? (
|
||||
<Link
|
||||
|
||||
@@ -12,6 +12,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";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Type guards
|
||||
@@ -79,14 +80,24 @@ export default async function IsoMantraPage({
|
||||
{/* Main content */}
|
||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||
{/* Top navigation */}
|
||||
<IsoNav prev={prev} next={next} />
|
||||
<IsoNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
{verse && <VerseContent verse={verse} />}
|
||||
{intro && <IntroContent intro={intro} />}
|
||||
|
||||
{/* Bottom navigation */}
|
||||
<IsoNav prev={prev} next={next} />
|
||||
<IsoNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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 (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/iso/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "verse" && prev.mantra != null && prev.mantra > 0
|
||||
? `Mantra ${prev.mantra}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<MobileNav
|
||||
groups={mobileNavGroups}
|
||||
currentSlug={currentSlug}
|
||||
bookTitle="Śrī Īśopaniṣad"
|
||||
/>
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/iso/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "verse" && prev.mantra != null && prev.mantra > 0
|
||||
? `Mantra ${prev.mantra}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="hidden lg:block" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{next ? (
|
||||
<Link
|
||||
|
||||
@@ -6,6 +6,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";
|
||||
|
||||
export default async function KbChapterPage({
|
||||
params,
|
||||
@@ -60,7 +61,13 @@ export default async function KbChapterPage({
|
||||
{/* Main content */}
|
||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||
{/* Top navigation */}
|
||||
<ChapterNav prev={prev} next={next} volume={vol} />
|
||||
<ChapterNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
volume={vol}
|
||||
chapters={allChapters}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
|
||||
{/* Chapter content */}
|
||||
<Card>
|
||||
@@ -78,7 +85,13 @@ export default async function KbChapterPage({
|
||||
</Card>
|
||||
|
||||
{/* Bottom navigation */}
|
||||
<ChapterNav prev={prev} next={next} volume={vol} />
|
||||
<ChapterNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
volume={vol}
|
||||
chapters={allChapters}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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 (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/kb/${volume}/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.title}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<MobileNav
|
||||
groups={mobileNavGroups}
|
||||
currentSlug={currentSlug}
|
||||
bookTitle={`Kṛṣṇa Book — Volume ${volume}`}
|
||||
/>
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/kb/${volume}/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.title}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="hidden lg:block" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{next ? (
|
||||
<Link
|
||||
|
||||
@@ -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 MgChapterPage({
|
||||
{/* Main content */}
|
||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||
{/* Top navigation */}
|
||||
<MgNav prev={prev} next={next} />
|
||||
<MgNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<Card>
|
||||
@@ -82,7 +88,12 @@ export default async function MgChapterPage({
|
||||
</Card>
|
||||
|
||||
{/* Bottom navigation */}
|
||||
<MgNav prev={prev} next={next} />
|
||||
<MgNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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 (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/mg/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<MobileNav
|
||||
groups={mobileNavGroups}
|
||||
currentSlug={currentSlug}
|
||||
bookTitle="Kṛṣṇa Consciousness: The Matchless Gift"
|
||||
/>
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/mg/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="hidden lg:block" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{next ? (
|
||||
<Link
|
||||
|
||||
@@ -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 NodChapterPage({
|
||||
{/* Main content */}
|
||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||
{/* Top navigation */}
|
||||
<NodNav prev={prev} next={next} />
|
||||
<NodNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<Card>
|
||||
@@ -82,7 +88,12 @@ export default async function NodChapterPage({
|
||||
</Card>
|
||||
|
||||
{/* Bottom navigation */}
|
||||
<NodNav prev={prev} next={next} />
|
||||
<NodNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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 (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/nod/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<MobileNav
|
||||
groups={mobileNavGroups}
|
||||
currentSlug={currentSlug}
|
||||
bookTitle="The Nectar of Devotion"
|
||||
/>
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/nod/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="hidden lg:block" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{next ? (
|
||||
<Link
|
||||
|
||||
@@ -12,6 +12,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";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Type guards
|
||||
@@ -79,14 +80,24 @@ export default async function NoiTextPage({
|
||||
{/* Main content */}
|
||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||
{/* Top navigation */}
|
||||
<NoiNav prev={prev} next={next} />
|
||||
<NoiNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
{verse && <VerseContent verse={verse} />}
|
||||
{intro && <IntroContent intro={intro} />}
|
||||
|
||||
{/* Bottom navigation */}
|
||||
<NoiNav prev={prev} next={next} />
|
||||
<NoiNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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 (
|
||||
<aside className="hidden lg:block w-56 shrink-0 sticky top-[89px] self-start max-h-[calc(100vh-89px)] overflow-y-auto py-8 pr-4">
|
||||
@@ -295,31 +304,90 @@ function SidebarLink({
|
||||
function NoiNav({
|
||||
prev,
|
||||
next,
|
||||
sidebarItems,
|
||||
currentSlug,
|
||||
}: {
|
||||
prev: NoiSidebarItem | null;
|
||||
next: NoiSidebarItem | null;
|
||||
sidebarItems: NoiSidebarItem[];
|
||||
currentSlug: string;
|
||||
}) {
|
||||
const mobileNavGroups: MobileNavGroup[] = [];
|
||||
|
||||
// Front matter (front-pages + preface)
|
||||
const frontMatterItems = sidebarItems.filter(
|
||||
(i) => i.slug === "intro-front-pages" || i.slug === "intro-preface",
|
||||
);
|
||||
if (frontMatterItems.length > 0) {
|
||||
mobileNavGroups.push({
|
||||
title: "Front Matter",
|
||||
items: frontMatterItems.map((i) => ({
|
||||
slug: i.slug,
|
||||
label: i.label,
|
||||
href: `/books/noi/${i.slug}`,
|
||||
type: i.type,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
// Texts (1-11)
|
||||
const textItems = sidebarItems.filter((i) => i.type === "verse");
|
||||
if (textItems.length > 0) {
|
||||
mobileNavGroups.push({
|
||||
title: "Texts",
|
||||
items: textItems.map((i) => ({
|
||||
slug: i.slug,
|
||||
label: i.label,
|
||||
href: `/books/noi/${i.slug}`,
|
||||
type: i.type,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
// Back matter (appendixes)
|
||||
const backMatterItems = sidebarItems.filter(
|
||||
(i) => i.slug === "intro-appendixes",
|
||||
);
|
||||
if (backMatterItems.length > 0) {
|
||||
mobileNavGroups.push({
|
||||
title: "Back Matter",
|
||||
items: backMatterItems.map((i) => ({
|
||||
slug: i.slug,
|
||||
label: i.label,
|
||||
href: `/books/noi/${i.slug}`,
|
||||
type: i.type,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/noi/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "verse" && prev.text != null
|
||||
? `Text ${prev.text}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<MobileNav
|
||||
groups={mobileNavGroups}
|
||||
currentSlug={currentSlug}
|
||||
bookTitle="The Nectar of Instruction"
|
||||
/>
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/noi/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "verse" && prev.text != null
|
||||
? `Text ${prev.text}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="hidden lg:block" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{next ? (
|
||||
<Link
|
||||
|
||||
@@ -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 OchkmChapterPage({
|
||||
{/* Main content */}
|
||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||
{/* Top navigation */}
|
||||
<OchkmNav prev={prev} next={next} />
|
||||
<OchkmNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<Card>
|
||||
@@ -82,7 +88,12 @@ export default async function OchkmChapterPage({
|
||||
</Card>
|
||||
|
||||
{/* Bottom navigation */}
|
||||
<OchkmNav prev={prev} next={next} />
|
||||
<OchkmNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@@ -174,31 +185,70 @@ function SidebarLink({
|
||||
function OchkmNav({
|
||||
prev,
|
||||
next,
|
||||
sidebarItems,
|
||||
currentSlug,
|
||||
}: {
|
||||
prev: OchkmSidebarItem | null;
|
||||
next: OchkmSidebarItem | null;
|
||||
sidebarItems: OchkmSidebarItem[];
|
||||
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/ochkm/${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/ochkm/${i.slug}`,
|
||||
type: i.type,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/ochkm/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<MobileNav
|
||||
groups={mobileNavGroups}
|
||||
currentSlug={currentSlug}
|
||||
bookTitle="On Chanting the Hare Kṛṣṇa Mantra"
|
||||
/>
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/ochkm/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="hidden lg:block" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{next ? (
|
||||
<Link
|
||||
|
||||
@@ -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 OwkChapterPage({
|
||||
{/* Main content */}
|
||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||
{/* Top navigation */}
|
||||
<OwkNav prev={prev} next={next} />
|
||||
<OwkNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<Card>
|
||||
@@ -82,7 +88,12 @@ export default async function OwkChapterPage({
|
||||
</Card>
|
||||
|
||||
{/* Bottom navigation */}
|
||||
<OwkNav prev={prev} next={next} />
|
||||
<OwkNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@@ -174,31 +185,70 @@ function SidebarLink({
|
||||
function OwkNav({
|
||||
prev,
|
||||
next,
|
||||
sidebarItems,
|
||||
currentSlug,
|
||||
}: {
|
||||
prev: OwkSidebarItem | null;
|
||||
next: OwkSidebarItem | null;
|
||||
sidebarItems: OwkSidebarItem[];
|
||||
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/owk/${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/owk/${i.slug}`,
|
||||
type: i.type,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/owk/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<MobileNav
|
||||
groups={mobileNavGroups}
|
||||
currentSlug={currentSlug}
|
||||
bookTitle="On the Way to Kṛṣṇa"
|
||||
/>
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/owk/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="hidden lg:block" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{next ? (
|
||||
<Link
|
||||
|
||||
@@ -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 PoyChapterPage({
|
||||
{/* Main content */}
|
||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||
{/* Top navigation */}
|
||||
<PoyNav prev={prev} next={next} />
|
||||
<PoyNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<Card>
|
||||
@@ -82,7 +88,12 @@ export default async function PoyChapterPage({
|
||||
</Card>
|
||||
|
||||
{/* Bottom navigation */}
|
||||
<PoyNav prev={prev} next={next} />
|
||||
<PoyNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@@ -174,31 +185,70 @@ function SidebarLink({
|
||||
function PoyNav({
|
||||
prev,
|
||||
next,
|
||||
sidebarItems,
|
||||
currentSlug,
|
||||
}: {
|
||||
prev: PoySidebarItem | null;
|
||||
next: PoySidebarItem | null;
|
||||
sidebarItems: PoySidebarItem[];
|
||||
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/poy/${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/poy/${i.slug}`,
|
||||
type: i.type,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/poy/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<MobileNav
|
||||
groups={mobileNavGroups}
|
||||
currentSlug={currentSlug}
|
||||
bookTitle="The Perfection of Yoga"
|
||||
/>
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/poy/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="hidden lg:block" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{next ? (
|
||||
<Link
|
||||
|
||||
@@ -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 PqpaChapterPage({
|
||||
{/* Main content */}
|
||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||
{/* Top navigation */}
|
||||
<PqpaNav prev={prev} next={next} />
|
||||
<PqpaNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<Card>
|
||||
@@ -82,7 +88,12 @@ export default async function PqpaChapterPage({
|
||||
</Card>
|
||||
|
||||
{/* Bottom navigation */}
|
||||
<PqpaNav prev={prev} next={next} />
|
||||
<PqpaNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@@ -233,31 +244,108 @@ function SidebarLink({
|
||||
function PqpaNav({
|
||||
prev,
|
||||
next,
|
||||
sidebarItems,
|
||||
currentSlug,
|
||||
}: {
|
||||
prev: PqpaSidebarItem | null;
|
||||
next: PqpaSidebarItem | null;
|
||||
sidebarItems: PqpaSidebarItem[];
|
||||
currentSlug: string;
|
||||
}) {
|
||||
const mobileNavGroups: MobileNavGroup[] = [];
|
||||
|
||||
const frontMatterItems: PqpaSidebarItem[] = [];
|
||||
const chapterItems: PqpaSidebarItem[] = [];
|
||||
const conclusionItems: PqpaSidebarItem[] = [];
|
||||
const backMatterItems: PqpaSidebarItem[] = [];
|
||||
let pastChapters = false;
|
||||
|
||||
for (const item of sidebarItems) {
|
||||
if (item.type === "chapter") {
|
||||
pastChapters = true;
|
||||
chapterItems.push(item);
|
||||
} else if (item.type === "conclusion") {
|
||||
pastChapters = true;
|
||||
conclusionItems.push(item);
|
||||
} else if (!pastChapters) {
|
||||
frontMatterItems.push(item);
|
||||
} else {
|
||||
backMatterItems.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (frontMatterItems.length > 0) {
|
||||
mobileNavGroups.push({
|
||||
title: "Front Matter",
|
||||
items: frontMatterItems.map((i) => ({
|
||||
slug: i.slug,
|
||||
label: i.label,
|
||||
href: `/books/pqpa/${i.slug}`,
|
||||
type: i.type,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
if (chapterItems.length > 0) {
|
||||
mobileNavGroups.push({
|
||||
title: "Chapters",
|
||||
items: [
|
||||
...chapterItems.map((i) => ({
|
||||
slug: i.slug,
|
||||
label: i.label,
|
||||
href: `/books/pqpa/${i.slug}`,
|
||||
type: i.type,
|
||||
})),
|
||||
...conclusionItems.map((i) => ({
|
||||
slug: i.slug,
|
||||
label: i.label,
|
||||
href: `/books/pqpa/${i.slug}`,
|
||||
type: i.type,
|
||||
})),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
if (backMatterItems.length > 0) {
|
||||
mobileNavGroups.push({
|
||||
title: "Back Matter",
|
||||
items: backMatterItems.map((i) => ({
|
||||
slug: i.slug,
|
||||
label: i.label,
|
||||
href: `/books/pqpa/${i.slug}`,
|
||||
type: i.type,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/pqpa/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<MobileNav
|
||||
groups={mobileNavGroups}
|
||||
currentSlug={currentSlug}
|
||||
bookTitle="Perfect Questions Perfect Answers"
|
||||
/>
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/pqpa/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="hidden lg:block" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{next ? (
|
||||
<Link
|
||||
|
||||
@@ -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 RvChapterPage({
|
||||
{/* Main content */}
|
||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||
{/* Top navigation */}
|
||||
<RvNav prev={prev} next={next} />
|
||||
<RvNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<Card>
|
||||
@@ -82,7 +88,12 @@ export default async function RvChapterPage({
|
||||
</Card>
|
||||
|
||||
{/* Bottom navigation */}
|
||||
<RvNav prev={prev} next={next} />
|
||||
<RvNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@@ -174,31 +185,70 @@ function SidebarLink({
|
||||
function RvNav({
|
||||
prev,
|
||||
next,
|
||||
sidebarItems,
|
||||
currentSlug,
|
||||
}: {
|
||||
prev: RvSidebarItem | null;
|
||||
next: RvSidebarItem | null;
|
||||
sidebarItems: RvSidebarItem[];
|
||||
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/rv/${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/rv/${i.slug}`,
|
||||
type: i.type,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/rv/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<MobileNav
|
||||
groups={mobileNavGroups}
|
||||
currentSlug={currentSlug}
|
||||
bookTitle="Rāja-vidyā: The King of Knowledge"
|
||||
/>
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/rv/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="hidden lg:block" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{next ? (
|
||||
<Link
|
||||
|
||||
@@ -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;
|
||||
@@ -48,6 +49,20 @@ export default async function SbVersePage({
|
||||
);
|
||||
if (!verseData) notFound();
|
||||
|
||||
const mobileNavGroups: MobileNavGroup[] = [
|
||||
{
|
||||
title: "Verses",
|
||||
items: verseIndex.map((v) => ({
|
||||
slug: String(v.verse),
|
||||
label: v.verseEnd
|
||||
? `Texts ${v.verse}–${v.verseEnd}`
|
||||
: `Text ${v.verse}`,
|
||||
href: `/books/sb/${canto}/${chapter}/${v.verse}`,
|
||||
type: "verse",
|
||||
})),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
<PageHeader sticky wide>
|
||||
@@ -76,6 +91,8 @@ export default async function SbVersePage({
|
||||
chapter={parseInt(chapter)}
|
||||
showBengali={false}
|
||||
basePath={`/books/sb/${canto}/${chapter}`}
|
||||
mobileNavGroups={mobileNavGroups}
|
||||
mobileNavBookTitle={`SB ${canto}.${chapter}`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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 Sb1962Meta = {
|
||||
book: string;
|
||||
@@ -46,6 +47,23 @@ export default async function VersePage({
|
||||
);
|
||||
if (!verse) notFound();
|
||||
|
||||
const mobileNavGroups: MobileNavGroup[] = [
|
||||
{
|
||||
title: "Verses",
|
||||
items: verseIndex.map((v) => {
|
||||
const label = v.verseEnd
|
||||
? `Verses ${v.verse}–${v.verseEnd}`
|
||||
: `Verse ${v.verse}`;
|
||||
return {
|
||||
slug: String(v.verse),
|
||||
label,
|
||||
href: `/books/sb1962/${chapter}/${v.verse}`,
|
||||
type: "verse",
|
||||
};
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
<PageHeader sticky wide>
|
||||
@@ -74,6 +92,8 @@ export default async function VersePage({
|
||||
chapter={parseInt(chapter)}
|
||||
basePath={`/books/sb1962/${chapter}`}
|
||||
showBengali={false}
|
||||
mobileNavGroups={mobileNavGroups}
|
||||
mobileNavBookTitle={`Śrīmad-Bhāgavatam (1962) — Ch. ${chapter}`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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 SsrChapterPage({
|
||||
{/* Main content */}
|
||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||
{/* Top navigation */}
|
||||
<SsrNav prev={prev} next={next} />
|
||||
<SsrNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<Card>
|
||||
@@ -88,7 +94,12 @@ export default async function SsrChapterPage({
|
||||
</Card>
|
||||
|
||||
{/* Bottom navigation */}
|
||||
<SsrNav prev={prev} next={next} />
|
||||
<SsrNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@@ -225,29 +236,89 @@ function SidebarLink({
|
||||
function SsrNav({
|
||||
prev,
|
||||
next,
|
||||
sidebarItems,
|
||||
currentSlug,
|
||||
}: {
|
||||
prev: SsrSidebarItem | null;
|
||||
next: SsrSidebarItem | null;
|
||||
sidebarItems: SsrSidebarItem[];
|
||||
currentSlug: string;
|
||||
}) {
|
||||
const mobileNavGroups: MobileNavGroup[] = [];
|
||||
|
||||
const frontMatter = sidebarItems.filter(
|
||||
(i) => i.type === "intro-segment" && i.slug !== "intro-about-the-author",
|
||||
);
|
||||
if (frontMatter.length > 0) {
|
||||
mobileNavGroups.push({
|
||||
title: "Front Matter",
|
||||
items: frontMatter.map((i) => ({
|
||||
slug: i.slug,
|
||||
label: i.label,
|
||||
href: `/books/ssr/${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/ssr/${i.slug}`,
|
||||
type: i.type,
|
||||
parentChapter: i.parentChapter,
|
||||
isParent: i.type === "parent",
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
const backMatter = sidebarItems.filter(
|
||||
(i) => i.slug === "intro-about-the-author",
|
||||
);
|
||||
if (backMatter.length > 0) {
|
||||
mobileNavGroups.push({
|
||||
title: "Back Matter",
|
||||
items: backMatter.map((i) => ({
|
||||
slug: i.slug,
|
||||
label: i.label,
|
||||
href: `/books/ssr/${i.slug}`,
|
||||
type: i.type,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/ssr/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<MobileNav
|
||||
groups={mobileNavGroups}
|
||||
currentSlug={currentSlug}
|
||||
bookTitle="The Science of Self-Realization"
|
||||
/>
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/ssr/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="hidden lg:block" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{next ? (
|
||||
<Link
|
||||
|
||||
@@ -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 TlcChapterPage({
|
||||
{/* Main content */}
|
||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||
{/* Top navigation */}
|
||||
<TlcNav prev={prev} next={next} />
|
||||
<TlcNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<Card>
|
||||
@@ -82,7 +88,12 @@ export default async function TlcChapterPage({
|
||||
</Card>
|
||||
|
||||
{/* Bottom navigation */}
|
||||
<TlcNav prev={prev} next={next} />
|
||||
<TlcNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@@ -183,31 +194,70 @@ function SidebarLink({
|
||||
function TlcNav({
|
||||
prev,
|
||||
next,
|
||||
sidebarItems,
|
||||
currentSlug,
|
||||
}: {
|
||||
prev: TlcSidebarItem | null;
|
||||
next: TlcSidebarItem | null;
|
||||
sidebarItems: TlcSidebarItem[];
|
||||
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/tlc/${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/tlc/${i.slug}`,
|
||||
type: i.type,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/tlc/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<MobileNav
|
||||
groups={mobileNavGroups}
|
||||
currentSlug={currentSlug}
|
||||
bookTitle="Teachings of Lord Caitanya"
|
||||
/>
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/tlc/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="hidden lg:block" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{next ? (
|
||||
<Link
|
||||
|
||||
@@ -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 TtpChapterPage({
|
||||
{/* Main content */}
|
||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||
{/* Top navigation */}
|
||||
<TtpNav prev={prev} next={next} />
|
||||
<TtpNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<Card>
|
||||
@@ -82,7 +88,12 @@ export default async function TtpChapterPage({
|
||||
</Card>
|
||||
|
||||
{/* Bottom navigation */}
|
||||
<TtpNav prev={prev} next={next} />
|
||||
<TtpNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
sidebarItems={sidebarItems}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@@ -174,31 +185,70 @@ function SidebarLink({
|
||||
function TtpNav({
|
||||
prev,
|
||||
next,
|
||||
sidebarItems,
|
||||
currentSlug,
|
||||
}: {
|
||||
prev: TtpSidebarItem | null;
|
||||
next: TtpSidebarItem | null;
|
||||
sidebarItems: TtpSidebarItem[];
|
||||
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/ttp/${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/ttp/${i.slug}`,
|
||||
type: i.type,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/ttp/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<MobileNav
|
||||
groups={mobileNavGroups}
|
||||
currentSlug={currentSlug}
|
||||
bookTitle="Transcendental Teachings of Prahlāda Mahārāja"
|
||||
/>
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/books/ttp/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.type === "chapter" && prev.chapter != null
|
||||
? `Ch. ${prev.chapter}`
|
||||
: prev.label}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="hidden lg:block" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{next ? (
|
||||
<Link
|
||||
|
||||
+55
-19
@@ -7,6 +7,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";
|
||||
import { prisma } from "@/lib/db";
|
||||
import type { JsonValue } from "@prisma/client/runtime/library";
|
||||
|
||||
@@ -127,7 +128,12 @@ export default async function EssayPage({
|
||||
{/* Main content */}
|
||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||
{/* Top navigation */}
|
||||
<EssayNav prev={prev} next={next} />
|
||||
<EssayNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
allEssays={allEssays}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
|
||||
{/* Content */}
|
||||
<Card>
|
||||
@@ -145,7 +151,12 @@ export default async function EssayPage({
|
||||
</Card>
|
||||
|
||||
{/* Bottom navigation */}
|
||||
<EssayNav prev={prev} next={next} />
|
||||
<EssayNav
|
||||
prev={prev}
|
||||
next={next}
|
||||
allEssays={allEssays}
|
||||
currentSlug={slug}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@@ -196,29 +207,54 @@ function EssaySidebar({
|
||||
function EssayNav({
|
||||
prev,
|
||||
next,
|
||||
allEssays,
|
||||
currentSlug,
|
||||
}: {
|
||||
prev: SidebarItem | null;
|
||||
next: SidebarItem | null;
|
||||
allEssays: SidebarItem[];
|
||||
currentSlug: string;
|
||||
}) {
|
||||
const mobileNavGroups: MobileNavGroup[] = [];
|
||||
|
||||
if (allEssays.length > 0) {
|
||||
mobileNavGroups.push({
|
||||
title: "Essays",
|
||||
items: allEssays.map((i) => ({
|
||||
slug: i.slug,
|
||||
label: i.title,
|
||||
href: `/essays/${i.slug}`,
|
||||
type: "chapter",
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/essays/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.title}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<MobileNav
|
||||
groups={mobileNavGroups}
|
||||
currentSlug={currentSlug}
|
||||
bookTitle="Essays"
|
||||
/>
|
||||
{prev ? (
|
||||
<Link
|
||||
href={`/essays/${prev.slug}`}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline", size: "sm" }),
|
||||
"gap-1.5",
|
||||
)}
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||
{prev.title}
|
||||
</span>
|
||||
<span className="sm:hidden">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<div className="hidden lg:block" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{next ? (
|
||||
<Link
|
||||
|
||||
Reference in New Issue
Block a user