rosary: fix scrolls with snaps, add footnotes indicating making the sign of the cross and bowing your head
All checks were successful
CI / update (push) Successful in 27s
All checks were successful
CI / update (push) Successful in 27s
This commit is contained in:
@@ -357,7 +357,39 @@ onMount(() => {
|
|||||||
const observer = new IntersectionObserver((entries) => {
|
const observer = new IntersectionObserver((entries) => {
|
||||||
entries.forEach((entry) => {
|
entries.forEach((entry) => {
|
||||||
if (entry.isIntersecting && scrollLock !== 'svg' && scrollLock !== 'click') {
|
if (entry.isIntersecting && scrollLock !== 'svg' && scrollLock !== 'click') {
|
||||||
activeSection = entry.target.dataset.section;
|
const section = entry.target.dataset.section;
|
||||||
|
activeSection = section;
|
||||||
|
|
||||||
|
// Don't auto-scroll if we're at the absolute top of the page and viewing the first section
|
||||||
|
const scrollY = window.scrollY || window.pageYOffset;
|
||||||
|
if (scrollY < 50 && section === 'cross') {
|
||||||
|
// User is at the very top - don't trigger auto-scroll, just update SVG
|
||||||
|
if (svgContainer && sectionPositions[activeSection] !== undefined) {
|
||||||
|
const svg = svgContainer.querySelector('svg');
|
||||||
|
if (!svg) return;
|
||||||
|
|
||||||
|
const svgYPosition = sectionPositions[activeSection];
|
||||||
|
const viewBox = svg.viewBox.baseVal;
|
||||||
|
const svgHeight = svg.clientHeight;
|
||||||
|
const viewBoxHeight = viewBox.height;
|
||||||
|
|
||||||
|
// Get CSS transform scale (3.5 on mobile, 1 on desktop)
|
||||||
|
const computedStyle = window.getComputedStyle(svg);
|
||||||
|
const matrix = new DOMMatrix(computedStyle.transform);
|
||||||
|
const cssScale = matrix.a || 1;
|
||||||
|
|
||||||
|
// Convert SVG coordinates to pixel coordinates
|
||||||
|
const scale = (svgHeight / viewBoxHeight) * cssScale;
|
||||||
|
const pixelPosition = svgYPosition * scale;
|
||||||
|
|
||||||
|
// Position with some padding to show context above
|
||||||
|
const targetScroll = pixelPosition - 100;
|
||||||
|
|
||||||
|
setScrollLock('prayer');
|
||||||
|
smoothScrollElement(svgContainer, Math.max(0, targetScroll));
|
||||||
|
}
|
||||||
|
return; // Skip the page scroll
|
||||||
|
}
|
||||||
|
|
||||||
// Scroll SVG to keep active section visible at top
|
// Scroll SVG to keep active section visible at top
|
||||||
if (svgContainer && sectionPositions[activeSection] !== undefined) {
|
if (svgContainer && sectionPositions[activeSection] !== undefined) {
|
||||||
@@ -398,6 +430,8 @@ onMount(() => {
|
|||||||
if (scrollLock === 'svg' || scrollLock === 'click' || !svgContainer) return;
|
if (scrollLock === 'svg' || scrollLock === 'click' || !svgContainer) return;
|
||||||
|
|
||||||
const viewportHeight = window.innerHeight;
|
const viewportHeight = window.innerHeight;
|
||||||
|
const scrollY = window.scrollY || window.pageYOffset;
|
||||||
|
const documentHeight = document.documentElement.scrollHeight;
|
||||||
|
|
||||||
// Get the first and final prayer sections
|
// Get the first and final prayer sections
|
||||||
const firstSection = sectionElements.cross;
|
const firstSection = sectionElements.cross;
|
||||||
@@ -407,8 +441,23 @@ onMount(() => {
|
|||||||
const firstSectionRect = firstSection.getBoundingClientRect();
|
const firstSectionRect = firstSection.getBoundingClientRect();
|
||||||
const finalSectionRect = finalSection.getBoundingClientRect();
|
const finalSectionRect = finalSection.getBoundingClientRect();
|
||||||
|
|
||||||
|
// Check if we're at the absolute top of the page
|
||||||
|
if (scrollY < 50) {
|
||||||
|
// Scroll SVG to top
|
||||||
|
if (svgContainer.scrollTop > 10) { // Only if not already at top
|
||||||
|
smoothScrollElement(svgContainer, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check if we're at the absolute bottom of the page
|
||||||
|
else if (scrollY + viewportHeight >= documentHeight - 50) {
|
||||||
|
// Scroll SVG to bottom
|
||||||
|
const maxScroll = svgContainer.scrollHeight - svgContainer.clientHeight;
|
||||||
|
if (svgContainer.scrollTop < maxScroll - 10) { // Only if not already at bottom
|
||||||
|
smoothScrollElement(svgContainer, maxScroll);
|
||||||
|
}
|
||||||
|
}
|
||||||
// Check if we've scrolled above the first section (it's completely below viewport)
|
// Check if we've scrolled above the first section (it's completely below viewport)
|
||||||
if (firstSectionRect.top > viewportHeight * 0.6) {
|
else if (firstSectionRect.top > viewportHeight * 0.6) {
|
||||||
// Scroll SVG to top
|
// Scroll SVG to top
|
||||||
if (svgContainer.scrollTop > 10) { // Only if not already at top
|
if (svgContainer.scrollTop > 10) { // Only if not already at top
|
||||||
smoothScrollElement(svgContainer, 0);
|
smoothScrollElement(svgContainer, 0);
|
||||||
@@ -1099,6 +1148,30 @@ h1 {
|
|||||||
border-color: var(--nord3);
|
border-color: var(--nord3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Footnote styles */
|
||||||
|
.footnotes-section {
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--nord4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media(prefers-color-scheme: light) {
|
||||||
|
.footnotes-section {
|
||||||
|
color: var(--nord0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footnotes-section p {
|
||||||
|
margin: 0.25rem 0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footnotes-section .symbol {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
color: var(--nord11);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title>Interaktiver Rosenkranz</title>
|
<title>Interaktiver Rosenkranz</title>
|
||||||
@@ -1291,6 +1364,10 @@ l536 389l-209 -629zM1671 934l-370 267l150 436l-378 -271l-371 271q8 -34 15 -68q10
|
|||||||
<Kreuzzeichen />
|
<Kreuzzeichen />
|
||||||
<h3>Credo</h3>
|
<h3>Credo</h3>
|
||||||
<Credo />
|
<Credo />
|
||||||
|
<div class="footnotes-section">
|
||||||
|
<p><span class="symbol">♱</span>Hier das Kreuzzeichen machen</p>
|
||||||
|
<p><span class="symbol">⚬</span>Hier den Kopf senken</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- First Large Bead -->
|
<!-- First Large Bead -->
|
||||||
@@ -1428,6 +1505,9 @@ l536 389l-209 -629zM1671 934l-370 267l150 436l-378 -271l-371 271q8 -34 15 -68q10
|
|||||||
<RosaryFinalPrayer />
|
<RosaryFinalPrayer />
|
||||||
|
|
||||||
<h3 style="text-align: center; font-size: 2.5rem; margin-top: 2rem;">♱</h3>
|
<h3 style="text-align: center; font-size: 2.5rem; margin-top: 2rem;">♱</h3>
|
||||||
|
<div class="footnotes-section">
|
||||||
|
<p><span class="symbol">♱</span>Hier das Kreuzzeichen machen</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user