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 { buttonVariants } from "@/components/ui/button";
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Page
|
// Page
|
||||||
@@ -64,7 +65,12 @@ export default async function BbdChapterPage({
|
|||||||
{/* Main content */}
|
{/* Main content */}
|
||||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||||
{/* Top navigation */}
|
{/* Top navigation */}
|
||||||
<BbdNav prev={prev} next={next} />
|
<BbdNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card>
|
||||||
@@ -82,7 +88,12 @@ export default async function BbdChapterPage({
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Bottom navigation */}
|
{/* Bottom navigation */}
|
||||||
<BbdNav prev={prev} next={next} />
|
<BbdNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -174,31 +185,68 @@ function SidebarLink({
|
|||||||
function BbdNav({
|
function BbdNav({
|
||||||
prev,
|
prev,
|
||||||
next,
|
next,
|
||||||
|
sidebarItems,
|
||||||
|
currentSlug,
|
||||||
}: {
|
}: {
|
||||||
prev: BbdSidebarItem | null;
|
prev: BbdSidebarItem | null;
|
||||||
next: 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 (
|
return (
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
{prev ? (
|
<div className="flex items-center gap-2">
|
||||||
<Link
|
<MobileNav
|
||||||
href={`/books/bbd/${prev.slug}`}
|
groups={mobileNavGroups}
|
||||||
className={cn(
|
currentSlug={currentSlug}
|
||||||
buttonVariants({ variant: "outline", size: "sm" }),
|
bookTitle="Beyond Birth and Death"
|
||||||
"gap-1.5",
|
/>
|
||||||
)}
|
{prev ? (
|
||||||
>
|
<Link
|
||||||
<ChevronLeft className="size-4" />
|
href={`/books/bbd/${prev.slug}`}
|
||||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
className={cn(
|
||||||
{prev.type === "chapter" && prev.chapter != null
|
buttonVariants({ variant: "outline", size: "sm" }),
|
||||||
? `Ch. ${prev.chapter}`
|
"gap-1.5",
|
||||||
: prev.label}
|
)}
|
||||||
</span>
|
>
|
||||||
<span className="sm:hidden">Previous</span>
|
<ChevronLeft className="size-4" />
|
||||||
</Link>
|
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||||
) : (
|
{prev.type === "chapter" && prev.chapter != null
|
||||||
<div />
|
? `Ch. ${prev.chapter}`
|
||||||
)}
|
: prev.label}
|
||||||
|
</span>
|
||||||
|
<span className="sm:hidden">Previous</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div className="hidden lg:block" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{next ? (
|
{next ? (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { PageHeader } from "@/components/page-header";
|
|||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { getBookMeta, getSingleVerse, getChapterVerseIndex } from "@/lib/api";
|
import { getBookMeta, getSingleVerse, getChapterVerseIndex } from "@/lib/api";
|
||||||
import { ChapterViewer } from "@/app/books/chapter-viewer";
|
import { ChapterViewer } from "@/app/books/chapter-viewer";
|
||||||
|
import type { MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
type BgMeta = {
|
type BgMeta = {
|
||||||
book: string;
|
book: string;
|
||||||
@@ -42,6 +43,19 @@ export default async function VersePage({
|
|||||||
);
|
);
|
||||||
if (!verse) notFound();
|
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 (
|
return (
|
||||||
<div className="min-h-screen bg-background">
|
<div className="min-h-screen bg-background">
|
||||||
<PageHeader sticky wide>
|
<PageHeader sticky wide>
|
||||||
@@ -70,6 +84,8 @@ export default async function VersePage({
|
|||||||
chapter={parseInt(chapter)}
|
chapter={parseInt(chapter)}
|
||||||
basePath={`/books/bg/${chapter}`}
|
basePath={`/books/bg/${chapter}`}
|
||||||
showBengali={false}
|
showBengali={false}
|
||||||
|
mobileNavGroups={mobileNavGroups}
|
||||||
|
mobileNavBookTitle="Bhagavad-gītā As It Is"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { PageHeader } from "@/components/page-header";
|
|||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { getBookMeta, getSingleVerse, getChapterVerseIndex } from "@/lib/api";
|
import { getBookMeta, getSingleVerse, getChapterVerseIndex } from "@/lib/api";
|
||||||
import { ChapterViewer } from "@/app/books/chapter-viewer";
|
import { ChapterViewer } from "@/app/books/chapter-viewer";
|
||||||
|
import type { MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
type ChapterInfo = {
|
type ChapterInfo = {
|
||||||
number: number;
|
number: number;
|
||||||
@@ -49,6 +50,23 @@ export default async function CcVersePage({
|
|||||||
);
|
);
|
||||||
if (!verseData) notFound();
|
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 (
|
return (
|
||||||
<div className="min-h-screen bg-background">
|
<div className="min-h-screen bg-background">
|
||||||
<PageHeader sticky wide>
|
<PageHeader sticky wide>
|
||||||
@@ -77,6 +95,8 @@ export default async function CcVersePage({
|
|||||||
chapter={parseInt(chapter)}
|
chapter={parseInt(chapter)}
|
||||||
showBengali={true}
|
showBengali={true}
|
||||||
basePath={`/books/cc/${lila}/${chapter}`}
|
basePath={`/books/cc/${lila}/${chapter}`}
|
||||||
|
mobileNavGroups={mobileNavGroups}
|
||||||
|
mobileNavBookTitle={`${lilaInfo.name} — Chapter ${chapter}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { Card, CardHeader, CardContent } from "@/components/ui/card";
|
|||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { ChevronLeft, ChevronRight, Loader2 } from "lucide-react";
|
import { ChevronLeft, ChevronRight, Loader2 } from "lucide-react";
|
||||||
|
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Types
|
// Types
|
||||||
@@ -60,6 +61,10 @@ type ChapterViewerProps = {
|
|||||||
showBengali?: boolean;
|
showBengali?: boolean;
|
||||||
/** Base path for verse URLs, e.g. "/books/bg/1" — verse number is appended */
|
/** Base path for verse URLs, e.g. "/books/bg/1" — verse number is appended */
|
||||||
basePath: string;
|
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,
|
onPrev,
|
||||||
onNext,
|
onNext,
|
||||||
verseIndex,
|
verseIndex,
|
||||||
|
mobileNavGroups,
|
||||||
|
currentVerseSlug,
|
||||||
|
mobileNavBookTitle,
|
||||||
}: {
|
}: {
|
||||||
currentIdx: number;
|
currentIdx: number;
|
||||||
total: number;
|
total: number;
|
||||||
onPrev: () => void;
|
onPrev: () => void;
|
||||||
onNext: () => void;
|
onNext: () => void;
|
||||||
verseIndex: VerseIndexEntry[];
|
verseIndex: VerseIndexEntry[];
|
||||||
|
mobileNavGroups?: MobileNavGroup[];
|
||||||
|
currentVerseSlug?: string;
|
||||||
|
mobileNavBookTitle?: string;
|
||||||
}) {
|
}) {
|
||||||
const hasPrev = currentIdx > 0;
|
const hasPrev = currentIdx > 0;
|
||||||
const hasNext = currentIdx < total - 1;
|
const hasNext = currentIdx < total - 1;
|
||||||
@@ -90,16 +101,25 @@ function VerseNav({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<Button
|
<div className="flex items-center gap-2">
|
||||||
variant="outline"
|
{mobileNavGroups && mobileNavGroups.length > 0 && (
|
||||||
size="sm"
|
<MobileNav
|
||||||
disabled={!hasPrev}
|
groups={mobileNavGroups}
|
||||||
onClick={onPrev}
|
currentSlug={currentVerseSlug ?? String(current?.verse ?? "")}
|
||||||
className="gap-1.5"
|
bookTitle={mobileNavBookTitle}
|
||||||
>
|
/>
|
||||||
<ChevronLeft className="size-4" />
|
)}
|
||||||
<span className="hidden sm:inline">Previous</span>
|
<Button
|
||||||
</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">
|
<span className="text-sm text-muted-foreground">
|
||||||
Verse {label} of {total}
|
Verse {label} of {total}
|
||||||
@@ -220,6 +240,8 @@ export function ChapterViewer({
|
|||||||
chapter,
|
chapter,
|
||||||
showBengali = false,
|
showBengali = false,
|
||||||
basePath,
|
basePath,
|
||||||
|
mobileNavGroups,
|
||||||
|
mobileNavBookTitle,
|
||||||
}: ChapterViewerProps) {
|
}: ChapterViewerProps) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@@ -409,6 +431,9 @@ export function ChapterViewer({
|
|||||||
onPrev={goPrev}
|
onPrev={goPrev}
|
||||||
onNext={goNext}
|
onNext={goNext}
|
||||||
verseIndex={verseIndex}
|
verseIndex={verseIndex}
|
||||||
|
mobileNavGroups={mobileNavGroups}
|
||||||
|
currentVerseSlug={String(currentVerseNum)}
|
||||||
|
mobileNavBookTitle={mobileNavBookTitle}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Verse content */}
|
{/* Verse content */}
|
||||||
@@ -432,6 +457,9 @@ export function ChapterViewer({
|
|||||||
onPrev={goPrev}
|
onPrev={goPrev}
|
||||||
onNext={goNext}
|
onNext={goNext}
|
||||||
verseIndex={verseIndex}
|
verseIndex={verseIndex}
|
||||||
|
mobileNavGroups={mobileNavGroups}
|
||||||
|
currentVerseSlug={String(currentVerseNum)}
|
||||||
|
mobileNavBookTitle={mobileNavBookTitle}
|
||||||
/>
|
/>
|
||||||
</main>
|
</main>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
|||||||
import { buttonVariants } from "@/components/ui/button";
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Page
|
// Page
|
||||||
@@ -70,7 +71,12 @@ export default async function DsChapterPage({
|
|||||||
{/* Main content */}
|
{/* Main content */}
|
||||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||||
{/* Top navigation */}
|
{/* Top navigation */}
|
||||||
<DsNav prev={prev} next={next} />
|
<DsNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card>
|
||||||
@@ -88,7 +94,12 @@ export default async function DsChapterPage({
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Bottom navigation */}
|
{/* Bottom navigation */}
|
||||||
<DsNav prev={prev} next={next} />
|
<DsNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -204,29 +215,72 @@ function SidebarLink({
|
|||||||
function DsNav({
|
function DsNav({
|
||||||
prev,
|
prev,
|
||||||
next,
|
next,
|
||||||
|
sidebarItems,
|
||||||
|
currentSlug,
|
||||||
}: {
|
}: {
|
||||||
prev: DsSidebarItem | null;
|
prev: DsSidebarItem | null;
|
||||||
next: 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 (
|
return (
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
{prev ? (
|
<div className="flex items-center gap-2">
|
||||||
<Link
|
<MobileNav
|
||||||
href={`/books/ds/${prev.slug}`}
|
groups={mobileNavGroups}
|
||||||
className={cn(
|
currentSlug={currentSlug}
|
||||||
buttonVariants({ variant: "outline", size: "sm" }),
|
bookTitle="Dialectic Spiritualism"
|
||||||
"gap-1.5",
|
/>
|
||||||
)}
|
{prev ? (
|
||||||
>
|
<Link
|
||||||
<ChevronLeft className="size-4" />
|
href={`/books/ds/${prev.slug}`}
|
||||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
className={cn(
|
||||||
{prev.label}
|
buttonVariants({ variant: "outline", size: "sm" }),
|
||||||
</span>
|
"gap-1.5",
|
||||||
<span className="sm:hidden">Previous</span>
|
)}
|
||||||
</Link>
|
>
|
||||||
) : (
|
<ChevronLeft className="size-4" />
|
||||||
<div />
|
<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 ? (
|
{next ? (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
|||||||
import { buttonVariants } from "@/components/ui/button";
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Page
|
// Page
|
||||||
@@ -64,7 +65,12 @@ export default async function EjChapterPage({
|
|||||||
{/* Main content */}
|
{/* Main content */}
|
||||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||||
{/* Top navigation */}
|
{/* Top navigation */}
|
||||||
<EjNav prev={prev} next={next} />
|
<EjNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card>
|
||||||
@@ -82,7 +88,12 @@ export default async function EjChapterPage({
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Bottom navigation */}
|
{/* Bottom navigation */}
|
||||||
<EjNav prev={prev} next={next} />
|
<EjNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -174,31 +185,70 @@ function SidebarLink({
|
|||||||
function EjNav({
|
function EjNav({
|
||||||
prev,
|
prev,
|
||||||
next,
|
next,
|
||||||
|
sidebarItems,
|
||||||
|
currentSlug,
|
||||||
}: {
|
}: {
|
||||||
prev: EjSidebarItem | null;
|
prev: EjSidebarItem | null;
|
||||||
next: 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 (
|
return (
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
{prev ? (
|
<div className="flex items-center gap-2">
|
||||||
<Link
|
<MobileNav
|
||||||
href={`/books/ej/${prev.slug}`}
|
groups={mobileNavGroups}
|
||||||
className={cn(
|
currentSlug={currentSlug}
|
||||||
buttonVariants({ variant: "outline", size: "sm" }),
|
bookTitle="Easy Journey to Other Planets"
|
||||||
"gap-1.5",
|
/>
|
||||||
)}
|
{prev ? (
|
||||||
>
|
<Link
|
||||||
<ChevronLeft className="size-4" />
|
href={`/books/ej/${prev.slug}`}
|
||||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
className={cn(
|
||||||
{prev.type === "chapter" && prev.chapter != null
|
buttonVariants({ variant: "outline", size: "sm" }),
|
||||||
? `Ch. ${prev.chapter}`
|
"gap-1.5",
|
||||||
: prev.label}
|
)}
|
||||||
</span>
|
>
|
||||||
<span className="sm:hidden">Previous</span>
|
<ChevronLeft className="size-4" />
|
||||||
</Link>
|
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||||
) : (
|
{prev.type === "chapter" && prev.chapter != null
|
||||||
<div />
|
? `Ch. ${prev.chapter}`
|
||||||
)}
|
: prev.label}
|
||||||
|
</span>
|
||||||
|
<span className="sm:hidden">Previous</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div className="hidden lg:block" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{next ? (
|
{next ? (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
|||||||
import { buttonVariants } from "@/components/ui/button";
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Page
|
// Page
|
||||||
@@ -64,7 +65,12 @@ export default async function EkChapterPage({
|
|||||||
{/* Main content */}
|
{/* Main content */}
|
||||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||||
{/* Top navigation */}
|
{/* Top navigation */}
|
||||||
<EkNav prev={prev} next={next} />
|
<EkNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card>
|
||||||
@@ -82,7 +88,12 @@ export default async function EkChapterPage({
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Bottom navigation */}
|
{/* Bottom navigation */}
|
||||||
<EkNav prev={prev} next={next} />
|
<EkNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -174,31 +185,70 @@ function SidebarLink({
|
|||||||
function EkNav({
|
function EkNav({
|
||||||
prev,
|
prev,
|
||||||
next,
|
next,
|
||||||
|
sidebarItems,
|
||||||
|
currentSlug,
|
||||||
}: {
|
}: {
|
||||||
prev: EkSidebarItem | null;
|
prev: EkSidebarItem | null;
|
||||||
next: 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 (
|
return (
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
{prev ? (
|
<div className="flex items-center gap-2">
|
||||||
<Link
|
<MobileNav
|
||||||
href={`/books/ek/${prev.slug}`}
|
groups={mobileNavGroups}
|
||||||
className={cn(
|
currentSlug={currentSlug}
|
||||||
buttonVariants({ variant: "outline", size: "sm" }),
|
bookTitle="Elevation to Kṛṣṇa Consciousness"
|
||||||
"gap-1.5",
|
/>
|
||||||
)}
|
{prev ? (
|
||||||
>
|
<Link
|
||||||
<ChevronLeft className="size-4" />
|
href={`/books/ek/${prev.slug}`}
|
||||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
className={cn(
|
||||||
{prev.type === "chapter" && prev.chapter != null
|
buttonVariants({ variant: "outline", size: "sm" }),
|
||||||
? `Ch. ${prev.chapter}`
|
"gap-1.5",
|
||||||
: prev.label}
|
)}
|
||||||
</span>
|
>
|
||||||
<span className="sm:hidden">Previous</span>
|
<ChevronLeft className="size-4" />
|
||||||
</Link>
|
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||||
) : (
|
{prev.type === "chapter" && prev.chapter != null
|
||||||
<div />
|
? `Ch. ${prev.chapter}`
|
||||||
)}
|
: prev.label}
|
||||||
|
</span>
|
||||||
|
<span className="sm:hidden">Previous</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div className="hidden lg:block" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{next ? (
|
{next ? (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
|||||||
import { buttonVariants } from "@/components/ui/button";
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Page
|
// Page
|
||||||
@@ -64,7 +65,12 @@ export default async function HkhChapterPage({
|
|||||||
{/* Main content */}
|
{/* Main content */}
|
||||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||||
{/* Top navigation */}
|
{/* Top navigation */}
|
||||||
<HkhNav prev={prev} next={next} />
|
<HkhNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card>
|
||||||
@@ -82,7 +88,12 @@ export default async function HkhChapterPage({
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Bottom navigation */}
|
{/* Bottom navigation */}
|
||||||
<HkhNav prev={prev} next={next} />
|
<HkhNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -174,31 +185,70 @@ function SidebarLink({
|
|||||||
function HkhNav({
|
function HkhNav({
|
||||||
prev,
|
prev,
|
||||||
next,
|
next,
|
||||||
|
sidebarItems,
|
||||||
|
currentSlug,
|
||||||
}: {
|
}: {
|
||||||
prev: HkhSidebarItem | null;
|
prev: HkhSidebarItem | null;
|
||||||
next: 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 (
|
return (
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
{prev ? (
|
<div className="flex items-center gap-2">
|
||||||
<Link
|
<MobileNav
|
||||||
href={`/books/hkh/${prev.slug}`}
|
groups={mobileNavGroups}
|
||||||
className={cn(
|
currentSlug={currentSlug}
|
||||||
buttonVariants({ variant: "outline", size: "sm" }),
|
bookTitle="The Kṛṣṇa Consciousness Handbook"
|
||||||
"gap-1.5",
|
/>
|
||||||
)}
|
{prev ? (
|
||||||
>
|
<Link
|
||||||
<ChevronLeft className="size-4" />
|
href={`/books/hkh/${prev.slug}`}
|
||||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
className={cn(
|
||||||
{prev.type === "chapter" && prev.chapter != null
|
buttonVariants({ variant: "outline", size: "sm" }),
|
||||||
? `Ch. ${prev.chapter}`
|
"gap-1.5",
|
||||||
: prev.label}
|
)}
|
||||||
</span>
|
>
|
||||||
<span className="sm:hidden">Previous</span>
|
<ChevronLeft className="size-4" />
|
||||||
</Link>
|
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||||
) : (
|
{prev.type === "chapter" && prev.chapter != null
|
||||||
<div />
|
? `Ch. ${prev.chapter}`
|
||||||
)}
|
: prev.label}
|
||||||
|
</span>
|
||||||
|
<span className="sm:hidden">Previous</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div className="hidden lg:block" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{next ? (
|
{next ? (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
|||||||
import { buttonVariants } from "@/components/ui/button";
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Type guards
|
// Type guards
|
||||||
@@ -79,14 +80,24 @@ export default async function IsoMantraPage({
|
|||||||
{/* Main content */}
|
{/* Main content */}
|
||||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||||
{/* Top navigation */}
|
{/* Top navigation */}
|
||||||
<IsoNav prev={prev} next={next} />
|
<IsoNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
{verse && <VerseContent verse={verse} />}
|
{verse && <VerseContent verse={verse} />}
|
||||||
{intro && <IntroContent intro={intro} />}
|
{intro && <IntroContent intro={intro} />}
|
||||||
|
|
||||||
{/* Bottom navigation */}
|
{/* Bottom navigation */}
|
||||||
<IsoNav prev={prev} next={next} />
|
<IsoNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -295,31 +306,90 @@ function SidebarLink({
|
|||||||
function IsoNav({
|
function IsoNav({
|
||||||
prev,
|
prev,
|
||||||
next,
|
next,
|
||||||
|
sidebarItems,
|
||||||
|
currentSlug,
|
||||||
}: {
|
}: {
|
||||||
prev: IsoSidebarItem | null;
|
prev: IsoSidebarItem | null;
|
||||||
next: 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 (
|
return (
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
{prev ? (
|
<div className="flex items-center gap-2">
|
||||||
<Link
|
<MobileNav
|
||||||
href={`/books/iso/${prev.slug}`}
|
groups={mobileNavGroups}
|
||||||
className={cn(
|
currentSlug={currentSlug}
|
||||||
buttonVariants({ variant: "outline", size: "sm" }),
|
bookTitle="Śrī Īśopaniṣad"
|
||||||
"gap-1.5",
|
/>
|
||||||
)}
|
{prev ? (
|
||||||
>
|
<Link
|
||||||
<ChevronLeft className="size-4" />
|
href={`/books/iso/${prev.slug}`}
|
||||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
className={cn(
|
||||||
{prev.type === "verse" && prev.mantra != null && prev.mantra > 0
|
buttonVariants({ variant: "outline", size: "sm" }),
|
||||||
? `Mantra ${prev.mantra}`
|
"gap-1.5",
|
||||||
: prev.label}
|
)}
|
||||||
</span>
|
>
|
||||||
<span className="sm:hidden">Previous</span>
|
<ChevronLeft className="size-4" />
|
||||||
</Link>
|
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||||
) : (
|
{prev.type === "verse" && prev.mantra != null && prev.mantra > 0
|
||||||
<div />
|
? `Mantra ${prev.mantra}`
|
||||||
)}
|
: prev.label}
|
||||||
|
</span>
|
||||||
|
<span className="sm:hidden">Previous</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div className="hidden lg:block" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{next ? (
|
{next ? (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
|||||||
import { buttonVariants } from "@/components/ui/button";
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
export default async function KbChapterPage({
|
export default async function KbChapterPage({
|
||||||
params,
|
params,
|
||||||
@@ -60,7 +61,13 @@ export default async function KbChapterPage({
|
|||||||
{/* Main content */}
|
{/* Main content */}
|
||||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||||
{/* Top navigation */}
|
{/* Top navigation */}
|
||||||
<ChapterNav prev={prev} next={next} volume={vol} />
|
<ChapterNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
volume={vol}
|
||||||
|
chapters={allChapters}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Chapter content */}
|
{/* Chapter content */}
|
||||||
<Card>
|
<Card>
|
||||||
@@ -78,7 +85,13 @@ export default async function KbChapterPage({
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Bottom navigation */}
|
{/* Bottom navigation */}
|
||||||
<ChapterNav prev={prev} next={next} volume={vol} />
|
<ChapterNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
volume={vol}
|
||||||
|
chapters={allChapters}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -154,32 +167,71 @@ function ChapterNav({
|
|||||||
prev,
|
prev,
|
||||||
next,
|
next,
|
||||||
volume,
|
volume,
|
||||||
|
chapters,
|
||||||
|
currentSlug,
|
||||||
}: {
|
}: {
|
||||||
prev: NavChapter | null;
|
prev: NavChapter | null;
|
||||||
next: NavChapter | null;
|
next: NavChapter | null;
|
||||||
volume: number;
|
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 (
|
return (
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
{prev ? (
|
<div className="flex items-center gap-2">
|
||||||
<Link
|
<MobileNav
|
||||||
href={`/books/kb/${volume}/${prev.slug}`}
|
groups={mobileNavGroups}
|
||||||
className={cn(
|
currentSlug={currentSlug}
|
||||||
buttonVariants({ variant: "outline", size: "sm" }),
|
bookTitle={`Kṛṣṇa Book — Volume ${volume}`}
|
||||||
"gap-1.5",
|
/>
|
||||||
)}
|
{prev ? (
|
||||||
>
|
<Link
|
||||||
<ChevronLeft className="size-4" />
|
href={`/books/kb/${volume}/${prev.slug}`}
|
||||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
className={cn(
|
||||||
{prev.type === "chapter" && prev.chapter != null
|
buttonVariants({ variant: "outline", size: "sm" }),
|
||||||
? `Ch. ${prev.chapter}`
|
"gap-1.5",
|
||||||
: prev.title}
|
)}
|
||||||
</span>
|
>
|
||||||
<span className="sm:hidden">Previous</span>
|
<ChevronLeft className="size-4" />
|
||||||
</Link>
|
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||||
) : (
|
{prev.type === "chapter" && prev.chapter != null
|
||||||
<div />
|
? `Ch. ${prev.chapter}`
|
||||||
)}
|
: prev.title}
|
||||||
|
</span>
|
||||||
|
<span className="sm:hidden">Previous</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div className="hidden lg:block" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{next ? (
|
{next ? (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
|||||||
import { buttonVariants } from "@/components/ui/button";
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Page
|
// Page
|
||||||
@@ -64,7 +65,12 @@ export default async function MgChapterPage({
|
|||||||
{/* Main content */}
|
{/* Main content */}
|
||||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||||
{/* Top navigation */}
|
{/* Top navigation */}
|
||||||
<MgNav prev={prev} next={next} />
|
<MgNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card>
|
||||||
@@ -82,7 +88,12 @@ export default async function MgChapterPage({
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Bottom navigation */}
|
{/* Bottom navigation */}
|
||||||
<MgNav prev={prev} next={next} />
|
<MgNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -174,31 +185,70 @@ function SidebarLink({
|
|||||||
function MgNav({
|
function MgNav({
|
||||||
prev,
|
prev,
|
||||||
next,
|
next,
|
||||||
|
sidebarItems,
|
||||||
|
currentSlug,
|
||||||
}: {
|
}: {
|
||||||
prev: MgSidebarItem | null;
|
prev: MgSidebarItem | null;
|
||||||
next: 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 (
|
return (
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
{prev ? (
|
<div className="flex items-center gap-2">
|
||||||
<Link
|
<MobileNav
|
||||||
href={`/books/mg/${prev.slug}`}
|
groups={mobileNavGroups}
|
||||||
className={cn(
|
currentSlug={currentSlug}
|
||||||
buttonVariants({ variant: "outline", size: "sm" }),
|
bookTitle="Kṛṣṇa Consciousness: The Matchless Gift"
|
||||||
"gap-1.5",
|
/>
|
||||||
)}
|
{prev ? (
|
||||||
>
|
<Link
|
||||||
<ChevronLeft className="size-4" />
|
href={`/books/mg/${prev.slug}`}
|
||||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
className={cn(
|
||||||
{prev.type === "chapter" && prev.chapter != null
|
buttonVariants({ variant: "outline", size: "sm" }),
|
||||||
? `Ch. ${prev.chapter}`
|
"gap-1.5",
|
||||||
: prev.label}
|
)}
|
||||||
</span>
|
>
|
||||||
<span className="sm:hidden">Previous</span>
|
<ChevronLeft className="size-4" />
|
||||||
</Link>
|
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||||
) : (
|
{prev.type === "chapter" && prev.chapter != null
|
||||||
<div />
|
? `Ch. ${prev.chapter}`
|
||||||
)}
|
: prev.label}
|
||||||
|
</span>
|
||||||
|
<span className="sm:hidden">Previous</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div className="hidden lg:block" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{next ? (
|
{next ? (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
|||||||
import { buttonVariants } from "@/components/ui/button";
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Page
|
// Page
|
||||||
@@ -64,7 +65,12 @@ export default async function NodChapterPage({
|
|||||||
{/* Main content */}
|
{/* Main content */}
|
||||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||||
{/* Top navigation */}
|
{/* Top navigation */}
|
||||||
<NodNav prev={prev} next={next} />
|
<NodNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card>
|
||||||
@@ -82,7 +88,12 @@ export default async function NodChapterPage({
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Bottom navigation */}
|
{/* Bottom navigation */}
|
||||||
<NodNav prev={prev} next={next} />
|
<NodNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -197,31 +208,79 @@ function SidebarLink({
|
|||||||
function NodNav({
|
function NodNav({
|
||||||
prev,
|
prev,
|
||||||
next,
|
next,
|
||||||
|
sidebarItems,
|
||||||
|
currentSlug,
|
||||||
}: {
|
}: {
|
||||||
prev: NodSidebarItem | null;
|
prev: NodSidebarItem | null;
|
||||||
next: 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 (
|
return (
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
{prev ? (
|
<div className="flex items-center gap-2">
|
||||||
<Link
|
<MobileNav
|
||||||
href={`/books/nod/${prev.slug}`}
|
groups={mobileNavGroups}
|
||||||
className={cn(
|
currentSlug={currentSlug}
|
||||||
buttonVariants({ variant: "outline", size: "sm" }),
|
bookTitle="The Nectar of Devotion"
|
||||||
"gap-1.5",
|
/>
|
||||||
)}
|
{prev ? (
|
||||||
>
|
<Link
|
||||||
<ChevronLeft className="size-4" />
|
href={`/books/nod/${prev.slug}`}
|
||||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
className={cn(
|
||||||
{prev.type === "chapter" && prev.chapter != null
|
buttonVariants({ variant: "outline", size: "sm" }),
|
||||||
? `Ch. ${prev.chapter}`
|
"gap-1.5",
|
||||||
: prev.label}
|
)}
|
||||||
</span>
|
>
|
||||||
<span className="sm:hidden">Previous</span>
|
<ChevronLeft className="size-4" />
|
||||||
</Link>
|
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||||
) : (
|
{prev.type === "chapter" && prev.chapter != null
|
||||||
<div />
|
? `Ch. ${prev.chapter}`
|
||||||
)}
|
: prev.label}
|
||||||
|
</span>
|
||||||
|
<span className="sm:hidden">Previous</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div className="hidden lg:block" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{next ? (
|
{next ? (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
|||||||
import { buttonVariants } from "@/components/ui/button";
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Type guards
|
// Type guards
|
||||||
@@ -79,14 +80,24 @@ export default async function NoiTextPage({
|
|||||||
{/* Main content */}
|
{/* Main content */}
|
||||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||||
{/* Top navigation */}
|
{/* Top navigation */}
|
||||||
<NoiNav prev={prev} next={next} />
|
<NoiNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
{verse && <VerseContent verse={verse} />}
|
{verse && <VerseContent verse={verse} />}
|
||||||
{intro && <IntroContent intro={intro} />}
|
{intro && <IntroContent intro={intro} />}
|
||||||
|
|
||||||
{/* Bottom navigation */}
|
{/* Bottom navigation */}
|
||||||
<NoiNav prev={prev} next={next} />
|
<NoiNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -210,9 +221,7 @@ function NoiSidebar({
|
|||||||
// Texts = 1-11
|
// Texts = 1-11
|
||||||
const textItems = items.filter((item) => item.type === "verse");
|
const textItems = items.filter((item) => item.type === "verse");
|
||||||
// Appendixes comes last
|
// Appendixes comes last
|
||||||
const appendixesItem = items.find(
|
const appendixesItem = items.find((item) => item.slug === "intro-appendixes");
|
||||||
(item) => item.slug === "intro-appendixes",
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
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">
|
<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({
|
function NoiNav({
|
||||||
prev,
|
prev,
|
||||||
next,
|
next,
|
||||||
|
sidebarItems,
|
||||||
|
currentSlug,
|
||||||
}: {
|
}: {
|
||||||
prev: NoiSidebarItem | null;
|
prev: NoiSidebarItem | null;
|
||||||
next: 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 (
|
return (
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
{prev ? (
|
<div className="flex items-center gap-2">
|
||||||
<Link
|
<MobileNav
|
||||||
href={`/books/noi/${prev.slug}`}
|
groups={mobileNavGroups}
|
||||||
className={cn(
|
currentSlug={currentSlug}
|
||||||
buttonVariants({ variant: "outline", size: "sm" }),
|
bookTitle="The Nectar of Instruction"
|
||||||
"gap-1.5",
|
/>
|
||||||
)}
|
{prev ? (
|
||||||
>
|
<Link
|
||||||
<ChevronLeft className="size-4" />
|
href={`/books/noi/${prev.slug}`}
|
||||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
className={cn(
|
||||||
{prev.type === "verse" && prev.text != null
|
buttonVariants({ variant: "outline", size: "sm" }),
|
||||||
? `Text ${prev.text}`
|
"gap-1.5",
|
||||||
: prev.label}
|
)}
|
||||||
</span>
|
>
|
||||||
<span className="sm:hidden">Previous</span>
|
<ChevronLeft className="size-4" />
|
||||||
</Link>
|
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||||
) : (
|
{prev.type === "verse" && prev.text != null
|
||||||
<div />
|
? `Text ${prev.text}`
|
||||||
)}
|
: prev.label}
|
||||||
|
</span>
|
||||||
|
<span className="sm:hidden">Previous</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div className="hidden lg:block" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{next ? (
|
{next ? (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
|||||||
import { buttonVariants } from "@/components/ui/button";
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Page
|
// Page
|
||||||
@@ -64,7 +65,12 @@ export default async function OchkmChapterPage({
|
|||||||
{/* Main content */}
|
{/* Main content */}
|
||||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||||
{/* Top navigation */}
|
{/* Top navigation */}
|
||||||
<OchkmNav prev={prev} next={next} />
|
<OchkmNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card>
|
||||||
@@ -82,7 +88,12 @@ export default async function OchkmChapterPage({
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Bottom navigation */}
|
{/* Bottom navigation */}
|
||||||
<OchkmNav prev={prev} next={next} />
|
<OchkmNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -174,31 +185,70 @@ function SidebarLink({
|
|||||||
function OchkmNav({
|
function OchkmNav({
|
||||||
prev,
|
prev,
|
||||||
next,
|
next,
|
||||||
|
sidebarItems,
|
||||||
|
currentSlug,
|
||||||
}: {
|
}: {
|
||||||
prev: OchkmSidebarItem | null;
|
prev: OchkmSidebarItem | null;
|
||||||
next: 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 (
|
return (
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
{prev ? (
|
<div className="flex items-center gap-2">
|
||||||
<Link
|
<MobileNav
|
||||||
href={`/books/ochkm/${prev.slug}`}
|
groups={mobileNavGroups}
|
||||||
className={cn(
|
currentSlug={currentSlug}
|
||||||
buttonVariants({ variant: "outline", size: "sm" }),
|
bookTitle="On Chanting the Hare Kṛṣṇa Mantra"
|
||||||
"gap-1.5",
|
/>
|
||||||
)}
|
{prev ? (
|
||||||
>
|
<Link
|
||||||
<ChevronLeft className="size-4" />
|
href={`/books/ochkm/${prev.slug}`}
|
||||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
className={cn(
|
||||||
{prev.type === "chapter" && prev.chapter != null
|
buttonVariants({ variant: "outline", size: "sm" }),
|
||||||
? `Ch. ${prev.chapter}`
|
"gap-1.5",
|
||||||
: prev.label}
|
)}
|
||||||
</span>
|
>
|
||||||
<span className="sm:hidden">Previous</span>
|
<ChevronLeft className="size-4" />
|
||||||
</Link>
|
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||||
) : (
|
{prev.type === "chapter" && prev.chapter != null
|
||||||
<div />
|
? `Ch. ${prev.chapter}`
|
||||||
)}
|
: prev.label}
|
||||||
|
</span>
|
||||||
|
<span className="sm:hidden">Previous</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div className="hidden lg:block" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{next ? (
|
{next ? (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
|||||||
import { buttonVariants } from "@/components/ui/button";
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Page
|
// Page
|
||||||
@@ -64,7 +65,12 @@ export default async function OwkChapterPage({
|
|||||||
{/* Main content */}
|
{/* Main content */}
|
||||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||||
{/* Top navigation */}
|
{/* Top navigation */}
|
||||||
<OwkNav prev={prev} next={next} />
|
<OwkNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card>
|
||||||
@@ -82,7 +88,12 @@ export default async function OwkChapterPage({
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Bottom navigation */}
|
{/* Bottom navigation */}
|
||||||
<OwkNav prev={prev} next={next} />
|
<OwkNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -174,31 +185,70 @@ function SidebarLink({
|
|||||||
function OwkNav({
|
function OwkNav({
|
||||||
prev,
|
prev,
|
||||||
next,
|
next,
|
||||||
|
sidebarItems,
|
||||||
|
currentSlug,
|
||||||
}: {
|
}: {
|
||||||
prev: OwkSidebarItem | null;
|
prev: OwkSidebarItem | null;
|
||||||
next: 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 (
|
return (
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
{prev ? (
|
<div className="flex items-center gap-2">
|
||||||
<Link
|
<MobileNav
|
||||||
href={`/books/owk/${prev.slug}`}
|
groups={mobileNavGroups}
|
||||||
className={cn(
|
currentSlug={currentSlug}
|
||||||
buttonVariants({ variant: "outline", size: "sm" }),
|
bookTitle="On the Way to Kṛṣṇa"
|
||||||
"gap-1.5",
|
/>
|
||||||
)}
|
{prev ? (
|
||||||
>
|
<Link
|
||||||
<ChevronLeft className="size-4" />
|
href={`/books/owk/${prev.slug}`}
|
||||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
className={cn(
|
||||||
{prev.type === "chapter" && prev.chapter != null
|
buttonVariants({ variant: "outline", size: "sm" }),
|
||||||
? `Ch. ${prev.chapter}`
|
"gap-1.5",
|
||||||
: prev.label}
|
)}
|
||||||
</span>
|
>
|
||||||
<span className="sm:hidden">Previous</span>
|
<ChevronLeft className="size-4" />
|
||||||
</Link>
|
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||||
) : (
|
{prev.type === "chapter" && prev.chapter != null
|
||||||
<div />
|
? `Ch. ${prev.chapter}`
|
||||||
)}
|
: prev.label}
|
||||||
|
</span>
|
||||||
|
<span className="sm:hidden">Previous</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div className="hidden lg:block" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{next ? (
|
{next ? (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
|||||||
import { buttonVariants } from "@/components/ui/button";
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Page
|
// Page
|
||||||
@@ -64,7 +65,12 @@ export default async function PoyChapterPage({
|
|||||||
{/* Main content */}
|
{/* Main content */}
|
||||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||||
{/* Top navigation */}
|
{/* Top navigation */}
|
||||||
<PoyNav prev={prev} next={next} />
|
<PoyNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card>
|
||||||
@@ -82,7 +88,12 @@ export default async function PoyChapterPage({
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Bottom navigation */}
|
{/* Bottom navigation */}
|
||||||
<PoyNav prev={prev} next={next} />
|
<PoyNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -174,31 +185,70 @@ function SidebarLink({
|
|||||||
function PoyNav({
|
function PoyNav({
|
||||||
prev,
|
prev,
|
||||||
next,
|
next,
|
||||||
|
sidebarItems,
|
||||||
|
currentSlug,
|
||||||
}: {
|
}: {
|
||||||
prev: PoySidebarItem | null;
|
prev: PoySidebarItem | null;
|
||||||
next: 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 (
|
return (
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
{prev ? (
|
<div className="flex items-center gap-2">
|
||||||
<Link
|
<MobileNav
|
||||||
href={`/books/poy/${prev.slug}`}
|
groups={mobileNavGroups}
|
||||||
className={cn(
|
currentSlug={currentSlug}
|
||||||
buttonVariants({ variant: "outline", size: "sm" }),
|
bookTitle="The Perfection of Yoga"
|
||||||
"gap-1.5",
|
/>
|
||||||
)}
|
{prev ? (
|
||||||
>
|
<Link
|
||||||
<ChevronLeft className="size-4" />
|
href={`/books/poy/${prev.slug}`}
|
||||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
className={cn(
|
||||||
{prev.type === "chapter" && prev.chapter != null
|
buttonVariants({ variant: "outline", size: "sm" }),
|
||||||
? `Ch. ${prev.chapter}`
|
"gap-1.5",
|
||||||
: prev.label}
|
)}
|
||||||
</span>
|
>
|
||||||
<span className="sm:hidden">Previous</span>
|
<ChevronLeft className="size-4" />
|
||||||
</Link>
|
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||||
) : (
|
{prev.type === "chapter" && prev.chapter != null
|
||||||
<div />
|
? `Ch. ${prev.chapter}`
|
||||||
)}
|
: prev.label}
|
||||||
|
</span>
|
||||||
|
<span className="sm:hidden">Previous</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div className="hidden lg:block" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{next ? (
|
{next ? (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
|||||||
import { buttonVariants } from "@/components/ui/button";
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Page
|
// Page
|
||||||
@@ -64,7 +65,12 @@ export default async function PqpaChapterPage({
|
|||||||
{/* Main content */}
|
{/* Main content */}
|
||||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||||
{/* Top navigation */}
|
{/* Top navigation */}
|
||||||
<PqpaNav prev={prev} next={next} />
|
<PqpaNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card>
|
||||||
@@ -82,7 +88,12 @@ export default async function PqpaChapterPage({
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Bottom navigation */}
|
{/* Bottom navigation */}
|
||||||
<PqpaNav prev={prev} next={next} />
|
<PqpaNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -233,31 +244,108 @@ function SidebarLink({
|
|||||||
function PqpaNav({
|
function PqpaNav({
|
||||||
prev,
|
prev,
|
||||||
next,
|
next,
|
||||||
|
sidebarItems,
|
||||||
|
currentSlug,
|
||||||
}: {
|
}: {
|
||||||
prev: PqpaSidebarItem | null;
|
prev: PqpaSidebarItem | null;
|
||||||
next: 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 (
|
return (
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
{prev ? (
|
<div className="flex items-center gap-2">
|
||||||
<Link
|
<MobileNav
|
||||||
href={`/books/pqpa/${prev.slug}`}
|
groups={mobileNavGroups}
|
||||||
className={cn(
|
currentSlug={currentSlug}
|
||||||
buttonVariants({ variant: "outline", size: "sm" }),
|
bookTitle="Perfect Questions Perfect Answers"
|
||||||
"gap-1.5",
|
/>
|
||||||
)}
|
{prev ? (
|
||||||
>
|
<Link
|
||||||
<ChevronLeft className="size-4" />
|
href={`/books/pqpa/${prev.slug}`}
|
||||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
className={cn(
|
||||||
{prev.type === "chapter" && prev.chapter != null
|
buttonVariants({ variant: "outline", size: "sm" }),
|
||||||
? `Ch. ${prev.chapter}`
|
"gap-1.5",
|
||||||
: prev.label}
|
)}
|
||||||
</span>
|
>
|
||||||
<span className="sm:hidden">Previous</span>
|
<ChevronLeft className="size-4" />
|
||||||
</Link>
|
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||||
) : (
|
{prev.type === "chapter" && prev.chapter != null
|
||||||
<div />
|
? `Ch. ${prev.chapter}`
|
||||||
)}
|
: prev.label}
|
||||||
|
</span>
|
||||||
|
<span className="sm:hidden">Previous</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div className="hidden lg:block" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{next ? (
|
{next ? (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
|||||||
import { buttonVariants } from "@/components/ui/button";
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Page
|
// Page
|
||||||
@@ -64,7 +65,12 @@ export default async function RvChapterPage({
|
|||||||
{/* Main content */}
|
{/* Main content */}
|
||||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||||
{/* Top navigation */}
|
{/* Top navigation */}
|
||||||
<RvNav prev={prev} next={next} />
|
<RvNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card>
|
||||||
@@ -82,7 +88,12 @@ export default async function RvChapterPage({
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Bottom navigation */}
|
{/* Bottom navigation */}
|
||||||
<RvNav prev={prev} next={next} />
|
<RvNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -174,31 +185,70 @@ function SidebarLink({
|
|||||||
function RvNav({
|
function RvNav({
|
||||||
prev,
|
prev,
|
||||||
next,
|
next,
|
||||||
|
sidebarItems,
|
||||||
|
currentSlug,
|
||||||
}: {
|
}: {
|
||||||
prev: RvSidebarItem | null;
|
prev: RvSidebarItem | null;
|
||||||
next: 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 (
|
return (
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
{prev ? (
|
<div className="flex items-center gap-2">
|
||||||
<Link
|
<MobileNav
|
||||||
href={`/books/rv/${prev.slug}`}
|
groups={mobileNavGroups}
|
||||||
className={cn(
|
currentSlug={currentSlug}
|
||||||
buttonVariants({ variant: "outline", size: "sm" }),
|
bookTitle="Rāja-vidyā: The King of Knowledge"
|
||||||
"gap-1.5",
|
/>
|
||||||
)}
|
{prev ? (
|
||||||
>
|
<Link
|
||||||
<ChevronLeft className="size-4" />
|
href={`/books/rv/${prev.slug}`}
|
||||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
className={cn(
|
||||||
{prev.type === "chapter" && prev.chapter != null
|
buttonVariants({ variant: "outline", size: "sm" }),
|
||||||
? `Ch. ${prev.chapter}`
|
"gap-1.5",
|
||||||
: prev.label}
|
)}
|
||||||
</span>
|
>
|
||||||
<span className="sm:hidden">Previous</span>
|
<ChevronLeft className="size-4" />
|
||||||
</Link>
|
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||||
) : (
|
{prev.type === "chapter" && prev.chapter != null
|
||||||
<div />
|
? `Ch. ${prev.chapter}`
|
||||||
)}
|
: prev.label}
|
||||||
|
</span>
|
||||||
|
<span className="sm:hidden">Previous</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div className="hidden lg:block" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{next ? (
|
{next ? (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { PageHeader } from "@/components/page-header";
|
|||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { getBookMeta, getSingleVerse, getChapterVerseIndex } from "@/lib/api";
|
import { getBookMeta, getSingleVerse, getChapterVerseIndex } from "@/lib/api";
|
||||||
import { ChapterViewer } from "@/app/books/chapter-viewer";
|
import { ChapterViewer } from "@/app/books/chapter-viewer";
|
||||||
|
import type { MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
type ChapterInfo = {
|
type ChapterInfo = {
|
||||||
number: number;
|
number: number;
|
||||||
@@ -48,6 +49,20 @@ export default async function SbVersePage({
|
|||||||
);
|
);
|
||||||
if (!verseData) notFound();
|
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 (
|
return (
|
||||||
<div className="min-h-screen bg-background">
|
<div className="min-h-screen bg-background">
|
||||||
<PageHeader sticky wide>
|
<PageHeader sticky wide>
|
||||||
@@ -76,6 +91,8 @@ export default async function SbVersePage({
|
|||||||
chapter={parseInt(chapter)}
|
chapter={parseInt(chapter)}
|
||||||
showBengali={false}
|
showBengali={false}
|
||||||
basePath={`/books/sb/${canto}/${chapter}`}
|
basePath={`/books/sb/${canto}/${chapter}`}
|
||||||
|
mobileNavGroups={mobileNavGroups}
|
||||||
|
mobileNavBookTitle={`SB ${canto}.${chapter}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { PageHeader } from "@/components/page-header";
|
|||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { getBookMeta, getSingleVerse, getChapterVerseIndex } from "@/lib/api";
|
import { getBookMeta, getSingleVerse, getChapterVerseIndex } from "@/lib/api";
|
||||||
import { ChapterViewer } from "@/app/books/chapter-viewer";
|
import { ChapterViewer } from "@/app/books/chapter-viewer";
|
||||||
|
import type { MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
type Sb1962Meta = {
|
type Sb1962Meta = {
|
||||||
book: string;
|
book: string;
|
||||||
@@ -46,6 +47,23 @@ export default async function VersePage({
|
|||||||
);
|
);
|
||||||
if (!verse) notFound();
|
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 (
|
return (
|
||||||
<div className="min-h-screen bg-background">
|
<div className="min-h-screen bg-background">
|
||||||
<PageHeader sticky wide>
|
<PageHeader sticky wide>
|
||||||
@@ -74,6 +92,8 @@ export default async function VersePage({
|
|||||||
chapter={parseInt(chapter)}
|
chapter={parseInt(chapter)}
|
||||||
basePath={`/books/sb1962/${chapter}`}
|
basePath={`/books/sb1962/${chapter}`}
|
||||||
showBengali={false}
|
showBengali={false}
|
||||||
|
mobileNavGroups={mobileNavGroups}
|
||||||
|
mobileNavBookTitle={`Śrīmad-Bhāgavatam (1962) — Ch. ${chapter}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
|||||||
import { buttonVariants } from "@/components/ui/button";
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Page
|
// Page
|
||||||
@@ -70,7 +71,12 @@ export default async function SsrChapterPage({
|
|||||||
{/* Main content */}
|
{/* Main content */}
|
||||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||||
{/* Top navigation */}
|
{/* Top navigation */}
|
||||||
<SsrNav prev={prev} next={next} />
|
<SsrNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card>
|
||||||
@@ -88,7 +94,12 @@ export default async function SsrChapterPage({
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Bottom navigation */}
|
{/* Bottom navigation */}
|
||||||
<SsrNav prev={prev} next={next} />
|
<SsrNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -225,29 +236,89 @@ function SidebarLink({
|
|||||||
function SsrNav({
|
function SsrNav({
|
||||||
prev,
|
prev,
|
||||||
next,
|
next,
|
||||||
|
sidebarItems,
|
||||||
|
currentSlug,
|
||||||
}: {
|
}: {
|
||||||
prev: SsrSidebarItem | null;
|
prev: SsrSidebarItem | null;
|
||||||
next: 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 (
|
return (
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
{prev ? (
|
<div className="flex items-center gap-2">
|
||||||
<Link
|
<MobileNav
|
||||||
href={`/books/ssr/${prev.slug}`}
|
groups={mobileNavGroups}
|
||||||
className={cn(
|
currentSlug={currentSlug}
|
||||||
buttonVariants({ variant: "outline", size: "sm" }),
|
bookTitle="The Science of Self-Realization"
|
||||||
"gap-1.5",
|
/>
|
||||||
)}
|
{prev ? (
|
||||||
>
|
<Link
|
||||||
<ChevronLeft className="size-4" />
|
href={`/books/ssr/${prev.slug}`}
|
||||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
className={cn(
|
||||||
{prev.label}
|
buttonVariants({ variant: "outline", size: "sm" }),
|
||||||
</span>
|
"gap-1.5",
|
||||||
<span className="sm:hidden">Previous</span>
|
)}
|
||||||
</Link>
|
>
|
||||||
) : (
|
<ChevronLeft className="size-4" />
|
||||||
<div />
|
<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 ? (
|
{next ? (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
|||||||
import { buttonVariants } from "@/components/ui/button";
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Page
|
// Page
|
||||||
@@ -64,7 +65,12 @@ export default async function TlcChapterPage({
|
|||||||
{/* Main content */}
|
{/* Main content */}
|
||||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||||
{/* Top navigation */}
|
{/* Top navigation */}
|
||||||
<TlcNav prev={prev} next={next} />
|
<TlcNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card>
|
||||||
@@ -82,7 +88,12 @@ export default async function TlcChapterPage({
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Bottom navigation */}
|
{/* Bottom navigation */}
|
||||||
<TlcNav prev={prev} next={next} />
|
<TlcNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -183,31 +194,70 @@ function SidebarLink({
|
|||||||
function TlcNav({
|
function TlcNav({
|
||||||
prev,
|
prev,
|
||||||
next,
|
next,
|
||||||
|
sidebarItems,
|
||||||
|
currentSlug,
|
||||||
}: {
|
}: {
|
||||||
prev: TlcSidebarItem | null;
|
prev: TlcSidebarItem | null;
|
||||||
next: 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 (
|
return (
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
{prev ? (
|
<div className="flex items-center gap-2">
|
||||||
<Link
|
<MobileNav
|
||||||
href={`/books/tlc/${prev.slug}`}
|
groups={mobileNavGroups}
|
||||||
className={cn(
|
currentSlug={currentSlug}
|
||||||
buttonVariants({ variant: "outline", size: "sm" }),
|
bookTitle="Teachings of Lord Caitanya"
|
||||||
"gap-1.5",
|
/>
|
||||||
)}
|
{prev ? (
|
||||||
>
|
<Link
|
||||||
<ChevronLeft className="size-4" />
|
href={`/books/tlc/${prev.slug}`}
|
||||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
className={cn(
|
||||||
{prev.type === "chapter" && prev.chapter != null
|
buttonVariants({ variant: "outline", size: "sm" }),
|
||||||
? `Ch. ${prev.chapter}`
|
"gap-1.5",
|
||||||
: prev.label}
|
)}
|
||||||
</span>
|
>
|
||||||
<span className="sm:hidden">Previous</span>
|
<ChevronLeft className="size-4" />
|
||||||
</Link>
|
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||||
) : (
|
{prev.type === "chapter" && prev.chapter != null
|
||||||
<div />
|
? `Ch. ${prev.chapter}`
|
||||||
)}
|
: prev.label}
|
||||||
|
</span>
|
||||||
|
<span className="sm:hidden">Previous</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div className="hidden lg:block" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{next ? (
|
{next ? (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
|||||||
import { buttonVariants } from "@/components/ui/button";
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Page
|
// Page
|
||||||
@@ -64,7 +65,12 @@ export default async function TtpChapterPage({
|
|||||||
{/* Main content */}
|
{/* Main content */}
|
||||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||||
{/* Top navigation */}
|
{/* Top navigation */}
|
||||||
<TtpNav prev={prev} next={next} />
|
<TtpNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card>
|
||||||
@@ -82,7 +88,12 @@ export default async function TtpChapterPage({
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Bottom navigation */}
|
{/* Bottom navigation */}
|
||||||
<TtpNav prev={prev} next={next} />
|
<TtpNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
sidebarItems={sidebarItems}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -174,31 +185,70 @@ function SidebarLink({
|
|||||||
function TtpNav({
|
function TtpNav({
|
||||||
prev,
|
prev,
|
||||||
next,
|
next,
|
||||||
|
sidebarItems,
|
||||||
|
currentSlug,
|
||||||
}: {
|
}: {
|
||||||
prev: TtpSidebarItem | null;
|
prev: TtpSidebarItem | null;
|
||||||
next: 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 (
|
return (
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
{prev ? (
|
<div className="flex items-center gap-2">
|
||||||
<Link
|
<MobileNav
|
||||||
href={`/books/ttp/${prev.slug}`}
|
groups={mobileNavGroups}
|
||||||
className={cn(
|
currentSlug={currentSlug}
|
||||||
buttonVariants({ variant: "outline", size: "sm" }),
|
bookTitle="Transcendental Teachings of Prahlāda Mahārāja"
|
||||||
"gap-1.5",
|
/>
|
||||||
)}
|
{prev ? (
|
||||||
>
|
<Link
|
||||||
<ChevronLeft className="size-4" />
|
href={`/books/ttp/${prev.slug}`}
|
||||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
className={cn(
|
||||||
{prev.type === "chapter" && prev.chapter != null
|
buttonVariants({ variant: "outline", size: "sm" }),
|
||||||
? `Ch. ${prev.chapter}`
|
"gap-1.5",
|
||||||
: prev.label}
|
)}
|
||||||
</span>
|
>
|
||||||
<span className="sm:hidden">Previous</span>
|
<ChevronLeft className="size-4" />
|
||||||
</Link>
|
<span className="hidden sm:inline truncate max-w-[180px]">
|
||||||
) : (
|
{prev.type === "chapter" && prev.chapter != null
|
||||||
<div />
|
? `Ch. ${prev.chapter}`
|
||||||
)}
|
: prev.label}
|
||||||
|
</span>
|
||||||
|
<span className="sm:hidden">Previous</span>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div className="hidden lg:block" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{next ? (
|
{next ? (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
+55
-19
@@ -7,6 +7,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
|||||||
import { buttonVariants } from "@/components/ui/button";
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { MobileNav, type MobileNavGroup } from "@/components/mobile-nav";
|
||||||
import { prisma } from "@/lib/db";
|
import { prisma } from "@/lib/db";
|
||||||
import type { JsonValue } from "@prisma/client/runtime/library";
|
import type { JsonValue } from "@prisma/client/runtime/library";
|
||||||
|
|
||||||
@@ -127,7 +128,12 @@ export default async function EssayPage({
|
|||||||
{/* Main content */}
|
{/* Main content */}
|
||||||
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
<main className="flex-1 min-w-0 px-6 py-8 space-y-8">
|
||||||
{/* Top navigation */}
|
{/* Top navigation */}
|
||||||
<EssayNav prev={prev} next={next} />
|
<EssayNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
allEssays={allEssays}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<Card>
|
<Card>
|
||||||
@@ -145,7 +151,12 @@ export default async function EssayPage({
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Bottom navigation */}
|
{/* Bottom navigation */}
|
||||||
<EssayNav prev={prev} next={next} />
|
<EssayNav
|
||||||
|
prev={prev}
|
||||||
|
next={next}
|
||||||
|
allEssays={allEssays}
|
||||||
|
currentSlug={slug}
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -196,29 +207,54 @@ function EssaySidebar({
|
|||||||
function EssayNav({
|
function EssayNav({
|
||||||
prev,
|
prev,
|
||||||
next,
|
next,
|
||||||
|
allEssays,
|
||||||
|
currentSlug,
|
||||||
}: {
|
}: {
|
||||||
prev: SidebarItem | null;
|
prev: SidebarItem | null;
|
||||||
next: 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 (
|
return (
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
{prev ? (
|
<div className="flex items-center gap-2">
|
||||||
<Link
|
<MobileNav
|
||||||
href={`/essays/${prev.slug}`}
|
groups={mobileNavGroups}
|
||||||
className={cn(
|
currentSlug={currentSlug}
|
||||||
buttonVariants({ variant: "outline", size: "sm" }),
|
bookTitle="Essays"
|
||||||
"gap-1.5",
|
/>
|
||||||
)}
|
{prev ? (
|
||||||
>
|
<Link
|
||||||
<ChevronLeft className="size-4" />
|
href={`/essays/${prev.slug}`}
|
||||||
<span className="hidden sm:inline truncate max-w-[180px]">
|
className={cn(
|
||||||
{prev.title}
|
buttonVariants({ variant: "outline", size: "sm" }),
|
||||||
</span>
|
"gap-1.5",
|
||||||
<span className="sm:hidden">Previous</span>
|
)}
|
||||||
</Link>
|
>
|
||||||
) : (
|
<ChevronLeft className="size-4" />
|
||||||
<div />
|
<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 ? (
|
{next ? (
|
||||||
<Link
|
<Link
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { Menu } from "lucide-react";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Drawer,
|
||||||
|
DrawerClose,
|
||||||
|
DrawerContent,
|
||||||
|
DrawerHeader,
|
||||||
|
DrawerTitle,
|
||||||
|
DrawerTrigger,
|
||||||
|
} from "@/components/ui/drawer";
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Types
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export type MobileNavItem = {
|
||||||
|
slug: string;
|
||||||
|
label: string;
|
||||||
|
href: string;
|
||||||
|
type: string;
|
||||||
|
/** For hierarchical books (SSR, DS) — parent chapter number */
|
||||||
|
parentChapter?: number | null;
|
||||||
|
/** Whether this is a non-clickable parent heading */
|
||||||
|
isParent?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MobileNavGroup = {
|
||||||
|
title?: string;
|
||||||
|
items: MobileNavItem[];
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Component
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mobile sidebar drawer triggered by a menu button.
|
||||||
|
*
|
||||||
|
* Usage: Place this component alongside the prev/next buttons in any
|
||||||
|
* book reader page. It renders a menu icon button (visible only on
|
||||||
|
* mobile / below `lg` breakpoint) that opens a bottom drawer with
|
||||||
|
* the full sidebar navigation.
|
||||||
|
*
|
||||||
|
* Supports two modes:
|
||||||
|
* 1. **Flat groups** — pass `groups` for simple grouped lists
|
||||||
|
* (Front Matter, Chapters, etc.)
|
||||||
|
* 2. **Hierarchical** — pass `groups` where some items have
|
||||||
|
* `isParent: true` to render parent headings with indented children
|
||||||
|
*/
|
||||||
|
export function MobileNav({
|
||||||
|
groups,
|
||||||
|
currentSlug,
|
||||||
|
bookTitle,
|
||||||
|
}: {
|
||||||
|
groups: MobileNavGroup[];
|
||||||
|
currentSlug: string;
|
||||||
|
bookTitle?: string;
|
||||||
|
}) {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Drawer open={open} onOpenChange={setOpen} direction="left">
|
||||||
|
<DrawerTrigger
|
||||||
|
className={cn(
|
||||||
|
buttonVariants({ variant: "outline", size: "sm" }),
|
||||||
|
"lg:hidden gap-1.5",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Menu className="size-4" />
|
||||||
|
<span className="hidden sm:inline">Contents</span>
|
||||||
|
</DrawerTrigger>
|
||||||
|
<DrawerContent direction="left" className="h-full">
|
||||||
|
<DrawerHeader className="text-left border-b border-border pb-4 mb-2">
|
||||||
|
<DrawerTitle>{bookTitle ?? "Contents"}</DrawerTitle>
|
||||||
|
</DrawerHeader>
|
||||||
|
<nav className="overflow-y-auto px-4 pb-6 pt-2 space-y-4">
|
||||||
|
{groups.map((group, gi) => (
|
||||||
|
<div key={gi}>
|
||||||
|
{group.title && (
|
||||||
|
<h3 className="text-xs font-bold uppercase tracking-wider text-muted-foreground mb-2 px-2">
|
||||||
|
{group.title}
|
||||||
|
</h3>
|
||||||
|
)}
|
||||||
|
<div className="flex flex-col gap-0.5">
|
||||||
|
{group.items.map((item) => {
|
||||||
|
if (item.isParent) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={item.slug}
|
||||||
|
className="px-2 py-1.5 text-xs font-bold text-muted-foreground mt-2"
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isActive = item.slug === currentSlug;
|
||||||
|
const isChild = item.parentChapter != null && !item.isParent;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DrawerClose key={item.slug} asChild>
|
||||||
|
<Link
|
||||||
|
href={item.href}
|
||||||
|
className={cn(
|
||||||
|
"px-2 py-2 rounded-md text-sm transition-colors truncate block",
|
||||||
|
isChild && "pl-4",
|
||||||
|
isActive
|
||||||
|
? "bg-primary/10 text-primary font-medium"
|
||||||
|
: "text-muted-foreground hover:bg-muted hover:text-foreground",
|
||||||
|
)}
|
||||||
|
onClick={() => setOpen(false)}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</Link>
|
||||||
|
</DrawerClose>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</nav>
|
||||||
|
</DrawerContent>
|
||||||
|
</Drawer>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
import { Drawer as DrawerPrimitive } from "vaul";
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
const Drawer = ({
|
||||||
|
shouldScaleBackground = true,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
|
||||||
|
<DrawerPrimitive.Root
|
||||||
|
shouldScaleBackground={shouldScaleBackground}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
Drawer.displayName = "Drawer";
|
||||||
|
|
||||||
|
const DrawerTrigger = DrawerPrimitive.Trigger;
|
||||||
|
|
||||||
|
const DrawerPortal = DrawerPrimitive.Portal;
|
||||||
|
|
||||||
|
const DrawerClose = DrawerPrimitive.Close;
|
||||||
|
|
||||||
|
const DrawerOverlay = React.forwardRef<
|
||||||
|
React.ComponentRef<typeof DrawerPrimitive.Overlay>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<DrawerPrimitive.Overlay
|
||||||
|
ref={ref}
|
||||||
|
className={cn("fixed inset-0 z-50 bg-black/80", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName;
|
||||||
|
|
||||||
|
const DrawerContent = React.forwardRef<
|
||||||
|
React.ComponentRef<typeof DrawerPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content> & {
|
||||||
|
direction?: "top" | "bottom" | "left" | "right";
|
||||||
|
}
|
||||||
|
>(({ className, children, direction = "bottom", ...props }, ref) => (
|
||||||
|
<DrawerPortal>
|
||||||
|
<DrawerOverlay />
|
||||||
|
<DrawerPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"fixed z-50 flex flex-col border bg-background",
|
||||||
|
direction === "left" &&
|
||||||
|
"inset-y-0 left-0 h-full w-[80%] max-w-sm rounded-r-[10px]",
|
||||||
|
direction === "right" &&
|
||||||
|
"inset-y-0 right-0 h-full w-[80%] max-w-sm rounded-l-[10px]",
|
||||||
|
direction === "bottom" &&
|
||||||
|
"inset-x-0 bottom-0 mt-24 h-auto rounded-t-[10px]",
|
||||||
|
direction === "top" && "inset-x-0 top-0 mb-24 h-auto rounded-b-[10px]",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{(direction === "bottom" || direction === "top") && (
|
||||||
|
<div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
|
||||||
|
)}
|
||||||
|
{children}
|
||||||
|
</DrawerPrimitive.Content>
|
||||||
|
</DrawerPortal>
|
||||||
|
));
|
||||||
|
DrawerContent.displayName = "DrawerContent";
|
||||||
|
|
||||||
|
const DrawerHeader = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
|
<div
|
||||||
|
className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
DrawerHeader.displayName = "DrawerHeader";
|
||||||
|
|
||||||
|
const DrawerFooter = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
|
<div
|
||||||
|
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
DrawerFooter.displayName = "DrawerFooter";
|
||||||
|
|
||||||
|
const DrawerTitle = React.forwardRef<
|
||||||
|
React.ComponentRef<typeof DrawerPrimitive.Title>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<DrawerPrimitive.Title
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"text-lg font-semibold leading-none tracking-tight",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
DrawerTitle.displayName = DrawerPrimitive.Title.displayName;
|
||||||
|
|
||||||
|
const DrawerDescription = React.forwardRef<
|
||||||
|
React.ComponentRef<typeof DrawerPrimitive.Description>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<DrawerPrimitive.Description
|
||||||
|
ref={ref}
|
||||||
|
className={cn("text-sm text-muted-foreground", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
DrawerDescription.displayName = DrawerPrimitive.Description.displayName;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Drawer,
|
||||||
|
DrawerPortal,
|
||||||
|
DrawerOverlay,
|
||||||
|
DrawerTrigger,
|
||||||
|
DrawerClose,
|
||||||
|
DrawerContent,
|
||||||
|
DrawerHeader,
|
||||||
|
DrawerFooter,
|
||||||
|
DrawerTitle,
|
||||||
|
DrawerDescription,
|
||||||
|
};
|
||||||
Generated
+486
-2
@@ -22,7 +22,8 @@
|
|||||||
"react-dom": "19.2.4",
|
"react-dom": "19.2.4",
|
||||||
"shadcn": "^4.2.0",
|
"shadcn": "^4.2.0",
|
||||||
"tailwind-merge": "^3.5.0",
|
"tailwind-merge": "^3.5.0",
|
||||||
"tw-animate-css": "^1.4.0"
|
"tw-animate-css": "^1.4.0",
|
||||||
|
"vaul": "^1.1.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/postcss": "^4",
|
"@tailwindcss/postcss": "^4",
|
||||||
@@ -2008,6 +2009,337 @@
|
|||||||
"@prisma/debug": "6.19.3"
|
"@prisma/debug": "6.19.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/primitive": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-compose-refs": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-context": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-dialog": {
|
||||||
|
"version": "1.1.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz",
|
||||||
|
"integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/primitive": "1.1.3",
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.2",
|
||||||
|
"@radix-ui/react-context": "1.1.2",
|
||||||
|
"@radix-ui/react-dismissable-layer": "1.1.11",
|
||||||
|
"@radix-ui/react-focus-guards": "1.1.3",
|
||||||
|
"@radix-ui/react-focus-scope": "1.1.7",
|
||||||
|
"@radix-ui/react-id": "1.1.1",
|
||||||
|
"@radix-ui/react-portal": "1.1.9",
|
||||||
|
"@radix-ui/react-presence": "1.1.5",
|
||||||
|
"@radix-ui/react-primitive": "2.1.3",
|
||||||
|
"@radix-ui/react-slot": "1.2.3",
|
||||||
|
"@radix-ui/react-use-controllable-state": "1.2.2",
|
||||||
|
"aria-hidden": "^1.2.4",
|
||||||
|
"react-remove-scroll": "^2.6.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-dismissable-layer": {
|
||||||
|
"version": "1.1.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz",
|
||||||
|
"integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/primitive": "1.1.3",
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.2",
|
||||||
|
"@radix-ui/react-primitive": "2.1.3",
|
||||||
|
"@radix-ui/react-use-callback-ref": "1.1.1",
|
||||||
|
"@radix-ui/react-use-escape-keydown": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-focus-guards": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-focus-scope": {
|
||||||
|
"version": "1.1.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz",
|
||||||
|
"integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.2",
|
||||||
|
"@radix-ui/react-primitive": "2.1.3",
|
||||||
|
"@radix-ui/react-use-callback-ref": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-id": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-portal": {
|
||||||
|
"version": "1.1.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz",
|
||||||
|
"integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-primitive": "2.1.3",
|
||||||
|
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-presence": {
|
||||||
|
"version": "1.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz",
|
||||||
|
"integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.2",
|
||||||
|
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-primitive": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
|
||||||
|
"integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-slot": "1.2.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-slot": {
|
||||||
|
"version": "1.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
|
||||||
|
"integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-use-callback-ref": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-use-controllable-state": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
|
||||||
|
"integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-use-effect-event": "0.0.2",
|
||||||
|
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-use-effect-event": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz",
|
||||||
|
"integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-use-escape-keydown": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-use-callback-ref": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-use-layout-effect": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@rtsao/scc": {
|
"node_modules/@rtsao/scc": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
|
||||||
@@ -2211,7 +2543,7 @@
|
|||||||
"version": "19.2.3",
|
"version": "19.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
|
||||||
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
|
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
|
||||||
"dev": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^19.2.0"
|
"@types/react": "^19.2.0"
|
||||||
@@ -2645,6 +2977,18 @@
|
|||||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||||
"license": "Python-2.0"
|
"license": "Python-2.0"
|
||||||
},
|
},
|
||||||
|
"node_modules/aria-hidden": {
|
||||||
|
"version": "1.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
|
||||||
|
"integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/aria-query": {
|
"node_modules/aria-query": {
|
||||||
"version": "5.3.2",
|
"version": "5.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
|
||||||
@@ -3684,6 +4028,12 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/detect-node-es": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/diff": {
|
"node_modules/diff": {
|
||||||
"version": "8.0.4",
|
"version": "8.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz",
|
||||||
@@ -5103,6 +5453,15 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/get-nonce": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/get-own-enumerable-keys": {
|
"node_modules/get-own-enumerable-keys": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/get-own-enumerable-keys/-/get-own-enumerable-keys-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/get-own-enumerable-keys/-/get-own-enumerable-keys-1.0.0.tgz",
|
||||||
@@ -7724,6 +8083,75 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/react-remove-scroll": {
|
||||||
|
"version": "2.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz",
|
||||||
|
"integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"react-remove-scroll-bar": "^2.3.7",
|
||||||
|
"react-style-singleton": "^2.2.3",
|
||||||
|
"tslib": "^2.1.0",
|
||||||
|
"use-callback-ref": "^1.3.3",
|
||||||
|
"use-sidecar": "^1.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-remove-scroll-bar": {
|
||||||
|
"version": "2.3.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz",
|
||||||
|
"integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"react-style-singleton": "^2.2.2",
|
||||||
|
"tslib": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-style-singleton": {
|
||||||
|
"version": "2.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
|
||||||
|
"integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"get-nonce": "^1.0.0",
|
||||||
|
"tslib": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/readdirp": {
|
"node_modules/readdirp": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
||||||
@@ -9212,6 +9640,49 @@
|
|||||||
"punycode": "^2.1.0"
|
"punycode": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/use-callback-ref": {
|
||||||
|
"version": "1.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
|
||||||
|
"integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/use-sidecar": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"detect-node-es": "^1.1.0",
|
||||||
|
"tslib": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/use-sync-external-store": {
|
"node_modules/use-sync-external-store": {
|
||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
|
||||||
@@ -9245,6 +9716,19 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vaul": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/vaul/-/vaul-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-dialog": "^1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/web-streams-polyfill": {
|
"node_modules/web-streams-polyfill": {
|
||||||
"version": "3.3.3",
|
"version": "3.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
|
||||||
|
|||||||
+2
-1
@@ -23,7 +23,8 @@
|
|||||||
"react-dom": "19.2.4",
|
"react-dom": "19.2.4",
|
||||||
"shadcn": "^4.2.0",
|
"shadcn": "^4.2.0",
|
||||||
"tailwind-merge": "^3.5.0",
|
"tailwind-merge": "^3.5.0",
|
||||||
"tw-animate-css": "^1.4.0"
|
"tw-animate-css": "^1.4.0",
|
||||||
|
"vaul": "^1.1.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/postcss": "^4",
|
"@tailwindcss/postcss": "^4",
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
User-agent: *
|
||||||
|
Disallow: /
|
||||||
@@ -686,6 +686,135 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@prisma/debug" "6.19.3"
|
"@prisma/debug" "6.19.3"
|
||||||
|
|
||||||
|
"@radix-ui/primitive@1.1.3":
|
||||||
|
version "1.1.3"
|
||||||
|
resolved "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz"
|
||||||
|
integrity sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==
|
||||||
|
|
||||||
|
"@radix-ui/react-compose-refs@1.1.2":
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz"
|
||||||
|
integrity sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==
|
||||||
|
|
||||||
|
"@radix-ui/react-context@1.1.2":
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz"
|
||||||
|
integrity sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==
|
||||||
|
|
||||||
|
"@radix-ui/react-dialog@^1.1.1":
|
||||||
|
version "1.1.15"
|
||||||
|
resolved "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz"
|
||||||
|
integrity sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==
|
||||||
|
dependencies:
|
||||||
|
"@radix-ui/primitive" "1.1.3"
|
||||||
|
"@radix-ui/react-compose-refs" "1.1.2"
|
||||||
|
"@radix-ui/react-context" "1.1.2"
|
||||||
|
"@radix-ui/react-dismissable-layer" "1.1.11"
|
||||||
|
"@radix-ui/react-focus-guards" "1.1.3"
|
||||||
|
"@radix-ui/react-focus-scope" "1.1.7"
|
||||||
|
"@radix-ui/react-id" "1.1.1"
|
||||||
|
"@radix-ui/react-portal" "1.1.9"
|
||||||
|
"@radix-ui/react-presence" "1.1.5"
|
||||||
|
"@radix-ui/react-primitive" "2.1.3"
|
||||||
|
"@radix-ui/react-slot" "1.2.3"
|
||||||
|
"@radix-ui/react-use-controllable-state" "1.2.2"
|
||||||
|
aria-hidden "^1.2.4"
|
||||||
|
react-remove-scroll "^2.6.3"
|
||||||
|
|
||||||
|
"@radix-ui/react-dismissable-layer@1.1.11":
|
||||||
|
version "1.1.11"
|
||||||
|
resolved "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz"
|
||||||
|
integrity sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==
|
||||||
|
dependencies:
|
||||||
|
"@radix-ui/primitive" "1.1.3"
|
||||||
|
"@radix-ui/react-compose-refs" "1.1.2"
|
||||||
|
"@radix-ui/react-primitive" "2.1.3"
|
||||||
|
"@radix-ui/react-use-callback-ref" "1.1.1"
|
||||||
|
"@radix-ui/react-use-escape-keydown" "1.1.1"
|
||||||
|
|
||||||
|
"@radix-ui/react-focus-guards@1.1.3":
|
||||||
|
version "1.1.3"
|
||||||
|
resolved "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz"
|
||||||
|
integrity sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==
|
||||||
|
|
||||||
|
"@radix-ui/react-focus-scope@1.1.7":
|
||||||
|
version "1.1.7"
|
||||||
|
resolved "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz"
|
||||||
|
integrity sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==
|
||||||
|
dependencies:
|
||||||
|
"@radix-ui/react-compose-refs" "1.1.2"
|
||||||
|
"@radix-ui/react-primitive" "2.1.3"
|
||||||
|
"@radix-ui/react-use-callback-ref" "1.1.1"
|
||||||
|
|
||||||
|
"@radix-ui/react-id@1.1.1":
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz"
|
||||||
|
integrity sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==
|
||||||
|
dependencies:
|
||||||
|
"@radix-ui/react-use-layout-effect" "1.1.1"
|
||||||
|
|
||||||
|
"@radix-ui/react-portal@1.1.9":
|
||||||
|
version "1.1.9"
|
||||||
|
resolved "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz"
|
||||||
|
integrity sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==
|
||||||
|
dependencies:
|
||||||
|
"@radix-ui/react-primitive" "2.1.3"
|
||||||
|
"@radix-ui/react-use-layout-effect" "1.1.1"
|
||||||
|
|
||||||
|
"@radix-ui/react-presence@1.1.5":
|
||||||
|
version "1.1.5"
|
||||||
|
resolved "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz"
|
||||||
|
integrity sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==
|
||||||
|
dependencies:
|
||||||
|
"@radix-ui/react-compose-refs" "1.1.2"
|
||||||
|
"@radix-ui/react-use-layout-effect" "1.1.1"
|
||||||
|
|
||||||
|
"@radix-ui/react-primitive@2.1.3":
|
||||||
|
version "2.1.3"
|
||||||
|
resolved "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz"
|
||||||
|
integrity sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==
|
||||||
|
dependencies:
|
||||||
|
"@radix-ui/react-slot" "1.2.3"
|
||||||
|
|
||||||
|
"@radix-ui/react-slot@1.2.3":
|
||||||
|
version "1.2.3"
|
||||||
|
resolved "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz"
|
||||||
|
integrity sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==
|
||||||
|
dependencies:
|
||||||
|
"@radix-ui/react-compose-refs" "1.1.2"
|
||||||
|
|
||||||
|
"@radix-ui/react-use-callback-ref@1.1.1":
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz"
|
||||||
|
integrity sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==
|
||||||
|
|
||||||
|
"@radix-ui/react-use-controllable-state@1.2.2":
|
||||||
|
version "1.2.2"
|
||||||
|
resolved "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz"
|
||||||
|
integrity sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==
|
||||||
|
dependencies:
|
||||||
|
"@radix-ui/react-use-effect-event" "0.0.2"
|
||||||
|
"@radix-ui/react-use-layout-effect" "1.1.1"
|
||||||
|
|
||||||
|
"@radix-ui/react-use-effect-event@0.0.2":
|
||||||
|
version "0.0.2"
|
||||||
|
resolved "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz"
|
||||||
|
integrity sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==
|
||||||
|
dependencies:
|
||||||
|
"@radix-ui/react-use-layout-effect" "1.1.1"
|
||||||
|
|
||||||
|
"@radix-ui/react-use-escape-keydown@1.1.1":
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz"
|
||||||
|
integrity sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==
|
||||||
|
dependencies:
|
||||||
|
"@radix-ui/react-use-callback-ref" "1.1.1"
|
||||||
|
|
||||||
|
"@radix-ui/react-use-layout-effect@1.1.1":
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz"
|
||||||
|
integrity sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==
|
||||||
|
|
||||||
"@rtsao/scc@^1.1.0":
|
"@rtsao/scc@^1.1.0":
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz"
|
resolved "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz"
|
||||||
@@ -791,12 +920,12 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
undici-types "~6.21.0"
|
undici-types "~6.21.0"
|
||||||
|
|
||||||
"@types/react-dom@^19":
|
"@types/react-dom@*", "@types/react-dom@^19":
|
||||||
version "19.2.3"
|
version "19.2.3"
|
||||||
resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz"
|
resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz"
|
||||||
integrity sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==
|
integrity sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==
|
||||||
|
|
||||||
"@types/react@^17 || ^18 || ^19", "@types/react@^19", "@types/react@^19.2.0":
|
"@types/react@*", "@types/react@^17 || ^18 || ^19", "@types/react@^19", "@types/react@^19.2.0":
|
||||||
version "19.2.14"
|
version "19.2.14"
|
||||||
resolved "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz"
|
resolved "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz"
|
||||||
integrity sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==
|
integrity sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==
|
||||||
@@ -998,6 +1127,13 @@ argparse@^2.0.1:
|
|||||||
resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz"
|
resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz"
|
||||||
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
|
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
|
||||||
|
|
||||||
|
aria-hidden@^1.2.4:
|
||||||
|
version "1.2.6"
|
||||||
|
resolved "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz"
|
||||||
|
integrity sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==
|
||||||
|
dependencies:
|
||||||
|
tslib "^2.0.0"
|
||||||
|
|
||||||
aria-query@^5.3.2:
|
aria-query@^5.3.2:
|
||||||
version "5.3.2"
|
version "5.3.2"
|
||||||
resolved "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz"
|
resolved "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz"
|
||||||
@@ -1578,6 +1714,11 @@ detect-libc@^2.0.3, detect-libc@^2.1.2:
|
|||||||
resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz"
|
resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz"
|
||||||
integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==
|
integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==
|
||||||
|
|
||||||
|
detect-node-es@^1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz"
|
||||||
|
integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==
|
||||||
|
|
||||||
diff@^8.0.2:
|
diff@^8.0.2:
|
||||||
version "8.0.4"
|
version "8.0.4"
|
||||||
resolved "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz"
|
resolved "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz"
|
||||||
@@ -2401,6 +2542,11 @@ get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@
|
|||||||
hasown "^2.0.2"
|
hasown "^2.0.2"
|
||||||
math-intrinsics "^1.1.0"
|
math-intrinsics "^1.1.0"
|
||||||
|
|
||||||
|
get-nonce@^1.0.0:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz"
|
||||||
|
integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==
|
||||||
|
|
||||||
get-own-enumerable-keys@^1.0.0:
|
get-own-enumerable-keys@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.npmjs.org/get-own-enumerable-keys/-/get-own-enumerable-keys-1.0.0.tgz"
|
resolved "https://registry.npmjs.org/get-own-enumerable-keys/-/get-own-enumerable-keys-1.0.0.tgz"
|
||||||
@@ -3791,7 +3937,7 @@ rc9@^2.1.2:
|
|||||||
defu "^6.1.4"
|
defu "^6.1.4"
|
||||||
destr "^2.0.3"
|
destr "^2.0.3"
|
||||||
|
|
||||||
"react-dom@^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom@^17 || ^18 || ^19", "react-dom@^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", react-dom@>=16.8.0, react-dom@19.2.4:
|
"react-dom@^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom@^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom@^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom@^17 || ^18 || ^19", "react-dom@^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", react-dom@>=16.8.0, react-dom@19.2.4:
|
||||||
version "19.2.4"
|
version "19.2.4"
|
||||||
resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz"
|
resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz"
|
||||||
integrity sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==
|
integrity sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==
|
||||||
@@ -3803,7 +3949,34 @@ react-is@^16.13.1:
|
|||||||
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
|
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
|
||||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||||
|
|
||||||
"react@^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^17 || ^18 || ^19", "react@^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", react@^19.2.4, "react@>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0", react@>=16.8.0, react@19.2.4:
|
react-remove-scroll-bar@^2.3.7:
|
||||||
|
version "2.3.8"
|
||||||
|
resolved "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz"
|
||||||
|
integrity sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==
|
||||||
|
dependencies:
|
||||||
|
react-style-singleton "^2.2.2"
|
||||||
|
tslib "^2.0.0"
|
||||||
|
|
||||||
|
react-remove-scroll@^2.6.3:
|
||||||
|
version "2.7.2"
|
||||||
|
resolved "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz"
|
||||||
|
integrity sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==
|
||||||
|
dependencies:
|
||||||
|
react-remove-scroll-bar "^2.3.7"
|
||||||
|
react-style-singleton "^2.2.3"
|
||||||
|
tslib "^2.1.0"
|
||||||
|
use-callback-ref "^1.3.3"
|
||||||
|
use-sidecar "^1.1.3"
|
||||||
|
|
||||||
|
react-style-singleton@^2.2.2, react-style-singleton@^2.2.3:
|
||||||
|
version "2.2.3"
|
||||||
|
resolved "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz"
|
||||||
|
integrity sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==
|
||||||
|
dependencies:
|
||||||
|
get-nonce "^1.0.0"
|
||||||
|
tslib "^2.0.0"
|
||||||
|
|
||||||
|
"react@^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react@^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react@^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^17 || ^18 || ^19", "react@^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", react@^19.2.4, "react@>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0", react@>=16.8.0, react@19.2.4:
|
||||||
version "19.2.4"
|
version "19.2.4"
|
||||||
resolved "https://registry.npmjs.org/react/-/react-19.2.4.tgz"
|
resolved "https://registry.npmjs.org/react/-/react-19.2.4.tgz"
|
||||||
integrity sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==
|
integrity sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==
|
||||||
@@ -4499,7 +4672,7 @@ tsconfig-paths@^4.2.0:
|
|||||||
minimist "^1.2.6"
|
minimist "^1.2.6"
|
||||||
strip-bom "^3.0.0"
|
strip-bom "^3.0.0"
|
||||||
|
|
||||||
tslib@^2.0.1, tslib@^2.8.0:
|
tslib@^2.0.0, tslib@^2.0.1, tslib@^2.1.0, tslib@^2.8.0:
|
||||||
version "2.8.1"
|
version "2.8.1"
|
||||||
resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz"
|
resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz"
|
||||||
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
||||||
@@ -4679,6 +4852,21 @@ uri-js@^4.2.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
punycode "^2.1.0"
|
punycode "^2.1.0"
|
||||||
|
|
||||||
|
use-callback-ref@^1.3.3:
|
||||||
|
version "1.3.3"
|
||||||
|
resolved "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz"
|
||||||
|
integrity sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==
|
||||||
|
dependencies:
|
||||||
|
tslib "^2.0.0"
|
||||||
|
|
||||||
|
use-sidecar@^1.1.3:
|
||||||
|
version "1.1.3"
|
||||||
|
resolved "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz"
|
||||||
|
integrity sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==
|
||||||
|
dependencies:
|
||||||
|
detect-node-es "^1.1.0"
|
||||||
|
tslib "^2.0.0"
|
||||||
|
|
||||||
use-sync-external-store@^1.6.0:
|
use-sync-external-store@^1.6.0:
|
||||||
version "1.6.0"
|
version "1.6.0"
|
||||||
resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz"
|
resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz"
|
||||||
@@ -4699,6 +4887,13 @@ vary@^1, vary@^1.1.2:
|
|||||||
resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz"
|
resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz"
|
||||||
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
|
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
|
||||||
|
|
||||||
|
vaul@^1.1.2:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.npmjs.org/vaul/-/vaul-1.1.2.tgz"
|
||||||
|
integrity sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==
|
||||||
|
dependencies:
|
||||||
|
"@radix-ui/react-dialog" "^1.1.1"
|
||||||
|
|
||||||
web-streams-polyfill@^3.0.3:
|
web-streams-polyfill@^3.0.3:
|
||||||
version "3.3.3"
|
version "3.3.3"
|
||||||
resolved "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz"
|
resolved "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz"
|
||||||
|
|||||||
Reference in New Issue
Block a user