Feature: Geburtstags-Banner in HUND-Welt — heute & morgen, mit Alter und Animation (SW by-v776)

This commit is contained in:
rene 2026-05-08 13:16:51 +02:00
parent 857c83bd65
commit 662190e308
5 changed files with 35 additions and 4 deletions

View file

@ -578,7 +578,7 @@
<script src="/js/api.js?v=94"></script>
<script src="/js/ui.js?v=94"></script>
<script src="/js/app.js?v=94"></script>
<script src="/js/worlds.js?v=775"></script>
<script src="/js/worlds.js?v=776"></script>
<!-- Feature-Seiten werden lazy geladen -->

View file

@ -3,7 +3,7 @@
Router, State-Management, Navigation, Initialisierung.
============================================================ */
const APP_VER = '775'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VER = '776'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VERSION = '1.5.0'; // ← semantische Version, wird bei make release gesetzt
const IS_STAGING = location.hostname === 'staging.banyaro.app';
// Cache-Bust-Parameter nach Update-Reload sofort entfernen

View file

@ -1236,6 +1236,23 @@ window.Worlds = (() => {
if (_dogIdx >= _dogs.length) _dogIdx = 0;
const dog = _dogs[_dogIdx];
// Geburtstag prüfen (heute oder morgen → Feature sichtbar)
function _birthdayState(geb) {
if (!geb) return null;
const today = new Date();
const tomorrow = new Date(today); tomorrow.setDate(today.getDate() + 1);
const mm = String(today.getMonth() + 1).padStart(2, '0');
const dd = String(today.getDate()).padStart(2, '0');
const mt = String(tomorrow.getMonth() + 1).padStart(2, '0');
const dt = String(tomorrow.getDate()).padStart(2, '0');
const mmdd = geb.slice(5); // 'MM-DD'
if (mmdd === `${mm}-${dd}`) return 'today';
if (mmdd === `${mt}-${dt}`) return 'tomorrow';
return null;
}
const bday = _birthdayState(dog.geburtstag);
const bdayYear = dog.geburtstag ? new Date().getFullYear() - parseInt(dog.geburtstag.slice(0, 4)) : null;
const [streakRes, diaryRes] = await Promise.allSettled([
_cachedGet(`streak_${dog.id}`, `/streak/${dog.id}`),
_cachedGet(`diary_${dog.id}`, `/dogs/${dog.id}/diary?limit=1`),
@ -1294,6 +1311,20 @@ window.Worlds = (() => {
<div style="justify-self:end;display:flex;align-items:center">${otherAvatarsHtml}</div>
</div>
</div>
${bday ? `
<div style="background:linear-gradient(135deg,rgba(196,132,58,0.25),rgba(232,168,87,0.15));
border:1px solid rgba(196,132,58,0.5);border-radius:16px;
padding:14px 16px;text-align:center;animation:wc-pulse 2s ease-in-out 3">
<div style="font-size:2rem;margin-bottom:4px">${bday === 'today' ? '🎂' : '🎁'}</div>
<div style="font-weight:700;font-size:var(--text-sm);color:rgba(255,255,255,0.95)">
${bday === 'today'
? `Alles Gute zum ${bdayYear}. Geburtstag, ${_esc(dog.name)}! 🎉`
: `Morgen hat ${_esc(dog.name)} Geburtstag! 🥳`}
</div>
${bdayYear ? `<div style="font-size:10px;color:rgba(255,255,255,0.55);margin-top:3px">
${bday === 'today' ? `${bdayYear} Jahr${bdayYear !== 1 ? 'e' : ''} gemeinsam` : `Wird ${bdayYear} Jahr${bdayYear !== 1 ? 'e' : ''} alt`}
</div>` : ''}
</div>` : ''}
</div>
<div class="world-bottom">
${!_hasBgPhoto ? `

View file

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