feat: enhance rosary with interactive Bible citations and improved mystery selection
All checks were successful
CI / update (push) Successful in 25s
All checks were successful
CI / update (push) Successful in 25s
- Add clickable Bible reference buttons that open modal with full verses - Create BibleModal component with backdrop blur and styled close button - Implement build-time data fetching for Bible texts while maintaining reactivity - Redesign mystery selector with responsive grid (3-in-row/4-in-row/2×2) - Add "Heutige" badge to indicate today's auto-selected mystery - Reposition luminous mysteries toggle below mystery selector - Integrate Bible reference and counter buttons side-by-side - Restructure Bible API under /api/glaube/bibel/ for better organization
This commit is contained in:
122
src/routes/api/glaube/bibel/[reference]/+server.ts
Normal file
122
src/routes/api/glaube/bibel/[reference]/+server.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
import { json, error } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
|
||||
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 }) => {
|
||||
const reference = params.reference;
|
||||
|
||||
if (!reference) {
|
||||
return error(400, 'Missing reference parameter');
|
||||
}
|
||||
|
||||
try {
|
||||
const verses = await loadVerses(fetch);
|
||||
const matchedVerses = getVersesByReference(verses, reference);
|
||||
|
||||
if (matchedVerses.length === 0) {
|
||||
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
|
||||
}))
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Error fetching Bible verses:', err);
|
||||
return error(500, 'Failed to fetch Bible verses');
|
||||
}
|
||||
};
|
||||
@@ -4,8 +4,8 @@ import type { RequestHandler } from './$types';
|
||||
interface BibleVerse {
|
||||
bookName: string;
|
||||
abbreviation: string;
|
||||
bookNumber: number;
|
||||
chapter: number;
|
||||
verse: number;
|
||||
verseNumber: number;
|
||||
text: string;
|
||||
}
|
||||
@@ -25,14 +25,14 @@ async function loadVerses(fetch: typeof globalThis.fetch): Promise<BibleVerse[]>
|
||||
}
|
||||
const content = await response.text();
|
||||
const lines = content.trim().split('\n');
|
||||
|
||||
|
||||
cachedVerses = lines.map(line => {
|
||||
const [bookName, abbreviation, chapter, verse, verseNumber, text] = line.split('\t');
|
||||
const [bookName, abbreviation, bookNumber, chapter, verseNumber, text] = line.split('\t');
|
||||
return {
|
||||
bookName,
|
||||
abbreviation,
|
||||
abbreviation,
|
||||
bookNumber: parseInt(bookNumber),
|
||||
chapter: parseInt(chapter),
|
||||
verse: parseInt(verse),
|
||||
verseNumber: parseInt(verseNumber),
|
||||
text
|
||||
};
|
||||
@@ -58,7 +58,7 @@ export const GET: RequestHandler = async ({ fetch }) => {
|
||||
try {
|
||||
const verses = await loadVerses(fetch);
|
||||
const randomVerse = getRandomVerse(verses);
|
||||
|
||||
|
||||
return json({
|
||||
text: randomVerse.text,
|
||||
reference: formatVerse(randomVerse),
|
||||
@@ -70,4 +70,4 @@ export const GET: RequestHandler = async ({ fetch }) => {
|
||||
console.error('Error fetching random Bible verse:', err);
|
||||
return error(500, 'Failed to fetch Bible verse');
|
||||
}
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user