Feature: Hilfe/FAQ, Übungen-Content, Navigation-Fixes (SW by-v727)

Hilfe & FAQ:
- Neue Seite /hilfe mit Akkordeon + Live-Suche (6 Kategorien, 25 Artikel)
- DB-Tabelle help_articles — Inhalte admin-seitig ohne Deploy änderbar
- Admin-Tab Hilfe/FAQ zum Bearbeiten aller Artikel
- Link in Einstellungen (unter Welten einrichten, über Abmelden)
- routes/help.py: GET (public), POST/PATCH/DELETE (Admin)

Übungen:
- 110 Übungen: beschreibung (kurz), schritte (JSON 4-6 Schritte), tipp — gutes Deutsch mit Umlauten
- Admin-Tab Übungen: Inline-Editor für alle drei Felder
- PUT /training/exercises/{id} (Admin) neu
- Übung-des-Tages Chip → scrollt jetzt korrekt zur Übung (exercise_id-Feldname-Fix)

Welten-Navigation:
- hide() stellt app-header + bottom-nav wieder her (worlds-hidden wurde nie entfernt)
- init() mit _setupDone-Guard (keine doppelten Event-Listener)
- Login ruft Worlds.init(_appState) statt show() — _state war null → falscher Render
- X-Button in Welten-Konfiguration: 30×30px, Icon 17px, besser sichtbar

Wetter:
- Motivation bei blockiertem Standort: 6-Schritte-iOS-Anleitung + Flugmodus-Tipp
- Auto-locate bleibt (kein Button-Only mehr)

achievements.py:
- my_achievements(): d.user_id → JOIN dogs (zweite Funktion war noch kaputt)
This commit is contained in:
rene 2026-05-05 21:46:16 +02:00
parent 55069d246b
commit 05ecf3b94a
13 changed files with 1158 additions and 43 deletions

View file

@ -73,23 +73,17 @@ window.Page_wetter = (() => {
_tryAutoLocate();
}
// ----------------------------------------------------------
// REFRESH
// ----------------------------------------------------------
async function refresh() {
_selDay = 0;
_selDay = 0;
_recordsLoaded = false;
_renderShell();
_tryAutoLocate();
}
// ----------------------------------------------------------
// RENDER — Grundstruktur
// ----------------------------------------------------------
function _renderShell() {
_container.innerHTML = `
<div id="wttr-body">
<div id="wttr-locating" style="text-align:center;padding:var(--space-10) var(--space-4)">
<div style="text-align:center;padding:var(--space-10) var(--space-4)">
<div style="margin-bottom:var(--space-3)">${_wmoIcon(2, '2.5rem')}</div>
<p style="color:var(--c-text-secondary)">Standort wird ermittelt</p>
</div>
@ -97,26 +91,55 @@ window.Page_wetter = (() => {
`;
}
// ----------------------------------------------------------
// STANDORT AUTOMATISCH ERMITTELN
// ----------------------------------------------------------
async function _tryAutoLocate() {
try {
const pos = await API.getLocation({ timeout: 8000, maximumAge: 300_000 });
await _loadData(pos.lat, pos.lon);
} catch {
_showLocationError();
} catch (err) {
_showLocationError(err?.code);
}
}
function _showLocationError() {
const body = _container.querySelector('#wttr-body');
function _showLocationError(errCode) {
const body = _container?.querySelector('#wttr-body');
if (!body) return;
const isLoggedIn = !!_appState?.user;
const isLoggedIn = !!_appState?.user;
const isDenied = errCode === 1; // GeolocationPositionError.PERMISSION_DENIED
const isIos = /iphone|ipad|ipod/i.test(navigator.userAgent);
const deniedHint = isDenied ? `
<div style="background:rgba(245,158,11,0.08);border:1px solid rgba(245,158,11,0.4);
border-radius:var(--radius-lg);padding:var(--space-4);margin-bottom:var(--space-4)">
<div style="display:flex;align-items:center;gap:var(--space-2);margin-bottom:var(--space-3)">
<svg class="ph-icon" style="width:1.2rem;height:1.2rem;color:#F59E0B;flex-shrink:0">
<use href="/icons/phosphor.svg#warning"></use>
</svg>
<div style="font-weight:700;font-size:var(--text-sm)">Standort-Zugriff blockiert</div>
</div>
${isIos ? `
<div style="color:var(--c-text-secondary);font-size:var(--text-sm);margin-bottom:var(--space-3)">
<b>Wichtig:</b> Die App läuft getrennt von Safari Safari-Einstellungen gelten hier nicht.
</div>
<ol style="margin:0;padding-left:var(--space-5);display:flex;flex-direction:column;gap:var(--space-1);
color:var(--c-text-secondary);font-size:var(--text-sm)">
<li>Öffne <b>Einstellungen Datenschutz &amp; Sicherheit Ortungsdienste</b></li>
<li>Scrolle ganz nach unten zu <b>Ban Yaro</b> (nicht Safari!)</li>
<li>Wähle <b>Beim Verwenden der App"</b></li>
<li>Komm zurück und tippe nochmal auf den Button</li>
</ol>
<div style="margin-top:var(--space-3);font-size:var(--text-xs);color:var(--c-text-secondary)">
<b>Letzter Ausweg:</b> Einstellungen Apps Safari Erweitert Website-Daten banyaro.app löschen. Danach nochmal öffnen und Button tippen.
</div>` : `
<div style="color:var(--c-text-secondary);font-size:var(--text-sm)">
Klicke auf das Schloss-Symbol in der Adressleiste <b>Standort</b> <b>Erlauben</b>, dann nochmal tippen.
</div>`}
</div>` : '';
body.innerHTML = `
<div style="max-width:420px;margin:0 auto;padding:var(--space-6) var(--space-4)">
${deniedHint}
<!-- Hero -->
<div style="text-align:center;margin-bottom:var(--space-6)">
<div style="font-size:4rem;line-height:1;margin-bottom:var(--space-2)">🌤🐾</div>