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,87 @@
<script>
import "$lib/css/nordtheme.css";
let {
value = $bindable(''),
placeholder = 'Search...',
clearTitle = 'Clear search',
onClear = () => {}
} = $props();
function handleClear() {
value = '';
onClear();
}
</script>
<style>
input {
all: unset;
box-sizing: border-box;
font-family: sans-serif;
background: var(--nord0);
color: #fff;
padding: 0.7rem 2rem;
border-radius: 1000px;
width: 100%;
}
input::placeholder {
color: var(--nord6);
}
.search {
width: 500px;
max-width: 85vw;
position: relative;
margin: 2.5rem auto 1.2rem;
font-size: 1.6rem;
display: flex;
align-items: center;
transition: 100ms;
filter: drop-shadow(0.4em 0.5em 0.4em rgba(0,0,0,0.4));
}
.search:hover,
.search:focus-within {
scale: 1.02 1.02;
filter: drop-shadow(0.4em 0.5em 1em rgba(0,0,0,0.6));
}
.search-button {
all: unset;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
right: 0.5em;
width: 1.5em;
height: 1.5em;
color: var(--nord6);
cursor: pointer;
transition: color 180ms ease-in-out;
}
.search-button:hover {
color: white;
scale: 1.1 1.1;
}
.search-button:active {
transition: 50ms;
scale: 0.8 0.8;
}
.search-button svg {
width: 100%;
height: 100%;
}
</style>
<div class="search">
<input type="text" {placeholder} bind:value>
{#if value}
<button type="button" class="search-button" onclick={handleClear}>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<title>{clearTitle}</title>
<path d="M135.19 390.14a28.79 28.79 0 0021.68 9.86h246.26A29 29 0 00432 371.13V140.87A29 29 0 00403.13 112H156.87a28.84 28.84 0 00-21.67 9.84v0L46.33 256l88.86 134.11z" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"/>
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M336.67 192.33L206.66 322.34M336.67 322.34L206.66 192.33"/>
</svg>
</button>
{/if}
</div>

View File

@@ -1,24 +1,30 @@
<p>
<v lang="de">Mein Herr und mein Gott,</v>
<v lang="en">My Lord and my God,</v>
<v lang="de">nimm alles von mir,</v>
<v lang="en">take from me everything</v>
<v lang="de">was mich hindert zu Dir.</v>
<v lang="en">that distances me from Thee.</v>
</p>
<p>
<v lang="de">Mein Herr und mein Gott,</v>
<v lang="en">My Lord and my God,</v>
<v lang="de">gib alles mir,</v>
<v lang="en">give me everything</v>
<v lang="de">was mich führet zu Dir.</v>
<v lang="en">that brings me closer to Thee.</v>
</p>
<p>
<v lang="de">Mein Herr und mein Gott,</v>
<v lang="en">My Lord and my God,</v>
<v lang="de">nimm mich mir</v>
<v lang="en">detach me from myself</v>
<v lang="de">und gib mich ganz zu eigen Dir.</v>
<v lang="en">to give my all to Thee.</v>
</p>
<script>
import Prayer from './Prayer.svelte';
</script>
<Prayer hasLatin={false}>
<p>
<v lang="de">Mein Herr und mein Gott,</v>
<v lang="en">My Lord and my God,</v>
<v lang="de">nimm alles von mir,</v>
<v lang="en">take from me everything</v>
<v lang="de">was mich hindert zu Dir.</v>
<v lang="en">that distances me from Thee.</v>
</p>
<p>
<v lang="de">Mein Herr und mein Gott,</v>
<v lang="en">My Lord and my God,</v>
<v lang="de">gib alles mir,</v>
<v lang="en">give me everything</v>
<v lang="de">was mich führet zu Dir.</v>
<v lang="en">that brings me closer to Thee.</v>
</p>
<p>
<v lang="de">Mein Herr und mein Gott,</v>
<v lang="en">My Lord and my God,</v>
<v lang="de">nimm mich mir</v>
<v lang="en">detach me from myself</v>
<v lang="de">und gib mich ganz zu eigen Dir.</v>
<v lang="en">to give my all to Thee.</v>
</p>
</Prayer>

View File

@@ -1,14 +1,20 @@
<p>
<v lang="de">Jungfräulicher Vater <i><sup></sup></i>Jesu,</v>
<v lang="en">Virgin Father of <i><sup></sup></i>Jesus,</v>
<v lang="de">Reinster Bräutigam <i><sup></sup></i>Mariä,</v>
<v lang="en">Most pure Spouse of <i><sup></sup></i>Mary,</v>
<v lang="de">Sankt Joseph, bitte Tag für Tag bei Jesus, dem Sohn Gottes.</v>
<v lang="en">Saint Joseph, pray each day to Jesus, the Son of God.</v>
<v lang="de">Seine Kraft und Gnade soll uns stärken,</v>
<v lang="en">May His power and grace strengthen us,</v>
<v lang="de">dass wir siegreich streiten im Leben</v>
<v lang="en">that we may fight victoriously in life</v>
<v lang="de">und die Krone von Ihm erhalten im Sterben.</v>
<v lang="en">and receive the crown from Him at death.</v>
</p>
<script>
import Prayer from './Prayer.svelte';
</script>
<Prayer hasLatin={false}>
<p>
<v lang="de">Jungfräulicher Vater <i><sup></sup></i>Jesu,</v>
<v lang="en">Virgin Father of <i><sup></sup></i>Jesus,</v>
<v lang="de">Reinster Bräutigam <i><sup></sup></i>Mariä,</v>
<v lang="en">Most pure Spouse of <i><sup></sup></i>Mary,</v>
<v lang="de">Sankt Joseph, bitte Tag für Tag bei Jesus, dem Sohn Gottes.</v>
<v lang="en">Saint Joseph, pray each day to Jesus, the Son of God.</v>
<v lang="de">Seine Kraft und Gnade soll uns stärken,</v>
<v lang="en">May His power and grace strengthen us,</v>
<v lang="de">dass wir siegreich streiten im Leben</v>
<v lang="en">that we may fight victoriously in life</v>
<v lang="de">und die Krone von Ihm erhalten im Sterben.</v>
<v lang="en">and receive the crown from Him at death.</v>
</p>
</Prayer>

View File

@@ -1,32 +1,38 @@
<p>
<v lang="la">Sáncte Míchael Archángele,</v>
<v lang="de">Heiliger Erzengel Michael,</v>
<v lang="en">Saint Michael the Archangel,</v>
<v lang="la">defénde nos in proélio,</v>
<v lang="de">verteidige uns im Kampfe!</v>
<v lang="en">defend us in battle.</v>
<v lang="la">cóntra nequítam et insídias</v>
<v lang="de">Gegen die Bosheit und Nachstellungen</v>
<v lang="en">Be our protection against the wickedness</v>
<v lang="la">diáboli ésto præsídium.</v>
<v lang="de">des Teufels sei unser Schutz. </v>
<v lang="en">and snares of the devil.</v>
<v lang="la">Ímperet ílli Déus, súpplices deprecámur:</v>
<v lang="de">»Gott gebiete ihm!«, so bitten wir flehentlich.</v>
<v lang="en">May God rebuke him, we humbly pray;</v>
<v lang="la">tuque, Prínceps milítæ cæléstis,</v>
<v lang="de">Du aber, Fürst der himmlischen Heerscharen,</v>
<v lang="en">and do thou, O Prince of the heavenly host,</v>
<v lang="la">Sátanam aliósque spíritus malígnos,</v>
<v lang="de">stosse den Satan und die anderen bösen Geister,</v>
<v lang="en">by the power of God, thrust into hell Satan</v>
<v lang="la">qui ad perditiónem animárum</v>
<v lang="la">pervagántur in múndo,</v>
<v lang="de">die in der Welt umhergehen,</v>
<v lang="de">um die Seelen zu verderben,</v>
<v lang="en">and all the evil spirits</v>
<v lang="en">who prowl about the world seeking the ruin of souls.</v>
<v lang="la">divína virtúte, in inférnum detrúde. Amen.</v>
<v lang="de">durch die Kraft Gottes in die Hölle. Amen.</v>
<v lang="en">Amen.</v>
</p>
<script>
import Prayer from './Prayer.svelte';
</script>
<Prayer>
<p>
<v lang="la">Sáncte Míchael Archángele,</v>
<v lang="de">Heiliger Erzengel Michael,</v>
<v lang="en">Saint Michael the Archangel,</v>
<v lang="la">defénde nos in proélio,</v>
<v lang="de">verteidige uns im Kampfe!</v>
<v lang="en">defend us in battle.</v>
<v lang="la">cóntra nequítam et insídias</v>
<v lang="de">Gegen die Bosheit und Nachstellungen</v>
<v lang="en">Be our protection against the wickedness</v>
<v lang="la">diáboli ésto præsídium.</v>
<v lang="de">des Teufels sei unser Schutz. </v>
<v lang="en">and snares of the devil.</v>
<v lang="la">Ímperet ílli Déus, súpplices deprecámur:</v>
<v lang="de">»Gott gebiete ihm!«, so bitten wir flehentlich.</v>
<v lang="en">May God rebuke him, we humbly pray;</v>
<v lang="la">tuque, Prínceps milítæ cæléstis,</v>
<v lang="de">Du aber, Fürst der himmlischen Heerscharen,</v>
<v lang="en">and do thou, O Prince of the heavenly host,</v>
<v lang="la">Sátanam aliósque spíritus malígnos,</v>
<v lang="de">stosse den Satan und die anderen bösen Geister,</v>
<v lang="en">by the power of God, thrust into hell Satan</v>
<v lang="la">qui ad perditiónem animárum</v>
<v lang="la">pervagántur in múndo,</v>
<v lang="de">die in der Welt umhergehen,</v>
<v lang="de">um die Seelen zu verderben,</v>
<v lang="en">and all the evil spirits</v>
<v lang="en">who prowl about the world seeking the ruin of souls.</v>
<v lang="la">divína virtúte, in inférnum detrúde. Amen.</v>
<v lang="de">durch die Kraft Gottes in die Hölle. Amen.</v>
<v lang="en">Amen.</v>
</p>
</Prayer>

View File

@@ -2,7 +2,7 @@
import type { Snippet } from 'svelte';
import { getLanguageContext } from '$lib/contexts/languageContext.js';
let { latinPrimary = true, children } = $props<{ latinPrimary?: boolean, children?: Snippet }>();
let { latinPrimary = true, hasLatin = true, children } = $props<{ latinPrimary?: boolean, hasLatin?: boolean, children?: Snippet }>();
// Get context if available (graceful fallback for standalone usage)
let showLatinStore;
@@ -47,6 +47,12 @@
.prayer-wrapper :global(v:lang(de)),
.prayer-wrapper :global(v:lang(en)) { color: grey; }
/* No-Latin prayers: vernacular gets primary color */
.prayer-wrapper.no-latin :global(v:lang(de)),
.prayer-wrapper.no-latin :global(v:lang(en)) {
color: var(--nord6);
}
/* Vernacular primary overrides */
.prayer-wrapper.vernacular-primary :global(v:lang(de)),
.prayer-wrapper.vernacular-primary :global(v:lang(en)) {
@@ -67,7 +73,9 @@
.prayer-wrapper :global(v:lang(la)),
.prayer-wrapper.vernacular-primary :global(v:lang(de)),
.prayer-wrapper.vernacular-primary :global(v:lang(en)),
.prayer-wrapper.monolingual :global(v:not(:lang(la))) {
.prayer-wrapper.monolingual :global(v:not(:lang(la))),
.prayer-wrapper.no-latin :global(v:lang(de)),
.prayer-wrapper.no-latin :global(v:lang(en)) {
color: black;
}
}
@@ -145,6 +153,7 @@
class="prayer-wrapper"
class:vernacular-primary={!latinPrimary}
class:monolingual={!showLatin}
class:no-latin={!hasLatin}
class:lang-de={urlLang === 'de'}
class:lang-en={urlLang === 'en'}
>