prayers: add search and individual prayer pages
All checks were successful
CI / update (push) Successful in 1m22s

- Add SearchInput component for reusable search UI
- Add search functionality to prayers list with two-tier results:
  - Primary matches (name/searchTerms) shown first
  - Secondary matches (text content) shown after with reduced opacity
- Add individual prayer pages with language-appropriate slugs
  (e.g., /glaube/gebete/ave-maria, /faith/prayers/hail-mary)
- Make prayer cards clickable to navigate to individual pages
- Fix language visibility for prayers without Latin (BruderKlaus, Joseph)
- Add Prayer wrapper to MichaelGebet for consistent styling
- Use CSS columns for masonry layout with dynamic reordering
This commit is contained in:
2026-02-02 22:22:49 +01:00
parent 8699bef209
commit 660a1b0539
10 changed files with 645 additions and 128 deletions

View File

@@ -0,0 +1,162 @@
<script>
import { createLanguageContext } from "$lib/contexts/languageContext.js";
import "$lib/css/christ.css";
import "$lib/css/nordtheme.css";
import LanguageToggle from "$lib/components/LanguageToggle.svelte";
import Kreuzzeichen from "$lib/components/prayers/Kreuzzeichen.svelte";
import GloriaPatri from "$lib/components/prayers/GloriaPatri.svelte";
import Paternoster from "$lib/components/prayers/Paternoster.svelte";
import Credo from "$lib/components/prayers/Credo.svelte";
import AveMaria from "$lib/components/prayers/AveMaria.svelte";
import SalveRegina from "$lib/components/prayers/SalveRegina.svelte";
import FatimaGebet from "$lib/components/prayers/FatimaGebet.svelte";
import Gloria from "$lib/components/prayers/Gloria.svelte";
import MichaelGebet from "$lib/components/prayers/MichaelGebet.svelte";
import BruderKlausGebet from "$lib/components/prayers/BruderKlausGebet.svelte";
import JosephGebet from "$lib/components/prayers/JosephGebet.svelte";
import Confiteor from "$lib/components/prayers/Confiteor.svelte";
let { data } = $props();
const langContext = createLanguageContext({ urlLang: data.lang });
$effect(() => {
langContext.lang.set(data.lang);
});
const isEnglish = $derived(data.lang === 'en');
// Prayer definitions with slugs
const prayerDefs = $derived({
'das-heilige-kreuzzeichen': { id: 'signOfCross', name: isEnglish ? 'The Sign of the Cross' : 'Das heilige Kreuzzeichen', bilingue: true },
'the-sign-of-the-cross': { id: 'signOfCross', name: isEnglish ? 'The Sign of the Cross' : 'Das heilige Kreuzzeichen', bilingue: true },
'gloria-patri': { id: 'gloriaPatri', name: 'Glória Patri', bilingue: true },
'paternoster': { id: 'paternoster', name: isEnglish ? 'Our Father' : 'Paternoster', bilingue: true },
'our-father': { id: 'paternoster', name: isEnglish ? 'Our Father' : 'Paternoster', bilingue: true },
'credo': { id: 'credo', name: isEnglish ? 'Nicene Creed' : 'Credo', bilingue: true },
'nicene-creed': { id: 'credo', name: isEnglish ? 'Nicene Creed' : 'Credo', bilingue: true },
'ave-maria': { id: 'aveMaria', name: isEnglish ? 'Hail Mary' : 'Ave Maria', bilingue: true },
'hail-mary': { id: 'aveMaria', name: isEnglish ? 'Hail Mary' : 'Ave Maria', bilingue: true },
'salve-regina': { id: 'salveRegina', name: 'Salve Regina', bilingue: true },
'das-fatimagebet': { id: 'fatima', name: isEnglish ? 'Fatima Prayer' : 'Das Fatimagebet', bilingue: true },
'fatima-prayer': { id: 'fatima', name: isEnglish ? 'Fatima Prayer' : 'Das Fatimagebet', bilingue: true },
'gloria': { id: 'gloria', name: 'Glória', bilingue: true },
'gebet-zum-hl-erzengel-michael': { id: 'michael', name: isEnglish ? 'Prayer to St. Michael the Archangel' : 'Gebet zum hl. Erzengel Michael', bilingue: true },
'prayer-to-st-michael-the-archangel': { id: 'michael', name: isEnglish ? 'Prayer to St. Michael the Archangel' : 'Gebet zum hl. Erzengel Michael', bilingue: true },
'bruder-klaus-gebet': { id: 'bruderKlaus', name: isEnglish ? 'Prayer of St. Nicholas of Flüe' : 'Bruder Klaus Gebet', bilingue: false },
'prayer-of-st-nicholas-of-flue': { id: 'bruderKlaus', name: isEnglish ? 'Prayer of St. Nicholas of Flüe' : 'Bruder Klaus Gebet', bilingue: false },
'josephgebet-des-hl-papst-pius-x': { id: 'joseph', name: isEnglish ? 'Prayer to St. Joseph by Pope St. Pius X' : 'Josephgebet des hl. Papst Pius X', bilingue: false },
'prayer-to-st-joseph-by-pope-st-pius-x': { id: 'joseph', name: isEnglish ? 'Prayer to St. Joseph by Pope St. Pius X' : 'Josephgebet des hl. Papst Pius X', bilingue: false },
'das-confiteor': { id: 'confiteor', name: isEnglish ? 'The Confiteor' : 'Das Confiteor', bilingue: true },
'the-confiteor': { id: 'confiteor', name: isEnglish ? 'The Confiteor' : 'Das Confiteor', bilingue: true }
});
const prayer = $derived(prayerDefs[data.prayer]);
const prayerName = $derived(prayer?.name || data.prayer);
const isBilingue = $derived(prayer?.bilingue ?? true);
const prayerId = $derived(prayer?.id);
const gloriaIntro = $derived(isEnglish
? 'This ancient hymn begins with the words the angels used to celebrate the newborn Savior. It first praises God the Father, then God the Son; it concludes with homage to the Most Holy Trinity, during which one makes the sign of the cross.'
: 'Der uralte Gesang beginnt mit den Worten, mit denen die Engelscharen den neugeborenen Welterlöser feierten. Er preist zunächst Gott Vater, dann Gott Sohn; er schliesst mit einer Huldigung an die Heiligste Dreifaltigkeit, wobei man sich mit dem grossen Kreuze bezeichnet.');
</script>
<svelte:head>
<title>{prayerName} - Bocken</title>
</svelte:head>
<style>
.container {
max-width: 700px;
margin: auto;
padding: 1em;
}
h1 {
text-align: center;
font-size: 2.5rem;
margin-bottom: 0.5em;
}
.toggle-controls {
display: flex;
justify-content: center;
margin-bottom: 2rem;
}
.gebet {
text-align: center;
font-size: 1.25em;
}
:global(.gebet v) {
margin: 0;
display: block;
}
:global(.gebet v:lang(la)) {
color: var(--nord6);
}
:global(.bilingue v:lang(de)) {
color: grey;
}
:global(.gebet i) {
font-style: normal;
color: var(--nord11);
font-weight: 900;
}
.gebet-wrapper {
padding: 1.5em;
background-color: var(--accent-dark);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.intro {
margin-bottom: 1em;
font-style: italic;
text-align: center;
}
@media(prefers-color-scheme: light) {
.gebet-wrapper {
background-color: var(--accent-light);
}
:global(.gebet v:lang(la)) {
color: black;
}
}
</style>
<div class="container">
<h1>{prayerName}</h1>
<div class="toggle-controls">
<LanguageToggle />
</div>
<div class="gebet-wrapper">
{#if prayerId === 'gloria'}
<p class="intro">{gloriaIntro}</p>
{/if}
<div class="gebet" class:bilingue={isBilingue}>
{#if prayerId === 'signOfCross'}
<Kreuzzeichen />
{:else if prayerId === 'gloriaPatri'}
<GloriaPatri />
{:else if prayerId === 'paternoster'}
<Paternoster />
{:else if prayerId === 'credo'}
<Credo />
{:else if prayerId === 'aveMaria'}
<AveMaria />
{:else if prayerId === 'salveRegina'}
<SalveRegina />
{:else if prayerId === 'fatima'}
<FatimaGebet />
{:else if prayerId === 'gloria'}
<Gloria />
{:else if prayerId === 'michael'}
<MichaelGebet />
{:else if prayerId === 'bruderKlaus'}
<BruderKlausGebet />
{:else if prayerId === 'joseph'}
<JosephGebet />
{:else if prayerId === 'confiteor'}
<Confiteor />
{/if}
</div>
</div>
</div>