Files
spsays-training/app/glossary/[letter]/page.tsx
T
2026-05-06 15:39:22 +05:30

107 lines
3.1 KiB
TypeScript

export const dynamic = "force-dynamic";
import type { Metadata } from "next";
import { notFound } from "next/navigation";
import { getAllGlossaryEntries } from "@/lib/api";
import { buildOgMeta } from "@/lib/og";
import { GlossaryClient } from "../glossary-client";
// ---------------------------------------------------------------------------
// Diacritic → base letter mapping
// ---------------------------------------------------------------------------
const DIACRITIC_TO_BASE: Record<string, string> = {
Ā: "A", Ä: "A",
Ī: "I", É: "I",
Ū: "U", Ü: "U",
Ṛ: "R", Ṝ: "R",
Ś: "S", Ç: "S", Ṣ: "S",
Ñ: "N", Ṇ: "N", Ṅ: "N",
Ṭ: "T",
Ḍ: "D",
Ḥ: "H",
};
function getBaseLetter(term: string): string {
if (!term) return "?";
const first = term[0].toUpperCase();
return DIACRITIC_TO_BASE[first] || first;
}
// ---------------------------------------------------------------------------
// Metadata
// ---------------------------------------------------------------------------
export async function generateMetadata({
params,
}: {
params: Promise<{ letter: string }>;
}): Promise<Metadata> {
const { letter } = await params;
const l = letter.toUpperCase();
return buildOgMeta({
title: `Glossary — ${l}`,
detail: `Sanskrit & Vedic terms starting with ${l}`,
quote:
"A comprehensive glossary of Sanskrit and Vedic terms from the books of Śrīla Prabhupāda.",
});
}
// ---------------------------------------------------------------------------
// Page
// ---------------------------------------------------------------------------
export default async function GlossaryLetterPage({
params,
}: {
params: Promise<{ letter: string }>;
}) {
const { letter: rawLetter } = await params;
const activeLetter = rawLetter.toUpperCase();
// Validate — single letter A-Z
if (!/^[A-Z]$/.test(activeLetter)) notFound();
// Fetch all entries (cached by Next.js request dedup within a single render)
const allEntries = await getAllGlossaryEntries();
// Group all entries by base letter
const byLetter: Record<string, typeof allEntries> = {};
for (const entry of allEntries) {
const base = getBaseLetter(entry.term);
if (!byLetter[base]) byLetter[base] = [];
byLetter[base].push(entry);
}
// All available letters (sorted)
const letters = Object.keys(byLetter).sort();
// Entries for the active letter
const letterEntries = byLetter[activeLetter] || [];
if (letterEntries.length === 0) notFound();
// Prepare client data — only the active letter's entries
const clientEntries = letterEntries.map((e) => ({
term: e.term,
definition: e.definition,
definition_html: e.definitionHtml,
}));
// Letter counts for the nav
const letterCounts: Record<string, number> = {};
for (const [l, entries] of Object.entries(byLetter)) {
letterCounts[l] = entries.length;
}
return (
<div className="min-h-screen bg-background">
<GlossaryClient
entries={clientEntries}
activeLetter={activeLetter}
letters={letters}
letterCounts={letterCounts}
/>
</div>
);
}