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:
29
src/routes/rezepte/[name]/+page.server.ts
Normal file
29
src/routes/rezepte/[name]/+page.server.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
|
||||
export const actions = {
|
||||
swapYeast: async ({ request, url }) => {
|
||||
const formData = await request.formData();
|
||||
const yeastId = parseInt(formData.get('yeastId') as string);
|
||||
|
||||
// Build new URL
|
||||
const newUrl = new URL(url.pathname, url.origin);
|
||||
|
||||
// Restore all parameters from the form data (they were submitted as currentParam_*)
|
||||
for (const [key, value] of formData.entries()) {
|
||||
if (key.startsWith('currentParam_')) {
|
||||
const paramName = key.substring('currentParam_'.length);
|
||||
newUrl.searchParams.set(paramName, value as string);
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle the yeast flag - if it exists, remove it; if not, add it
|
||||
const yeastParam = `y${yeastId}`;
|
||||
if (newUrl.searchParams.has(yeastParam)) {
|
||||
newUrl.searchParams.delete(yeastParam);
|
||||
} else {
|
||||
newUrl.searchParams.set(yeastParam, '1');
|
||||
}
|
||||
|
||||
throw redirect(303, newUrl.toString());
|
||||
}
|
||||
};
|
@@ -22,6 +22,85 @@ export async function load({ fetch, params, url}) {
|
||||
// Get multiplier from URL parameters
|
||||
const multiplier = parseFloat(url.searchParams.get('multiplier') || '1');
|
||||
|
||||
// Handle yeast swapping from URL parameters based on toggle flags
|
||||
// Look for parameters like y0=1, y1=1 (yeast #0 and #1 are toggled)
|
||||
if (item.ingredients) {
|
||||
let yeastCounter = 0;
|
||||
|
||||
// Iterate through all ingredients to find yeast and apply conversions
|
||||
for (let listIndex = 0; listIndex < item.ingredients.length; listIndex++) {
|
||||
const list = item.ingredients[listIndex];
|
||||
if (list.list) {
|
||||
for (let ingredientIndex = 0; ingredientIndex < list.list.length; ingredientIndex++) {
|
||||
const ingredient = list.list[ingredientIndex];
|
||||
|
||||
// Check if this is a yeast ingredient
|
||||
if (ingredient.name === "Frischhefe" || ingredient.name === "Trockenhefe") {
|
||||
// Check if this yeast should be toggled
|
||||
const yeastParam = `y${yeastCounter}`;
|
||||
const isToggled = url.searchParams.has(yeastParam);
|
||||
|
||||
if (isToggled) {
|
||||
// Perform yeast conversion from original recipe data
|
||||
const originalName = ingredient.name;
|
||||
const originalAmount = parseFloat(ingredient.amount);
|
||||
const originalUnit = ingredient.unit;
|
||||
|
||||
let newName: string, newAmount: string, newUnit: string;
|
||||
|
||||
if (originalName === "Frischhefe") {
|
||||
// Convert fresh yeast to dry yeast
|
||||
newName = "Trockenhefe";
|
||||
|
||||
if (originalUnit === "Prise") {
|
||||
// "1 Prise Frischhefe" → "1 Prise Trockenhefe"
|
||||
newAmount = ingredient.amount;
|
||||
newUnit = "Prise";
|
||||
} else if (originalUnit === "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 (originalName === "Trockenhefe") {
|
||||
// Convert dry yeast to fresh yeast
|
||||
newName = "Frischhefe";
|
||||
|
||||
if (originalUnit === "Prise") {
|
||||
// "1 Prise Trockenhefe" → "1 g Frischhefe"
|
||||
newAmount = "1";
|
||||
newUnit = "g";
|
||||
} else {
|
||||
// Normal conversion: "1 g Trockenhefe" → "3 g Frischhefe" (multiply by 3)
|
||||
newAmount = (originalAmount * 3).toString();
|
||||
newUnit = "g";
|
||||
}
|
||||
} else {
|
||||
// Fallback
|
||||
newName = originalName;
|
||||
newAmount = ingredient.amount;
|
||||
newUnit = originalUnit;
|
||||
}
|
||||
|
||||
// Apply the conversion
|
||||
item.ingredients[listIndex].list[ingredientIndex] = {
|
||||
...item.ingredients[listIndex].list[ingredientIndex],
|
||||
name: newName,
|
||||
amount: newAmount,
|
||||
unit: newUnit
|
||||
};
|
||||
}
|
||||
|
||||
yeastCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...item,
|
||||
isFavorite,
|
||||
|
Reference in New Issue
Block a user