diff --git a/backend/static/js/app.js b/backend/static/js/app.js
index d7180a4..2f96495 100644
--- a/backend/static/js/app.js
+++ b/backend/static/js/app.js
@@ -3,7 +3,7 @@
Router, State-Management, Navigation, Initialisierung.
============================================================ */
-const APP_VER = '422'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
+const APP_VER = '423'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const App = (() => {
diff --git a/backend/static/js/pages/welcome.js b/backend/static/js/pages/welcome.js
index d857361..53f744a 100644
--- a/backend/static/js/pages/welcome.js
+++ b/backend/static/js/pages/welcome.js
@@ -53,34 +53,200 @@ window.Page_welcome = (() => {
|| window.navigator.standalone === true;
const user = _appState?.user;
+ _injectStyles();
+
+ if (user) {
+ _renderLoggedIn(isInstalled);
+ } else {
+ _renderLanding(isInstalled);
+ }
+
+ _bindEvents();
+ _pulseMenuBtn();
+ }
+
+ // ----------------------------------------------------------
+ // LANDING PAGE — nicht eingeloggte Besucher
+ // ----------------------------------------------------------
+ function _renderLanding(isInstalled) {
+ const hasPrompt = !!App.getInstallPrompt();
+
+ _container.innerHTML = `
+
+
+
+
+
+
Alles für deinen Hund.
+
+ Tagebuch, Gesundheit, Karte, Community —
+ auf einem Server in Deutschland. Kostenlos.
+
+
+
+ ${hasPrompt ? `
+
+
+ App installieren
+
+ ` : `
+
+
+ Kostenlos loslegen
+
+ `}
+
+ Schon dabei? Anmelden
+
+
+
+
+
+
+ Kostenlos
+
+
+
+ Kein App Store
+
+
+
+ Daten in Deutschland
+
+
+
+
+
+
+
+
+
+
+
Tagebuch & Erinnerungen
+
Halte jeden gemeinsamen Moment fest — Fotos, Einträge, Stimmungen. Nur für dich, privat und sicher.
+
+
+
+
+
+
+
+
+
+
Gesundheit im Blick
+
Impfungen, Gewicht, Tierarzttermine — alles an einem Ort. Du siehst immer, wann was ansteht.
+
+
+
+
+
+
+
+
+
+
Community vor Ort
+
Giftköder-Warnungen, Gassi-Treffen, Events — was in deiner Gegend gerade passiert.
+
+
+
+
+
+
+
+
+
+
Training & KI-Trainer
+
Über 100 Übungen mit Schritt-für-Schritt-Anleitungen. Mit KI-Unterstützung, die deinen Hund kennt.
+
+
+
+
+
+
+
+
+
Deine Daten gehören dir.
+
+ Kein Facebook. Kein Google. Keine Werbung.
+ Ban Yaro läuft auf einem eigenen Server in Deutschland —
+ dein Tagebuch, deine Routen, deine Gesundheitsdaten
+ bleiben privat.
+
+
+
+
+
+
Und noch viel mehr
+
+ ${FEATURES.map(f => `
+
+ `).join('')}
+
+
+
+
+
+ ${hasPrompt ? `
+
+
+ App installieren — kostenlos
+
+ ` : `
+
+
+ Jetzt kostenlos starten
+
+ `}
+
Kein App Store · Direkt auf den Home-Bildschirm
+
+ ${!isInstalled ? `
+
+
+ Installationsanleitung
+
+ ` : ''}
+
+
+
+ ${_showInstall ? `
+
+ ` : ''}
+
+
+
+ `;
+ }
+
+ // ----------------------------------------------------------
+ // EINGELOGGTE ANSICHT — kompakter Überblick
+ // ----------------------------------------------------------
+ function _renderLoggedIn(isInstalled) {
_container.innerHTML = `
-
Ban Yaro
- ${user
- ? `Schön, dass du wieder da bist${user.name ? ', ' + UI.escape(user.name) + ' ' : ''}! 🐾`
- : 'Die Community für Hundebesitzer — Tagebuch, Gesundheit, Karte und mehr.'}
+ Schön, dass du wieder da bist${_appState?.user?.name ? ', ' + UI.escape(_appState.user.name) + ' ' : ''}!
- ${!user ? `
-
-
-
- Kostenlos registrieren
-
- Anmelden
-
- ` : ''}
-
-
Was Ban Yaro kann
-
${FEATURES.map(f => `
@@ -92,42 +258,179 @@ window.Page_welcome = (() => {
`).join('')}
-
${(!isInstalled || _showInstall) ? `
-
- ${_installHTML()}
-
+
${_installHTML()}
` : ''}
-
-
-
+
`;
-
- _injectStyles();
- _bindEvents();
- _pulseMenuBtn();
}
// ----------------------------------------------------------
- // STYLES (einmalig injizieren)
+ // STYLES
// ----------------------------------------------------------
function _injectStyles() {
if (document.getElementById('wc-styles')) return;
const s = document.createElement('style');
s.id = 'wc-styles';
s.textContent = `
+ /* ── Landing Page ──────────────────────────────────────── */
+ .wc-landing { display: flex; flex-direction: column; }
+
/* Hero */
+ .wc-lhero {
+ background: linear-gradient(160deg, var(--c-primary) 0%, color-mix(in srgb, var(--c-primary) 70%, transparent) 60%, var(--c-bg) 100%);
+ text-align: center;
+ padding: var(--space-8) var(--space-5) var(--space-8);
+ position: relative;
+ overflow: hidden;
+ }
+ .wc-lhero::before {
+ content: '';
+ position: absolute; inset: 0;
+ background: radial-gradient(ellipse at 50% 0%, rgba(255,255,255,0.18) 0%, transparent 65%);
+ pointer-events: none;
+ }
+ .wc-lhero-icon {
+ width: 80px; height: 80px;
+ border-radius: 20px;
+ box-shadow: 0 8px 32px rgba(0,0,0,0.25);
+ display: block; margin: 0 auto var(--space-5);
+ position: relative;
+ }
+ .wc-lhero-headline {
+ font-size: 2.6rem; font-weight: 800; line-height: 1.1;
+ color: #fff;
+ margin: 0 0 var(--space-4);
+ text-shadow: 0 2px 12px rgba(0,0,0,0.15);
+ letter-spacing: -0.02em;
+ position: relative;
+ }
+ .wc-lhero-sub {
+ font-size: var(--text-base); color: rgba(255,255,255,0.88);
+ line-height: 1.6; margin: 0 0 var(--space-6);
+ position: relative;
+ }
+ .wc-lhero-cta {
+ display: flex; flex-direction: column;
+ align-items: center; gap: var(--space-3);
+ margin-bottom: var(--space-6);
+ position: relative;
+ }
+ .wc-btn-hero {
+ background: #fff; color: var(--c-primary);
+ font-size: var(--text-base); font-weight: var(--weight-bold);
+ padding: 14px var(--space-6); border-radius: 100px;
+ border: none; width: 100%; max-width: 320px;
+ box-shadow: 0 4px 20px rgba(0,0,0,0.2);
+ display: flex; align-items: center; justify-content: center; gap: var(--space-2);
+ transition: transform 0.1s, box-shadow 0.1s;
+ }
+ .wc-btn-hero:active { transform: scale(0.97); box-shadow: 0 2px 10px rgba(0,0,0,0.15); }
+ .wc-btn-login {
+ color: rgba(255,255,255,0.9) !important;
+ font-size: var(--text-sm);
+ padding: var(--space-2) var(--space-4);
+ border-color: rgba(255,255,255,0.35) !important;
+ }
+ .wc-trust-strip {
+ display: flex; justify-content: center;
+ gap: var(--space-4); flex-wrap: wrap;
+ position: relative;
+ }
+ .wc-trust-strip span {
+ display: flex; align-items: center; gap: 5px;
+ font-size: var(--text-xs); color: rgba(255,255,255,0.8);
+ font-weight: var(--weight-semibold);
+ }
+ .wc-trust-strip .ph-icon { width: 13px; height: 13px; }
+
+ /* Feature Cards */
+ .wc-feature {
+ display: flex; align-items: flex-start; gap: var(--space-4);
+ padding: var(--space-6) var(--space-5);
+ border-bottom: 1px solid var(--c-border-light);
+ }
+ .wc-feature--a { background: var(--c-bg); }
+ .wc-feature--b { background: var(--c-surface); }
+ .wc-feature--c { background: var(--c-bg); }
+ .wc-feature--d { background: var(--c-surface); }
+ .wc-feature-icon {
+ width: 52px; height: 52px; border-radius: var(--radius-lg); flex-shrink: 0;
+ background: var(--c-primary-subtle);
+ display: flex; align-items: center; justify-content: center;
+ }
+ .wc-feature-icon .ph-icon { width: 26px; height: 26px; color: var(--c-primary); }
+ .wc-feature-text h2 {
+ font-size: var(--text-base); font-weight: var(--weight-bold);
+ color: var(--c-text); margin: 0 0 var(--space-1);
+ }
+ .wc-feature-text p {
+ font-size: var(--text-sm); color: var(--c-text-secondary);
+ line-height: 1.6; margin: 0;
+ }
+
+ /* Privacy Block */
+ .wc-privacy {
+ background: var(--c-primary);
+ padding: var(--space-8) var(--space-5);
+ text-align: center;
+ }
+ .wc-privacy-icon {
+ width: 56px; height: 56px; border-radius: 50%;
+ background: rgba(255,255,255,0.2);
+ display: flex; align-items: center; justify-content: center;
+ margin: 0 auto var(--space-4);
+ }
+ .wc-privacy-icon .ph-icon { width: 28px; height: 28px; color: #fff; }
+ .wc-privacy-title {
+ font-size: var(--text-xl); font-weight: var(--weight-bold);
+ color: #fff; margin: 0 0 var(--space-3);
+ }
+ .wc-privacy-sub {
+ font-size: var(--text-sm); color: rgba(255,255,255,0.85);
+ line-height: 1.7; margin: 0; max-width: 360px; margin: 0 auto;
+ }
+
+ /* Und noch mehr */
+ .wc-more {
+ padding: var(--space-6) var(--space-4);
+ background: var(--c-bg);
+ border-top: 1px solid var(--c-border-light);
+ }
+ .wc-more-label {
+ font-size: var(--text-xs); font-weight: var(--weight-semibold);
+ color: var(--c-text-secondary); text-transform: uppercase;
+ letter-spacing: 0.07em; margin: 0 0 var(--space-4); text-align: center;
+ }
+
+ /* Bottom CTA */
+ .wc-bottom-cta {
+ padding: var(--space-8) var(--space-5) var(--space-6);
+ display: flex; flex-direction: column; align-items: center;
+ gap: var(--space-3); background: var(--c-bg);
+ border-top: 1px solid var(--c-border-light);
+ }
+ .wc-bottom-hint {
+ font-size: var(--text-xs); color: var(--c-text-muted); margin: 0;
+ }
+ .wc-install-link {
+ background: none; border: none; cursor: pointer;
+ font-size: var(--text-xs); color: var(--c-text-secondary);
+ display: flex; align-items: center; gap: 4px;
+ padding: var(--space-2); margin-top: var(--space-1);
+ }
+ .wc-install-link .ph-icon { width: 12px; height: 12px; }
+
+ /* ── Logged-in Hero (kompakt) ──────────────────────────── */
.wc-hero {
background: linear-gradient(160deg, var(--c-primary-subtle) 0%, var(--c-bg) 70%);
text-align: center;
@@ -135,8 +438,7 @@ window.Page_welcome = (() => {
border-bottom: 1px solid var(--c-border-light);
}
.wc-hero-icon {
- width: 96px; height: 96px;
- border-radius: 22px;
+ width: 96px; height: 96px; border-radius: 22px;
box-shadow: 0 8px 28px rgba(0,0,0,0.15);
display: block; margin: 0 auto var(--space-4);
}
@@ -146,52 +448,43 @@ window.Page_welcome = (() => {
}
.wc-hero-sub {
font-size: var(--text-base); color: var(--c-text-secondary);
- margin: 0; line-height: 1.6; max-width: 420px; margin: 0 auto;
- }
- .wc-hero-cta {
- display: flex; gap: var(--space-3); justify-content: center;
- flex-wrap: wrap; margin-top: var(--space-5);
+ margin: 0 auto; line-height: 1.6; max-width: 420px;
}
- /* Section title */
+ /* ── Shared ────────────────────────────────────────────── */
.wc-section-title {
- font-size: var(--text-sm); font-weight: var(--weight-semibold);
+ font-size: var(--text-xs); font-weight: var(--weight-semibold);
color: var(--c-text-secondary); text-transform: uppercase;
- letter-spacing: 0.06em; margin: 0 0 var(--space-4);
+ letter-spacing: 0.07em; margin: 0 0 var(--space-4); text-align: center;
}
-
- /* Feature Grid */
.wc-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: var(--space-3);
- margin-bottom: var(--space-6);
+ margin-bottom: var(--space-4);
}
.wc-tile {
- display: flex; flex-direction: column;
- align-items: center; gap: var(--space-2);
- padding: var(--space-4) var(--space-2);
- background: var(--c-surface);
- border: 1px solid var(--c-border-light);
- border-radius: var(--radius-lg);
- cursor: pointer; transition: background var(--transition-fast), transform 0.1s;
+ display: flex; flex-direction: column; align-items: center;
+ gap: var(--space-2); padding: var(--space-4) var(--space-2);
+ background: var(--c-surface); border: 1px solid var(--c-border-light);
+ border-radius: var(--radius-lg); cursor: pointer;
+ transition: background var(--transition-fast), transform 0.1s;
}
.wc-tile:hover { background: var(--c-surface-2); }
.wc-tile:active { transform: scale(0.96); }
+ .wc-tile--static { cursor: default; }
+ .wc-tile--static:hover { background: var(--c-surface); }
+ .wc-tile--static:active { transform: none; }
.wc-tile-icon {
- width: 44px; height: 44px; border-radius: var(--radius-md);
+ width: 40px; height: 40px; border-radius: var(--radius-md);
background: var(--c-primary-subtle);
display: flex; align-items: center; justify-content: center;
}
- .wc-tile-icon .ph-icon {
- width: 22px; height: 22px; color: var(--c-primary);
- }
+ .wc-tile-icon .ph-icon { width: 20px; height: 20px; color: var(--c-primary); }
.wc-tile-label {
font-size: var(--text-xs); font-weight: var(--weight-semibold);
color: var(--c-text); text-align: center; line-height: 1.3;
}
-
- /* Install card */
.wc-install-card { margin-bottom: var(--space-5); }
.wc-install-header {
display: flex; align-items: center; gap: var(--space-2);
@@ -201,19 +494,23 @@ window.Page_welcome = (() => {
letter-spacing: 0.05em; border-bottom: 1px solid var(--c-border);
}
.wc-install-header .ph-icon { width: 14px; height: 14px; }
-
- /* Footer */
.wc-footer {
text-align: center; font-size: var(--text-xs);
- color: var(--c-text-muted); margin: 0;
+ color: var(--c-text-muted); padding: var(--space-4);
}
- /* Desktop: 8-spaltig */
+ @media (min-width: 640px) {
+ .wc-lhero-headline { font-size: 3.2rem; }
+ .wc-lhero-cta { flex-direction: row; justify-content: center; }
+ .wc-btn-hero { width: auto; }
+ .wc-grid { grid-template-columns: repeat(4, 1fr); }
+ }
@media (min-width: 1024px) {
+ .wc-lhero { padding: var(--space-8) var(--space-4) var(--space-10); }
+ .wc-feature { max-width: 680px; margin: 0 auto; }
.wc-grid { grid-template-columns: repeat(8, 1fr); }
}
- /* Pulse animation */
@keyframes wc-pulse {
0%,100% { transform: scale(1); box-shadow: none; }
50% { transform: scale(1.25); box-shadow: 0 0 0 6px var(--c-primary-subtle); }
@@ -231,10 +528,8 @@ window.Page_welcome = (() => {
const isIOS = /iPad|iPhone|iPod/.test(ua) && !window.MSStream;
const isSafari = /^((?!chrome|android).)*safari/i.test(ua);
const isAndroid = /android/i.test(ua);
- const isMobile = isIOS || isAndroid;
const hasPrompt = !!App.getInstallPrompt();
- // Android: Browser hat Install-Prompt bereit (Chrome, Edge, Samsung Internet neu)
if (hasPrompt) {
return `
@@ -246,7 +541,6 @@ window.Page_welcome = (() => {
`;
}
- // iOS Safari: Teilen-Menü
if (isIOS && isSafari) {
return `
@@ -262,7 +556,6 @@ window.Page_welcome = (() => {
`;
}
- // iOS, aber nicht Safari (Chrome, Firefox, etc.)
if (isIOS && !isSafari) {
return `
@@ -280,7 +573,6 @@ window.Page_welcome = (() => {
`;
}
- // Android ohne Prompt (Firefox, älterer Samsung Browser, etc.)
if (isAndroid) {
return `
@@ -298,7 +590,6 @@ window.Page_welcome = (() => {
`;
}
- // Desktop — beide Plattformen zeigen
return `
{
${_steps([
- ['arrow-square-in', 'Öffne banyaro.app in Chrome oder Edge'],
- ['monitor', 'Klicke auf das Installations-Symbol in der Adressleiste'],
- ['check', 'Bestätigen — fertig!'],
+ ['arrow-square-in', 'Öffne banyaro.app in Chrome oder Edge'],
+ ['monitor', 'Klicke auf das Installations-Symbol in der Adressleiste'],
+ ['check', 'Bestätigen — fertig!'],
])}
@@ -346,17 +637,30 @@ window.Page_welcome = (() => {
// EVENTS
// ----------------------------------------------------------
function _bindEvents() {
- _container.querySelector('#install-android-btn')?.addEventListener('click', async () => {
+ // Install-Prompt Buttons
+ const installBtn = async () => {
const prompt = App.getInstallPrompt();
if (!prompt) return;
prompt.prompt();
const { outcome } = await prompt.userChoice;
- if (outcome === 'accepted') {
- UI.toast.success('Ban Yaro wird installiert!');
- _render();
- }
+ if (outcome === 'accepted') { UI.toast.success('Ban Yaro wird installiert!'); _render(); }
+ };
+ _container.querySelector('#install-android-btn')?.addEventListener('click', installBtn);
+ _container.querySelector('#welcome-install-hero-btn')?.addEventListener('click', installBtn);
+ _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 });
});
+ // Link kopieren
_container.querySelector('#install-copy-btn')?.addEventListener('click', async () => {
await navigator.clipboard.writeText('https://banyaro.app');
UI.toast.success('Link kopiert!');
@@ -378,9 +682,7 @@ window.Page_welcome = (() => {
_container.querySelector('#inst-tab-android').style.cssText = 'flex:1';
});
- _container.querySelector('#welcome-register-btn')?.addEventListener('click', () => App.navigate('settings'));
- _container.querySelector('#welcome-login-btn')?.addEventListener('click', () => App.navigate('settings'));
-
+ // Feature-Tiles (nur eingeloggte Ansicht)
_container.querySelectorAll('[data-nav]').forEach(btn => {
btn.addEventListener('click', () => App.navigate(btn.dataset.nav));
});
@@ -392,9 +694,8 @@ window.Page_welcome = (() => {
setTimeout(() => {
btn.classList.add('wc-pulsing');
btn.addEventListener('animationend', () => btn.classList.remove('wc-pulsing'), { once: true });
- }, 800);
+ }, 1200);
}
return { init, refresh, onDogChange };
-
})();
diff --git a/backend/static/sw.js b/backend/static/sw.js
index 948a202..8f003c6 100644
--- a/backend/static/sw.js
+++ b/backend/static/sw.js
@@ -3,7 +3,7 @@
Offline-Cache + Push Notifications + Tile-Cache
============================================================ */
-const CACHE_VERSION = 'by-v443';
+const CACHE_VERSION = 'by-v444';
const CACHE_STATIC = `${CACHE_VERSION}-static`;
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten