"use client"; import { useState, useMemo } from "react"; import Link from "next/link"; import { Card, CardHeader, CardTitle, CardDescription, CardContent, } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { cn } from "@/lib/utils"; import { Search } from "lucide-react"; import { ExtractedVerseCount } from "./extracted-verse-count"; export type BookInfo = { slug: string; title: string; author: string; description: string; contentDescription: string; totalVerses: number; href: string; }; /** * Strip diacritics / accents so that "Krsna" matches "Kṛṣṇa", * "Gita" matches "Gītā", "Srimad" matches "Śrīmad", etc. * * Uses Unicode NFD decomposition to split base characters from * combining marks, then removes the marks. Also handles special * IAST characters that don't decompose cleanly via NFD. */ function normalize(text: string): string { return ( text .toLowerCase() // Handle IAST characters that NFD doesn't decompose into ASCII base .replace(/ṛ/g, "r") .replace(/ṝ/g, "r") .replace(/ṣ/g, "s") .replace(/ś/g, "s") .replace(/ṭ/g, "t") .replace(/ḍ/g, "d") .replace(/ṇ/g, "n") .replace(/ñ/g, "n") .replace(/ṅ/g, "n") .replace(/ḥ/g, "h") .replace(/ṁ/g, "m") .replace(/ṃ/g, "m") .replace(/ḷ/g, "l") // NFD decompose + strip combining marks (handles ā→a, ī→i, ū→u, etc.) .normalize("NFD") .replace(/[\u0300-\u036f]/g, "") ); } export function BooksGrid({ books }: { books: BookInfo[] }) { const [query, setQuery] = useState(""); const normalizedBooks = useMemo( () => books.map((book) => ({ book, searchText: normalize( `${book.title} ${book.contentDescription} ${book.description} ${book.slug}`, ), })), [books], ); const filtered = useMemo(() => { const base = query.trim() ? normalizedBooks .filter((entry) => entry.searchText.includes(normalize(query.trim())), ) .map((entry) => entry.book) : books; return [...base].sort((a, b) => normalize(a.title).localeCompare(normalize(b.title)), ); }, [books, normalizedBooks, query]); return (
{filtered.length === 0 ? "No books found" : `${filtered.length} book${filtered.length === 1 ? "" : "s"} found`}
)} {/* Grid */}