Browse Source

handle torah and quran fallbacks

imwald
Silberengel 3 months ago
parent
commit
b7d5c9010f
  1. 179
      src/components/Bookstr/BookstrContent.tsx

179
src/components/Bookstr/BookstrContent.tsx

@ -29,6 +29,148 @@ interface BookSection { @@ -29,6 +29,148 @@ interface BookSection {
originalChapter?: number
}
/**
* Get the first verse number from a verse string (handles ranges and lists)
*/
function getFirstVerse(verse: string): number | null {
if (!verse) return null
// Split by comma to handle lists like "6,8,10"
const firstPart = verse.split(',')[0].trim()
// Handle ranges like "6-8" - take the first number
if (firstPart.includes('-')) {
const start = parseInt(firstPart.split('-')[0].trim(), 10)
return isNaN(start) ? null : start
}
// Single verse number
const verseNum = parseInt(firstPart, 10)
return isNaN(verseNum) ? null : verseNum
}
/**
* Normalize book name to Sefaria format (capitalize first letter of each word)
*/
function normalizeSefariaBookName(bookName: string): string {
return bookName
.split(' ')
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
.join(' ')
}
/**
* Build Sefaria URL for a torah reference
*/
function buildSefariaUrl(reference: BookReference): string | null {
if (!reference.book) return null
// Sefaria uses exact book names: Genesis, Exodus, Leviticus, Numbers, Deuteronomy
const bookName = normalizeSefariaBookName(reference.book)
if (!reference.chapter) {
// Book only
return `https://www.sefaria.org/${bookName}?tab=contents`
}
if (!reference.verse) {
// Chapter only
return `https://www.sefaria.org/${bookName}.${reference.chapter}?lang=bi`
}
// Verse - get first verse from range/list
const firstVerse = getFirstVerse(reference.verse)
if (firstVerse === null) {
// Invalid verse, fall back to chapter
return `https://www.sefaria.org/${bookName}.${reference.chapter}?lang=bi`
}
// Verse with chapter
return `https://www.sefaria.org/${bookName}.${reference.chapter}.${firstVerse}?lang=bi&with=all&lang2=en`
}
/**
* Mapping from Quran surah names to surah numbers (1-114)
*/
const surahNameToNumber: Record<string, number> = {
'Al-Fatiha': 1, 'Al-Baqarah': 2, 'Ali Imran': 3, 'An-Nisa': 4, 'Al-Maidah': 5,
'Al-Anam': 6, 'Al-Araf': 7, 'Al-Anfal': 8, 'At-Tawbah': 9, 'Yunus': 10,
'Hud': 11, 'Yusuf': 12, 'Ar-Rad': 13, 'Ibrahim': 14, 'Al-Hijr': 15,
'An-Nahl': 16, 'Al-Isra': 17, 'Al-Kahf': 18, 'Maryam': 19, 'Taha': 20,
'Al-Anbiya': 21, 'Al-Hajj': 22, 'Al-Muminun': 23, 'An-Nur': 24, 'Al-Furqan': 25,
'Ash-Shuara': 26, 'An-Naml': 27, 'Al-Qasas': 28, 'Al-Ankabut': 29, 'Ar-Rum': 30,
'Luqman': 31, 'As-Sajdah': 32, 'Al-Ahzab': 33, 'Saba': 34, 'Fatir': 35,
'Ya-Sin': 36, 'As-Saffat': 37, 'Sad': 38, 'Az-Zumar': 39, 'Ghafir': 40,
'Fussilat': 41, 'Ash-Shura': 42, 'Az-Zukhruf': 43, 'Ad-Dukhan': 44, 'Al-Jathiyah': 45,
'Al-Ahqaf': 46, 'Muhammad': 47, 'Al-Fath': 48, 'Al-Hujurat': 49, 'Qaf': 50,
'Adh-Dhariyat': 51, 'At-Tur': 52, 'An-Najm': 53, 'Al-Qamar': 54, 'Ar-Rahman': 55,
'Al-Waqiah': 56, 'Al-Hadid': 57, 'Al-Mujadilah': 58, 'Al-Hashr': 59, 'Al-Mumtahanah': 60,
'As-Saff': 61, 'Al-Jumuah': 62, 'Al-Munafiqun': 63, 'At-Taghabun': 64, 'At-Talaq': 65,
'At-Tahrim': 66, 'Al-Mulk': 67, 'Al-Qalam': 68, 'Al-Haqqah': 69, 'Al-Maarij': 70,
'Nuh': 71, 'Al-Jinn': 72, 'Al-Muzzammil': 73, 'Al-Muddaththir': 74, 'Al-Qiyamah': 75,
'Al-Insan': 76, 'Al-Mursalat': 77, 'An-Naba': 78, 'An-Naziat': 79, 'Abasa': 80,
'At-Takwir': 81, 'Al-Infitar': 82, 'Al-Mutaffifin': 83, 'Al-Inshiqaq': 84, 'Al-Buruj': 85,
'At-Tariq': 86, 'Al-Ala': 87, 'Al-Ghashiyah': 88, 'Al-Fajr': 89, 'Al-Balad': 90,
'Ash-Shams': 91, 'Al-Layl': 92, 'Ad-Duha': 93, 'Ash-Sharh': 94, 'At-Tin': 95,
'Al-Alaq': 96, 'Al-Qadr': 97, 'Al-Bayyinah': 98, 'Az-Zalzalah': 99, 'Al-Adiyat': 100,
'Al-Qariah': 101, 'At-Takathur': 102, 'Al-Asr': 103, 'Al-Humazah': 104, 'Al-Fil': 105,
'Quraysh': 106, 'Al-Maun': 107, 'Al-Kawthar': 108, 'Al-Kafirun': 109, 'An-Nasr': 110,
'Al-Masad': 111, 'Al-Ikhlas': 112, 'Al-Falaq': 113, 'An-Nas': 114
}
/**
* Build quran.com URL for a quran reference
*/
function buildQuranComUrl(reference: BookReference): string | null {
if (!reference.book) return null
// For Quran, "chapter" is actually the surah number
let surahNumber: number | undefined
if (reference.chapter && typeof reference.chapter === 'number' && reference.chapter >= 1 && reference.chapter <= 114) {
surahNumber = reference.chapter
} else {
// Try book name lookup
const bookAsNumber = parseInt(reference.book.trim(), 10)
if (!isNaN(bookAsNumber) && bookAsNumber >= 1 && bookAsNumber <= 114) {
surahNumber = bookAsNumber
} else {
// Try case-insensitive lookup
const normalizedBook = reference.book.trim()
const matchingKey = Object.keys(surahNameToNumber).find(
key => key.toLowerCase() === normalizedBook.toLowerCase()
)
if (matchingKey) {
surahNumber = surahNameToNumber[matchingKey]
} else {
// Try normalized matching (remove hyphens, spaces, etc.)
const normalizedBookClean = normalizedBook.toLowerCase().replace(/[^a-z0-9]/g, '')
const matchingKey2 = Object.keys(surahNameToNumber).find(key => {
const normalizedKey = key.toLowerCase().replace(/[^a-z0-9]/g, '')
return normalizedKey === normalizedBookClean
})
if (matchingKey2) {
surahNumber = surahNameToNumber[matchingKey2]
}
}
}
}
if (!surahNumber) {
return null
}
// In Quran, "verse" is the ayah
if (reference.verse) {
const firstAyah = getFirstVerse(reference.verse)
if (firstAyah === null) {
return `https://quran.com/${surahNumber}`
}
return `https://quran.com/${surahNumber}?startingVerse=${firstAyah}`
}
return `https://quran.com/${surahNumber}`
}
/**
* Build Bible Gateway URL for a passage
*/
@ -43,7 +185,6 @@ function buildBibleGatewayUrl(reference: BookReference, version?: string): strin @@ -43,7 +185,6 @@ function buildBibleGatewayUrl(reference: BookReference, version?: string): strin
}
// Map version codes to Bible Gateway codes
// Common mappings: DRB -> DRA (Douay-Rheims), etc.
const versionMap: Record<string, string> = {
'DRB': 'DRA', // Douay-Rheims Bible -> Douay-Rheims 1899 American Edition
'DRA': 'DRA', // Already correct
@ -57,6 +198,20 @@ function buildBibleGatewayUrl(reference: BookReference, version?: string): strin @@ -57,6 +198,20 @@ function buildBibleGatewayUrl(reference: BookReference, version?: string): strin
return `https://www.biblegateway.com/passage/?search=${encodedPassage}&version=${bgVersion}`
}
/**
* Build external URL for a book reference based on bookType
*/
function buildExternalUrl(reference: BookReference, bookType: string, version?: string): string | null {
if (bookType === 'torah') {
return buildSefariaUrl(reference)
} else if (bookType === 'quran') {
return buildQuranComUrl(reference)
} else {
// Default to Bible Gateway for bible and other types
return buildBibleGatewayUrl(reference, version)
}
}
export function BookstrContent({ wikilink, className }: BookstrContentProps) {
const [sections, setSections] = useState<BookSection[]>([])
const [isLoading, setIsLoading] = useState(false) // Start as false, only set to true when actually fetching
@ -787,6 +942,22 @@ export function BookstrContent({ wikilink, className }: BookstrContentProps) { @@ -787,6 +942,22 @@ export function BookstrContent({ wikilink, className }: BookstrContentProps) {
}}
/>
</div>
{(() => {
// Get bookType from parsed wikilink (defaults to 'bible')
const bookType = parsed?.bookType || 'bible'
// Only show external link for bible, torah, or quran collections
// Other collections (secular books) don't have external links
if (!['bible', 'torah', 'quran'].includes(bookType)) {
return null
}
const externalUrl = buildExternalUrl(section.reference, bookType, selectedVersion)
const serviceName = bookType === 'torah' ? 'Sefaria' : bookType === 'quran' ? 'quran.com' : 'Bible Gateway'
if (!externalUrl) return null
return (
<Button
variant="ghost"
size="sm"
@ -794,14 +965,16 @@ export function BookstrContent({ wikilink, className }: BookstrContentProps) { @@ -794,14 +965,16 @@ export function BookstrContent({ wikilink, className }: BookstrContentProps) {
asChild
>
<a
href={buildBibleGatewayUrl(section.reference, selectedVersion)}
href={externalUrl}
target="_blank"
rel="noopener noreferrer"
title="View on Bible Gateway"
title={`View on ${serviceName}`}
>
<ExternalLink className="h-3 w-3" />
</a>
</Button>
)
})()}
</div>
{/* Verses - render all verses together, including ranges */}

Loading…
Cancel
Save