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:
parent
55069d246b
commit
05ecf3b94a
13 changed files with 1158 additions and 43 deletions
|
|
@ -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 & 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>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue