From cad34711b7a345e26c5867d28d4e43dbd2635481 Mon Sep 17 00:00:00 2001 From: rene Date: Fri, 29 May 2026 09:31:32 +0200 Subject: [PATCH] =?UTF-8?q?Welten:=20adaptive=20Abdunklung=20getrennt=20f?= =?UTF-8?q?=C3=BCr=20oben=20(Banner+JETZT-Chips)=20und=20unten=20(Feature-?= =?UTF-8?q?Chips)=20=E2=80=94=20obere/untere=20Bildh=C3=A4lfte=20separat?= =?UTF-8?q?=20gemessen,=20SW=20v1131?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- VERSION | 2 +- backend/static/css/components.css | 14 ++++---- backend/static/index.html | 24 +++++++------- backend/static/js/app.js | 2 +- backend/static/js/worlds.js | 54 +++++++++++++++++++------------ backend/static/landing.html | 2 +- backend/static/sw.js | 2 +- 7 files changed, 57 insertions(+), 43 deletions(-) diff --git a/VERSION b/VERSION index 0b078c5..2d0ce9f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1130 \ No newline at end of file +1131 \ No newline at end of file diff --git a/backend/static/css/components.css b/backend/static/css/components.css index 1e64f97..ebeb6d2 100644 --- a/backend/static/css/components.css +++ b/backend/static/css/components.css @@ -8179,7 +8179,7 @@ svg.empty-state-icon { /* Frosted-Glass Info-Card (oben in jeder Welt) */ .world-info-card { - background: rgba(0, 0, 0, var(--wbg-dim, 0.38)); + background: rgba(0, 0, 0, var(--wbg-dim-top, 0.38)); backdrop-filter: blur(var(--wbg-blur, 18px)) saturate(1.6); -webkit-backdrop-filter: blur(var(--wbg-blur, 18px)) saturate(1.6); border: 1px solid var(--wborder, rgba(99, 130, 220, 0.55)); @@ -8202,7 +8202,7 @@ svg.empty-state-icon { /* Frosted-Glass Reminder-Card (für Streak, Alerts) */ .world-reminder { - background: rgba(0, 0, 0, var(--wbg-dim, 0.32)); + background: rgba(0, 0, 0, var(--wbg-dim-top, 0.32)); backdrop-filter: blur(var(--wbg-blur, 12px)); -webkit-backdrop-filter: blur(var(--wbg-blur, 12px)); border: 1px solid var(--wborder, rgba(99, 130, 220, 0.55)); @@ -8242,7 +8242,7 @@ svg.empty-state-icon { /* Einzelner Chip: Frosted Glass */ .world-chip { - background: rgba(0, 0, 0, var(--wbg-dim, 0.35)); + background: rgba(0, 0, 0, var(--wbg-dim-bottom, 0.35)); backdrop-filter: blur(var(--wbg-blur, 12px)); -webkit-backdrop-filter: blur(var(--wbg-blur, 12px)); border-radius: 16px; @@ -8278,8 +8278,10 @@ svg.empty-state-icon { -webkit-box-orient: vertical; } -/* Chip/Banner-Abdunklung + Blur: einheitlich auf allen drei Welten (reduziert) */ -.world-panel { --wbg-dim: 0.14; --wbg-blur: 3px; } +/* Chip/Banner-Abdunklung + Blur. --wbg-dim-top/-bottom werden in worlds.js + adaptiv je nach Bildhelligkeit der oberen/unteren Bildhälfte gesetzt; + hier nur die Fallback-Defaults (falls JS nicht misst). */ +.world-panel { --wbg-dim-top: 0.14; --wbg-dim-bottom: 0.14; --wbg-blur: 3px; } /* Rahmenfarbe je Welt (Alpha einheitlich 0.55) — gilt für Chips + Banner oben Gedämpfte Erdtöne: JETZT orange, HUND naturgrün, WELT blaugrau */ @@ -8306,7 +8308,7 @@ svg.empty-state-icon { .wj-chip { flex: 1; min-width: 0; - background: rgba(0, 0, 0, var(--wbg-dim, 0.32)); + background: rgba(0, 0, 0, var(--wbg-dim-top, 0.32)); backdrop-filter: blur(var(--wbg-blur, 12px)); -webkit-backdrop-filter: blur(var(--wbg-blur, 12px)); border: 1px solid var(--wborder, rgba(99, 130, 220, 0.55)); diff --git a/backend/static/index.html b/backend/static/index.html index fe40e45..2cbbd06 100644 --- a/backend/static/index.html +++ b/backend/static/index.html @@ -86,14 +86,14 @@ Ban Yaro - + - - - - - + + + + + @@ -617,11 +617,11 @@ - - - - - + + + + + @@ -631,7 +631,7 @@ - + diff --git a/backend/static/js/app.js b/backend/static/js/app.js index 51efb28..bbc25c6 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 = '1130'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen +const APP_VER = '1131'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen const APP_VERSION = '1.6.0'; // ← semantische Version, wird bei make release gesetzt window.APP_VER = APP_VER; // global verfügbar für andere Module (z.B. offline-indicator) window.APP_VERSION = APP_VERSION; diff --git a/backend/static/js/worlds.js b/backend/static/js/worlds.js index 02b21cf..c6e05eb 100644 --- a/backend/static/js/worlds.js +++ b/backend/static/js/worlds.js @@ -981,7 +981,7 @@ window.Worlds = (() => { } let _bgUrl = null; // aktuell gesetztes Hintergrundbild - let _bgBrightness = null; // gemessene Roh-Helligkeit des Bildes (0–255) für adaptive Abdunklung + let _bgBrightness = null; // { top, bottom } Roh-Helligkeit (0–255) je Bildhälfte für adaptive Abdunklung function _isDarkMode() { const t = document.documentElement.getAttribute('data-theme'); @@ -1025,37 +1025,49 @@ window.Worlds = (() => { new MutationObserver(() => { _applyBgOrientation(); _applyAdaptiveDim(); }) .observe(document.documentElement, { attributeFilter: ['data-theme'] }); - // Durchschnittliche Helligkeit (0–255) eines geladenen Bildes via Mini-Canvas. + // Helligkeit (0–255) der oberen und unteren Bildhälfte via Mini-Canvas. + // Oben = Begrüßungs-Banner + JETZT-Chip-Reihe, unten = Feature-Chips. // Gibt null zurück bei CORS-Tainting oder Fehler (→ Fallback-Abdunklung). - function _measureBrightness(img) { + function _measureBrightnessRegions(img) { try { const c = document.createElement('canvas'); const w = c.width = 32, h = c.height = 32; const ctx = c.getContext('2d', { willReadFrequently: true }); ctx.drawImage(img, 0, 0, w, h); const data = ctx.getImageData(0, 0, w, h).data; - let sum = 0; - for (let i = 0; i < data.length; i += 4) { - sum += 0.299 * data[i] + 0.587 * data[i + 1] + 0.114 * data[i + 2]; + const half = h / 2; + let sumTop = 0, sumBot = 0, nTop = 0, nBot = 0; + for (let y = 0; y < h; y++) { + for (let x = 0; x < w; x++) { + const i = (y * w + x) * 4; + const lum = 0.299 * data[i] + 0.587 * data[i + 1] + 0.114 * data[i + 2]; + if (y < half) { sumTop += lum; nTop++; } else { sumBot += lum; nBot++; } + } } - return sum / (data.length / 4); + return { top: sumTop / nTop, bottom: sumBot / nBot }; } catch { return null; } } - // Setzt --wbg-dim adaptiv: helles Bild → mehr Abdunklung (Lesbarkeit), - // dunkles Bild → wenig. Im Dark Mode liegt zusätzlich ein 0.45-Overlay - // über dem Bild, daher wirkt es dort dunkler (effektive Helligkeit ↓). + // Helligkeit (0–255) → Abdunklungs-Alpha. Im Dark Mode liegt zusätzlich + // ein 0.45-Overlay über dem Bild, daher wirkt es dort dunkler. + function _dimForBrightness(b) { + if (_isDarkMode()) b *= 0.55; + if (b <= 90) return 0.14; + if (b >= 190) return 0.48; + return 0.14 + (b - 90) / 100 * (0.48 - 0.14); + } + + // Setzt --wbg-dim-top/-bottom adaptiv pro Bildbereich: heller Bereich → + // mehr Abdunklung (Lesbarkeit), dunkler → wenig. function _applyAdaptiveDim() { - let b = _bgBrightness; - if (b == null) b = 110; // neutraler Default wenn Messung fehlschlug - if (_isDarkMode()) b *= 0.55; // 0.45-Bild-Overlay reduziert sichtbare Helligkeit - let dim; - if (b <= 90) dim = 0.14; - else if (b >= 190) dim = 0.48; - else dim = 0.14 + (b - 90) / 100 * (0.48 - 0.14); - const val = dim.toFixed(2); + const r = _bgBrightness || { top: 110, bottom: 110 }; + const dimTop = _dimForBrightness(r.top).toFixed(2); + const dimBot = _dimForBrightness(r.bottom).toFixed(2); ['wp-jetzt', 'wp-hund', 'wp-welt'].forEach(id => { - document.getElementById(id)?.style.setProperty('--wbg-dim', val); + const el = document.getElementById(id); + if (!el) return; + el.style.setProperty('--wbg-dim-top', dimTop); + el.style.setProperty('--wbg-dim-bottom', dimBot); }); } @@ -1068,7 +1080,7 @@ window.Worlds = (() => { toLoad.onload = () => { _hasBgPhoto = true; _bgUrl = url; - _bgBrightness = _measureBrightness(toLoad); + _bgBrightness = _measureBrightnessRegions(toLoad); _applyAdaptiveDim(); _applyBgOrientation(); const hint = document.getElementById('wh-photo-hint'); @@ -1091,7 +1103,7 @@ window.Worlds = (() => { } else { _hasBgPhoto = false; _bgUrl = null; - _bgBrightness = 20; // dunkler Fallback-Gradient → minimale Abdunklung + _bgBrightness = { top: 20, bottom: 20 }; // dunkler Fallback-Gradient → minimale Abdunklung _applyAdaptiveDim(); track.style.backgroundImage = ''; ov.style.backgroundImage = 'linear-gradient(160deg,#1a1f35 0%,#16213e 33%,#1a2535 67%,#0f1921 100%)'; diff --git a/backend/static/landing.html b/backend/static/landing.html index dbcbae3..a4d6f80 100644 --- a/backend/static/landing.html +++ b/backend/static/landing.html @@ -4,7 +4,7 @@ - + Ban Yaro — Die Hunde-App für Deutschland, Österreich & Schweiz diff --git a/backend/static/sw.js b/backend/static/sw.js index fefbf33..ac211d5 100644 --- a/backend/static/sw.js +++ b/backend/static/sw.js @@ -4,7 +4,7 @@ ============================================================ */ // ← EINZIGE Stelle für die Version — STATIC_ASSETS und CACHE_VERSION leiten sich ab -const VER = '1130'; +const VER = '1131'; const CACHE_VERSION = `by-v${VER}`; const CACHE_STATIC = `${CACHE_VERSION}-static`; const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten