User-Feedback: separater Indikator zu viel — die Pfote IM FAB selbst
soll je nach Score grün eingefärbt werden.
- Separater #offline-indicator Button entfernt (HTML + CSS)
- Welten-FAB-Icon: <use phosphor.svg#paw-print> ersetzt durch
Inline-SVG mit 5 einzelnen paw-elem-Pfaden (1 Ballen + 4 Zehen)
- CSS: Default weiß (wie bisher), .filled wird leuchtendes Grün
(#16a34a) — überzeichnet auf orangem FAB klar erkennbar
- offline-indicator.js: zeigt jetzt nur noch die FAB-Pfade ein/aus,
kein eigenes Element mehr; Klick-Status-Modal als window.OfflineIndicator.openStatus() weiter verfügbar (kann
später bei Bedarf an Long-Press oder Menüpunkt gehängt werden)
Logik umgedreht: Default ist 'sichtbar', JS setzt .is-hidden nur wenn
explizit nicht in Welten. So robust gegen Sibling-Selektor-Probleme
oder CSS-Compositing-Eigenheiten auf iOS PWA.
Außerdem: Hintergrund prominenter (rgba 0.95 statt 0.85), echter
Border statt Glas-Filter, stärkerer Schatten — bei den vorigen
Versuchen war die Pfote vermutlich auch durch Transparenz schwer zu
erkennen auf grauem Hintergrund.
Der reine CSS-Sibling-Selektor klappte nicht zuverlässig (vermutlich
SW-Cache-Mismatch oder DOM-Reihenfolge im aktuellen Zustand des
Users). Lösung: MutationObserver in offline-indicator.js beobachtet
class/style auf #worlds-overlay und togglet .visible auf
#offline-indicator. CSS akzeptiert jetzt beide Wege:
#worlds-overlay.worlds-visible ~ #offline-indicator,
#offline-indicator.visible { display: flex; }
So bleibt das Layout funktional auch wenn CSS-Compositing oder
Cache-Versatz mal nicht greift. console.warn wenn das Element nicht
im DOM ist (z.B. wenn alte index.html aus SW-Cache).
- Position: bottom-right über dem #worlds-fab (right:20px, bottom-
Berechnung folgt FAB + 12px Abstand). Gleiche horizontale Achse
wie FAB → ergibt eine 'Pfoten-Säule' (Indikator oben, FAB unten)
- Sichtbarkeit per CSS-Sibling-Selektor:
#worlds-overlay.worlds-visible ~ #offline-indicator { display:flex }
→ Indikator nur sichtbar wenn Welten aktiv sind. Auf Detail-Seiten
(Tagebuch, Karte, Admin etc.) bleibt er aus.
- z-index 61 (eine Stufe über dem FAB, unter Modals)
Der Header (#app-header) ist in den Welten per 'display:none !important'
ausgeblendet (Welten übernehmen Navigation). Mein Pfötchen saß da
drin und war genau dort unsichtbar wo es sichtbar sein sollte.
- Button aus dem Header rausgeholt, am Ende vom body als schwebendes
Element platziert (position:fixed; top-right; z-index:9000)
- Eigener Stil: 40px runder Glas-Hintergrund, blur-Effekt, leichter
Schatten — passt zur FAB-Optik unten rechts
- Dark-Mode Hintergrund: dunkles Glas
- Sichtbar in allen Welten und auf allen Seiten (auch wo Header da
ist — sitzt daneben)
- 'hidden'-Default raus, Element ist sofort sichtbar (nur Färbung
wartet auf refresh())
- CACHE_API hieß bei mir 'by-api', tatsächlich aber 'ban-yaro-api-v1'
→ korrigiert, sonst hätte step 3+5 nie grün werden können
- Step 5 prüfte auf gecachte Diary-Foto-Previews — die werden vom SW
aber gar nicht gecacht (nur API-Routen sind in _CACHEABLE_GET).
Stattdessen jetzt 'Training & Wissen' (training/exercises +
wiki/rassen) — ist im SW-Cache abgedeckt und passt zur WELT-Welt
- _fetchMissing für Step 5 entsprechend angepasst
Footer-Layout neu strukturiert — kein Umbruch-Chaos mehr:
- Erste Zeile: Abbrechen | Speichern (Grid 1fr 1fr, gleich breit)
oder bei sent/paid nur 'Schließen' volle Breite
- Zweite Zeile (wenn vorhanden): Stornieren als volle Breite,
ghost-Style mit rotem Rand — destruktive Aktion klar getrennt
- Button-Text 'Änderungen speichern' → 'Speichern' (kein Abschneiden
mehr auf iPhone)
- Backend: /admin/upgrade-requests liefert pro Request die offene
Rechnung (id+number+status) per Subquery aus der invoices-Tabelle
(status draft|sent → also nicht bezahlt, nicht storniert)
- Frontend: Wenn schon eine Rechnung existiert, wird statt 'Rechnung
erstellen' (orange) der Button 'Rechnung bearbeiten' (gelb,
#eab308) gezeigt. Klick lädt die Rechnung und öffnet das Modal im
Edit-Modus — kein doppeltes Anlegen, Nummerierung bleibt sauber.
- 'null is not an object (wrap2.remove)': Wrapper-Div hat keine
Klasse .diary-media-thumb-wrap → closest() lieferte null. Fallback
auf btn.parentElement + Null-Check vor remove()
- Bei 404 'Medium nicht gefunden' wird das verwaiste Foto jetzt
trotzdem lokal aufgeräumt (entry.media_items + DOM), statt einen
Error-Toast zu zeigen. Verwaiste Phantome verschwinden so beim
ersten Lösch-Klick.
- Toggle-Buttons oben im Protokoll-Tab
- 'Nach Übung': gruppiert alle Sessions pro Übung, sortiert nach zuletzt trainiert
- Pro Übung: Ø-Erfolgsquote als Kreis, Trend-Pfeil (↑↓→★), Anzahl Einheiten + TOP-Count
- Aufklappbare Session-Liste pro Übung (Datum · Emoji · % · Wdh.)
- Hinweis wenn mehr Sessions vorhanden als geladen
- Verlauf: _verlaufLoading-Flag verhindert parallele Loads
- Verlauf: el nach await neu holen (stale DOM-Referenz nach Re-Render)
- Verlauf: bei _renderContent() Shell nur rendern wenn keine Sessions im Cache
- Backend: hund_stimmung/zufriedenheit als Optional[str/int] → akzeptiert null
- Neuer Tab 'Protokoll' in der Übungen-Seite: zeigt alle Trainingseinheiten
chronologisch nach Datum gruppiert (Heute/Gestern/Datum-Label)
- Jede Einheit: Übungsname, Wdh., Erfolgs-Emoji, Stimmung, Sterne, Notiz, TOP-Badge
- 'Weitere laden' Pagination (30 Einheiten pro Seite)
- Backend: Training erstellt keine Tagebuch-Einträge mehr (weder bei ist_top noch manuell)
- Frontend: 'Als Meilenstein ins Tagebuch' Checkbox komplett entfernt
- onDogChange setzt Verlauf-State zurück
Statt try/except mit pass: PRAGMA table_info prüft ob Spalte existiert,
loggt explizit ob hinzugefügt oder bereits vorhanden.
SW by-v1032, APP_VER 1032
bday/bdayYear: nur truthy wenn bdayDog.id === dog.id (aktiver Hund)
otherBdayDog: zeigt Hinweis wenn ein ANDERER Hund Geburtstag hat
SW by-v1031, APP_VER 1031
Nach Object.assign(_appState.user, updated) wurde Worlds.refresh() nie
aufgerufen → JETZT-Welt zeigte alten Render ohne Geburtstags-Greeting.
SW by-v1030, APP_VER 1030
Wenn ein anderer Hund (nicht der angezeigte) Geburtstag hat:
- Cake-Icon (Phosphor) animiert bounce in der Info-Karte unten
- "[Name] hat heute/morgen Geburtstag!" + Pfeil-Button
- Klick → wechselt direkt zum Geburtstagshund + zeigt Birthday-Banner
Kein Tab-Indicator (nur HUND-Welt). SW by-v1027, APP_VER 1027
design-system.css: .leaflet-tile-pane bekommt den invert/hue-rotate-Filter
im Dark-Mode — gilt für walks, lost, poison, forum, routes und alle
anderen Seiten mit eingebetteten Leaflet-Karten.
design-system.css ?v=1025, SW by-v1026, APP_VER 1026
Zeigt ein realistisches Beispiel (Luna vom Bergwald) mit Deckdaten,
Trächtigkeits-Meilensteinen und Progesteronkurve — im bestehenden
Züchter-Abschnitt, kein neuer Section-Break.
SW by-v1017, APP_VER 1017
Äußerer Wrapper hatte max-width:860px aber kein margin:0 auto → klebte links.
Toolbar und List-Container bekamen fehlende Seitenabstände.
SW by-v1015, APP_VER 1015
- app.js: _applyDesktopWidth() setzt nach Page-Init die Klasse pc-desktop
auf dem ersten Kind-Div aller Standard-Seiten (excl. admin/map/chat/etc.)
- layout.css: .pc-desktop { max-width:860px !important; margin:0 auto }
- layout.css: .page-container ab 768px auf 860px (statt erst 1024px)
- main.py: /force-update Text "Service Worker wird entfernt" →
"Wir besorgen neue Leckerlis 🦴"
- layout.css ?v=1013, components.css ?v=1010, SW by-v1014, APP_VER 1014
Greeting-Karte + Wetter/Route/Übung-Chips stretchen nicht mehr auf volle
Desktopbreite. Chips sind je ~280px breit — deutlich kompakter als vorher.
components.css ?v=1010, SW by-v1013, APP_VER 1013