Implement progressive enhancement for yeast swapper with state persistence
Some checks failed
CI / update (push) Failing after 9s
Some checks failed
CI / update (push) Failing after 9s
- Add server-side form handling for yeast swapping without JavaScript - Implement toggle-based URL parameter system (y0=1, y1=1) for clean URLs - Add server action to toggle yeast flags and preserve all URL state - Update multiplier forms to preserve yeast toggle states across submissions - Calculate yeast conversions server-side from original recipe data - Fix {{multiplier}} placeholder replacement to handle non-numeric amounts - Enable multiple independent yeast swappers with full state preservation - Maintain perfect progressive enhancement: works with and without JS 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,51 +1,39 @@
|
||||
<script>
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { browser } from '$app/environment';
|
||||
import { enhance } from '$app/forms';
|
||||
import { page } from '$app/stores';
|
||||
|
||||
export let item;
|
||||
export let multiplier = 1;
|
||||
export let yeastId = 0;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
function toggleHefe() {
|
||||
let newName, newAmount, newUnit = item.unit;
|
||||
|
||||
if (item.name === "Frischhefe") {
|
||||
// Convert fresh yeast to dry yeast
|
||||
const originalAmount = parseFloat(item.amount) / multiplier;
|
||||
newName = "Trockenhefe";
|
||||
// Get all current URL parameters to preserve state
|
||||
$: currentParams = browser ? new URLSearchParams(window.location.search) : $page.url.searchParams;
|
||||
|
||||
function toggleHefe(event) {
|
||||
// If JavaScript is available, prevent form submission and handle client-side
|
||||
if (browser) {
|
||||
event.preventDefault();
|
||||
|
||||
if (item.unit === "Prise") {
|
||||
// "1 Prise Frischhefe" → "1 Prise Trockenhefe"
|
||||
newAmount = item.amount;
|
||||
newUnit = "Prise";
|
||||
} else if (item.unit === "g" && originalAmount === 1) {
|
||||
// "1 g Frischhefe" → "1 Prise Trockenhefe"
|
||||
newAmount = "1";
|
||||
newUnit = "Prise";
|
||||
} else {
|
||||
// Normal conversion: "9 g Frischhefe" → "3 g Trockenhefe" (divide by 3)
|
||||
newAmount = (originalAmount / 3).toString();
|
||||
newUnit = "g";
|
||||
}
|
||||
} else if (item.name === "Trockenhefe") {
|
||||
// Convert dry yeast to fresh yeast
|
||||
const originalAmount = parseFloat(item.amount) / multiplier;
|
||||
newName = "Frischhefe";
|
||||
// Simply toggle the yeast flag in the URL
|
||||
const url = new URL(window.location);
|
||||
const yeastParam = `y${yeastId}`;
|
||||
|
||||
if (item.unit === "Prise") {
|
||||
// "1 Prise Trockenhefe" → "1 g Frischhefe"
|
||||
newAmount = "1";
|
||||
newUnit = "g";
|
||||
if (url.searchParams.has(yeastParam)) {
|
||||
url.searchParams.delete(yeastParam);
|
||||
} else {
|
||||
// Normal conversion: "1 g Trockenhefe" → "3 g Frischhefe" (multiply by 3)
|
||||
newAmount = (originalAmount * 3).toString();
|
||||
newUnit = "g";
|
||||
url.searchParams.set(yeastParam, '1');
|
||||
}
|
||||
|
||||
window.history.replaceState({}, '', url);
|
||||
|
||||
// Trigger page reload to recalculate ingredients server-side
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
if (newName && newAmount) {
|
||||
dispatch('toggle', { name: newName, amount: newAmount, unit: newUnit });
|
||||
}
|
||||
// If no JS, form will submit normally
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
@@ -60,6 +48,13 @@
|
||||
fill: var(--blue);
|
||||
}
|
||||
</style>
|
||||
<button on:click={toggleHefe} title="Zwischen Frischhefe und Trockenhefe wechseln">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M105.1 202.6c7.7-21.8 20.2-42.3 37.8-59.8c62.5-62.5 163.8-62.5 226.3 0L386.3 160 352 160c-17.7 0-32 14.3-32 32s14.3 32 32 32l111.5 0c0 0 0 0 0 0l.4 0c17.7 0 32-14.3 32-32l0-112c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 35.2L414.4 97.6c-87.5-87.5-229.3-87.5-316.8 0C73.2 122 55.6 150.7 44.8 181.4c-5.9 16.7 2.9 34.9 19.5 40.8s34.9-2.9 40.8-19.5zM39 289.3c-5 1.5-9.8 4.2-13.7 8.2c-4 4-6.7 8.8-8.1 14c-.3 1.2-.6 2.5-.8 3.8c-.3 1.7-.4 3.4-.4 5.1L16 432c0 17.7 14.3 32 32 32s32-14.3 32-32l0-35.1 17.6 17.5c0 0 0 0 0 0c87.5 87.4 229.3 87.4 316.7 0c24.4-24.4 42.1-53.1 52.9-83.8c5.9-16.7-2.9-34.9-19.5-40.8s-34.9 2.9-40.8 19.5c-7.7 21.8-20.2 42.3-37.8 59.8c-62.5 62.5-163.8 62.5-226.3 0l-.1-.1L125.6 352l34.4 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L48.4 288c-1.6 0-3.2 .1-4.8 .3s-3.1 .5-4.6 1z"/></svg>
|
||||
</button>
|
||||
<form method="post" action="?/swapYeast" style="display: inline;" use:enhance>
|
||||
<input type="hidden" name="yeastId" value={yeastId} />
|
||||
<!-- Include all current URL parameters to preserve state -->
|
||||
{#each Array.from(currentParams.entries()) as [key, value]}
|
||||
<input type="hidden" name="currentParam_{key}" value={value} />
|
||||
{/each}
|
||||
<button type="submit" on:click={toggleHefe} title="Zwischen Frischhefe und Trockenhefe wechseln">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M105.1 202.6c7.7-21.8 20.2-42.3 37.8-59.8c62.5-62.5 163.8-62.5 226.3 0L386.3 160 352 160c-17.7 0-32 14.3-32 32s14.3 32 32 32l111.5 0c0 0 0 0 0 0l.4 0c17.7 0 32-14.3 32-32l0-112c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 35.2L414.4 97.6c-87.5-87.5-229.3-87.5-316.8 0C73.2 122 55.6 150.7 44.8 181.4c-5.9 16.7 2.9 34.9 19.5 40.8s34.9-2.9 40.8-19.5zM39 289.3c-5 1.5-9.8 4.2-13.7 8.2c-4 4-6.7 8.8-8.1 14c-.3 1.2-.6 2.5-.8 3.8c-.3 1.7-.4 3.4-.4 5.1L16 432c0 17.7 14.3 32 32 32s32-14.3 32-32l0-35.1 17.6 17.5c0 0 0 0 0 0c87.5 87.4 229.3 87.4 316.7 0c24.4-24.4 42.1-53.1 52.9-83.8c5.9-16.7-2.9-34.9-19.5-40.8s-34.9 2.9-40.8 19.5c-7.7 21.8-20.2 42.3-37.8 59.8c-62.5 62.5-163.8 62.5-226.3 0l-.1-.1L125.6 352l34.4 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L48.4 288c-1.6 0-3.2 .1-4.8 .3s-3.1 .5-4.6 1z"/></svg>
|
||||
</button>
|
||||
</form>
|
||||
|
Reference in New Issue
Block a user