Files
biblical-guide.com/lib/bible-search.ts
Andrei 4287a74805 fix: add accessibility attributes, fix placeholder, ensure consistent abbreviation matching
- Add aria-label and role attributes to search TextField for screen readers
- Add role="listbox" and aria-label to search results Paper
- Add role="option", aria-selected, and minHeight to ListItemButton for accessibility
- Update placeholder from "John 3:16" to "John 3" to match chapter-level search
- Change parseReference abbreviation matching from === to startsWith() for consistency with searchBooks

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 19:31:30 +00:00

144 lines
5.8 KiB
TypeScript

// Bible books data with abbreviations
const BIBLE_BOOKS = [
// Old Testament
{ id: 1, name: 'Genesis', abbr: 'Gen', chapters: 50 },
{ id: 2, name: 'Exodus', abbr: 'Ex', chapters: 40 },
{ id: 3, name: 'Leviticus', abbr: 'Lev', chapters: 27 },
{ id: 4, name: 'Numbers', abbr: 'Num', chapters: 36 },
{ id: 5, name: 'Deuteronomy', abbr: 'Deut', chapters: 34 },
{ id: 6, name: 'Joshua', abbr: 'Josh', chapters: 24 },
{ id: 7, name: 'Judges', abbr: 'Judg', chapters: 21 },
{ id: 8, name: 'Ruth', abbr: 'Ruth', chapters: 4 },
{ id: 9, name: '1 Samuel', abbr: '1Sam', chapters: 31 },
{ id: 10, name: '2 Samuel', abbr: '2Sam', chapters: 24 },
{ id: 11, name: '1 Kings', abbr: '1Kgs', chapters: 22 },
{ id: 12, name: '2 Kings', abbr: '2Kgs', chapters: 25 },
{ id: 13, name: '1 Chronicles', abbr: '1Chr', chapters: 29 },
{ id: 14, name: '2 Chronicles', abbr: '2Chr', chapters: 36 },
{ id: 15, name: 'Ezra', abbr: 'Ezra', chapters: 10 },
{ id: 16, name: 'Nehemiah', abbr: 'Neh', chapters: 13 },
{ id: 17, name: 'Esther', abbr: 'Esth', chapters: 10 },
{ id: 18, name: 'Job', abbr: 'Job', chapters: 42 },
{ id: 19, name: 'Psalms', abbr: 'Ps', chapters: 150 },
{ id: 20, name: 'Proverbs', abbr: 'Prov', chapters: 31 },
{ id: 21, name: 'Ecclesiastes', abbr: 'Eccl', chapters: 12 },
{ id: 22, name: 'Song of Solomon', abbr: 'Song', chapters: 8 },
{ id: 23, name: 'Isaiah', abbr: 'Isa', chapters: 66 },
{ id: 24, name: 'Jeremiah', abbr: 'Jer', chapters: 52 },
{ id: 25, name: 'Lamentations', abbr: 'Lam', chapters: 5 },
{ id: 26, name: 'Ezekiel', abbr: 'Ezek', chapters: 48 },
{ id: 27, name: 'Daniel', abbr: 'Dan', chapters: 12 },
{ id: 28, name: 'Hosea', abbr: 'Hos', chapters: 14 },
{ id: 29, name: 'Joel', abbr: 'Joel', chapters: 3 },
{ id: 30, name: 'Amos', abbr: 'Amos', chapters: 9 },
{ id: 31, name: 'Obadiah', abbr: 'Obad', chapters: 1 },
{ id: 32, name: 'Jonah', abbr: 'Jonah', chapters: 4 },
{ id: 33, name: 'Micah', abbr: 'Mic', chapters: 7 },
{ id: 34, name: 'Nahum', abbr: 'Nah', chapters: 3 },
{ id: 35, name: 'Habakkuk', abbr: 'Hab', chapters: 3 },
{ id: 36, name: 'Zephaniah', abbr: 'Zeph', chapters: 3 },
{ id: 37, name: 'Haggai', abbr: 'Hag', chapters: 2 },
{ id: 38, name: 'Zechariah', abbr: 'Zech', chapters: 14 },
{ id: 39, name: 'Malachi', abbr: 'Mal', chapters: 4 },
// New Testament
{ id: 40, name: 'Matthew', abbr: 'Matt', chapters: 28 },
{ id: 41, name: 'Mark', abbr: 'Mark', chapters: 16 },
{ id: 42, name: 'Luke', abbr: 'Luke', chapters: 24 },
{ id: 43, name: 'John', abbr: 'John', chapters: 21 },
{ id: 44, name: 'Acts', abbr: 'Acts', chapters: 28 },
{ id: 45, name: 'Romans', abbr: 'Rom', chapters: 16 },
{ id: 46, name: '1 Corinthians', abbr: '1Cor', chapters: 16 },
{ id: 47, name: '2 Corinthians', abbr: '2Cor', chapters: 13 },
{ id: 48, name: 'Galatians', abbr: 'Gal', chapters: 6 },
{ id: 49, name: 'Ephesians', abbr: 'Eph', chapters: 6 },
{ id: 50, name: 'Philippians', abbr: 'Phil', chapters: 4 },
{ id: 51, name: 'Colossians', abbr: 'Col', chapters: 4 },
{ id: 52, name: '1 Thessalonians', abbr: '1Thess', chapters: 5 },
{ id: 53, name: '2 Thessalonians', abbr: '2Thess', chapters: 3 },
{ id: 54, name: '1 Timothy', abbr: '1Tim', chapters: 6 },
{ id: 55, name: '2 Timothy', abbr: '2Tim', chapters: 4 },
{ id: 56, name: 'Titus', abbr: 'Titus', chapters: 3 },
{ id: 57, name: 'Philemon', abbr: 'Phlm', chapters: 1 },
{ id: 58, name: 'Hebrews', abbr: 'Heb', chapters: 13 },
{ id: 59, name: 'James', abbr: 'Jas', chapters: 5 },
{ id: 60, name: '1 Peter', abbr: '1Pet', chapters: 5 },
{ id: 61, name: '2 Peter', abbr: '2Pet', chapters: 3 },
{ id: 62, name: '1 John', abbr: '1John', chapters: 5 },
{ id: 63, name: '2 John', abbr: '2John', chapters: 1 },
{ id: 64, name: '3 John', abbr: '3John', chapters: 1 },
{ id: 65, name: 'Jude', abbr: 'Jude', chapters: 1 },
{ id: 66, name: 'Revelation', abbr: 'Rev', chapters: 22 }
]
export interface SearchResult {
bookId: number
bookName: string
chapter: number
reference: string
}
export function searchBooks(query: string): SearchResult[] {
if (!query.trim()) return []
const lowerQuery = query.toLowerCase()
const results: SearchResult[] = []
// Try to parse as "Book Chapter" format (e.g., "Genesis 1", "Gen 1")
const refMatch = query.match(/^([a-z\s]+)\s*(\d+)?/i)
if (refMatch) {
const bookQuery = refMatch[1].toLowerCase().trim()
const chapterNum = refMatch[2] ? parseInt(refMatch[2]) : 1
for (const book of BIBLE_BOOKS) {
if (book.name.toLowerCase().startsWith(bookQuery) ||
book.abbr.toLowerCase().startsWith(bookQuery)) {
if (chapterNum <= book.chapters) {
results.push({
bookId: book.id,
bookName: book.name,
chapter: chapterNum,
reference: `${book.name} ${chapterNum}`
})
}
}
}
}
// Fuzzy match on book names if exact prefix didn't work
if (results.length === 0) {
for (const book of BIBLE_BOOKS) {
if (book.name.toLowerCase().includes(lowerQuery) ||
book.abbr.toLowerCase().includes(lowerQuery)) {
results.push({
bookId: book.id,
bookName: book.name,
chapter: 1,
reference: book.name
})
}
}
}
return results.slice(0, 10) // Return top 10
}
export function parseReference(ref: string): { bookId: number; chapter: number } | null {
const match = ref.match(/^([a-z\s]+)\s*(\d+)?/i)
if (!match) return null
const bookQuery = match[1].toLowerCase().trim()
const chapterNum = match[2] ? parseInt(match[2]) : 1
for (const book of BIBLE_BOOKS) {
if (book.name.toLowerCase().startsWith(bookQuery) ||
book.abbr.toLowerCase().startsWith(bookQuery)) {
return {
bookId: book.id,
chapter: Math.max(1, Math.min(chapterNum, book.chapters))
}
}
}
return null
}