diff --git a/backend/static/js/app.js b/backend/static/js/app.js index 702f5ac..d7180a4 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 = '424'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen +const APP_VER = '422'; // ← 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 36d74f7..d857361 100644 --- a/backend/static/js/pages/welcome.js +++ b/backend/static/js/pages/welcome.js @@ -4,25 +4,9 @@ window.Page_welcome = (() => { - let _container = null; - let _appState = null; + let _container = null; + let _appState = null; let _showInstall = false; - let _heroInterval = null; - - // ---------------------------------------------------------- - // HERO-SLIDES — rotieren alle 4 Sekunden - // ---------------------------------------------------------- - const HERO_SLIDES = [ - { headline: 'Jeder Moment zählt.', sub: 'Fotos, Notizen, Stimmungen — das Tagebuch deines Hundes.' }, - { headline: 'Deine Gegend. Sein Revier.', sub: 'Hundeparks, Gassi-Spots und mehr — alles auf der Karte.' }, - { headline: 'Kein Termin verpasst.', sub: 'Impfungen, Gewicht, Tierarzt — mit KI, individuell auf deinen Hund angepasst.' }, - { headline: 'Wir achten auf deinen Hund.', sub: 'Gefahren in deiner Nähe — damit ihr gezielt aus dem Weg gehen könnt.' }, - { headline: 'Wie eine App. Nur ohne App Store.', sub: 'Einmal auf „Zum Homescreen" — fertig. Kein Store, keine Updates, kein Stress.' }, - { headline: 'Lieblingsrouten für immer.', sub: 'Speichere eure besten Strecken — und entdecke neue in der Nähe.' }, - { headline: 'Gassi ist kein Solosport.', sub: 'Triff andere Hundebesitzer — spontan, in deiner Umgebung.' }, - { headline: '100+ Übungen. Ein Trainer, der deinen Hund kennt.', sub: 'Schritt für Schritt — mit KI, die sich an euch anpasst.' }, - { headline: 'Frag nach. Du bist nicht allein.', sub: 'Erfahrungen, Tipps, Hilfe — von Hundebesitzern für Hundebesitzer.' }, - ]; async function init(container, appState, params = {}) { _container = container; @@ -65,209 +49,38 @@ window.Page_welcome = (() => { // RENDER // ---------------------------------------------------------- function _render() { - if (_heroInterval) { clearInterval(_heroInterval); _heroInterval = null; } - const isInstalled = window.matchMedia('(display-mode: standalone)').matches || 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 = ` -
- - -
- Ban Yaro -

${HERO_SLIDES[0].headline}

-

${HERO_SLIDES[0].sub}

-
- ${HERO_SLIDES.map((_, i) => ``).join('')} -
- -
- ${hasPrompt ? ` - - ` : ` - - `} - -
- -
- - - 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. -

-
- - -
- -
- ${FEATURES.map(f => ` -
-
- -
- ${f.label} -
- `).join('')} -
-
- - -
- ${hasPrompt ? ` - - ` : ` - - `} -

Kein App Store · Direkt auf den Home-Bildschirm

- - ${!isInstalled ? ` - - ` : ''} -
- - - ${_showInstall ? ` -
-
-
- - App installieren -
-
${_installHTML()}
-
-
- ` : ''} - - -
- `; - } - - // ---------------------------------------------------------- - // EINGELOGGTE ANSICHT — kompakter Überblick - // ---------------------------------------------------------- - function _renderLoggedIn(isInstalled) { _container.innerHTML = `
+
Ban Yaro

Ban Yaro

- Schön, dass du wieder da bist${_appState?.user?.name ? ', ' + UI.escape(_appState.user.name) + '' : ''}! + ${user + ? `Schön, dass du wieder da bist${user.name ? ', ' + UI.escape(user.name) + '' : ''}! 🐾` + : 'Die Community für Hundebesitzer — Tagebuch, Gesundheit, Karte und mehr.'}

+ ${!user ? ` +
+ + +
+ ` : ''}
+
+

Was Ban Yaro kann

+
${FEATURES.map(f => `
+ ${(!isInstalled || _showInstall) ? `
App installieren
-
${_installHTML()}
+
+ ${_installHTML()} +
` : ''} - + + +
`; + + _injectStyles(); + _bindEvents(); + _pulseMenuBtn(); } // ---------------------------------------------------------- - // STYLES + // STYLES (einmalig injizieren) // ---------------------------------------------------------- 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; - transition: opacity 0.4s ease; - } - .wc-lhero-sub { - font-size: var(--text-base); color: rgba(255,255,255,0.88); - line-height: 1.6; margin: 0 0 var(--space-3); - position: relative; - transition: opacity 0.4s ease; - } - .wc-hero-dots { - display: flex; justify-content: center; gap: 6px; - margin-bottom: var(--space-6); position: relative; - } - .wc-hero-dot { - width: 6px; height: 6px; border-radius: 50%; - background: rgba(255,255,255,0.35); - transition: background 0.3s, transform 0.3s; - } - .wc-hero-dot--active { - background: rgba(255,255,255,0.9); - transform: scale(1.3); - } - .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-4) var(--space-4); - background: var(--c-bg); - border-top: 1px solid var(--c-border-light); - } - .wc-more-toggle { - display: flex; align-items: center; justify-content: center; - gap: var(--space-2); width: 100%; - background: none; border: none; cursor: pointer; - font-size: var(--text-xs); font-weight: var(--weight-semibold); - color: var(--c-text-secondary); text-transform: uppercase; - letter-spacing: 0.07em; padding: var(--space-2) 0; - margin-bottom: var(--space-3); - } - .wc-more-chevron { - width: 14px; height: 14px; - transition: transform 0.25s ease; - } - .wc-grid--collapsed { display: none; } - - /* 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; @@ -483,7 +135,8 @@ 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); } @@ -493,43 +146,52 @@ window.Page_welcome = (() => { } .wc-hero-sub { font-size: var(--text-base); color: var(--c-text-secondary); - margin: 0 auto; line-height: 1.6; max-width: 420px; + 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); } - /* ── Shared ────────────────────────────────────────────── */ + /* Section title */ .wc-section-title { - font-size: var(--text-xs); font-weight: var(--weight-semibold); + font-size: var(--text-sm); 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; + letter-spacing: 0.06em; margin: 0 0 var(--space-4); } + + /* Feature Grid */ .wc-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-3); - margin-bottom: var(--space-4); + margin-bottom: var(--space-6); } .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: 40px; height: 40px; border-radius: var(--radius-md); + width: 44px; height: 44px; border-radius: var(--radius-md); background: var(--c-primary-subtle); display: flex; align-items: center; justify-content: center; } - .wc-tile-icon .ph-icon { width: 20px; height: 20px; color: var(--c-primary); } + .wc-tile-icon .ph-icon { + width: 22px; height: 22px; 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); @@ -539,23 +201,19 @@ 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); padding: var(--space-4); + color: var(--c-text-muted); margin: 0; } - @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); } - } + /* Desktop: 8-spaltig */ @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); } @@ -565,31 +223,6 @@ window.Page_welcome = (() => { document.head.appendChild(s); } - // ---------------------------------------------------------- - // HERO-ROTATION - // ---------------------------------------------------------- - function _startHeroRotation() { - let idx = 0; - const headline = _container.querySelector('#wc-hero-headline'); - const sub = _container.querySelector('#wc-hero-sub'); - const dots = _container.querySelectorAll('.wc-hero-dot'); - if (!headline || !sub) return; - - _heroInterval = setInterval(() => { - headline.style.opacity = '0'; - sub.style.opacity = '0'; - - setTimeout(() => { - idx = (idx + 1) % HERO_SLIDES.length; - headline.textContent = HERO_SLIDES[idx].headline; - sub.textContent = HERO_SLIDES[idx].sub; - headline.style.opacity = '1'; - sub.style.opacity = '1'; - dots.forEach((d, i) => d.classList.toggle('wc-hero-dot--active', i === idx)); - }, 400); - }, 4000); - } - // ---------------------------------------------------------- // INSTALLATIONS-ANLEITUNG // ---------------------------------------------------------- @@ -598,8 +231,10 @@ 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 `

@@ -611,6 +246,7 @@ window.Page_welcome = (() => { `; } + // iOS Safari: Teilen-Menü if (isIOS && isSafari) { return `

@@ -626,6 +262,7 @@ window.Page_welcome = (() => {

`; } + // iOS, aber nicht Safari (Chrome, Firefox, etc.) if (isIOS && !isSafari) { return `

@@ -643,6 +280,7 @@ window.Page_welcome = (() => { `; } + // Android ohne Prompt (Firefox, älterer Samsung Browser, etc.) if (isAndroid) { return `

@@ -660,6 +298,7 @@ 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!'], ])}