refactor: extract language toggle into reusable components
All checks were successful
CI / update (push) Successful in 24s
All checks were successful
CI / update (push) Successful in 24s
Create Toggle and LanguageToggle components to reduce code duplication and enable shared state across pages. - Add Toggle.svelte: Generic iOS-style toggle with customizable accent color - Add LanguageToggle.svelte: Language-specific toggle with localStorage persistence - Refactor rosary page to use new toggle components - Add language toggle to gebete page - Toggle state persists across both pages via localStorage - Reduce min-height of Ave Maria decades in monolingual mode (50vh → 30vh)
This commit is contained in:
39
src/lib/components/LanguageToggle.svelte
Normal file
39
src/lib/components/LanguageToggle.svelte
Normal file
@@ -0,0 +1,39 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { getLanguageContext } from '$lib/contexts/languageContext.js';
|
||||
import Toggle from './Toggle.svelte';
|
||||
|
||||
// Get the language context (must be created by parent page)
|
||||
const { showLatin } = getLanguageContext();
|
||||
|
||||
// Local state for the checkbox
|
||||
let showBilingual = true;
|
||||
|
||||
// Flag to prevent saving before we've loaded from localStorage
|
||||
let hasLoadedFromStorage = false;
|
||||
|
||||
// Sync checkbox with context
|
||||
$: $showLatin = showBilingual;
|
||||
|
||||
// Save to localStorage whenever it changes (but only after initial load)
|
||||
$: if (typeof localStorage !== 'undefined' && hasLoadedFromStorage) {
|
||||
localStorage.setItem('rosary_showBilingual', showBilingual.toString());
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
// Load from localStorage
|
||||
const saved = localStorage.getItem('rosary_showBilingual');
|
||||
if (saved !== null) {
|
||||
showBilingual = saved === 'true';
|
||||
}
|
||||
|
||||
// Now allow saving
|
||||
hasLoadedFromStorage = true;
|
||||
});
|
||||
</script>
|
||||
|
||||
<Toggle
|
||||
bind:checked={showBilingual}
|
||||
label="Lateinisch und Deutsch anzeigen"
|
||||
accentColor="var(--nord14)"
|
||||
/>
|
||||
85
src/lib/components/Toggle.svelte
Normal file
85
src/lib/components/Toggle.svelte
Normal file
@@ -0,0 +1,85 @@
|
||||
<script>
|
||||
export let checked = false;
|
||||
export let label = "";
|
||||
export let accentColor = "var(--nord14)"; // Default to nord14, can be overridden
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.toggle-wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 2rem;
|
||||
max-width: 1200px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.toggle-wrapper label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
cursor: pointer;
|
||||
font-size: 0.95rem;
|
||||
color: var(--nord4);
|
||||
}
|
||||
|
||||
@media(prefers-color-scheme: light) {
|
||||
.toggle-wrapper label {
|
||||
color: var(--nord2);
|
||||
}
|
||||
}
|
||||
|
||||
.toggle-wrapper span {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* iOS-style toggle switch */
|
||||
.toggle-wrapper input[type="checkbox"] {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
width: 51px;
|
||||
height: 31px;
|
||||
background: var(--nord2);
|
||||
border-radius: 31px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s ease;
|
||||
outline: none;
|
||||
border: none;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@media(prefers-color-scheme: light) {
|
||||
.toggle-wrapper input[type="checkbox"] {
|
||||
background: var(--nord4);
|
||||
}
|
||||
}
|
||||
|
||||
.toggle-wrapper input[type="checkbox"]:checked {
|
||||
background: var(--accent-color);
|
||||
}
|
||||
|
||||
.toggle-wrapper input[type="checkbox"]::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 27px;
|
||||
height: 27px;
|
||||
border-radius: 50%;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
background: white;
|
||||
transition: transform 0.3s ease;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.toggle-wrapper input[type="checkbox"]:checked::before {
|
||||
transform: translateX(20px);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="toggle-wrapper" style="--accent-color: {accentColor}">
|
||||
<label>
|
||||
<input type="checkbox" bind:checked on:change />
|
||||
<span>{label}</span>
|
||||
</label>
|
||||
</div>
|
||||
Reference in New Issue
Block a user