Feature: Welten-Onboarding, Wetter-Motivation, UX-Fixes (SW by-v715)

Welten (worlds.js):
- Swipe-Hints beim ersten Öffnen (JETZT ← → WELT animiert, einmalig)
- Kein-Hund-Onboarding: Feature-Preview-Grid statt leerer Karte
- Hintergrund-Foto-Hint: Kamera-Karte wenn noch kein Tagebuchfoto
- worlds-back: navigiert zu Welcome wenn kein User eingeloggt
- Nach Logout: worlds-back Button sofort ausgeblendet

Wetter (wetter.js):
- Standort-Fehlerseite zu Motivations-Seite umgebaut
- Feature-Preview: Gassi-Score, 7-Tage, Regenradar, Rekorde
- CTA: Standort freigeben + Registrieren (nur für Gäste)

Settings (settings.js):
- Logo in Auth-Form: display:block + margin:0 auto zentriert
- Header bleibt sichtbar (FAB/Zurück-Navigation funktioniert)

Jobs (jobs.js):
- 2-Spalten-Grid auf Mobile: auto-fit statt festes 1fr 1fr
- Kein doppeltes Padding im Wrapper

Backend:
- weather.py, achievements.py: diary JOIN fix (d.user_id → dogs JOIN)
- Neue Wetter-Badges: wetter_tapfer, jahreszeiten, schnee
- Ernährungs-, Reise-, Ausgaben-Seite: diverse UX-Verbesserungen
- Presse-Seite erweitert
- Ban Yaro Foto-Assets (WebP + HIRES JPG)
This commit is contained in:
rene 2026-05-05 17:32:03 +02:00
parent aa4849d947
commit 55069d246b
28 changed files with 719 additions and 198 deletions

View file

@ -112,22 +112,82 @@ window.Page_wetter = (() => {
function _showLocationError() {
const body = _container.querySelector('#wttr-body');
if (!body) return;
const isLoggedIn = !!_appState?.user;
body.innerHTML = `
<div style="text-align:center;padding:var(--space-10) var(--space-4)">
<div style="font-size:2.5rem;margin-bottom:var(--space-3)">📍</div>
<h3 style="margin-bottom:var(--space-2)">Standort nicht verfügbar</h3>
<p style="color:var(--c-text-secondary);margin-bottom:var(--space-5);max-width:300px;margin-inline:auto">
Bitte erlaube den Zugriff auf deinen Standort, um die Wettervorhersage zu laden.
</p>
<button class="btn btn-primary" id="wttr-btn-retry">
${UI.icon('map-pin')} Nochmal versuchen
</button>
<div style="max-width:420px;margin:0 auto;padding:var(--space-6) var(--space-4)">
<!-- 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>
<h2 style="font-size:var(--text-xl);font-weight:800;margin:0 0 var(--space-2)">
Das Gassi-Wetter wartet auf dich
</h2>
<p style="color:var(--c-text-secondary);font-size:var(--text-sm);margin:0">
Erfahre sekundengenau, ob gerade der perfekte Moment für eine Runde ist
zugeschnitten auf dich und deinen Hund.
</p>
</div>
<!-- Feature-Liste -->
<div style="display:flex;flex-direction:column;gap:var(--space-3);margin-bottom:var(--space-6)">
${[
['sun', '#F59E0B', 'Gassi-Score 110', 'Wetter bewertet nach Temperatur, Regen und Wind'],
['thermometer', '#3B82F6', '7-Tage-Vorschau', 'Plane deine Runden für die ganze Woche voraus'],
['drop', '#06B6D4', 'Regenradar stündlich', '24h-Niederschlagstimeline auf einen Blick'],
['trophy', '#10B981', 'Wetter-Rekorde', 'Wärmster, nassester und stürmischster Gassi-Tag'],
].map(([icon, color, title, sub]) => `
<div style="display:flex;align-items:center;gap:var(--space-3);
background:var(--c-bg-card);border:1px solid var(--c-border);
border-radius:var(--radius-lg);padding:var(--space-3) var(--space-4)">
<div style="width:38px;height:38px;border-radius:var(--radius-md);
background:${color}18;display:flex;align-items:center;
justify-content:center;flex-shrink:0">
<svg class="ph-icon" style="width:1.1rem;height:1.1rem;color:${color}">
<use href="/icons/phosphor.svg#${icon}"></use>
</svg>
</div>
<div>
<div style="font-weight:700;font-size:var(--text-sm)">${title}</div>
<div style="color:var(--c-text-secondary);font-size:var(--text-xs)">${sub}</div>
</div>
</div>
`).join('')}
</div>
<!-- CTAs -->
<div style="display:flex;flex-direction:column;gap:var(--space-3)">
<button class="btn btn-primary" id="wttr-btn-retry"
style="display:flex;align-items:center;justify-content:center;gap:var(--space-2)">
<svg class="ph-icon" style="width:1rem;height:1rem">
<use href="/icons/phosphor.svg#map-pin"></use>
</svg>
Standort freigeben &amp; loslegen
</button>
${!isLoggedIn ? `
<button class="btn btn-secondary" id="wttr-btn-login"
style="display:flex;align-items:center;justify-content:center;gap:var(--space-2)">
<svg class="ph-icon" style="width:1rem;height:1rem">
<use href="/icons/phosphor.svg#user"></use>
</svg>
Kostenlos registrieren
</button>
<p style="text-align:center;font-size:var(--text-xs);color:var(--c-text-secondary);margin:0">
Mit Account werden Rekorde &amp; Gassi-Score für deinen Hund gespeichert.
</p>
` : ''}
</div>
</div>
`;
body.querySelector('#wttr-btn-retry')?.addEventListener('click', () => {
_renderShell();
_tryAutoLocate();
});
body.querySelector('#wttr-btn-login')?.addEventListener('click', () => {
if (window.App) App.navigate('settings');
});
}
// ----------------------------------------------------------
@ -1007,19 +1067,21 @@ window.Page_wetter = (() => {
function _recordCard(emoji, title, value, subtitle, color) {
return `
<div style="background:var(--c-bg-card);border:1px solid var(--c-border);
border-radius:var(--radius);padding:var(--space-3) var(--space-3);
display:flex;flex-direction:column;gap:2px">
<div style="font-size:var(--text-xs);color:var(--c-text-secondary);
display:flex;align-items:center;gap:4px;font-weight:600">
<div style="background:${color}10;border:1px solid ${color}33;
border-radius:var(--radius);padding:var(--space-3);
display:flex;flex-direction:column;gap:3px">
<div style="font-size:10px;color:var(--c-text-secondary);
display:flex;align-items:center;gap:3px;font-weight:700;
text-transform:uppercase;letter-spacing:.04em">
<span>${emoji}</span>
<span>${_esc(title)}</span>
</div>
<div style="font-size:var(--text-xl);font-weight:800;color:${color};line-height:1.1">
<div style="font-size:var(--text-lg);font-weight:800;color:${color};line-height:1.1">
${_esc(value)}
</div>
<div style="font-size:var(--text-xs);color:var(--c-text-secondary);
white-space:nowrap;overflow:hidden;text-overflow:ellipsis">
<div style="font-size:10px;color:var(--c-text-secondary);
overflow:hidden;display:-webkit-box;
-webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:1.3">
${_esc(subtitle)}
</div>
</div>