perf: pre-generate Bible verse data and reduce DOM via conditional rendering

- Extract Bible lookup logic into shared src/lib/server/bible.ts module
- Add build script to pre-generate all 20 mystery verse lookups as static data,
  eliminating runtime API calls on rosary page load
- Update Prayer.svelte to pass showLatin/urlLang as snippet parameters; all 14
  prayer components now conditionally render only visible language elements
  instead of hiding via CSS
- Extract 4 inline mystery selector SVGs into MysteryIcon.svelte component
- Remove unused CSS selectors from angelus page
This commit is contained in:
2026-02-03 14:27:39 +01:00
parent ca0f78c9ff
commit 3eccb7ca50
23 changed files with 1251 additions and 720 deletions
@@ -1,94 +1,8 @@
import { json, error } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { lookupReference } from '$lib/server/bible';
interface BibleVerse {
bookName: string;
abbreviation: string;
bookNumber: number;
chapter: number;
verseNumber: number;
text: string;
}
// Cache for parsed verses to avoid reading file repeatedly
let cachedVerses: BibleVerse[] | null = null;
async function loadVerses(fetch: typeof globalThis.fetch): Promise<BibleVerse[]> {
if (cachedVerses) {
return cachedVerses;
}
try {
const response = await fetch('/allioli.tsv');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const content = await response.text();
const lines = content.trim().split('\n');
cachedVerses = lines.map(line => {
const [bookName, abbreviation, bookNumber, chapter, verseNumber, text] = line.split('\t');
return {
bookName,
abbreviation,
bookNumber: parseInt(bookNumber),
chapter: parseInt(chapter),
verseNumber: parseInt(verseNumber),
text
};
});
return cachedVerses;
} catch (err) {
console.error('Error loading Bible verses:', err);
throw new Error('Failed to load Bible verses');
}
}
function parseReference(reference: string): { bookRef: string; isFullName: boolean; chapter: number; startVerse: number; endVerse: number } | null {
// Parse various reference formats:
// "Mt 3, 16-17", "Mt3:16-17", "Mt 3:16-17", "Lk1:3", "Matthäus 3, 16-17"
// Match book name (letters and umlauts), optional space, chapter, separator (: or ,), optional space, verse(s)
const match = reference.match(/^([A-Za-zäöüÄÖÜß]+)\s*(\d+)[\s,:]+(\d+)(?:[-:](\d+))?$/);
if (!match) {
return null;
}
const [, bookRef, chapterStr, startVerseStr, endVerseStr] = match;
// If book reference is longer than 5 characters, assume it's a full name
// Otherwise, assume it's an abbreviation
const isFullName = bookRef.length > 5;
return {
bookRef,
isFullName,
chapter: parseInt(chapterStr),
startVerse: parseInt(startVerseStr),
endVerse: endVerseStr ? parseInt(endVerseStr) : parseInt(startVerseStr)
};
}
function getVersesByReference(verses: BibleVerse[], reference: string): BibleVerse[] {
const parsed = parseReference(reference);
if (!parsed) {
return [];
}
return verses.filter(v => {
// Match based on whether we're using full name or abbreviation
const bookMatches = parsed.isFullName
? v.bookName === parsed.bookRef
: v.abbreviation === parsed.bookRef;
return bookMatches &&
v.chapter === parsed.chapter &&
v.verseNumber >= parsed.startVerse &&
v.verseNumber <= parsed.endVerse;
});
}
export const GET: RequestHandler = async ({ params, fetch }) => {
export const GET: RequestHandler = async ({ params }) => {
const reference = params.reference;
if (!reference) {
@@ -96,25 +10,13 @@ export const GET: RequestHandler = async ({ params, fetch }) => {
}
try {
const verses = await loadVerses(fetch);
const matchedVerses = getVersesByReference(verses, reference);
const result = lookupReference(reference);
if (matchedVerses.length === 0) {
if (!result) {
return error(404, 'No verses found for the given reference');
}
// Extract book and chapter from first verse (they're all the same)
const firstVerse = matchedVerses[0];
return json({
reference,
book: firstVerse.bookName,
chapter: firstVerse.chapter,
verses: matchedVerses.map(v => ({
verse: v.verseNumber,
text: v.text
}))
});
return json(result);
} catch (err) {
console.error('Error fetching Bible verses:', err);
return error(500, 'Failed to fetch Bible verses');