Toast-Queue als $state-Store mit Auto-Dismiss nach 3 s und manuellem
dismiss(id). Drei Kinds: info/error/success (Farbe). Renderer als
<Toast /> im Root-Layout, fix-positioniert oben mittig. Wird
vom Offline-Check der Schreib-Aktionen genutzt und später auch für
Sync-Abschluss-Meldungen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reaktiver Store basierend auf navigator.onLine und den window-
Events online/offline. Kein aktives Heuristik-Probing — für
unseren Offline-PWA-Use-Case reicht der Browser-Status. Wird von
SyncIndicator und require-online-Helper konsumiert.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rezeptwelt lieferte Zubereitungs-Steps immer als einen einzigen Treffer,
oft mit vermischtem Icon-alt-Text. Zwei Ursachen, beide in der
generischen Microdata-Logik — kein rezeptwelt-spezifischer Parser nötig.
1. HowToSection wrappt HowToSteps als itemListElement, unser Parser sah
nur das erste. Jetzt: recipeInstructions-Container mit itemtype=
HowToSection werden abgestiegen, jedes itemListElement wird ein Step.
2. Ein einzelner HowToStep kann intern "1. …<br>2. …<br>3. …" enthalten.
Neuer textWithLineBreaks(el) konvertiert <br>/Block-Grenzen zu \n und
ignoriert <img>/<script>/<style>. splitStepText(raw) erkennt
nummerierte Zeilen und erzeugt einen eigenen Step pro Nummer; Fort-
setzungszeilen ohne Nummer hängen an den aktuellen Step an.
3 neue Tests: HowToSection-Kette, inline-nummerierter Multi-Step,
<img>-alt-Unterdrückung.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bisher scheiterte der Import auf Seiten wie rezeptwelt.de mit „Diese Seite
enthält kein Rezept", obwohl unser Such-Filter die Treffer durchließ
(Microdata wird seit dem vorherigen Commit erkannt). Jetzt kann der
Importer die Daten auch tatsächlich extrahieren:
- extractRecipeFromMicrodata(html): parst [itemtype=schema.org/Recipe]-
Scopes per linkedom, sammelt itemprop-Werte unter Beachtung der
verschachtelten itemscope-Grenzen (HowToStep-Texts landen nicht im
Haupt-Scope).
- Übernimmt Content-Attribute auf <meta>/<time> (z.B. prepTime="PT20M"),
src auf <img>, textContent als Fallback — die Standard-Microdata-
Value-Regeln.
- Behandelt HowToStep-Items UND einfache <li>/<ol>-Listen als
recipeInstructions.
- extractRecipeFromHtml ruft JSON-LD zuerst, fällt nur bei null auf
Microdata zurück — damit bleibt bestehendes Verhalten stabil.
Tests: Königsberger-Klopse-Fixture mit HowToSteps, einfache ol/li-
Variante und Priorität-JSON-LD-über-Microdata-Check.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Aus dem Log (q="Königsberger klopse"): 11 rezeptwelt-Treffer kamen durch
alle URL-Filter, wurden aber von hasRecipeJsonLd als non-recipe gedroppt.
Ursache: rezeptwelt.de nutzt Microdata (itemtype=schema.org/Recipe) statt
application/ld+json.
- hasRecipeJsonLd → hasRecipeMarkup: prüft jetzt zusätzlich per Regex
auf itemtype=(https?://)schema.org/Recipe. Alter Export bleibt als
Deprecated-Weiterleitung erhalten.
- Log zeigt jetzt auch die ersten 3 gedropten URLs als dropped samples,
damit neue Problem-Domains einfach zu diagnostizieren sind.
- Migration 010 räumt alle thumbnail_cache-Einträge mit has_recipe=0 aus
— die waren mit dem alten Check falsch-negativ und müssen neu
klassifiziert werden.
Tests: 4 neue Cases für hasRecipeMarkup (JSON-LD, http/https Microdata,
Negativ-Fall).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
RecipeView needs scaleIngredients on the client for live portion scaling.
Moved scaler.ts from $lib/server/recipes/ to $lib/recipes/.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>