Feature: HUND-Geburtstag-Hint für Nicht-aktiven Hund
Wenn ein anderer Hund (nicht der angezeigte) Geburtstag hat: - Cake-Icon (Phosphor) animiert bounce in der Info-Karte unten - "[Name] hat heute/morgen Geburtstag!" + Pfeil-Button - Klick → wechselt direkt zum Geburtstagshund + zeigt Birthday-Banner Kein Tab-Indicator (nur HUND-Welt). SW by-v1027, APP_VER 1027
This commit is contained in:
parent
d8b75fbcab
commit
1328e2c4e3
4 changed files with 55 additions and 3 deletions
|
|
@ -410,7 +410,7 @@ async def serve_media(path: str, request: _Request):
|
||||||
raise _HE(404, "Nicht gefunden.")
|
raise _HE(404, "Nicht gefunden.")
|
||||||
return _media_response(filepath)
|
return _media_response(filepath)
|
||||||
|
|
||||||
APP_VER = "1026" # muss mit APP_VER in app.js übereinstimmen
|
APP_VER = "1027" # muss mit APP_VER in app.js übereinstimmen
|
||||||
|
|
||||||
@app.get("/.well-known/assetlinks.json")
|
@app.get("/.well-known/assetlinks.json")
|
||||||
async def assetlinks():
|
async def assetlinks():
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
Router, State-Management, Navigation, Initialisierung.
|
Router, State-Management, Navigation, Initialisierung.
|
||||||
============================================================ */
|
============================================================ */
|
||||||
|
|
||||||
const APP_VER = '1026'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
const APP_VER = '1027'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||||
const APP_VERSION = '1.6.0'; // ← semantische Version, wird bei make release gesetzt
|
const APP_VERSION = '1.6.0'; // ← semantische Version, wird bei make release gesetzt
|
||||||
const IS_STAGING = location.hostname === 'staging.banyaro.app';
|
const IS_STAGING = location.hostname === 'staging.banyaro.app';
|
||||||
// Cache-Bust-Parameter nach Update-Reload sofort entfernen
|
// Cache-Bust-Parameter nach Update-Reload sofort entfernen
|
||||||
|
|
|
||||||
|
|
@ -1360,6 +1360,9 @@ window.Worlds = (() => {
|
||||||
const bday = bdayDog ? _birthdayState(bdayDog.geburtstag) : null;
|
const bday = bdayDog ? _birthdayState(bdayDog.geburtstag) : null;
|
||||||
const bdayYear = bdayDog?.geburtstag ? new Date().getFullYear() - parseInt(bdayDog.geburtstag.slice(0, 4)) : null;
|
const bdayYear = bdayDog?.geburtstag ? new Date().getFullYear() - parseInt(bdayDog.geburtstag.slice(0, 4)) : null;
|
||||||
|
|
||||||
|
// Merken ob ein anderer Hund Geburtstag hat (für Info-Karte unten)
|
||||||
|
const otherBdayDog = (bdayDog && bdayDog.id !== dog.id) ? bdayDog : null;
|
||||||
|
|
||||||
const [streakRes, diaryRes] = await Promise.allSettled([
|
const [streakRes, diaryRes] = await Promise.allSettled([
|
||||||
_cachedGet(`streak_${dog.id}`, `/streak/${dog.id}`),
|
_cachedGet(`streak_${dog.id}`, `/streak/${dog.id}`),
|
||||||
_cachedGet(`diary_${dog.id}`, `/dogs/${dog.id}/diary?limit=1`),
|
_cachedGet(`diary_${dog.id}`, `/dogs/${dog.id}/diary?limit=1`),
|
||||||
|
|
@ -1417,6 +1420,22 @@ window.Worlds = (() => {
|
||||||
</div>
|
</div>
|
||||||
<div style="justify-self:end;display:flex;align-items:center">${otherAvatarsHtml}</div>
|
<div style="justify-self:end;display:flex;align-items:center">${otherAvatarsHtml}</div>
|
||||||
</div>
|
</div>
|
||||||
|
${otherBdayDog ? `
|
||||||
|
<div style="margin-top:8px;padding-top:8px;border-top:1px solid rgba(255,255,255,0.12);
|
||||||
|
display:flex;align-items:center;gap:8px;cursor:pointer"
|
||||||
|
id="wh-other-bday-hint">
|
||||||
|
<span style="animation:by-bday-bounce 1.2s ease-in-out infinite;display:inline-flex">
|
||||||
|
<svg class="ph-icon" style="width:1.2rem;height:1.2rem;color:#f59e0b" aria-hidden="true">
|
||||||
|
<use href="/icons/phosphor.svg#cake"></use>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span style="font-size:var(--text-xs);color:rgba(255,255,255,0.75);font-weight:600">
|
||||||
|
${_esc(otherBdayDog.name)} hat ${_birthdayState(otherBdayDog.geburtstag) === 'today' ? 'heute' : 'morgen'} Geburtstag!
|
||||||
|
</span>
|
||||||
|
<svg class="ph-icon" style="width:.9rem;height:.9rem;color:rgba(196,132,58,0.8);margin-left:auto" aria-hidden="true">
|
||||||
|
<use href="/icons/phosphor.svg#arrow-circle-right"></use>
|
||||||
|
</svg>
|
||||||
|
</div>` : ''}
|
||||||
</div>
|
</div>
|
||||||
${bday ? `
|
${bday ? `
|
||||||
<style>
|
<style>
|
||||||
|
|
@ -1523,6 +1542,19 @@ window.Worlds = (() => {
|
||||||
if (!isNaN(idx) && idx !== _dogIdx) { _dogIdx = idx; _renderHund(); }
|
if (!isNaN(idx) && idx !== _dogIdx) { _dogIdx = idx; _renderHund(); }
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// Geburtstag-Hinweis → zum Geburtstagshund wechseln
|
||||||
|
if (otherBdayDog) {
|
||||||
|
if (!document.getElementById('by-bday-anim-style')) {
|
||||||
|
const s = document.createElement('style');
|
||||||
|
s.id = 'by-bday-anim-style';
|
||||||
|
s.textContent = '@keyframes by-bday-bounce{0%,100%{transform:translateY(0) scale(1)}50%{transform:translateY(-5px) scale(1.3)}}';
|
||||||
|
document.head.appendChild(s);
|
||||||
|
}
|
||||||
|
el.querySelector('#wh-other-bday-hint')?.addEventListener('click', () => {
|
||||||
|
const idx = _dogs.indexOf(otherBdayDog);
|
||||||
|
if (idx >= 0) { _dogIdx = idx; _renderHund(); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Geburtstags-Banner → KI
|
// Geburtstags-Banner → KI
|
||||||
el.querySelector('#wh-bday-banner')?.addEventListener('click', () => _openBdayKI(dog, bday));
|
el.querySelector('#wh-bday-banner')?.addEventListener('click', () => _openBdayKI(dog, bday));
|
||||||
|
|
@ -1717,6 +1749,26 @@ window.Worlds = (() => {
|
||||||
`).join('');
|
`).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _updateBdayTabIndicator(bdayDog) {
|
||||||
|
if (bdayDog && !document.getElementById('by-bday-tab-style')) {
|
||||||
|
const s = document.createElement('style');
|
||||||
|
s.id = 'by-bday-tab-style';
|
||||||
|
s.textContent = '@keyframes by-bday-bounce{0%,100%{transform:translateY(0) scale(1)}50%{transform:translateY(-5px) scale(1.25)}}' +
|
||||||
|
'.wlabel-bday-ic{display:inline-block;animation:by-bday-bounce 1.2s ease-in-out infinite;margin-left:3px;font-size:.85em}';
|
||||||
|
document.head.appendChild(s);
|
||||||
|
}
|
||||||
|
const hundTab = document.querySelectorAll('#world-labels .wlabel')[1];
|
||||||
|
if (!hundTab) return;
|
||||||
|
hundTab.querySelector('.wlabel-bday-ic')?.remove();
|
||||||
|
if (bdayDog) {
|
||||||
|
const ic = document.createElement('span');
|
||||||
|
ic.className = 'wlabel-bday-ic';
|
||||||
|
ic.textContent = '🎂';
|
||||||
|
ic.title = `${bdayDog.name} hat ${_birthdayState(bdayDog.geburtstag) === 'today' ? 'heute' : 'morgen'} Geburtstag!`;
|
||||||
|
hundTab.appendChild(ic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function _fmtDate(d) {
|
function _fmtDate(d) {
|
||||||
if (!d) return '';
|
if (!d) return '';
|
||||||
try { return new Date(d).toLocaleDateString('de-DE', { day:'numeric', month:'short' }); }
|
try { return new Date(d).toLocaleDateString('de-DE', { day:'numeric', month:'short' }); }
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
Offline-Cache + Push Notifications + Tile-Cache
|
Offline-Cache + Push Notifications + Tile-Cache
|
||||||
============================================================ */
|
============================================================ */
|
||||||
|
|
||||||
const CACHE_VERSION = 'by-v1026';
|
const CACHE_VERSION = 'by-v1027';
|
||||||
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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue