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) os.makedirs(MEDIA_DIR, exist_ok=True)
app.mount("/media", StaticFiles(directory=MEDIA_DIR), name="media") 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") @app.get("/api/version")
async def app_version(): async def app_version():

View file

@ -578,7 +578,7 @@
<script src="/js/api.js?v=94"></script> <script src="/js/api.js?v=94"></script>
<script src="/js/ui.js?v=94"></script> <script src="/js/ui.js?v=94"></script>
<script src="/js/app.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 --> <!-- Feature-Seiten werden lazy geladen -->

View file

@ -3,7 +3,7 @@
Router, State-Management, Navigation, Initialisierung. 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 APP_VERSION = '1.5.0'; // ← semantische Version, wird bei make release gesetzt
const IS_STAGING = location.hostname === 'staging.banyaro.app'; const IS_STAGING = location.hostname === 'staging.banyaro.app';

View file

@ -50,10 +50,12 @@ window.Page_settings = (() => {
// ---------------------------------------------------------- // ----------------------------------------------------------
// INIT / REFRESH // INIT / REFRESH
// ---------------------------------------------------------- // ----------------------------------------------------------
async function init(container, appState) { async function init(container, appState, params = {}) {
_container = container; _container = container;
_appState = appState; _appState = appState;
_render(); _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 // Frischen User-State laden damit Badges (is_founder, is_partner) aktuell sind
if (_appState.user) { if (_appState.user) {
try { try {

View file

@ -87,7 +87,6 @@ window.Page_welcome = (() => {
// LANDING PAGE — nicht eingeloggte Besucher // LANDING PAGE — nicht eingeloggte Besucher
// ---------------------------------------------------------- // ----------------------------------------------------------
function _renderLanding(isInstalled) { function _renderLanding(isInstalled) {
// Browser-Besucher (kein PWA) ohne Login → auf /info weiterleiten
const isPWA = window.matchMedia('(display-mode: standalone)').matches const isPWA = window.matchMedia('(display-mode: standalone)').matches
|| window.navigator.standalone === true; || window.navigator.standalone === true;
if (!isPWA && !sessionStorage.getItem('by_stay_in_app')) { if (!isPWA && !sessionStorage.getItem('by_stay_in_app')) {
@ -113,17 +112,10 @@ window.Page_welcome = (() => {
</div> </div>
<div class="wc-lhero-cta"> <div class="wc-lhero-cta">
${hasPrompt ? ` <button class="btn wc-btn-hero" id="welcome-register-btn">
<button class="btn wc-btn-hero" id="welcome-install-hero-btn"> <svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#paw-print"></use></svg>
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#download-simple"></use></svg> Kostenlos registrieren
Zum Home-Bildschirm hinzufügen </button>
</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-login" id="welcome-login-btn"> <button class="btn wc-btn-login" id="welcome-login-btn">
Schon dabei? Anmelden Schon dabei? Anmelden
</button> </button>
@ -145,7 +137,33 @@ window.Page_welcome = (() => {
</div> </div>
</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 wc-feature--a">
<div class="wc-feature-icon"> <div class="wc-feature-icon">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#book-open"></use></svg> <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> <p>Halte jeden gemeinsamen Moment fest Fotos, Einträge, Stimmungen. Nur für dich, privat und sicher.</p>
</div> </div>
</div> </div>
<!-- Feature 2: Gesundheit -->
<div class="wc-feature wc-feature--b"> <div class="wc-feature wc-feature--b">
<div class="wc-feature-icon"> <div class="wc-feature-icon">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#first-aid"></use></svg> <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> <p>Impfungen, Gewicht, Tierarzttermine alles an einem Ort. Du siehst immer, wann was ansteht.</p>
</div> </div>
</div> </div>
<!-- Feature 3: Community -->
<div class="wc-feature wc-feature--c"> <div class="wc-feature wc-feature--c">
<div class="wc-feature-icon"> <div class="wc-feature-icon">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#map-trifold"></use></svg> <svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#map-trifold"></use></svg>
</div> </div>
<div class="wc-feature-text"> <div class="wc-feature-text">
<h2>Community vor Ort</h2> <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>
</div> </div>
<!-- Feature 4: Training -->
<div class="wc-feature wc-feature--d"> <div class="wc-feature wc-feature--d">
<div class="wc-feature-icon"> <div class="wc-feature-icon">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#target"></use></svg> <svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#target"></use></svg>
</div> </div>
<div class="wc-feature-text"> <div class="wc-feature-text">
<h2>Training & KI-Trainer</h2> <h2>Training & Übungen</h2>
<p>Über 100 Übungen mit Schritt-für-Schritt-Anleitungen. Mit KI-Unterstützung, die deinen Hund kennt.</p> <p>Über 100 Übungen mit Schritt-für-Schritt-Anleitungen. Fortschritt tracken, Streaks aufbauen.</p>
</div> </div>
</div> </div>
@ -198,65 +210,21 @@ window.Page_welcome = (() => {
<p class="wc-privacy-sub"> <p class="wc-privacy-sub">
Kein Facebook. Kein Google. Keine Werbung.<br> Kein Facebook. Kein Google. Keine Werbung.<br>
Ban Yaro läuft auf einem eigenen Server in Deutschland Ban Yaro läuft auf einem eigenen Server in Deutschland
dein Tagebuch, deine Routen, deine Gesundheitsdaten dein Tagebuch, deine Routen, deine Gesundheitsdaten bleiben privat.
bleiben privat.
</p> </p>
</div> </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 --> <!-- Bottom CTA -->
<div class="wc-bottom-cta"> <div class="wc-bottom-cta">
${hasPrompt ? ` <button class="btn wc-btn-hero" id="welcome-register-btn2">
<button class="btn wc-btn-hero" id="welcome-install-hero-btn2"> <svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#paw-print"></use></svg>
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#download-simple"></use></svg> Jetzt kostenlos starten
Zum Home-Bildschirm hinzufügen </button>
</button> <button class="btn wc-btn-login" id="welcome-login-btn2" style="max-width:320px;width:100%">
` : ` Schon dabei? Anmelden
<button class="btn wc-btn-hero" id="welcome-register-btn2"> </button>
<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>
` : ''}
</div> </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> <p class="wc-footer">Ban Yaro · Deine Daten auf eigenem Server in Deutschland</p>
</div> </div>
`; `;
@ -811,6 +779,43 @@ window.Page_welcome = (() => {
} }
.wc-grid.wc-grid--collapsed { display: none; } .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 */ /* Bottom CTA */
.wc-bottom-cta { .wc-bottom-cta {
padding: var(--space-8) var(--space-5) var(--space-6); 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); _container.querySelector('#welcome-install-hero-btn2')?.addEventListener('click', installBtn);
// Register / Login // Register / Login
const toSettings = () => App.navigate('settings'); _container.querySelector('#welcome-register-btn')?.addEventListener('click', () => App.navigate('settings', true, { tab: 'register' }));
_container.querySelector('#welcome-register-btn')?.addEventListener('click', toSettings); _container.querySelector('#welcome-register-btn2')?.addEventListener('click', () => App.navigate('settings', true, { tab: 'register' }));
_container.querySelector('#welcome-register-btn2')?.addEventListener('click', toSettings); _container.querySelector('#welcome-login-btn')?.addEventListener('click', () => App.navigate('settings', true, { tab: 'login' }));
_container.querySelector('#welcome-login-btn')?.addEventListener('click', toSettings); _container.querySelector('#welcome-login-btn2')?.addEventListener('click', () => App.navigate('settings', true, { tab: 'login' }));
// Installationsanleitung Link
_container.querySelector('#welcome-install-link')?.addEventListener('click', () => {
App.navigate('welcome', true, { install: true });
});
// Link kopieren // Link kopieren
_container.querySelector('#install-copy-btn')?.addEventListener('click', async () => { _container.querySelector('#install-copy-btn')?.addEventListener('click', async () => {

View file

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