UX: Welcome-Seite — Anmelde-Einstieg vereinfacht, Install-Block prominent mit PWA-Erklärung (SW by-v755)

This commit is contained in:
rene 2026-05-07 17:15:19 +02:00
parent b31116abf6
commit e5e95efaed
6 changed files with 90 additions and 88 deletions

View file

@ -327,7 +327,7 @@ MEDIA_DIR = os.getenv("MEDIA_DIR", "/data/media")
os.makedirs(MEDIA_DIR, exist_ok=True)
app.mount("/media", StaticFiles(directory=MEDIA_DIR), name="media")
APP_VER = "754" # muss mit APP_VER in app.js übereinstimmen
APP_VER = "755" # muss mit APP_VER in app.js übereinstimmen
@app.get("/api/version")
async def app_version():

View file

@ -578,7 +578,7 @@
<script src="/js/api.js?v=94"></script>
<script src="/js/ui.js?v=94"></script>
<script src="/js/app.js?v=94"></script>
<script src="/js/worlds.js?v=754"></script>
<script src="/js/worlds.js?v=755"></script>
<!-- Feature-Seiten werden lazy geladen -->

View file

@ -3,7 +3,7 @@
Router, State-Management, Navigation, Initialisierung.
============================================================ */
const APP_VER = '754'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VER = '755'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VERSION = '1.5.0'; // ← semantische Version, wird bei make release gesetzt
const IS_STAGING = location.hostname === 'staging.banyaro.app';

View file

@ -50,10 +50,12 @@ window.Page_settings = (() => {
// ----------------------------------------------------------
// INIT / REFRESH
// ----------------------------------------------------------
async function init(container, appState) {
async function init(container, appState, params = {}) {
_container = container;
_appState = appState;
_render();
if (params.tab === 'login') setTimeout(() => _renderAuth('login'), 50);
if (params.tab === 'register') setTimeout(() => _renderAuth('register'), 50);
// Frischen User-State laden damit Badges (is_founder, is_partner) aktuell sind
if (_appState.user) {
try {

View file

@ -87,7 +87,6 @@ window.Page_welcome = (() => {
// LANDING PAGE — nicht eingeloggte Besucher
// ----------------------------------------------------------
function _renderLanding(isInstalled) {
// Browser-Besucher (kein PWA) ohne Login → auf /info weiterleiten
const isPWA = window.matchMedia('(display-mode: standalone)').matches
|| window.navigator.standalone === true;
if (!isPWA && !sessionStorage.getItem('by_stay_in_app')) {
@ -113,17 +112,10 @@ window.Page_welcome = (() => {
</div>
<div class="wc-lhero-cta">
${hasPrompt ? `
<button class="btn wc-btn-hero" id="welcome-install-hero-btn">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#download-simple"></use></svg>
Zum Home-Bildschirm hinzufügen
</button>
` : `
<button class="btn wc-btn-hero" id="welcome-register-btn">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#paw-print"></use></svg>
Kostenlos loslegen
</button>
`}
<button class="btn wc-btn-hero" id="welcome-register-btn">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#paw-print"></use></svg>
Kostenlos registrieren
</button>
<button class="btn wc-btn-login" id="welcome-login-btn">
Schon dabei? Anmelden
</button>
@ -145,7 +137,33 @@ window.Page_welcome = (() => {
</div>
</div>
<!-- Feature 1: Tagebuch -->
<!-- Install-Block -->
${!isInstalled ? `
<div class="wc-install-block">
<div class="wc-install-block-header">
<div class="wc-install-block-icon">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#device-mobile"></use></svg>
</div>
<div>
<div class="wc-install-block-title">Kein App Store nötig</div>
<div class="wc-install-block-sub">Füge Ban Yaro zum Home-Bildschirm hinzu einmal, dann immer griffbereit</div>
</div>
</div>
<p class="wc-install-block-why">
Ban Yaro ist eine Web-App (PWA). Das bedeutet: kein App-Store-Download, automatische Updates ohne dein Zutun, und sie verhält sich genau wie eine native App mit Icon, Vollbild und Offline-Modus.
</p>
${hasPrompt ? `
<button class="btn btn-primary wc-install-block-btn" id="welcome-install-hero-btn">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#download-simple"></use></svg>
Jetzt zum Home-Bildschirm hinzufügen
</button>
` : `
<div class="wc-install-block-steps">${_installHTML()}</div>
`}
</div>
` : ''}
<!-- Features -->
<div class="wc-feature wc-feature--a">
<div class="wc-feature-icon">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#book-open"></use></svg>
@ -155,8 +173,6 @@ window.Page_welcome = (() => {
<p>Halte jeden gemeinsamen Moment fest Fotos, Einträge, Stimmungen. Nur für dich, privat und sicher.</p>
</div>
</div>
<!-- Feature 2: Gesundheit -->
<div class="wc-feature wc-feature--b">
<div class="wc-feature-icon">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#first-aid"></use></svg>
@ -166,26 +182,22 @@ window.Page_welcome = (() => {
<p>Impfungen, Gewicht, Tierarzttermine alles an einem Ort. Du siehst immer, wann was ansteht.</p>
</div>
</div>
<!-- Feature 3: Community -->
<div class="wc-feature wc-feature--c">
<div class="wc-feature-icon">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#map-trifold"></use></svg>
</div>
<div class="wc-feature-text">
<h2>Community vor Ort</h2>
<p>Giftköder-Warnungen, Gassi-Treffen, Events was in deiner Gegend gerade passiert.</p>
<p>Giftköder-Warnungen, Forum, Events was in deiner Gegend gerade passiert.</p>
</div>
</div>
<!-- Feature 4: Training -->
<div class="wc-feature wc-feature--d">
<div class="wc-feature-icon">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#target"></use></svg>
</div>
<div class="wc-feature-text">
<h2>Training & KI-Trainer</h2>
<p>Über 100 Übungen mit Schritt-für-Schritt-Anleitungen. Mit KI-Unterstützung, die deinen Hund kennt.</p>
<h2>Training & Übungen</h2>
<p>Über 100 Übungen mit Schritt-für-Schritt-Anleitungen. Fortschritt tracken, Streaks aufbauen.</p>
</div>
</div>
@ -198,65 +210,21 @@ window.Page_welcome = (() => {
<p class="wc-privacy-sub">
Kein Facebook. Kein Google. Keine Werbung.<br>
Ban Yaro läuft auf einem eigenen Server in Deutschland
dein Tagebuch, deine Routen, deine Gesundheitsdaten
bleiben privat.
dein Tagebuch, deine Routen, deine Gesundheitsdaten bleiben privat.
</p>
</div>
<!-- Und noch mehr (einklappbar) -->
<div class="wc-more">
<button class="wc-more-toggle" id="wc-more-toggle" aria-expanded="false">
<span>Und noch viel mehr</span>
<svg class="ph-icon wc-more-chevron" aria-hidden="true"><use href="/icons/phosphor.svg#caret-down"></use></svg>
</button>
<div class="wc-grid wc-grid--collapsed" id="wc-more-grid">
${FEATURES.map(f => `
<div class="wc-tile wc-tile--static">
<div class="wc-tile-icon">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#${f.icon}"></use></svg>
</div>
<span class="wc-tile-label">${f.label}</span>
</div>
`).join('')}
</div>
</div>
<!-- Bottom CTA -->
<div class="wc-bottom-cta">
${hasPrompt ? `
<button class="btn wc-btn-hero" id="welcome-install-hero-btn2">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#download-simple"></use></svg>
Zum Home-Bildschirm hinzufügen
</button>
` : `
<button class="btn wc-btn-hero" id="welcome-register-btn2">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#paw-print"></use></svg>
Jetzt kostenlos starten
</button>
`}
<p class="wc-bottom-hint">Kein App Store · Direkt auf den Home-Bildschirm</p>
${!isInstalled ? `
<button class="wc-install-link" id="welcome-install-link">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#download-simple"></use></svg>
Zum Home-Bildschirm hinzufügen
</button>
` : ''}
<button class="btn wc-btn-hero" id="welcome-register-btn2">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#paw-print"></use></svg>
Jetzt kostenlos starten
</button>
<button class="btn wc-btn-login" id="welcome-login-btn2" style="max-width:320px;width:100%">
Schon dabei? Anmelden
</button>
</div>
<!-- Install Card (via Einstellungen) -->
${_showInstall ? `
<div class="page-container" style="padding:0 var(--space-4) var(--space-6)">
<div class="card wc-install-card">
<div class="wc-install-header">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#download-simple"></use></svg>
Immer griffbereit kein App Store
</div>
<div style="padding:var(--space-4)">${_installHTML()}</div>
</div>
</div>
` : ''}
<p class="wc-footer">Ban Yaro · Deine Daten auf eigenem Server in Deutschland</p>
</div>
`;
@ -811,6 +779,43 @@ window.Page_welcome = (() => {
}
.wc-grid.wc-grid--collapsed { display: none; }
/* Install Block */
.wc-install-block {
background: var(--c-bg-card);
border-top: 3px solid var(--c-primary);
padding: var(--space-5) var(--space-5) var(--space-6);
}
.wc-install-block-header {
display: flex; align-items: flex-start; gap: var(--space-3);
margin-bottom: var(--space-3);
}
.wc-install-block-icon {
width: 44px; height: 44px; border-radius: var(--radius-md);
background: var(--c-primary-subtle); flex-shrink: 0;
display: flex; align-items: center; justify-content: center;
}
.wc-install-block-icon .ph-icon { width: 22px; height: 22px; color: var(--c-primary); }
.wc-install-block-title {
font-size: var(--text-base); font-weight: var(--weight-bold);
color: var(--c-text); margin-bottom: 2px;
}
.wc-install-block-sub {
font-size: var(--text-sm); color: var(--c-text-secondary); line-height: 1.4;
}
.wc-install-block-why {
font-size: var(--text-sm); color: var(--c-text-secondary);
line-height: 1.6; margin: 0 0 var(--space-4);
padding: var(--space-3) var(--space-4);
background: var(--c-surface); border-radius: var(--radius-md);
border-left: 3px solid var(--c-primary);
}
.wc-install-block-btn {
width: 100%; font-size: var(--text-base);
padding: 14px; border-radius: var(--radius-lg);
display: flex; align-items: center; justify-content: center; gap: var(--space-2);
}
.wc-install-block-steps { margin-top: var(--space-2); }
/* Bottom CTA */
.wc-bottom-cta {
padding: var(--space-8) var(--space-5) var(--space-6);
@ -1194,15 +1199,10 @@ window.Page_welcome = (() => {
_container.querySelector('#welcome-install-hero-btn2')?.addEventListener('click', installBtn);
// Register / Login
const toSettings = () => App.navigate('settings');
_container.querySelector('#welcome-register-btn')?.addEventListener('click', toSettings);
_container.querySelector('#welcome-register-btn2')?.addEventListener('click', toSettings);
_container.querySelector('#welcome-login-btn')?.addEventListener('click', toSettings);
// Installationsanleitung Link
_container.querySelector('#welcome-install-link')?.addEventListener('click', () => {
App.navigate('welcome', true, { install: true });
});
_container.querySelector('#welcome-register-btn')?.addEventListener('click', () => App.navigate('settings', true, { tab: 'register' }));
_container.querySelector('#welcome-register-btn2')?.addEventListener('click', () => App.navigate('settings', true, { tab: 'register' }));
_container.querySelector('#welcome-login-btn')?.addEventListener('click', () => App.navigate('settings', true, { tab: 'login' }));
_container.querySelector('#welcome-login-btn2')?.addEventListener('click', () => App.navigate('settings', true, { tab: 'login' }));
// Link kopieren
_container.querySelector('#install-copy-btn')?.addEventListener('click', async () => {

View file

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