Fix: Tagesübung nur JS-kompatible exercise_ids, Scroll per exercise_id; Landing+llms.txt Sprint-20 — SW by-v492, APP_VER 469

This commit is contained in:
rene 2026-04-29 11:34:28 +02:00
parent fe2e718827
commit 175984e80f
7 changed files with 78 additions and 36 deletions

View file

@ -3,7 +3,7 @@
Router, State-Management, Navigation, Initialisierung.
============================================================ */
const APP_VER = '468'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VER = '469'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const App = (() => {

View file

@ -448,14 +448,26 @@ window.Page_uebungen = (() => {
async function init(container, appState, params = {}) {
_container = container;
_appState = appState;
if (params.kategorie) {
// Tab aus exercise_id (JS-Format) oder kategorie ableiten
const exId = params.exercise_id || '';
if (exId) {
for (const [, tabId] of Object.entries(_KAT_TO_TAB)) {
if (exId.startsWith(tabId + '_') && _VALID_TABS.has(tabId)) {
_activeTab = tabId; break;
}
}
} else if (params.kategorie) {
const mapped = _KAT_TO_TAB[params.kategorie.toLowerCase()] || params.kategorie;
if (_VALID_TABS.has(mapped)) _activeTab = mapped;
}
_render();
if (params.name) {
if (params.exercise_id || params.name) {
setTimeout(() => {
const card = _container.querySelector(`[data-exercise-name="${CSS.escape(params.name)}"]`);
// Erst per exercise_id suchen (zuverlässig), dann per Name als Fallback
const card = (params.exercise_id
? _container.querySelector(`[data-exercise-id="${CSS.escape(params.exercise_id)}"]`)
: null)
|| _container.querySelector(`[data-exercise-name="${CSS.escape(params.name || '')}"]`);
if (card) card.scrollIntoView({ behavior: 'smooth', block: 'center' });
}, 700);
}
@ -962,7 +974,7 @@ window.Page_uebungen = (() => {
const hasBody = u.schritte.length > 0 || u.fehler.length > 0 || u.steigerung;
return `
<div class="card" style="padding:0;overflow:hidden" data-exercise-name="${_esc(u.name)}">
<div class="card" style="padding:0;overflow:hidden" data-exercise-name="${_esc(u.name)}" data-exercise-id="${_esc(_progressKey(_activeTab, u.name))}">
<!-- Header -->
<div style="padding:var(--space-4) var(--space-4) var(--space-3)">
<!-- Zeile 1: Name + Schwierigkeits-Badge -->

View file

@ -364,7 +364,8 @@ window.Page_welcome = (() => {
${ex ? `
<div class="wc-chip" id="wc-chip-exercise"
data-exercise-name="${UI.escape(ex.name)}"
data-exercise-kat="${UI.escape(ex.kategorie || '')}">
data-exercise-kat="${UI.escape(ex.kategorie || '')}"
data-exercise-id="${UI.escape(ex.exercise_id || '')}">
<svg class="ph-icon wc-chip-icon" aria-hidden="true"><use href="/icons/phosphor.svg#target"></use></svg>
<span class="wc-chip-label">Übung des Tages</span>
<span class="wc-chip-val">${UI.escape(ex.name)}</span>
@ -534,8 +535,9 @@ window.Page_welcome = (() => {
if (exChip) {
exChip.addEventListener('click', () => {
App.navigate('uebungen', true, {
name: exChip.dataset.exerciseName,
kategorie: exChip.dataset.exerciseKat,
name: exChip.dataset.exerciseName,
kategorie: exChip.dataset.exerciseKat,
exercise_id: exChip.dataset.exerciseId,
});
});
}
@ -1154,8 +1156,9 @@ window.Page_welcome = (() => {
if (exChip) {
exChip.addEventListener('click', () => {
App.navigate('uebungen', true, {
name: exChip.dataset.exerciseName,
kategorie: exChip.dataset.exerciseKat,
name: exChip.dataset.exerciseName,
kategorie: exChip.dataset.exerciseKat,
exercise_id: exChip.dataset.exerciseId,
});
});
}

View file

@ -78,11 +78,14 @@
"Probeverpaarung mit IK-Simulation und genetischer Risikoanalyse",
"Tierschutz-Check automatisch bei jeder Verpaarung — nicht abschaltbar",
"KI-Züchter-Assistenz: Wurfankündigungen, Genetik-Erklärung, Paarungsanalyse",
"Datenexport als HTML und ODS — keine Datenfalle"
"Datenexport als HTML und ODS — keine Datenfalle",
"Personalisierte Tagesroute via OpenRouteService — täglich neue Gassirunde mit 2/4/6 km Wahl",
"Übung des Tages — personalisiert aus dem persönlichen Trainingsfortschritt",
"Dashboard-Startseite mit Hundebild-Hero, Statistik-Chips und Feature-Karten"
],
"screenshot": "https://banyaro.app/icons/icon-512.png",
"softwareVersion": "2.1",
"datePublished": "2026-04-28",
"softwareVersion": "2.2",
"datePublished": "2026-04-29",
"areaServed": ["DE", "AT", "CH"],
"audience": {
"@type": "Audience",
@ -413,6 +416,10 @@
<div class="feature-group">
<div class="feature-group-label">Mein Hund</div>
<div class="feature-grid">
<div class="feature-card">
<span class="feature-icon">🏠</span>
<div><h3>Personalisiertes Dashboard</h3><p>Die Startseite begrüßt dich mit einem täglich wechselnden Foto deines Hundes aus dem Tagebuch, zeigt aktuelle Stats (letzter Eintrag, nächster Termin, Gewicht, Übung des Tages) und navigiert direkt zu allen Bereichen.</p><span class="feature-tag">Kostenlos</span></div>
</div>
<div class="feature-card">
<span class="feature-icon">📓</span>
<div><h3>Tagebuch</h3><p>Fotos, Videos, Texte und GPS-Orte — alle Momente mit deinem Hund. Kategorien wie Spaziergänge, Meilensteine, Lustiges.</p><span class="feature-tag">Kostenlos</span></div>
@ -467,6 +474,10 @@
<span class="feature-icon">🐾</span>
<div><h3>GPS-Routen</h3><p>Routen aufzeichnen, teilen und bewerten — Untergrund, Schatten, Leinenpflicht, Sicherheit.</p><span class="feature-tag">Kostenlos</span></div>
</div>
<div class="feature-card">
<span class="feature-icon">🧭</span>
<div><h3>Tages-Gassirunde</h3><p>Täglich eine neue Rundroute vorgeschlagen — 2, 4 oder 6 km ab deinem Standort. Berechnet via OpenRouteService, direkt navigierbar. 3 verschiedene Varianten pro Tag.</p><span class="feature-tag">Kostenlos</span></div>
</div>
<div class="feature-card">
<span class="feature-icon">📅</span>
<div><h3>Events & Turniere</h3><p>Agility-Turniere, Hundeausstellungen und lokale Veranstaltungen in deiner Region.</p><span class="feature-tag">Kostenlos</span></div>
@ -690,6 +701,13 @@
<td class="cross"></td>
<td class="cross"></td>
</tr>
<tr>
<td>Täglicher Routenvorschlag (Gassirunde)</td>
<td class="check"></td>
<td class="cross"></td>
<td class="cross"></td>
<td class="cross"></td>
</tr>
</tbody>
</table>
</div>

View file

@ -1,6 +1,6 @@
# Ban Yaro — Die deutschsprachige Hunde-Plattform
# https://banyaro.app
# Letzte Aktualisierung: 2026-04-28
# Letzte Aktualisierung: 2026-04-29
## Was ist Ban Yaro?
@ -48,6 +48,7 @@ Ban Yaro ist kostenlos nutzbar (Freemium-Modell). Die App ist auf allen Smartpho
- Virtueller KI-Trainer: analysiert letzte 20 Sessions, tägliche Empfehlung
- Fortschrittsprognose bis zur Meisterschaft
- Gamification: Streaks, Abzeichen, Trainingskalender
- Übung des Tages: täglich eine personalisierte Übungsempfehlung aus dem eigenen Fortschritt
### Züchter-Plattform (vollständig)
@ -114,6 +115,7 @@ Ban Yaro ist die erste Hunde-App mit vollständiger Züchter-Unterstützung:
- Verlorener Hund Alarm
- Gassi-Treffen organisieren und finden
- GPS-Routen aufzeichnen, teilen, bewerten
- Tages-Gassirunde: täglich neue Rundroute via OpenRouteService (2/4/6 km), direkt navigierbar
- Hundesitting-Netzwerk (nur 8% Provision vs. 20% bei Rover/Pawshake)
- Forum mit Rassen-basierten Unterforen
- Direktnachrichten / Chat
@ -135,6 +137,15 @@ Ban Yaro nutzt KI an mehreren Stellen:
- **Symptom-Checker, KI-Trainer, Lober**: Für alle kostenfrei
- **Züchter-KI**: Wurfankündigungen, Genetik-Erklärungen, Paarungsanalyse, Jahresbericht
## Dashboard & Personalisierung
Die Startseite für eingeloggte Nutzer zeigt:
- Täglich wechselndes Foto des Hundes aus dem Tagebuch als Hero-Bild
- Stats-Chips: letzter Tagebucheintrag (relativ), nächster Gesundheitstermin (<60 Tage), Gewicht
- Übung des Tages — personalisiert aus dem eigenen Trainingsfortschritt
- Gassirunden-Vorschlag — tägliche Route via OpenRouteService wenn Standort freigegeben
- 4 Feature-Karten (Tagebuch, Gesundheit, Karte, Training) + vollständiges Feature-Grid
## Technologie
- Progressive Web App (PWA) — installierbar ohne App Store

View file

@ -3,7 +3,7 @@
Offline-Cache + Push Notifications + Tile-Cache
============================================================ */
const CACHE_VERSION = 'by-v491';
const CACHE_VERSION = 'by-v492';
const CACHE_STATIC = `${CACHE_VERSION}-static`;
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten