diff --git a/app/glossary/[letter]/page.tsx b/app/glossary/[letter]/page.tsx index 879a7c26..2e295e3c 100644 --- a/app/glossary/[letter]/page.tsx +++ b/app/glossary/[letter]/page.tsx @@ -3,7 +3,7 @@ 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 { buildOgMeta, extractQuoteFromHl } from "@/lib/og"; import { GlossaryClient } from "../glossary-client"; // --------------------------------------------------------------------------- @@ -11,12 +11,20 @@ import { GlossaryClient } from "../glossary-client"; // --------------------------------------------------------------------------- const DIACRITIC_TO_BASE: Record = { - Ā: "A", Ä: "A", - Ī: "I", É: "I", - Ū: "U", Ü: "U", - Ṛ: "R", Ṝ: "R", - Ś: "S", Ç: "S", Ṣ: "S", - Ñ: "N", Ṇ: "N", Ṅ: "N", + Ā: "A", + Ä: "A", + Ī: "I", + É: "I", + Ū: "U", + Ü: "U", + Ṛ: "R", + Ṝ: "R", + Ś: "S", + Ç: "S", + Ṣ: "S", + Ñ: "N", + Ṇ: "N", + Ṅ: "N", Ṭ: "T", Ḍ: "D", Ḥ: "H", @@ -34,11 +42,53 @@ function getBaseLetter(term: string): string { export async function generateMetadata({ params, + searchParams, }: { params: Promise<{ letter: string }>; + searchParams: Promise>; }): Promise { const { letter } = await params; + const sp = await searchParams; const l = letter.toUpperCase(); + + // If a specific term is referenced via ?term= param, show it in the OG image + const termParam = typeof sp.term === "string" ? sp.term : null; + if (termParam) { + const allEntries = await getAllGlossaryEntries(); + const entry = allEntries.find( + (e) => e.term.toLowerCase() === termParam.toLowerCase(), + ); + if (entry) { + // Strip HTML tags from definition for OG quote + const plainDef = entry.definitionHtml + .replace(/<[^>]*>/g, "") + .replace(/&[^;]+;/g, " ") + .trim(); + + // Check for ?hl= highlight param — extract actual selected text from definition + const hlQuote = extractQuoteFromHl(sp, [entry.definitionHtml]); + + return buildOgMeta({ + title: entry.term, + detail: "Glossary — Prabhupāda Says", + quote: + hlQuote || + (plainDef.length > 260 ? plainDef.slice(0, 257) + "..." : plainDef), + }); + } + } + + // Check for ?hl= without ?term= — try to extract quote from all entries for this letter + const hlQuote = extractQuoteFromHl(sp); + if (hlQuote) { + return buildOgMeta({ + title: `Glossary — ${l}`, + detail: "Sanskrit & Vedic terms", + quote: hlQuote, + }); + } + + // Default: letter-level OG return buildOgMeta({ title: `Glossary — ${l}`, detail: `Sanskrit & Vedic terms starting with ${l}`, diff --git a/app/glossary/glossary-client.tsx b/app/glossary/glossary-client.tsx index fb99ae0b..990de813 100644 --- a/app/glossary/glossary-client.tsx +++ b/app/glossary/glossary-client.tsx @@ -1,6 +1,7 @@ "use client"; import { useState, useMemo, useRef, useEffect, useCallback } from "react"; +import { useRouter } from "next/navigation"; import Link from "next/link"; import { Search, X, Menu, ChevronLeft, ChevronRight } from "lucide-react"; import { Input } from "@/components/ui/input"; @@ -289,6 +290,7 @@ export function GlossaryClient({ letters, letterCounts, }: Props) { + const router = useRouter(); const [query, setQuery] = useState(""); const [activeTermRaw, setActiveTerm] = useState(entries[0]?.term || ""); const contentRef = useRef(null); @@ -347,6 +349,17 @@ export function GlossaryClient({ return idx !== undefined ? entries[idx] : null; }, [entries, termIndex, activeTerm]); + // Update URL with ?term= when active term changes (for OG + shareable links) + useEffect(() => { + const url = new URL(window.location.href); + if (activeTerm) { + url.searchParams.set("term", activeTerm); + } else { + url.searchParams.delete("term"); + } + window.history.replaceState({}, "", url.toString()); + }, [activeTerm]); + const handleSelectTerm = useCallback((term: string) => { setActiveTerm(term); contentRef.current?.scrollIntoView({ behavior: "smooth", block: "start" }); diff --git a/lib/source-reference.ts b/lib/source-reference.ts index 5eb8d256..a258063b 100644 --- a/lib/source-reference.ts +++ b/lib/source-reference.ts @@ -164,8 +164,27 @@ export function getSourceReference(): { return { title: parentTitle, detail: chapterTitle, url }; } - // /glossary — general + // /glossary/[letter]?term=... if (parts[0] === "glossary") { + const h1 = document.querySelector("h1"); + const termFromH1 = h1?.textContent?.replace(/^Glossary:\s*/, "").trim(); + + // Try to get the term from the URL ?term= param + const urlParams = new URLSearchParams(window.location.search); + const termFromUrl = urlParams.get("term"); + + const term = termFromUrl || termFromH1 || null; + + if (term) { + return { title: term, detail: "Glossary — Prabhupāda Says", url }; + } + + // Fallback: letter-level + const letter = parts[1]?.toUpperCase(); + if (letter) { + return { title: `Glossary — ${letter}`, detail: null, url }; + } + return { title: "Glossary", detail: null, url }; }