Compare commits

2 Commits

Author SHA1 Message Date
0e0af55ce7 prayers: add plenary indulgence explanation to postcommunio
All checks were successful
CI / update (push) Successful in 1m29s
2026-02-13 15:34:20 +01:00
601e2f6513 prayers: add 5 new prayers, move Angelus route, liturgical seasons
Add Guardian Angel, Apostles' Creed, Tantum Ergo, Angelus, and Regina
Caeli to the prayers collection. Move standalone Angelus route into the
prayers system with a 301 redirect from the old path. Extract Easter
computation into shared utility ($lib/js/easter.svelte.ts) and use it
for liturgical season awareness: during Eastertide the rosary defaults
to Glorious mysteries and swaps Salve Regina for Regina Caeli; during
Lent it defaults to Sorrowful mysteries. Seasonal badges shown on both
the mystery selector and prayer sections.
2026-02-13 14:56:12 +01:00
23 changed files with 890 additions and 306 deletions

View File

@@ -16,8 +16,8 @@
// Faith subroute mappings
const faithSubroutes: Record<string, Record<string, string>> = {
en: { gebete: 'prayers', rosenkranz: 'rosary', angelus: 'angelus' },
de: { prayers: 'gebete', rosary: 'rosenkranz', angelus: 'angelus' }
en: { gebete: 'prayers', rosenkranz: 'rosary' },
de: { prayers: 'gebete', rosary: 'rosenkranz' }
};
$effect(() => {

View File

@@ -0,0 +1,108 @@
<script>
import Prayer from './Prayer.svelte';
import AveMaria from './AveMaria.svelte';
let { verbose = false } = $props();
</script>
<Prayer>
{#snippet children(showLatin, urlLang)}
<p>
{#if showLatin}<v lang="la"><i>℣.</i> Ángelus Dómini nuntiávit Maríæ.</v>{/if}
{#if urlLang === 'de'}<v lang="de"><i>℣.</i> Der Engel des Herrn brachte Maria die Botschaft</v>{/if}
{#if urlLang === 'en'}<v lang="en"><i>℣.</i> The Angel of the Lord declared unto Mary.</v>{/if}
{#if showLatin}<v lang="la"><i>℟.</i> Et concépit de Spíritu Sancto.</v>{/if}
{#if urlLang === 'de'}<v lang="de"><i>℟.</i> und sie empfing vom Heiligen Geist.</v>{/if}
{#if urlLang === 'en'}<v lang="en"><i>℟.</i> And she conceived of the Holy Spirit.</v>{/if}
</p>
{/snippet}
</Prayer>
{#if verbose}
<AveMaria />
{:else}
<p class="ave-indicator"><i>— Ave Maria —</i></p>
{/if}
<Prayer>
{#snippet children(showLatin, urlLang)}
<p>
{#if showLatin}<v lang="la"><i>℣.</i> Ecce ancílla Dómini,</v>{/if}
{#if urlLang === 'de'}<v lang="de"><i>℣.</i> Maria sprach: Siehe, ich bin die Magd des Herrn</v>{/if}
{#if urlLang === 'en'}<v lang="en"><i>℣.</i> Behold the handmaid of the Lord.</v>{/if}
{#if showLatin}<v lang="la"><i>℟.</i> Fiat mihi secúndum verbum tuum.</v>{/if}
{#if urlLang === 'de'}<v lang="de"><i>℟.</i> mir geschehe nach Deinem Wort.</v>{/if}
{#if urlLang === 'en'}<v lang="en"><i>℟.</i> Be it done unto me according to thy word.</v>{/if}
</p>
{/snippet}
</Prayer>
{#if verbose}
<AveMaria />
{:else}
<p class="ave-indicator"><i>— Ave Maria —</i></p>
{/if}
<Prayer>
{#snippet children(showLatin, urlLang)}
<p>
{#if showLatin}<v lang="la"><i>℣.</i> Et Verbum caro factum est,</v>{/if}
{#if urlLang === 'de'}<v lang="de"><i>℣.</i> Und das Wort ist Fleisch geworden</v>{/if}
{#if urlLang === 'en'}<v lang="en"><i>℣.</i> And the Word was made flesh.</v>{/if}
{#if showLatin}<v lang="la"><i>℟.</i> Et habitávit in nobis.</v>{/if}
{#if urlLang === 'de'}<v lang="de"><i>℟.</i> und hat unter uns gewohnt.</v>{/if}
{#if urlLang === 'en'}<v lang="en"><i>℟.</i> And dwelt among us.</v>{/if}
</p>
{/snippet}
</Prayer>
{#if verbose}
<AveMaria />
{:else}
<p class="ave-indicator"><i>— Ave Maria —</i></p>
{/if}
<Prayer>
{#snippet children(showLatin, urlLang)}
<p>
{#if showLatin}<v lang="la"><i>℣.</i> Ora pro nobis, sancta Dei Génetrix,</v>{/if}
{#if urlLang === 'de'}<v lang="de"><i>℣.</i> Bitte für uns, heilige Gottesmutter,</v>{/if}
{#if urlLang === 'en'}<v lang="en"><i>℣.</i> Pray for us, O holy Mother of God.</v>{/if}
{#if showLatin}<v lang="la"><i>℟.</i> Ut digni efficiámur promissiónibus Christi.</v>{/if}
{#if urlLang === 'de'}<v lang="de"><i>℟.</i> auf dass wir würdig werden der Verheissungen Christi.</v>{/if}
{#if urlLang === 'en'}<v lang="en"><i>℟.</i> That we may be made worthy of the promises of Christ.</v>{/if}
</p>
{/snippet}
</Prayer>
<Prayer>
{#snippet children(showLatin, urlLang)}
<p>
{#if showLatin}<v lang="la"><i>℣.</i> Orémus.</v>{/if}
{#if urlLang === 'de'}<v lang="de"><i>℣.</i> Lasset uns beten.</v>{/if}
{#if urlLang === 'en'}<v lang="en"><i>℣.</i> Let us pray:</v>{/if}
</p>
<p>
{#if showLatin}<v lang="la">Grátiam tuam, quǽsumus, Dómine, méntibus nostris infúnde;</v>{/if}
{#if urlLang === 'de'}<v lang="de">Allmächtiger Gott, giesse deine Gnade in unsere Herzen ein.</v>{/if}
{#if urlLang === 'en'}<v lang="en">Pour forth, we beseech Thee, O Lord, Thy grace into our hearts,</v>{/if}
{#if showLatin}<v lang="la">ut qui, Ángelo nuntiánte, Christi Fílii tui incarnatiónem cognóvimus,</v>{/if}
{#if urlLang === 'de'}<v lang="de">Durch die Botschaft des Engels haben wir die Menschwerdung Christi, deines Sohnes, erkannt.</v>{/if}
{#if urlLang === 'en'}<v lang="en">that we to whom the Incarnation of Christ Thy Son was made known by the message of an angel,</v>{/if}
{#if showLatin}<v lang="la">per passiónem eius et crucem ad resurrectiónis glóriam perducámur.</v>{/if}
{#if urlLang === 'de'}<v lang="de">Lass uns durch sein Leiden und Kreuz zur Herrlichkeit der Auferstehung gelangen.</v>{/if}
{#if urlLang === 'en'}<v lang="en">may by His Passion and Cross be brought to the glory of His Resurrection.</v>{/if}
{#if showLatin}<v lang="la">Per eúmdem Christum Dóminum nostrum. Amen.</v>{/if}
{#if urlLang === 'de'}<v lang="de">Darum bitten wir durch Christus, unseren Herrn. Amen.</v>{/if}
{#if urlLang === 'en'}<v lang="en">Through the same Christ Our Lord. Amen.</v>{/if}
</p>
{/snippet}
</Prayer>
<style>
.ave-indicator {
text-align: center;
color: grey;
margin: 0.5em 0;
}
</style>

View File

@@ -0,0 +1,53 @@
<script>
import Prayer from './Prayer.svelte';
import Paternoster from './Paternoster.svelte';
import AveMaria from './AveMaria.svelte';
import GloriaPatri from './GloriaPatri.svelte';
</script>
<Prayer>
{#snippet children(showLatin, urlLang)}
<p>
{#if showLatin}<v lang=la>Ánima Christi, santífica me.</v>{/if}
{#if urlLang=='de'}<v lang=de>Seele Christi, heilige mich.</v>{/if}
{#if urlLang=='en'}<v lang=en>Soul of Christ, sanctify me.</v>{/if}
{#if showLatin}<v lang=la>Corpus Christi, salva me.</v>{/if}
{#if urlLang=='de'}<v lang=de>Leib Christi, erlöse mich.</v>{/if}
{#if urlLang=='en'}<v lang=en>Body of Christ, save me.</v>{/if}
{#if showLatin}<v lang=la>Sanguis Christi, inébria me.</v>{/if}
{#if urlLang=='de'}<v lang=de>Blut Christi, tränke mich.</v>{/if}
{#if urlLang=='en'}<v lang=en>Blood of Christ, inebriate me.</v>{/if}
{#if showLatin}<v lang=la>Aqua láteris Christi, lava me.</v>{/if}
{#if urlLang=='de'}<v lang=de>Wasser der Seite Christi, wasche mich.</v>{/if}
{#if urlLang=='en'}<v lang=en>Water from the side of Christ, wash me.</v>{/if}
{#if showLatin}<v lang=la>Pássio Christi, confórta me.</v>{/if}
{#if urlLang=='de'}<v lang=de>Leiden Christi, stärke mich.</v>{/if}
{#if urlLang=='en'}<v lang=en>Passion of Christ, strenghten me.</v>{/if}
{#if showLatin}<v lang=la>O bone Iesu, exáudi me.</v>{/if}
{#if urlLang=='de'}<v lang=de>O gütiger Jesus, erhöre mich.</v>{/if}
{#if urlLang=='en'}<v lang=en>O good Jesus, hear me.</v>{/if}
{#if showLatin}<v lang=la>Intra tua vúlnera abscónde me.</v>{/if}
{#if urlLang=='de'}<v lang=de>Verbirg in Deine Wunden mich.</v>{/if}
{#if urlLang=='en'}<v lang=en>Within Thy wounds hide me.</v>{/if}
{#if showLatin}<v lang=la>Ne permíttas me separári a te.</v>{/if}
{#if urlLang=='de'}<v lang=de>Von Dir lass nimmer scheiden mich.</v>{/if}
{#if urlLang=='en'}<v lang=en>Separated from Thee let me never be.</v>{/if}
{#if showLatin}<v lang=la>Ab hoste malígno defénde me.</v>{/if}
{#if urlLang=='de'}<v lang=de>Vor dem bösen Feind beschütze mich.</v>{/if}
{#if urlLang=='en'}<v lang=en>From the malignant enemeny, defend me.</v>{/if}
{#if showLatin}<v lang=la>In hora mortis meæ voca me.</v>{/if}
{#if urlLang=='de'}<v lang=de>In meiner Todesstunde rufe mich,</v>{/if}
{#if urlLang=='en'}<v lang=en>At the hour of death, call me.</v>{/if}
{#if showLatin}<v lang=la>Et iube me veníre ad te,</v>{/if}
{#if urlLang=='de'}<v lang=de>Und heisse zur Dir kommen mich,</v>{/if}
{#if urlLang=='en'}<v lang=en>And bid me come unto Thee</v>{/if}
{#if showLatin}<v lang=la>Ut cum Sanctis tuis laudem te</v>{/if}
{#if urlLang=='de'}<v lang=de>Damit ich möge loben Dich</v>{/if}
{#if urlLang=='en'}<v lang=en>That with Thy Saints I may praise Thee</v>{/if}
{#if showLatin}<v lang=la>in sǽcula sæculórum.</v>{/if}
{#if urlLang=='de'}<v lang=de>Mit Deinen Heiligen ewiglich.</v>{/if}
{#if urlLang=='en'}<v lang=en>forever and ever.</v>{/if}
<v lang=und>Amen.</v>
</p>
{/snippet}
</Prayer>

View File

@@ -0,0 +1,68 @@
<script>
import Prayer from './Prayer.svelte';
</script>
<Prayer>
{#snippet children(showLatin, urlLang)}
<p>
{#if showLatin}<v lang="la">Credo in Deum Patrem omnipoténtem,</v>{/if}
{#if urlLang === 'de'}<v lang="de">Ich glaube an Gott, den Vater, den Allmächtigen,</v>{/if}
{#if urlLang === 'en'}<v lang="en">I believe in God, the Father almighty,</v>{/if}
{#if showLatin}<v lang="la">Creatórem cæli et terræ.</v>{/if}
{#if urlLang === 'de'}<v lang="de">den Schöpfer des Himmels und der Erde.</v>{/if}
{#if urlLang === 'en'}<v lang="en">Creator of heaven and earth.</v>{/if}
</p>
<p>
{#if showLatin}<v lang="la">Et in Iesum Christum, Fílium eius únicum, Dóminum nostrum,</v>{/if}
{#if urlLang === 'de'}<v lang="de">Und an Jesus Christus, seinen eingeborenen Sohn, unsern Herrn,</v>{/if}
{#if urlLang === 'en'}<v lang="en">And in Jesus Christ, His only Son, our Lord,</v>{/if}
{#if showLatin}<v lang="la">qui concéptus est de Spíritu Sancto,</v>{/if}
{#if urlLang === 'de'}<v lang="de">der empfangen ist vom Heiligen Geist,</v>{/if}
{#if urlLang === 'en'}<v lang="en">who was conceived by the Holy Spirit,</v>{/if}
{#if showLatin}<v lang="la">natus ex María Vírgine,</v>{/if}
{#if urlLang === 'de'}<v lang="de">geboren von der Jungfrau Maria,</v>{/if}
{#if urlLang === 'en'}<v lang="en">born of the Virgin Mary,</v>{/if}
{#if showLatin}<v lang="la">passus sub Póntio Piláto,</v>{/if}
{#if urlLang === 'de'}<v lang="de">gelitten unter Pontius Pilatus,</v>{/if}
{#if urlLang === 'en'}<v lang="en">suffered under Pontius Pilate,</v>{/if}
{#if showLatin}<v lang="la">crucifíxus, mórtuus, et sepúltus,</v>{/if}
{#if urlLang === 'de'}<v lang="de">gekreuzigt, gestorben und begraben,</v>{/if}
{#if urlLang === 'en'}<v lang="en">was crucified, died, and was buried.</v>{/if}
{#if showLatin}<v lang="la">descéndit ad ínferos,</v>{/if}
{#if urlLang === 'de'}<v lang="de">hinabgestiegen in das Reich des Todes,</v>{/if}
{#if urlLang === 'en'}<v lang="en">He descended into hell.</v>{/if}
{#if showLatin}<v lang="la">tértia die resurréxit a mórtuis,</v>{/if}
{#if urlLang === 'de'}<v lang="de">am dritten Tage auferstanden von den Toten,</v>{/if}
{#if urlLang === 'en'}<v lang="en">On the third day He rose again from the dead.</v>{/if}
{#if showLatin}<v lang="la">ascéndit ad cælos,</v>{/if}
{#if urlLang === 'de'}<v lang="de">aufgefahren in den Himmel,</v>{/if}
{#if urlLang === 'en'}<v lang="en">He ascended into heaven,</v>{/if}
{#if showLatin}<v lang="la">sedet ad déxteram Dei Patris omnipoténtis,</v>{/if}
{#if urlLang === 'de'}<v lang="de">er sitzet zur Rechten Gottes, des allmächtigen Vaters;</v>{/if}
{#if urlLang === 'en'}<v lang="en">and sits at the right hand of God the Father almighty.</v>{/if}
{#if showLatin}<v lang="la">inde ventúrus est iudicáre vivos et mórtuos.</v>{/if}
{#if urlLang === 'de'}<v lang="de">von dort wird er kommen, zu richten die Lebenden und die Toten.</v>{/if}
{#if urlLang === 'en'}<v lang="en">From thence He shall come to judge the living and the dead.</v>{/if}
</p>
<p>
{#if showLatin}<v lang="la">Credo in Spíritum Sanctum,</v>{/if}
{#if urlLang === 'de'}<v lang="de">Ich glaube an den Heiligen Geist,</v>{/if}
{#if urlLang === 'en'}<v lang="en">I believe in the Holy Spirit,</v>{/if}
{#if showLatin}<v lang="la">sanctam Ecclésiam cathólicam,</v>{/if}
{#if urlLang === 'de'}<v lang="de">die heilige katholische Kirche,</v>{/if}
{#if urlLang === 'en'}<v lang="en">the holy catholic Church,</v>{/if}
{#if showLatin}<v lang="la">sanctórum communiónem,</v>{/if}
{#if urlLang === 'de'}<v lang="de">Gemeinschaft der Heiligen,</v>{/if}
{#if urlLang === 'en'}<v lang="en">the communion of saints,</v>{/if}
{#if showLatin}<v lang="la">remissiónem peccatórum,</v>{/if}
{#if urlLang === 'de'}<v lang="de">Vergebung der Sünden,</v>{/if}
{#if urlLang === 'en'}<v lang="en">the forgiveness of sins,</v>{/if}
{#if showLatin}<v lang="la">carnis resurrectiónem,</v>{/if}
{#if urlLang === 'de'}<v lang="de">Auferstehung der Toten</v>{/if}
{#if urlLang === 'en'}<v lang="en">the resurrection of the body,</v>{/if}
{#if showLatin}<v lang="la">vitam ætérnam. Amen.</v>{/if}
{#if urlLang === 'de'}<v lang="de">und das ewige Leben. Amen.</v>{/if}
{#if urlLang === 'en'}<v lang="en">and life everlasting. Amen.</v>{/if}
</p>
{/snippet}
</Prayer>

View File

@@ -1,7 +1,20 @@
<script>
import Prayer from './Prayer.svelte';
let { intro = false } = $props();
</script>
{#if intro}
<Prayer hasLatin={false}>
{#snippet children(showLatin, urlLang)}
<p class="intro">
{#if urlLang === 'en'}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.{/if}
{#if urlLang === 'de'}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.{/if}
</p>
{/snippet}
</Prayer>
{/if}
<Prayer>
{#snippet children(showLatin, urlLang)}
<p>

View File

@@ -0,0 +1,25 @@
<script>
import Prayer from './Prayer.svelte';
</script>
<Prayer>
{#snippet children(showLatin, urlLang)}
<p>
{#if showLatin}<v lang="la">Ángele Dei,</v>{/if}
{#if urlLang === 'de'}<v lang="de">Engel Gottes,</v>{/if}
{#if urlLang === 'en'}<v lang="en">Angel of God,</v>{/if}
{#if showLatin}<v lang="la">qui custos es mei,</v>{/if}
{#if urlLang === 'de'}<v lang="de">mein Beschützer,</v>{/if}
{#if urlLang === 'en'}<v lang="en">my guardian dear,</v>{/if}
{#if showLatin}<v lang="la">me, tibi commíssum pietáte supérna,</v>{/if}
{#if urlLang === 'de'}<v lang="de">dir hat Gottes Vorsehung mich anvertraut;</v>{/if}
{#if urlLang === 'en'}<v lang="en">to whom God's love commits me here,</v>{/if}
{#if showLatin}<v lang="la">illúmina, custódi, rege et gubérna.</v>{/if}
{#if urlLang === 'de'}<v lang="de">erleuchte, beschütze, leite und führe mich.</v>{/if}
{#if urlLang === 'en'}<v lang="en">ever this day be at my side, to light and guard, to rule and guide.</v>{/if}
{#if showLatin}<v lang="la">Amen.</v>{/if}
{#if urlLang === 'de'}<v lang="de">Amen.</v>{/if}
{#if urlLang === 'en'}<v lang="en">Amen.</v>{/if}
</p>
{/snippet}
</Prayer>

View File

@@ -0,0 +1,41 @@
<script>
import Prayer from './Prayer.svelte';
import Paternoster from './Paternoster.svelte';
import AveMaria from './AveMaria.svelte';
import GloriaPatri from './GloriaPatri.svelte';
import AnimaChristi from './AnimaChristi.svelte';
import PrayerBeforeACrucifix from './PrayerBeforeACrucifix.svelte';
let {onlyIntro = false } = $props();
</script>
<Prayer hasLatin={false}>
{#snippet children(showLatin, urlLang)}
<p class="intro">
{#if urlLang === 'en'}A plenary indulgence is granted to the faithful who devoutly recite these prayers after Holy Communion. The usual conditions apply: sacramental confession, Eucharistic communion, prayer for the intentions of the Holy Father, and detachment from all sin, even venial.{/if}
{#if urlLang === 'de'}Den Gläubigen, die diese Gebete nach der heiligen Kommunion andächtig verrichten, wird ein vollkommener Ablass gewährt. Die üblichen Bedingungen gelten: sakramentale Beichte, eucharistische Kommunion, Gebet in den Anliegen des Heiligen Vaters und Loslösung von jeder Sünde, auch von lässlichen.{/if}
</p>
{/snippet}
</Prayer>
{#if !onlyIntro}
<Prayer>
{#snippet children(showLatin, urlLang)}
<h3> Ánima Christi </h3>
<AnimaChristi />
<h3>
{#if urlLang=='en'}Plenary Indulgence{:else}Vollkommener Ablass{/if}
</h3>
<h3>
{#if urlLang=='en'}Prayer Before a Crucifix{:else}Gebet vor einem Kruzifix{/if}
</h3>
<h4> Paternoster </h4>
<Paternoster />
<h4> Ave Maria </h4>
<AveMaria />
<h4> Gloria Patri </h4>
<GloriaPatri />
<PrayerBeforeACrucifix />
{/snippet}
</Prayer>
{/if}

View File

@@ -0,0 +1,38 @@
<script>
import Prayer from './Prayer.svelte';
import Paternoster from './Paternoster.svelte';
import AveMaria from './AveMaria.svelte';
import GloriaPatri from './GloriaPatri.svelte';
</script>
<Prayer>
{#snippet children(showLatin, urlLang)}
<p>
{#if showLatin}<v lang=la>En ego, o bone et dulcíssime Jesu,</v>{/if}
{#if urlLang=='de'}<v lang=de>Siehe, o gütiger und milder Jesus,</v>{/if}
{#if urlLang=='en'}<v lang=en>Behold, O good and sweetest Jesus,</v>{/if}
{#if showLatin}<v lang=la>ante conspéctum tuum génibus me provólvo </v>{/if}
{#if urlLang=='de'}<v lang=de>ich werfe mich vor Deinen Augen auf die Knie. </v>{/if}
{#if urlLang=='en'}<v lang=en>I cast myself upon my knees in Thy sight,</v>{/if}
{#if showLatin}<v lang=la>ac máximo ánimi ardóre te oro atque obtéstor, </v>{/if}
{#if urlLang=='de'}<v lang=de>Inbrünstig bitte und beschwöre ich Dich:</v>{/if}
{#if urlLang=='en'}<v lang=en>and with the most fervent desire of my soul I pray and beseech Thee</v>{/if}
{#if showLatin}<v lang=la> ut meum in in cor vívidos fídei, spei et caritátis sensus, atque veram peccatórum meórum pœniténtiam,</v>{/if}
{#if urlLang=='de'}<v lang=de>Präge meinem Herzen lebendige Gefühle des Glaubens, der Hoffung und der Liebe ein</v>{/if}
{#if urlLang=='en'}<v lang=en>to impress upon my heart lively sentiments of faith, hope and charity,</v>{/if}
{#if showLatin} <v lang=la>éaque emendándi firmíssimam voluntátem velis</v>{/if}
{#if urlLang=='de'}<v lang=de>sowie wahre Reue über meine Sünden und den ganz festen Willen, mich zu bessern.</v>{/if}
{#if urlLang=='en'}<v lang=en>with true repentance for my sins and a most firm desire of amendment:</v>{/if}
{#if showLatin} <v lang=la> imprímere; dum magno ánimi afféctu et dolóre tua quinque vúlnera mecum ipse consídero ac mente contémplor,</v>{/if}
{#if urlLang=='de'}<v lang=de>Voll Liebe und Schmerz schaue ich Deine fünf Wunden und betrachte sie in meinem Geiste.</v>{/if}
{#if urlLang=='en'}<v lang=en>whilst with deep affection and grief of soul I consider within myself and mentally contemplate Thy five most precious Wounds,</v>{/if}
{#if showLatin}<v lang=la>illud præ óculis habens, quod jam in ore ponébat tuo David Prophéta de te, o bone Jesu:</v>{/if}
{#if urlLang=='de'}<v lang=de>Dabei halte ich mir vor Augen, was im Hinblick auf Dich, o guter Jesus, schon der Prophet David Dir in den Mund legte:</v>{/if}
{#if urlLang=='en'}<v lang=en>having before mine eyes that which David, the prophet, long ago spoke in Thine Own person concerning Thee, my Jesus:</v>{/if}
{#if showLatin}<v lang=la> «Fodérunt manus meas et pedes meos; dinumeravérunt ómnio ossa mea.» (Ps. 21, 17-18)</v>{/if}
{#if urlLang=='de'}<v lang=de>«Sie haben Meine Hände und Meine Füsse durchbohrt; alle meine Gebeine haben sie gezählt.» (Ps. 21, 17-18)</v>{/if}
{#if urlLang=='en'}<v lang=en>"They have pierced My hands and My feet, they have numbered all My bones." (Ps. 21:17-18</v>{/if}
<v lang=und>Amen.</v>
</p>
{/snippet}
</Prayer>

View File

@@ -0,0 +1,46 @@
<script>
import Prayer from './Prayer.svelte';
</script>
<Prayer>
{#snippet children(showLatin, urlLang)}
<p>
{#if showLatin}<v lang="la">Regína Cæli, lætáre, allelúia.</v>{/if}
{#if urlLang === 'de'}<v lang="de">Freu dich, du Himmelskönigin, alleluja.</v>{/if}
{#if urlLang === 'en'}<v lang="en">Queen of Heaven, rejoice, alleluia.</v>{/if}
{#if showLatin}<v lang="la">Quia quem meruísti portáre, allelúia.</v>{/if}
{#if urlLang === 'de'}<v lang="de">Den du zu tragen würdig warst, alleluja.</v>{/if}
{#if urlLang === 'en'}<v lang="en">For He whom thou didst merit to bear, alleluia.</v>{/if}
{#if showLatin}<v lang="la">Resurréxit, sicut dixit, allelúia.</v>{/if}
{#if urlLang === 'de'}<v lang="de">Er ist auferstanden, wie er gesagt hat, alleluja.</v>{/if}
{#if urlLang === 'en'}<v lang="en">Has risen, as He said, alleluia.</v>{/if}
{#if showLatin}<v lang="la">Ora pro nobis Deum, allelúia.</v>{/if}
{#if urlLang === 'de'}<v lang="de">Bitt Gott für uns, alleluja.</v>{/if}
{#if urlLang === 'en'}<v lang="en">Pray for us to God, alleluia.</v>{/if}
</p>
<p>
{#if showLatin}<v lang="la"><i>℣.</i> Gaude et lætáre, Virgo María, allelúia.</v>{/if}
{#if urlLang === 'de'}<v lang="de"><i>℣.</i> Freu dich und frohlocke, Jungfrau Maria, alleluja.</v>{/if}
{#if urlLang === 'en'}<v lang="en"><i>℣.</i> Rejoice and be glad, O Virgin Mary, alleluia.</v>{/if}
{#if showLatin}<v lang="la"><i>℟.</i> Quia surréxit Dóminus vere, allelúia.</v>{/if}
{#if urlLang === 'de'}<v lang="de"><i>℟.</i> Denn der Herr ist wahrhaft auferstanden, alleluja.</v>{/if}
{#if urlLang === 'en'}<v lang="en"><i>℟.</i> For the Lord has truly risen, alleluia.</v>{/if}
</p>
<p>
{#if showLatin}<v lang="la"><i>℣.</i> Orémus.</v>{/if}
{#if urlLang === 'de'}<v lang="de"><i>℣.</i> Lasset uns beten.</v>{/if}
{#if urlLang === 'en'}<v lang="en"><i>℣.</i> Let us pray:</v>{/if}
</p>
<p>
{#if showLatin}<v lang="la">Deus, qui per resurrectiónem Fílii tui Dómini nostri Iesu Christi mundum lætificáre dignátus es,</v>{/if}
{#if urlLang === 'de'}<v lang="de">O Gott, der du durch die Auferstehung deines Sohnes, unseres Herrn Jesus Christus, die Welt zu erfreuen dich gewürdigt hast,</v>{/if}
{#if urlLang === 'en'}<v lang="en">O God, who through the resurrection of Thy Son our Lord Jesus Christ didst vouchsafe to give joy to the world,</v>{/if}
{#if showLatin}<v lang="la">præsta, quǽsumus, ut per eius Genetrícem Vírginem Maríam perpétuæ capiámus gáudia vitæ.</v>{/if}
{#if urlLang === 'de'}<v lang="de">verleihe uns, wir bitten dich, dass wir durch seine Mutter, die Jungfrau Maria, die Freuden des ewigen Lebens erlangen.</v>{/if}
{#if urlLang === 'en'}<v lang="en">grant, we beseech Thee, that through His Mother the Virgin Mary we may obtain the joys of everlasting life.</v>{/if}
{#if showLatin}<v lang="la">Per eúmdem Christum Dóminum nostrum. Amen.</v>{/if}
{#if urlLang === 'de'}<v lang="de">Durch Christus, unseren Herrn. Amen.</v>{/if}
{#if urlLang === 'en'}<v lang="en">Through the same Christ our Lord. Amen.</v>{/if}
</p>
{/snippet}
</Prayer>

View File

@@ -0,0 +1,48 @@
<script>
import Prayer from './Prayer.svelte';
</script>
<Prayer>
{#snippet children(showLatin, urlLang)}
<p>
{#if showLatin}<v lang="la">Tantum ergo Sacraméntum</v>{/if}
{#if urlLang === 'de'}<v lang="de">Darum lasst uns tief verehren</v>{/if}
{#if urlLang === 'en'}<v lang="en">Therefore so great a Sacrament</v>{/if}
{#if showLatin}<v lang="la">venerémur cérnui:</v>{/if}
{#if urlLang === 'de'}<v lang="de">ein so grosses Sakrament;</v>{/if}
{#if urlLang === 'en'}<v lang="en">let us venerate with bowed heads;</v>{/if}
{#if showLatin}<v lang="la">et antíquum documéntum</v>{/if}
{#if urlLang === 'de'}<v lang="de">dieser Bund soll ewig währen</v>{/if}
{#if urlLang === 'en'}<v lang="en">and the old rite</v>{/if}
{#if showLatin}<v lang="la">novo cedat rítui:</v>{/if}
{#if urlLang === 'de'}<v lang="de">und den neuen Bund ersetzt.</v>{/if}
{#if urlLang === 'en'}<v lang="en">give way to the new:</v>{/if}
{#if showLatin}<v lang="la">præstet fides suppleméntum</v>{/if}
{#if urlLang === 'de'}<v lang="de">Unser Glaube soll uns lehren,</v>{/if}
{#if urlLang === 'en'}<v lang="en">let faith provide a supplement</v>{/if}
{#if showLatin}<v lang="la">sénsuum deféctui.</v>{/if}
{#if urlLang === 'de'}<v lang="de">was das Auge nicht erkennt.</v>{/if}
{#if urlLang === 'en'}<v lang="en">for the failure of the senses.</v>{/if}
</p>
<p>
{#if showLatin}<v lang="la">Genitóri, Genitóque</v>{/if}
{#if urlLang === 'de'}<v lang="de">Gott dem Vater und dem Sohne</v>{/if}
{#if urlLang === 'en'}<v lang="en">To the Begetter and the Begotten</v>{/if}
{#if showLatin}<v lang="la">laus et iubilátio,</v>{/if}
{#if urlLang === 'de'}<v lang="de">sei Lob und Preis und Ehre,</v>{/if}
{#if urlLang === 'en'}<v lang="en">be praise and jubilation,</v>{/if}
{#if showLatin}<v lang="la">salus, honor, virtus quoque</v>{/if}
{#if urlLang === 'de'}<v lang="de">Heil und Ruhm und Macht und Wonne</v>{/if}
{#if urlLang === 'en'}<v lang="en">salvation, honour, virtue also</v>{/if}
{#if showLatin}<v lang="la">sit et benedíctio:</v>{/if}
{#if urlLang === 'de'}<v lang="de">und Segen immerdar,</v>{/if}
{#if urlLang === 'en'}<v lang="en">and blessing too:</v>{/if}
{#if showLatin}<v lang="la">procedénti ab utróque</v>{/if}
{#if urlLang === 'de'}<v lang="de">und dem der von beiden ausgeht,</v>{/if}
{#if urlLang === 'en'}<v lang="en">to Him proceeding from both</v>{/if}
{#if showLatin}<v lang="la">compar sit laudátio. Amen.</v>{/if}
{#if urlLang === 'de'}<v lang="de">sei gleiche Ehre. Amen.</v>{/if}
{#if urlLang === 'en'}<v lang="en">let there be equal praise. Amen.</v>{/if}
</p>
{/snippet}
</Prayer>

View File

@@ -0,0 +1,56 @@
/**
* Compute Easter Sunday for a given year (Anonymous Gregorian algorithm).
*/
export function computeEaster(year: number): Date {
const a = year % 19;
const b = Math.floor(year / 100);
const c = year % 100;
const d = Math.floor(b / 4);
const e = b % 4;
const f = Math.floor((b + 8) / 25);
const g = Math.floor((b - f + 1) / 3);
const h = (19 * a + b - d - g + 15) % 30;
const i = Math.floor(c / 4);
const k = c % 4;
const l = (32 + 2 * e + 2 * i - h - k) % 7;
const m = Math.floor((a + 11 * h + 22 * l) / 451);
const month = Math.floor((h + l - 7 * m + 114) / 31);
const day = ((h + l - 7 * m + 114) % 31) + 1;
return new Date(year, month - 1, day);
}
/**
* Check if a date falls within Eastertide (Easter Sunday to Pentecost Sunday, inclusive).
*/
export function isEastertide(date: Date = new Date()): boolean {
const year = date.getFullYear();
const easter = computeEaster(year);
const pentecost = new Date(easter);
pentecost.setDate(pentecost.getDate() + 49);
return date >= easter && date <= pentecost;
}
/**
* Check if a date falls within Lent (Ash Wednesday to Holy Saturday, inclusive).
* Ash Wednesday = Easter 46 days; Holy Saturday = Easter 1 day.
*/
export function isLent(date: Date = new Date()): boolean {
const year = date.getFullYear();
const easter = computeEaster(year);
const ashWednesday = new Date(easter);
ashWednesday.setDate(ashWednesday.getDate() - 46);
const holySaturday = new Date(easter);
holySaturday.setDate(holySaturday.getDate() - 1);
return date >= ashWednesday && date <= holySaturday;
}
export type LiturgicalSeason = 'eastertide' | 'lent' | null;
/**
* Get the current liturgical season relevant for rosary mystery selection.
*/
export function getLiturgicalSeason(date: Date = new Date()): LiturgicalSeason {
if (isEastertide(date)) return 'eastertide';
if (isLent(date)) return 'lent';
return null;
}

View File

@@ -28,7 +28,7 @@ function isActive(path) {
<ul class=site_header>
<li><a href="/{data.faithLang}/{prayersPath}" class:active={isActive(`/${data.faithLang}/${prayersPath}`)}>{labels.prayers}</a></li>
<li><a href="/{data.faithLang}/{rosaryPath}" class:active={isActive(`/${data.faithLang}/${rosaryPath}`)}>{labels.rosary}</a></li>
<li><a href="/{data.faithLang}/angelus" class:active={isActive(`/${data.faithLang}/angelus`)}>Angelus</a></li>
<li><a href="/{data.faithLang}/{prayersPath}/angelus" class:active={isActive(`/${data.faithLang}/${prayersPath}/angelus`)}>Angelus</a></li>
</ul>
{/snippet}

View File

@@ -71,7 +71,7 @@
</svg>
<h3>{labels.rosary}</h3>
</a>
<a href="/{data.faithLang}/angelus">
<a href="/{data.faithLang}/{prayersPath}/angelus">
<svg xmlns="http://www.w3.org/2000/svg"viewBox="6 -274 564 548"><path d="M392-162c-4-10-9-18-15-26 5-4 7-8 7-12 0-18-43-32-96-32s-96 14-96 32c0 4 3 8 7 12-6 8-11 16-15 26-15-11-24-24-24-38 0-35 57-64 128-64s128 29 128 64c0 14-9 27-24 38zm-104-22c35 0 64 29 64 64s-29 64-64 64-64-29-64-64 29-64 64-64zM82 159c3-22-3-48-20-64C34 68 16 30 16-12v-64c0-42 34-76 76-76 23 0 44 10 59 27l65 78c-21 16-37 40-43 67l-43 195c-4 17-2 34 5 49h-21c-26 0-46-24-42-50l10-55zm364 56L403 20c-6-27-21-51-42-67l64-77c15-18 36-28 59-28 42 0 76 34 76 76v64c0 42-18 80-46 107-17 16-23 42-20 64l10 56c4 26-16 49-42 49h-20c6-15 8-32 4-49zM220 31c7-32 35-55 68-55s61 23 68 55l43 194c5 20-11 39-31 39H208c-21 0-36-19-31-39l43-194z"/></svg>
<h3>Angelus</h3>
</a>

View File

@@ -5,8 +5,14 @@ export const load: PageServerLoad = async ({ url }) => {
const hasUrlLatin = latinParam !== null;
const initialLatin = hasUrlLatin ? latinParam !== '0' : true;
const categoryParam = url.searchParams.get('category');
const hasUrlCategory = categoryParam !== null;
const initialCategory = hasUrlCategory ? categoryParam : null;
return {
initialLatin,
hasUrlLatin
hasUrlLatin,
initialCategory,
hasUrlCategory
};
};

View File

@@ -19,8 +19,16 @@
import BruderKlausGebet from "$lib/components/faith/prayers/BruderKlausGebet.svelte";
import JosephGebet from "$lib/components/faith/prayers/JosephGebet.svelte";
import Confiteor from "$lib/components/faith/prayers/Confiteor.svelte";
import AblassGebete from "$lib/components/faith/prayers/AblassGebete.svelte";
import GuardianAngel from "$lib/components/faith/prayers/GuardianAngel.svelte";
import ApostlesCreed from "$lib/components/faith/prayers/ApostlesCreed.svelte";
import TantumErgo from "$lib/components/faith/prayers/TantumErgo.svelte";
import Angelus from "$lib/components/faith/prayers/Angelus.svelte";
import ReginaCaeli from "$lib/components/faith/prayers/ReginaCaeli.svelte";
import AnimaChristi from "$lib/components/faith/prayers/AnimaChristi.svelte";
import PrayerBeforeACrucifix from "$lib/components/faith/prayers/PrayerBeforeACrucifix.svelte";
import Postcommunio from "$lib/components/faith/prayers/Postcommunio.svelte";
import Prayer from "$lib/components/faith/prayers/Prayer.svelte";
import { isEastertide as checkEastertide } from "$lib/js/easter.svelte";
let { data } = $props();
@@ -48,9 +56,6 @@
salveRegina: 'Salve Regina',
fatima: isEnglish ? 'Fatima Prayer' : 'Das Fatimagebet',
gloria: 'Glória',
gloriaIntro: 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.',
michael: isEnglish ? 'Prayer to St. Michael the Archangel' : 'Gebet zum hl. Erzengel Michael',
bruderKlaus: isEnglish ? 'Prayer of St. Nicholas of Flüe' : 'Bruder Klaus Gebet',
joseph: isEnglish ? 'Prayer to St. Joseph by Pope St. Pius X' : 'Josephgebet des hl. Papst Pius X',
@@ -58,13 +63,69 @@
searchPlaceholder: isEnglish ? 'Search prayers...' : 'Gebete suchen...',
clearSearch: isEnglish ? 'Clear search' : 'Suche löschen',
textMatch: isEnglish ? 'Match in prayer text' : 'Treffer im Gebetstext',
ablassgebete: 'Ablassgebete'
postcommunio: isEnglish ? 'Postcommunio Prayers' : 'Nachkommuniongebete',
animachristi: 'Ánima Christi',
prayerbeforeacrucifix: isEnglish ? 'Prayer Before a Crucifix' : 'Gebet vor einem Kruzifix',
guardianAngel: isEnglish ? 'Guardian Angel Prayer' : 'Schutzengel-Gebet',
apostlesCreed: isEnglish ? "Apostles' Creed" : 'Apostolisches Glaubensbekenntnis',
tantumErgo: 'Tantum Ergo',
angelus: 'Angelus',
reginaCaeli: 'Regína Cæli'
});
// TODO: Add categories: 'meal' (Tischgebete/Meal) and 'morning_evening' (Morgen-/Abendgebete/Morning & Evening)
// when corresponding prayers are added to the collection
const categories = [
{ id: 'essential', de: 'Grundgebete', en: 'Essential' },
{ id: 'marian', de: 'Marianisch', en: 'Marian' },
{ id: 'saints', de: 'Heilige', en: 'Saints' },
{ id: 'eucharistic', de: 'Eucharistie', en: 'Eucharistic' },
{ id: 'praise', de: 'Lobpreis', en: 'Praise' },
{ id: 'penitential', de: 'Busse', en: 'Penitential' },
];
const prayerCategories = {
signOfCross: ['essential'],
gloriaPatri: ['essential', 'praise'],
paternoster: ['essential'],
credo: ['essential'],
aveMaria: ['essential', 'marian'],
salveRegina: ['marian'],
fatima: ['marian', 'penitential'],
gloria: ['praise'],
michael: ['saints'],
bruderKlaus: ['saints'],
joseph: ['saints'],
confiteor: ['penitential'],
guardianAngel: ['essential'],
apostlesCreed: ['essential'],
tantumErgo: ['eucharistic', 'praise'],
angelus: ['marian'],
reginaCaeli: ['marian'],
animachristi: ['eucharistic'],
prayerbeforeacrucifix: ['eucharistic', 'penitential'],
postcommunio: ['eucharistic'],
};
let selectedCategory = $state(data.initialCategory);
// JS-only search (hidden without JS)
let jsEnabled = $state(false);
let searchQuery = $state('');
/**
* Build href for category filter, preserving latin param state
* @param {string|null} categoryId
*/
function buildFilterHref(categoryId) {
const params = new URLSearchParams();
if (categoryId) params.set('category', categoryId);
if (!data.initialLatin) params.set('latin', '0');
const qs = params.toString();
return qs ? `?${qs}` : '?';
}
onMount(() => {
jsEnabled = true;
@@ -92,7 +153,14 @@
{ id: 'bruderKlaus', searchTerms: ['bruder klaus', 'nicholas', 'niklaus', 'flüe'], slug: isEnglish ? 'prayer-of-st-nicholas-of-flue' : 'bruder-klaus-gebet' },
{ id: 'joseph', searchTerms: ['joseph', 'josef', 'pius'], slug: isEnglish ? 'prayer-to-st-joseph-by-pope-st-pius-x' : 'josephgebet-des-hl-papst-pius-x' },
{ id: 'confiteor', searchTerms: ['confiteor', 'i confess', 'ich bekenne', 'mea culpa'], slug: isEnglish ? 'the-confiteor' : 'das-confiteor' },
{ id: 'ablassgebete', searchTerms: ['ablass', 'kommunion'], slug: 'ablassgebete' }
{ id: 'guardianAngel', searchTerms: ['schutzengel', 'guardian angel', 'angele dei', 'engel gottes'], slug: isEnglish ? 'guardian-angel-prayer' : 'schutzengel-gebet' },
{ id: 'apostlesCreed', searchTerms: ['apostolisches glaubensbekenntnis', "apostles' creed", 'symbolum apostolorum', 'ich glaube an gott'], slug: isEnglish ? 'apostles-creed' : 'apostolisches-glaubensbekenntnis' },
{ id: 'tantumErgo', searchTerms: ['tantum ergo', 'genitori', 'sakrament', 'sacrament'], slug: 'tantum-ergo' },
{ id: 'angelus', searchTerms: ['angelus', 'engel des herrn', 'angel of the lord'], slug: 'angelus' },
{ id: 'reginaCaeli', searchTerms: ['regina caeli', 'regina coeli', 'himmelskönigin', 'queen of heaven'], slug: 'regina-caeli' },
{ id: 'animachristi', searchTerms: ['anima christi', 'seele christi', 'soul of christ'], slug: 'anima-christi' },
{ id: 'prayerbeforeacrucifix', searchTerms: ['kruzifix', 'crucifix', 'kreuz', 'cross', 'en ego'], slug: isEnglish ? 'prayer-before-a-crucifix' : 'gebet-vor-einem-kruzifix' },
{ id: 'postcommunio', searchTerms: ['postcommunio', 'nachkommunion', 'kommunion', 'communion'], slug: 'postcommunio' }
]);
// Base URL for prayer links
@@ -113,7 +181,14 @@
bruderKlaus: labels.bruderKlaus,
joseph: labels.joseph,
confiteor: labels.confiteor,
ablassgebete: labels.ablassgebete
guardianAngel: labels.guardianAngel,
apostlesCreed: labels.apostlesCreed,
tantumErgo: labels.tantumErgo,
angelus: labels.angelus,
reginaCaeli: labels.reginaCaeli,
animachristi: labels.animachristi,
prayerbeforeacrucifix: labels.prayerbeforeacrucifix,
postcommunio: labels.postcommunio
};
return nameMap[id] || id;
}
@@ -189,11 +264,15 @@
return 'no-match';
}
// Sorted prayers array - primary matches first, then secondary, then hidden
const sortedPrayers = $derived.by(() => {
if (!searchQuery.trim()) return prayers;
// Filtered by category, then sorted by search match
const filteredPrayers = $derived.by(() => {
let result = prayers;
if (selectedCategory) {
result = result.filter(p => prayerCategories[p.id]?.includes(selectedCategory));
}
if (!searchQuery.trim()) return result;
return [...prayers].sort((a, b) => {
return [...result].sort((a, b) => {
const matchA = matchResults.get(a.id);
const matchB = matchResults.get(b.id);
@@ -217,9 +296,19 @@
michael: { bilingue: true },
bruderKlaus: { bilingue: false },
joseph: { bilingue: false },
confiteor: { bilingue: true }
confiteor: { bilingue: true },
guardianAngel: { bilingue: true },
apostlesCreed: { bilingue: true },
tantumErgo: { bilingue: true },
angelus: { bilingue: true },
reginaCaeli: { bilingue: true },
animachristi: { bilingue: true },
prayerbeforeacrucifix: { bilingue: true },
postcommunio: { bilingue: true }
};
const isEastertide = $derived(checkEastertide());
// Toggle href for no-JS fallback (navigates to opposite latin state)
const latinToggleHref = $derived(data.initialLatin ? '?latin=0' : '?');
</script>
@@ -254,6 +343,49 @@ h1{
margin-bottom: 2rem;
}
/* Category filters */
.category-filters {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 0.5em;
margin-bottom: 1.5rem;
padding: 0 1em;
}
.category-pill {
padding: 0.35em 0.9em;
border: 1.5px solid var(--nord3);
border-radius: 999px;
color: var(--nord4);
text-decoration: none;
font-size: 0.9em;
transition: border-color 0.15s, color 0.15s, background-color 0.15s;
}
.category-pill:hover {
border-color: var(--nord8);
color: var(--nord8);
}
.category-pill.selected {
border-color: var(--nord8);
background-color: var(--nord8);
color: var(--nord0);
}
@media(prefers-color-scheme: light) {
.category-pill {
border-color: var(--nord4);
color: var(--nord3);
}
.category-pill:hover {
border-color: var(--nord10);
color: var(--nord10);
}
.category-pill.selected {
border-color: var(--nord10);
background-color: var(--nord10);
color: var(--nord6);
}
}
/* Search result styling */
.prayer-wrapper {
position: relative;
@@ -285,6 +417,57 @@ h1{
}
}
/* Postcommunio section */
.postcommunio-section {
max-width: 600px;
margin: 2rem auto;
padding: 1.5em;
background-color: var(--accent-dark);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
@media(prefers-color-scheme: light) {
.postcommunio-section {
background-color: var(--nord5);
}
}
.postcommunio-section h2 {
text-align: center;
padding-bottom: 0.5em;
}
.postcommunio-links {
list-style: none;
padding: 0;
margin: 0;
text-align: center;
}
.postcommunio-links li {
margin: 0.75em 0;
}
.postcommunio-links a {
color: var(--nord8);
text-decoration: none;
font-size: 1.15em;
}
.postcommunio-links a:hover {
text-decoration: underline;
}
@media(prefers-color-scheme: light) {
.postcommunio-links a {
color: var(--nord10);
}
}
/* Seasonal badge */
.seasonal-badge {
display: inline-block;
margin-top: 0.5em;
padding: 0.2em 0.7em;
font-size: 0.75em;
border-radius: 999px;
background-color: var(--nord14);
color: var(--nord0);
}
/* Search is hidden without JS */
.js-only {
display: none;
@@ -304,6 +487,23 @@ h1{
/>
</div>
<nav class="category-filters" aria-label={isEnglish ? 'Filter by category' : 'Nach Kategorie filtern'}>
<a
href={buildFilterHref(null)}
class="category-pill"
class:selected={!selectedCategory}
onclick={(e) => { e.preventDefault(); selectedCategory = null; }}
>{isEnglish ? 'All' : 'Alle'}</a>
{#each categories as cat (cat.id)}
<a
href={buildFilterHref(cat.id)}
class="category-pill"
class:selected={selectedCategory === cat.id}
onclick={(e) => { e.preventDefault(); selectedCategory = cat.id; }}
>{isEnglish ? cat.en : cat.de}</a>
{/each}
</nav>
<div class="js-only">
<SearchInput
bind:value={searchQuery}
@@ -314,21 +514,9 @@ h1{
<div class="ccontainer">
<div class=container>
{#each sortedPrayers as prayer (prayer.id)}
{#each filteredPrayers as prayer (prayer.id)}
<div class="prayer-wrapper {getMatchClass(prayer.id)}" data-match-label={labels.textMatch}>
{#if prayer.id === 'gloria'}
<Gebet name={getPrayerName(prayer.id)} is_bilingue={true} id={prayer.id} href="{baseUrl}/{prayer.slug}">
<p slot="intro">{labels.gloriaIntro}</p>
<Gloria />
</Gebet>
{:else if prayer.id === 'ablassgebete'}
{#if data.lang === 'de'}
<Gebet name={getPrayerName(prayer.id)} is_bilingue={false} id={prayer.id} href="{baseUrl}/{prayer.slug}">
<AblassGebete />
</Gebet>
{/if}
{:else}
<Gebet name={getPrayerName(prayer.id)} is_bilingue={prayerMeta[prayer.id]?.bilingue ?? true} id={prayer.id} href="{baseUrl}/{prayer.slug}">
<Gebet name={getPrayerName(prayer.id)} is_bilingue={prayerMeta[prayer.id]?.bilingue ?? true} id={prayer.id} href="{baseUrl}/{prayer.slug}">
{#if prayer.id === 'signOfCross'}
<Kreuzzeichen />
{:else if prayer.id === 'gloriaPatri'}
@@ -351,11 +539,32 @@ h1{
<JosephGebet />
{:else if prayer.id === 'confiteor'}
<Confiteor />
{:else if prayer.id === 'guardianAngel'}
<GuardianAngel />
{:else if prayer.id === 'apostlesCreed'}
<ApostlesCreed />
{:else if prayer.id === 'tantumErgo'}
<TantumErgo />
{:else if prayer.id === 'angelus'}
<Angelus />
{:else if prayer.id === 'reginaCaeli'}
<ReginaCaeli />
{:else if prayer.id === 'animachristi'}
<AnimaChristi />
{:else if prayer.id === 'prayerbeforeacrucifix'}
<PrayerBeforeACrucifix />
{:else if prayer.id === 'gloria'}
<Gloria intro={true} />
{:else if prayer.id === 'postcommunio'}
<Postcommunio onlyIntro={true} />
{/if}
{#if prayer.id === 'reginaCaeli' && isEastertide}
<span class="seasonal-badge">{isEnglish ? 'Eastertide' : 'Osterzeit'}</span>
{/if}
</Gebet>
{/if}
</div>
{/each}
</div>
</div>
</div>

View File

@@ -15,7 +15,14 @@ const validSlugs = new Set([
'bruder-klaus-gebet', 'prayer-of-st-nicholas-of-flue',
'josephgebet-des-hl-papst-pius-x', 'prayer-to-st-joseph-by-pope-st-pius-x',
'das-confiteor', 'the-confiteor',
'ablassgebete',
'postcommunio',
'anima-christi',
'prayer-before-a-crucifix', 'gebet-vor-einem-kruzifix',
'schutzengel-gebet', 'guardian-angel-prayer',
'apostolisches-glaubensbekenntnis', 'apostles-creed',
'tantum-ergo',
'angelus',
'regina-caeli',
]);
export const load: PageServerLoad = async ({ params, url }) => {
@@ -23,10 +30,6 @@ export const load: PageServerLoad = async ({ params, url }) => {
throw error(404, 'Prayer not found');
}
if (params.faithLang === 'faith' && params.prayer === 'ablassgebete') {
throw error(404, 'Prayer not found');
}
const latinParam = url.searchParams.get('latin');
const hasUrlLatin = latinParam !== null;
const initialLatin = hasUrlLatin ? latinParam !== '0' : true;

View File

@@ -16,7 +16,14 @@
import BruderKlausGebet from "$lib/components/faith/prayers/BruderKlausGebet.svelte";
import JosephGebet from "$lib/components/faith/prayers/JosephGebet.svelte";
import Confiteor from "$lib/components/faith/prayers/Confiteor.svelte";
import AblassGebete from "$lib/components/faith/prayers/AblassGebete.svelte";
import Postcommunio from "$lib/components/faith/prayers/Postcommunio.svelte";
import AnimaChristi from "$lib/components/faith/prayers/AnimaChristi.svelte";
import PrayerBeforeACrucifix from "$lib/components/faith/prayers/PrayerBeforeACrucifix.svelte";
import GuardianAngel from "$lib/components/faith/prayers/GuardianAngel.svelte";
import ApostlesCreed from "$lib/components/faith/prayers/ApostlesCreed.svelte";
import TantumErgo from "$lib/components/faith/prayers/TantumErgo.svelte";
import AngelusComponent from "$lib/components/faith/prayers/Angelus.svelte";
import ReginaCaeli from "$lib/components/faith/prayers/ReginaCaeli.svelte";
import StickyImage from "$lib/components/faith/StickyImage.svelte";
let { data } = $props();
@@ -52,7 +59,17 @@
'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 },
'ablassgebete': { id: 'ablassgebete', name: 'Ablassgebete', bilingue: true }
'postcommunio': { id: 'postcommunio', name: isEnglish ? 'Postcommunio Prayers' : 'Nachkommuniongebete', bilingue: true },
'anima-christi': { id: 'animachristi', name: 'Ánima Christi', bilingue: true },
'prayer-before-a-crucifix': { id: 'prayerbeforeacrucifix', name: isEnglish ? 'Prayer Before a Crucifix' : 'Gebet vor einem Kruzifix', bilingue: true },
'gebet-vor-einem-kruzifix': { id: 'prayerbeforeacrucifix', name: isEnglish ? 'Prayer Before a Crucifix' : 'Gebet vor einem Kruzifix', bilingue: true },
'schutzengel-gebet': { id: 'guardianAngel', name: isEnglish ? 'Guardian Angel Prayer' : 'Schutzengel-Gebet', bilingue: true },
'guardian-angel-prayer': { id: 'guardianAngel', name: isEnglish ? 'Guardian Angel Prayer' : 'Schutzengel-Gebet', bilingue: true },
'apostolisches-glaubensbekenntnis': { id: 'apostlesCreed', name: isEnglish ? "Apostles' Creed" : 'Apostolisches Glaubensbekenntnis', bilingue: true },
'apostles-creed': { id: 'apostlesCreed', name: isEnglish ? "Apostles' Creed" : 'Apostolisches Glaubensbekenntnis', bilingue: true },
'tantum-ergo': { id: 'tantumErgo', name: 'Tantum Ergo', bilingue: true },
'angelus': { id: 'angelus', name: 'Angelus', bilingue: true },
'regina-caeli': { id: 'reginaCaeli', name: 'Regína Cæli', bilingue: true }
});
const prayer = $derived(prayerDefs[data.prayer]);
@@ -136,7 +153,7 @@ h1 {
}
}
</style>
{#if prayerId === 'ablassgebete'}
{#if prayerId === 'postcommunio' || prayerId === 'prayerbeforeacrucifix'}
<h1>{prayerName}</h1>
@@ -151,7 +168,11 @@ h1 {
<StickyImage src="/glaube/crucifix.webp" alt="Crucifix">
<div class="gebet-wrapper">
<div class="gebet" class:bilingue={isBilingue}>
<AblassGebete verbose={true} />
{#if prayerId === 'postcommunio'}
<Postcommunio onlyIntro={false} />
{:else}
<PrayerBeforeACrucifix verbose={true} />
{/if}
</div>
</div>
</StickyImage>
@@ -197,6 +218,20 @@ h1 {
<JosephGebet />
{:else if prayerId === 'confiteor'}
<Confiteor />
{:else if prayerId === 'animachristi'}
<AnimaChristi />
{:else if prayerId === 'prayerbeforeacrucifix'}
<PrayerBeforeACrucifix />
{:else if prayerId === 'guardianAngel'}
<GuardianAngel />
{:else if prayerId === 'apostlesCreed'}
<ApostlesCreed />
{:else if prayerId === 'tantumErgo'}
<TantumErgo />
{:else if prayerId === 'angelus'}
<AngelusComponent verbose={true} />
{:else if prayerId === 'reginaCaeli'}
<ReginaCaeli />
{/if}
</div>
</div>

View File

@@ -1,4 +1,5 @@
import { mysteryVerseDataDe, mysteryVerseDataEn } from '$lib/data/mysteryVerseData';
import { getLiturgicalSeason } from '$lib/js/easter.svelte';
import type { PageServerLoad, Actions } from './$types';
interface StreakData {
@@ -8,6 +9,11 @@ interface StreakData {
const validMysteries = ['freudenreich', 'schmerzhaften', 'glorreichen', 'lichtreichen'] as const;
const seasonalMysteryMap: Record<string, string> = {
eastertide: 'glorreichen',
lent: 'schmerzhaften',
};
function getMysteryForWeekday(date: Date, includeLuminous: boolean): string {
const dayOfWeek = date.getDay();
@@ -55,14 +61,17 @@ export const load: PageServerLoad = async ({ url, fetch, locals, params }) => {
const initialShowImages = hasUrlImages ? imagesParam !== '0' : true;
const todaysMystery = getMysteryForWeekday(new Date(), initialLuminous);
const season = getLiturgicalSeason();
const seasonalMystery = season ? seasonalMysteryMap[season] ?? null : null;
const defaultMystery = seasonalMystery ?? todaysMystery;
let initialMystery = (validMysteries as readonly string[]).includes(mysteryParam ?? '')
? mysteryParam!
: todaysMystery;
: defaultMystery;
// If luminous is off and luminous mystery was selected, fall back
if (!initialLuminous && initialMystery === 'lichtreichen') {
initialMystery = todaysMystery;
initialMystery = defaultMystery;
}
// Fetch streak data for logged-in users via API route

View File

@@ -12,6 +12,7 @@ import AveMaria from "$lib/components/faith/prayers/AveMaria.svelte";
import GloriaPatri from "$lib/components/faith/prayers/GloriaPatri.svelte";
import FatimaGebet from "$lib/components/faith/prayers/FatimaGebet.svelte";
import SalveRegina from "$lib/components/faith/prayers/SalveRegina.svelte";
import ReginaCaeli from "$lib/components/faith/prayers/ReginaCaeli.svelte";
import RosaryFinalPrayer from "$lib/components/faith/prayers/RosaryFinalPrayer.svelte";
import MichaelGebet from "$lib/components/faith/prayers/MichaelGebet.svelte";
import CounterButton from "$lib/components/CounterButton.svelte";
@@ -23,6 +24,7 @@ import RosarySvg from "./RosarySvg.svelte";
import MysterySelector from "./MysterySelector.svelte";
import MysteryImageColumn from "./MysteryImageColumn.svelte";
import { mysteries, mysteriesLatin, mysteriesEnglish, mysteryTitles, mysteryTitlesEnglish, allMysteryImages, getLabels, getMysteryForWeekday, BEAD_SPACING, DECADE_OFFSET, sectionPositions } from "./rosaryData.js";
import { isEastertide, getLiturgicalSeason } from "$lib/js/easter.svelte";
import { setupScrollSync } from "./rosaryScrollSync.js";
let { data } = $props();
@@ -98,7 +100,9 @@ let imagesToggleHref = $derived(buildHref({ images: !showImages }));
$effect(() => {
todaysMystery = getMysteryForWeekday(new Date(), includeLuminous);
if (!includeLuminous && selectedMystery === 'lichtreichen') {
selectedMystery = todaysMystery;
const season = getLiturgicalSeason();
const seasonalMap = { eastertide: 'glorreichen', lent: 'schmerzhaften' };
selectedMystery = (season ? seasonalMap[season] : null) ?? todaysMystery;
}
});
@@ -276,7 +280,9 @@ onMount(() => {
// If no mystery was specified in URL, recompute based on loaded preferences
if (!data.hasUrlMystery) {
todaysMystery = getMysteryForWeekday(new Date(), includeLuminous);
selectMystery(todaysMystery);
const season = getLiturgicalSeason();
const seasonalMap = { eastertide: 'glorreichen', lent: 'schmerzhaften' };
selectMystery(season ? seasonalMap[season] ?? todaysMystery : todaysMystery);
}
// Clean up URL params after hydration (state is now in component state)
@@ -493,6 +499,19 @@ onMount(() => {
font-size: 1.8rem;
}
.eastertide-badge {
position: absolute;
top: 0.5rem;
right: 0.5rem;
padding: 0.25em 0.6em;
font-size: 0.75rem;
font-weight: 600;
border-radius: 999px;
background-color: var(--nord14);
color: var(--nord0);
z-index: 1;
}
.prayer-section h3 {
color: var(--nord11);
margin-top: 1.5rem;
@@ -696,7 +715,7 @@ h1 {
<h2 style="text-align:center;">{labels.mysteries}</h2>
<!-- Mystery Selector (links for no-JS, enhanced with onclick for JS) -->
<MysterySelector {selectedMystery} {todaysMystery} {includeLuminous} {labels} {mysteryHref} {selectMystery} />
<MysterySelector {selectedMystery} {todaysMystery} {includeLuminous} {labels} {mysteryHref} {selectMystery} season={getLiturgicalSeason()} />
<!-- Toggle Controls & Streak Counter -->
<div class="controls-row">
@@ -905,8 +924,14 @@ h1 {
bind:this={sectionElements.final_salve}
data-section="final_salve"
>
<h3>Salve Regina</h3>
<SalveRegina />
{#if isEastertide()}
<span class="eastertide-badge">{labels.eastertide}</span>
<h3>Regína Cæli</h3>
<ReginaCaeli />
{:else}
<h3>Salve Regina</h3>
<SalveRegina />
{/if}
</div>
<div

View File

@@ -1,7 +1,19 @@
<script>
import MysteryIcon from "$lib/components/faith/MysteryIcon.svelte";
let { selectedMystery, todaysMystery, includeLuminous, labels, mysteryHref, selectMystery } = $props();
let { selectedMystery, todaysMystery, includeLuminous, labels, mysteryHref, selectMystery, season = null } = $props();
const seasonalMystery = $derived(
season === 'eastertide' ? 'glorreichen'
: season === 'lent' ? 'schmerzhaften'
: null
);
const seasonLabel = $derived(
season === 'eastertide' ? labels.eastertide
: season === 'lent' ? labels.lent
: ''
);
</script>
<style>
/* Mystery selector grid */
@@ -159,6 +171,24 @@
font-weight: 600;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.season-badge {
background: var(--nord14);
}
.badge-stack {
position: absolute;
top: 1rem;
right: 1rem;
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 0.3rem;
}
.badge-stack .today-badge {
position: static;
}
</style>
<div class="mystery-selector" class:four-mysteries={includeLuminous}>
@@ -168,10 +198,13 @@
href={mysteryHref('freudenreich')}
onclick={(e) => { e.preventDefault(); selectMystery('freudenreich'); }}
>
{#if todaysMystery === 'freudenreich'}
<span class="today-badge">{labels.today}</span>
{#if seasonalMystery === 'freudenreich' || todaysMystery === 'freudenreich'}
<div class="badge-stack">
{#if seasonalMystery === 'freudenreich'}<span class="today-badge season-badge">{seasonLabel}</span>{/if}
{#if todaysMystery === 'freudenreich'}<span class="today-badge">{labels.today}</span>{/if}
</div>
{/if}
<MysteryIcon type="joyful" />
<MysteryIcon type="joyful" />
<h3>{labels.joyful}</h3>
</a>
@@ -181,8 +214,11 @@
href={mysteryHref('schmerzhaften')}
onclick={(e) => { e.preventDefault(); selectMystery('schmerzhaften'); }}
>
{#if todaysMystery === 'schmerzhaften'}
<span class="today-badge">{labels.today}</span>
{#if seasonalMystery === 'schmerzhaften' || todaysMystery === 'schmerzhaften'}
<div class="badge-stack">
{#if seasonalMystery === 'schmerzhaften'}<span class="today-badge season-badge">{seasonLabel}</span>{/if}
{#if todaysMystery === 'schmerzhaften'}<span class="today-badge">{labels.today}</span>{/if}
</div>
{/if}
<MysteryIcon type="sorrowful" />
<h3>{labels.sorrowful}</h3>
@@ -194,10 +230,13 @@
href={mysteryHref('glorreichen')}
onclick={(e) => { e.preventDefault(); selectMystery('glorreichen'); }}
>
{#if todaysMystery === 'glorreichen'}
<span class="today-badge">{labels.today}</span>
{#if seasonalMystery === 'glorreichen' || todaysMystery === 'glorreichen'}
<div class="badge-stack">
{#if seasonalMystery === 'glorreichen'}<span class="today-badge season-badge">{seasonLabel}</span>{/if}
{#if todaysMystery === 'glorreichen'}<span class="today-badge">{labels.today}</span>{/if}
</div>
{/if}
<MysteryIcon type="glorious" />
<MysteryIcon type="glorious" />
<h3>{labels.glorious}</h3>
</a>
@@ -209,10 +248,11 @@
onclick={(e) => { e.preventDefault(); selectMystery('lichtreichen'); }}
>
{#if todaysMystery === 'lichtreichen'}
<span class="today-badge">{labels.today}</span>
<div class="badge-stack">
<span class="today-badge">{labels.today}</span>
</div>
{/if}
<MysteryIcon type="luminous" />
<MysteryIcon type="luminous" />
<h3>{labels.luminous}</h3>
</a>
{/if}

View File

@@ -191,7 +191,9 @@ export function getLabels(isEnglish) {
showBibleVerse: isEnglish ? 'Show Bible verse' : 'Bibelstelle anzeigen',
mysteryFaith: isEnglish ? 'Jesus, who may increase our faith' : 'Jesus, der in uns den Glauben vermehre',
mysteryHope: isEnglish ? 'Jesus, who may strengthen our hope' : 'Jesus, der in uns die Hoffnung stärke',
mysteryLove: isEnglish ? 'Jesus, who may kindle our love' : 'Jesus, der in uns die Liebe entzünde'
mysteryLove: isEnglish ? 'Jesus, who may kindle our love' : 'Jesus, der in uns die Liebe entzünde',
eastertide: isEnglish ? 'Eastertide' : 'Osterzeit',
lent: isEnglish ? 'Lent' : 'Fastenzeit'
};
}

View File

@@ -1,12 +1,7 @@
import { redirect } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ url }) => {
const latinParam = url.searchParams.get('latin');
const hasUrlLatin = latinParam !== null;
const initialLatin = hasUrlLatin ? latinParam !== '0' : true;
return {
initialLatin,
hasUrlLatin
};
export const load: PageServerLoad = async ({ params }) => {
const prayersPath = params.faithLang === 'faith' ? 'prayers' : 'gebete';
redirect(301, `/${params.faithLang}/${prayersPath}/angelus`);
};

View File

@@ -1,236 +0,0 @@
<script>
import { onMount } from 'svelte';
import { createLanguageContext } from "$lib/contexts/languageContext.js";
import LanguageToggle from "$lib/components/faith/LanguageToggle.svelte";
import Prayer from '$lib/components/faith/prayers/Prayer.svelte';
import AveMaria from '$lib/components/faith/prayers/AveMaria.svelte';
import "$lib/css/christ.css";
import "$lib/css/rosenkranz.css";
let { data } = $props();
// Create language context for prayer components
const langContext = createLanguageContext({ urlLang: data.lang, initialLatin: data.initialLatin });
// Toggle href for no-JS fallback (navigates to opposite latin state)
const latinToggleHref = $derived(data.initialLatin ? '?latin=0' : '?');
// Update lang store when data.lang changes (e.g., after navigation)
$effect(() => {
langContext.lang.set(data.lang);
});
onMount(() => {
// Clean up URL params after hydration (state is now in component state)
if (window.location.search) {
history.replaceState({}, '', window.location.pathname);
}
});
</script>
<svelte:head>
<title>Angelus - The Angel of the Lord</title>
<meta name="description" content="Pray the Angelus prayer in Latin, German, and English" />
</svelte:head>
<div class="angelus-page">
<h1>Angelus</h1>
<div class="toggle-controls">
<LanguageToggle
initialLatin={data.initialLatin}
hasUrlLatin={data.hasUrlLatin}
href={latinToggleHref}
/>
</div>
<div class="prayers-content">
<div class="prayer-section">
<Prayer>
{#snippet children(showLatin, urlLang)}
<!-- First Versicle and Response -->
<p>
{#if showLatin}<v lang="la"><i>℣.</i> Angelus Domini nuntiavit Mariæ.</v>{/if}
{#if urlLang === 'de'}<v lang="de"><i>℣.</i> Der Engel des Herrn brachte Maria die Botschaft</v>{/if}
{#if urlLang === 'en'}<v lang="en"><i>℣.</i> The Angel of the Lord declared unto Mary.</v>{/if}
{#if showLatin}<v lang="la"><i>℟.</i> Et concepit de Spiritu Sancto.</v>{/if}
{#if urlLang === 'de'}<v lang="de"><i>℟.</i> und sie empfing vom Heiligen Geist.</v>{/if}
{#if urlLang === 'en'}<v lang="en"><i>℟.</i> And she conceived of the Holy Spirit.</v>{/if}
</p>
{/snippet}
</Prayer>
</div>
<div class="prayer-section">
<AveMaria />
</div>
</div>
<div class="prayer-section">
<Prayer>
{#snippet children(showLatin, urlLang)}
<!-- Second Versicle and Response -->
<p>
{#if showLatin}<v lang="la"><i>℣.</i> Ecce ancilla Domini,</v>{/if}
{#if urlLang === 'de'}<v lang="de"><i>℣.</i> Maria sprach: Siehe, ich bin die Magd des Herrn</v>{/if}
{#if urlLang === 'en'}<v lang="en"><i>℣.</i> Behold the handmaid of the Lord.</v>{/if}
{#if showLatin}<v lang="la"><i>℟.</i> Fiat mihi secundum verbum tuum.</v>{/if}
{#if urlLang === 'de'}<v lang="de"><i>℟.</i> mir geschehe nach Deinem Wort.</v>{/if}
{#if urlLang === 'en'}<v lang="en"><i>℟.</i> Be it done unto me according to thy word.</v>{/if}
</p>
{/snippet}
</Prayer>
</div>
<div class="prayer-section">
<AveMaria />
</div>
<div class="prayer-section">
<Prayer>
{#snippet children(showLatin, urlLang)}
<!-- Third Versicle and Response -->
<p>
{#if showLatin}<v lang="la"><i>℣.</i> Et Verbum caro factum est,</v>{/if}
{#if urlLang === 'de'}<v lang="de"><i>℣.</i> Und das Wort ist Fleisch geworden</v>{/if}
{#if urlLang === 'en'}<v lang="en"><i>℣.</i> And the Word was made flesh.</v>{/if}
{#if showLatin}<v lang="la"><i>℟.</i> Et habitavit in nobis.</v>{/if}
{#if urlLang === 'de'}<v lang="de"><i>℟.</i> und hat unter uns gewohnt.</v>{/if}
{#if urlLang === 'en'}<v lang="en"><i>℟.</i> And dwelt among us.</v>{/if}
</p>
{/snippet}
</Prayer>
</div>
<div class="prayer-section">
<AveMaria />
</div>
<div class="prayer-section">
<Prayer>
{#snippet children(showLatin, urlLang)}
<!-- Fourth Versicle and Response -->
<p>
{#if showLatin}<v lang="la"><i>℣.</i> Ora pro nobis, sancta Dei Genetrix,</v>{/if}
{#if urlLang === 'de'}<v lang="de"><i>℣.</i> Bitte für uns Heilige Gottesmutter</v>{/if}
{#if urlLang === 'en'}<v lang="en"><i>℣.</i> Pray for us, O holy Mother of God.</v>{/if}
{#if showLatin}<v lang="la"><i>℟.</i> Ut digni efficiamur promissionibus Christi.</v>{/if}
{#if urlLang === 'de'}<v lang="de"><i>℟.</i> auf dass wir würdig werden der Verheißungen Christi.</v>{/if}
{#if urlLang === 'en'}<v lang="en"><i>℟.</i> That we may be made worthy of the promises of Christ.</v>{/if}
</p>
{/snippet}
</Prayer>
</div>
<div class="prayer-section">
<Prayer>
{#snippet children(showLatin, urlLang)}
<!-- Closing Prayer -->
<p>
{#if showLatin}<v lang="la"><i>℣.</i> Oremus.</v>{/if}
{#if urlLang === 'de'}<v lang="de"><i>℣.</i> Lasset uns beten.</v>{/if}
{#if urlLang === 'en'}<v lang="en"><i>℣.</i> Let us pray:</v>{/if}
</p>
<p>
{#if showLatin}<v lang="la">
Gratiam tuam, quaesumus, Domine, mentibus nostris infunde;
</v>{/if}
{#if urlLang === 'de'}<v lang="de">
Allmächtiger Gott, gieße deine Gnade in unsere Herzen ein.
</v>{/if}
{#if urlLang === 'en'}<v lang="en">
Pour forth, we beseech Thee, O Lord, Thy grace into our hearts,
</v>{/if}
{#if showLatin}<v lang="la">
ut qui, Angelo nuntiante, Christi Filii tui incarnationem cognovimus,
</v>{/if}
{#if urlLang === 'de'}<v lang="de">
Durch die Botschaft des Engels haben wir die Menschwerdung Christi, deines Sohnes, erkannt.
</v>{/if}
{#if urlLang === 'en'}<v lang="en">
that we to whom the Incarnation of Christ Thy Son was made known by the message of an angel,
</v>{/if}
{#if showLatin}<v lang="la">
per passionem eius et crucem ad resurrectionis gloriam perducamur.
</v>{/if}
{#if urlLang === 'de'}<v lang="de">
Lass uns durch sein Leiden und Kreuz zur Herrlichkeit der Auferstehung gelangen.
</v>{/if}
{#if urlLang === 'en'}<v lang="en">
may by His Passion and Cross be brought to the glory of His Resurrection.
</v>{/if}
{#if showLatin}<v lang="la">
Per eumdem Christum Dominum nostrum. Amen.
</v>{/if}
{#if urlLang === 'de'}<v lang="de">
Darum bitten wir durch Christus, unseren Herrn. Amen.
</v>{/if}
{#if urlLang === 'en'}<v lang="en">
Through the same Christ Our Lord. Amen.
</v>{/if}
</p>
{/snippet}
</Prayer>
</div>
</div>
<style>
.angelus-page {
max-width: 800px;
margin: 0 auto;
padding: 2rem 1rem;
}
h1 {
color: var(--nord6);
margin: 0;
}
@media (prefers-color-scheme: light) {
h1 {
color: black;
}
}
.prayer-section {
scroll-snap-align: start;
padding: 2rem;
margin-bottom: 2rem;
background: var(--accent-dark);
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
position: relative;
font-size: 1.25em;
text-align: center;
}
@media (prefers-color-scheme: light) {
.prayer-section {
background: var(--nord5);
}
}
.prayers-content {
scroll-snap-type: y proximity;
max-width: 700px;
}
v[lang=de] i,
v[lang=en] i{
color: grey;
}
:global(.monolingual) v[lang=de] i,
:global(.monolingual) v[lang=en] i{
color: var(--red);
}
h1 {
text-align: center;
font-size: 2.5rem;
margin-bottom: 0.5em;
}
.toggle-controls {
display: flex;
justify-content: center;
margin-bottom: 2rem;
}
</style>