rosary: add show/hide images toggle, fix PiP timing and breakpoint
- Add "Bilder anzeigen" / "Show Images" toggle persisted to localStorage - Bump mystery image column/PiP breakpoint from 900px to 1200px so prayers keep full width on medium screens - Fix PiP not appearing on page load by splitting $effect and using tick() to wait for DOM before measuring element dimensions - Fix Toggle checkbox default margin causing misalignment
This commit is contained in:
@@ -34,6 +34,7 @@
|
|||||||
.toggle-wrapper input[type="checkbox"] {
|
.toggle-wrapper input[type="checkbox"] {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
width: 44px;
|
width: 44px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
background: var(--nord2);
|
background: var(--nord2);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte";
|
import { onMount, tick } from "svelte";
|
||||||
import { createLanguageContext } from "$lib/contexts/languageContext.js";
|
import { createLanguageContext } from "$lib/contexts/languageContext.js";
|
||||||
import { createPip } from "$lib/js/pip.svelte";
|
import { createPip } from "$lib/js/pip.svelte";
|
||||||
import "$lib/css/christ.css";
|
import "$lib/css/christ.css";
|
||||||
@@ -183,6 +183,9 @@ const mysteryTitlesEnglish = {
|
|||||||
// Toggle for including Luminous mysteries (initialized from URL param or default)
|
// Toggle for including Luminous mysteries (initialized from URL param or default)
|
||||||
let includeLuminous = $state(data.initialLuminous);
|
let includeLuminous = $state(data.initialLuminous);
|
||||||
|
|
||||||
|
// Toggle for showing mystery images
|
||||||
|
let showImages = $state(true);
|
||||||
|
|
||||||
// Flag to prevent saving before we've loaded from localStorage
|
// Flag to prevent saving before we've loaded from localStorage
|
||||||
let hasLoadedFromStorage = false;
|
let hasLoadedFromStorage = false;
|
||||||
|
|
||||||
@@ -208,6 +211,7 @@ const labels = $derived({
|
|||||||
glorious: isEnglish ? 'Glorious' : 'Glorreichen',
|
glorious: isEnglish ? 'Glorious' : 'Glorreichen',
|
||||||
luminous: isEnglish ? 'Luminous' : 'Lichtreichen',
|
luminous: isEnglish ? 'Luminous' : 'Lichtreichen',
|
||||||
includeLuminous: isEnglish ? 'Include Luminous Mysteries' : 'Lichtreiche Geheimnisse einbeziehen',
|
includeLuminous: isEnglish ? 'Include Luminous Mysteries' : 'Lichtreiche Geheimnisse einbeziehen',
|
||||||
|
showImages: isEnglish ? 'Show Images' : 'Bilder anzeigen',
|
||||||
beginning: isEnglish ? 'Beginning' : 'Anfang',
|
beginning: isEnglish ? 'Beginning' : 'Anfang',
|
||||||
signOfCross: isEnglish ? '♱ Sign of the Cross' : '♱ Das Kreuzzeichen',
|
signOfCross: isEnglish ? '♱ Sign of the Cross' : '♱ Das Kreuzzeichen',
|
||||||
ourFather: isEnglish ? 'Our Father' : 'Vater unser',
|
ourFather: isEnglish ? 'Our Father' : 'Vater unser',
|
||||||
@@ -230,12 +234,17 @@ const labels = $derived({
|
|||||||
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'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Save luminous toggle state to localStorage whenever it changes (but only after initial load)
|
// Save toggle states to localStorage whenever they change (but only after initial load)
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (typeof localStorage !== 'undefined' && hasLoadedFromStorage) {
|
if (typeof localStorage !== 'undefined' && hasLoadedFromStorage) {
|
||||||
localStorage.setItem('rosary_includeLuminous', includeLuminous.toString());
|
localStorage.setItem('rosary_includeLuminous', includeLuminous.toString());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
$effect(() => {
|
||||||
|
if (typeof localStorage !== 'undefined' && hasLoadedFromStorage) {
|
||||||
|
localStorage.setItem('rosary_showImages', showImages.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Function to get the appropriate mystery for a given weekday
|
// Function to get the appropriate mystery for a given weekday
|
||||||
function getMysteryForWeekday(date, includeLuminous) {
|
function getMysteryForWeekday(date, includeLuminous) {
|
||||||
@@ -315,7 +324,7 @@ let sectionElements = {};
|
|||||||
let svgContainer;
|
let svgContainer;
|
||||||
|
|
||||||
// Whether the rosary has mystery images (stable, doesn't change during scroll)
|
// Whether the rosary has mystery images (stable, doesn't change during scroll)
|
||||||
const hasMysteryImages = $derived(selectedMystery === 'schmerzhaften');
|
const hasMysteryImages = $derived(showImages && selectedMystery === 'schmerzhaften');
|
||||||
|
|
||||||
// Mystery image scroll target based on active section
|
// Mystery image scroll target based on active section
|
||||||
function getMysteryScrollTarget(section) {
|
function getMysteryScrollTarget(section) {
|
||||||
@@ -359,14 +368,20 @@ let rosaryPipEl = $state(null);
|
|||||||
let lastPipSrc = $state(null);
|
let lastPipSrc = $state(null);
|
||||||
|
|
||||||
function isMobilePip() {
|
function isMobilePip() {
|
||||||
return !window.matchMedia('(min-width: 900px)').matches;
|
return !window.matchMedia('(min-width: 1200px)').matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (mysteryPipSrc) lastPipSrc = mysteryPipSrc;
|
if (mysteryPipSrc) lastPipSrc = mysteryPipSrc;
|
||||||
|
});
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
if (!rosaryPipEl || !isMobilePip()) return;
|
if (!rosaryPipEl || !isMobilePip()) return;
|
||||||
if (mysteryPipSrc) {
|
if (mysteryPipSrc) {
|
||||||
pip.show(rosaryPipEl);
|
// Wait for DOM update so the <img> has rendered with dimensions
|
||||||
|
tick().then(() => {
|
||||||
|
if (rosaryPipEl) pip.show(rosaryPipEl);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
pip.hide();
|
pip.hide();
|
||||||
}
|
}
|
||||||
@@ -489,13 +504,17 @@ for (let d = 1; d < 5; d++) {
|
|||||||
const pos = sectionPositions;
|
const pos = sectionPositions;
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
// Load toggle state from localStorage only if not overridden by URL params
|
// Load toggle states from localStorage only if not overridden by URL params
|
||||||
if (!data.hasUrlLuminous) {
|
if (!data.hasUrlLuminous) {
|
||||||
const savedIncludeLuminous = localStorage.getItem('rosary_includeLuminous');
|
const savedIncludeLuminous = localStorage.getItem('rosary_includeLuminous');
|
||||||
if (savedIncludeLuminous !== null) {
|
if (savedIncludeLuminous !== null) {
|
||||||
includeLuminous = savedIncludeLuminous === 'true';
|
includeLuminous = savedIncludeLuminous === 'true';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const savedShowImages = localStorage.getItem('rosary_showImages');
|
||||||
|
if (savedShowImages !== null) {
|
||||||
|
showImages = savedShowImages === 'true';
|
||||||
|
}
|
||||||
|
|
||||||
// If no mystery was specified in URL, recompute based on loaded preferences
|
// If no mystery was specified in URL, recompute based on loaded preferences
|
||||||
if (!data.hasUrlMystery) {
|
if (!data.hasUrlMystery) {
|
||||||
@@ -1387,7 +1406,7 @@ h1 {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 900px) {
|
@media (min-width: 1200px) {
|
||||||
.rosary-layout.has-mystery-image {
|
.rosary-layout.has-mystery-image {
|
||||||
grid-template-columns: clamp(250px, 30vw, 400px) 1fr auto;
|
grid-template-columns: clamp(250px, 30vw, 400px) 1fr auto;
|
||||||
}
|
}
|
||||||
@@ -1445,7 +1464,7 @@ h1 {
|
|||||||
.mystery-pip.enlarged img {
|
.mystery-pip.enlarged img {
|
||||||
height: 37.5vh;
|
height: 37.5vh;
|
||||||
}
|
}
|
||||||
@media (min-width: 900px) {
|
@media (min-width: 1200px) {
|
||||||
.mystery-pip {
|
.mystery-pip {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@@ -1530,6 +1549,11 @@ h1 {
|
|||||||
href={luminousToggleHref}
|
href={luminousToggleHref}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Toggle
|
||||||
|
bind:checked={showImages}
|
||||||
|
label={labels.showImages}
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- Language Toggle (link for no-JS, enhanced with onclick for JS) -->
|
<!-- Language Toggle (link for no-JS, enhanced with onclick for JS) -->
|
||||||
<LanguageToggle
|
<LanguageToggle
|
||||||
initialLatin={data.initialLatin}
|
initialLatin={data.initialLatin}
|
||||||
|
|||||||
Reference in New Issue
Block a user