Feature: Schnell-Gassi-Log + Hunde-Visitenkarte mit QR-Code (SW by-v698)
- Worlds-FAB: neuer 'Schnell-Gassi' Button im Gassi-Chip — öffnet schlankes Bottom-Sheet mit Dauer-Toggle (15/30/45/60 min), auto-Wetter aus Cache, postet direkt als Tagebucheintrag typ='gassi' ohne GPS-Tracking - dog-profile.js: 'Visitenkarte teilen' Button öffnet Modal mit gestalteter Karte (Hundefoto, Name, Rasse/Alter, Wohnort) + QR-Code via qrserver.com, Link-kopieren und native Web-Share-API
This commit is contained in:
parent
6e4bf25581
commit
a4e97348ed
2 changed files with 356 additions and 62 deletions
|
|
@ -165,13 +165,24 @@ window.Worlds = (() => {
|
|||
document.querySelectorAll('.wlabel').forEach((l, i) => l.classList.toggle('active', i === _cur));
|
||||
}
|
||||
|
||||
function _fabOptions() {
|
||||
const worldNames = ['jetzt', 'hund', 'welt'];
|
||||
const chips = _chipsForWorld(worldNames[_cur]);
|
||||
const opts = [];
|
||||
for (const chip of chips) {
|
||||
if (chip.fab) for (const o of chip.fab) { if (opts.length < 6) opts.push(o); }
|
||||
}
|
||||
return opts;
|
||||
}
|
||||
|
||||
function _updateFab() {
|
||||
const fab = document.getElementById('worlds-fab');
|
||||
if (!fab) return;
|
||||
const icons = ['note-pencil', 'paw-print', 'warning'];
|
||||
const titles = ['Schnelleintrag', 'Hund-Eintrag', 'Alarm melden'];
|
||||
fab.querySelector('use')?.setAttribute('href', `/icons/phosphor.svg#${icons[_cur]}`);
|
||||
fab.title = titles[_cur];
|
||||
const opts = _fabOptions();
|
||||
if (!opts.length) { fab.style.display = 'none'; return; }
|
||||
fab.style.display = '';
|
||||
fab.querySelector('use')?.setAttribute('href', `/icons/phosphor.svg#paw-print`);
|
||||
fab.title = 'Schnellaktion';
|
||||
}
|
||||
|
||||
function _setupButtons() {
|
||||
|
|
@ -195,21 +206,13 @@ window.Worlds = (() => {
|
|||
}
|
||||
|
||||
function _openFab() {
|
||||
const isWelt = _cur === 2;
|
||||
const dogName = _state?.user ? null : null; // falls mehrere Hunde: erweiterbar
|
||||
const options = _fabOptions();
|
||||
if (!options.length) return;
|
||||
|
||||
const options = isWelt ? [
|
||||
{ icon:'skull', color:'#EF4444', label:'Giftköder melden', sub:'Warnung für andere Hundebesitzer', page:'poison' },
|
||||
{ icon:'dog', color:'#3B82F6', label:'Verlorenen Hund melden', sub:'Hilf beim Wiederfinden', page:'lost' },
|
||||
{ icon:'map-pin', color:'#10B981', label:'Ort vorschlagen', sub:'Neuen POI auf der Karte', page:'map' },
|
||||
] : [
|
||||
{ icon:'book-open', color:'#8B5CF6', label:'Tagebucheintrag', sub:'Erlebnis, Foto oder Notiz', page:'diary', action:'openNew' },
|
||||
{ icon:'target', color:'#F59E0B', label:'Training aufzeichnen',sub:'Übung absolviert', page:'uebungen' },
|
||||
{ icon:'heartbeat', color:'#EF4444', label:'Tierarztbesuch', sub:'Befund oder Impfung eintragen', page:'health' },
|
||||
{ icon:'wave-sine', color:'#06B6D4', label:'Gewicht messen', sub:'Aktuelles Gewicht eintragen', page:'health' },
|
||||
];
|
||||
const meldenPages = new Set(['poison','lost','recalls','map']);
|
||||
const meldenCount = options.filter(o => meldenPages.has(o.page)).length;
|
||||
const title = meldenCount > options.length / 2 ? 'Was möchtest du melden?' : 'Was möchtest du eintragen?';
|
||||
|
||||
// Overlay erstellen
|
||||
const ov = document.createElement('div');
|
||||
ov.id = 'fab-overlay';
|
||||
ov.style.cssText = 'position:fixed;inset:0;z-index:300;display:flex;flex-direction:column;justify-content:flex-end';
|
||||
|
|
@ -219,9 +222,7 @@ window.Worlds = (() => {
|
|||
padding:20px 16px calc(env(safe-area-inset-bottom,16px) + 16px);
|
||||
box-shadow:0 -8px 32px rgba(0,0,0,0.2)">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px">
|
||||
<div style="font-size:var(--text-base);font-weight:700">
|
||||
${isWelt ? 'Was möchtest du melden?' : 'Was möchtest du eintragen?'}
|
||||
</div>
|
||||
<div style="font-size:var(--text-base);font-weight:700">${title}</div>
|
||||
<button id="fab-close" style="background:var(--c-border);border:none;border-radius:50%;
|
||||
width:28px;height:28px;cursor:pointer;display:flex;align-items:center;justify-content:center">
|
||||
<svg class="ph-icon" style="width:14px;height:14px"><use href="/icons/phosphor.svg#x"></use></svg>
|
||||
|
|
@ -260,6 +261,10 @@ window.Worlds = (() => {
|
|||
_close();
|
||||
const page = btn.dataset.page;
|
||||
const action = btn.dataset.action;
|
||||
if (action === 'quickGassi') {
|
||||
_openQuickGassi();
|
||||
return;
|
||||
}
|
||||
navigateTo(page);
|
||||
if (action === 'openNew') {
|
||||
setTimeout(() => window.App?.callModule?.(page, 'openNew'), 400);
|
||||
|
|
@ -268,42 +273,185 @@ window.Worlds = (() => {
|
|||
});
|
||||
}
|
||||
|
||||
// ── SCHNELL-GASSI ─────────────────────────────────────────────
|
||||
|
||||
async function _openQuickGassi() {
|
||||
const dog = _dogs[_dogIdx] || null;
|
||||
if (!dog) {
|
||||
UI.toast?.error('Kein Hund gefunden. Bitte zuerst ein Profil anlegen.');
|
||||
navigateTo('dog-profile');
|
||||
return;
|
||||
}
|
||||
|
||||
// Wetter aus Cache holen (kein Wait nötig)
|
||||
let weatherData = null;
|
||||
try {
|
||||
const wc = _wLoad('weather');
|
||||
if (wc?.data) weatherData = wc.data;
|
||||
} catch {}
|
||||
|
||||
let selectedMin = 30;
|
||||
const durations = [15, 30, 45, 60];
|
||||
|
||||
const ov = document.createElement('div');
|
||||
ov.id = 'quick-gassi-overlay';
|
||||
ov.style.cssText = 'position:fixed;inset:0;z-index:400;display:flex;flex-direction:column;justify-content:flex-end';
|
||||
|
||||
const weatherLine = weatherData
|
||||
? `<div style="font-size:var(--text-xs);color:var(--c-text-secondary);margin-top:6px">
|
||||
🌡 ${Math.round(weatherData.temp_c)}° · ${_esc(weatherData.desc?.split(' ')[0] || '')}
|
||||
</div>` : '';
|
||||
|
||||
ov.innerHTML = `
|
||||
<div id="qg-backdrop" style="position:absolute;inset:0;background:rgba(0,0,0,0.6);backdrop-filter:blur(3px)"></div>
|
||||
<div style="position:relative;z-index:1;background:var(--c-bg);border-radius:24px 24px 0 0;
|
||||
padding:24px 16px calc(env(safe-area-inset-bottom,16px) + 20px);
|
||||
box-shadow:0 -8px 32px rgba(0,0,0,0.25)">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:20px">
|
||||
<div>
|
||||
<div style="font-size:var(--text-base);font-weight:700">🐾 Schnell-Gassi</div>
|
||||
<div style="font-size:var(--text-xs);color:var(--c-text-secondary);margin-top:2px">
|
||||
${_esc(dog.name)} · ohne GPS
|
||||
</div>
|
||||
${weatherLine}
|
||||
</div>
|
||||
<button id="qg-close" style="background:var(--c-border);border:none;border-radius:50%;
|
||||
width:32px;height:32px;cursor:pointer;display:flex;align-items:center;justify-content:center">
|
||||
<svg class="ph-icon" style="width:16px;height:16px"><use href="/icons/phosphor.svg#x"></use></svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div style="font-size:var(--text-sm);font-weight:600;margin-bottom:10px">Dauer</div>
|
||||
<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin-bottom:24px">
|
||||
${durations.map(d => `
|
||||
<button class="qg-dur" data-min="${d}"
|
||||
style="padding:12px 6px;border-radius:12px;border:2px solid ${d === selectedMin ? 'var(--c-primary)' : 'var(--c-border)'};
|
||||
background:${d === selectedMin ? 'var(--c-primary-subtle)' : 'var(--c-bg-card)'};
|
||||
cursor:pointer;font-weight:700;font-size:var(--text-sm);
|
||||
color:${d === selectedMin ? 'var(--c-primary)' : 'var(--c-text)'}">
|
||||
${d} min
|
||||
</button>
|
||||
`).join('')}
|
||||
</div>
|
||||
|
||||
<button id="qg-submit" style="width:100%;padding:16px;border-radius:14px;
|
||||
background:var(--c-primary);color:white;border:none;cursor:pointer;
|
||||
font-size:var(--text-base);font-weight:700;
|
||||
display:flex;align-items:center;justify-content:center;gap:8px">
|
||||
<svg class="ph-icon" style="width:1.2rem;height:1.2rem"><use href="/icons/phosphor.svg#check"></use></svg>
|
||||
Eintragen
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.body.appendChild(ov);
|
||||
|
||||
const _close = () => ov.remove();
|
||||
ov.querySelector('#qg-backdrop').addEventListener('click', _close);
|
||||
ov.querySelector('#qg-close').addEventListener('click', _close);
|
||||
|
||||
// Dauer-Toggle
|
||||
ov.querySelectorAll('.qg-dur').forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
selectedMin = parseInt(btn.dataset.min);
|
||||
ov.querySelectorAll('.qg-dur').forEach(b => {
|
||||
const active = parseInt(b.dataset.min) === selectedMin;
|
||||
b.style.borderColor = active ? 'var(--c-primary)' : 'var(--c-border)';
|
||||
b.style.background = active ? 'var(--c-primary-subtle)' : 'var(--c-bg-card)';
|
||||
b.style.color = active ? 'var(--c-primary)' : 'var(--c-text)';
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Eintragen
|
||||
ov.querySelector('#qg-submit').addEventListener('click', async () => {
|
||||
const submitBtn = ov.querySelector('#qg-submit');
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.textContent = 'Wird eingetragen…';
|
||||
|
||||
try {
|
||||
const payload = {
|
||||
typ: 'gassi',
|
||||
titel: 'Schnell-Gassi 🐾',
|
||||
text: `Kurze Runde, ${selectedMin} Minuten`,
|
||||
};
|
||||
if (weatherData) {
|
||||
payload.weather_json = JSON.stringify(weatherData);
|
||||
}
|
||||
await API.post(`/dogs/${dog.id}/diary`, payload);
|
||||
_close();
|
||||
UI.toast?.success(`Gassi eingetragen! ${selectedMin} min 🐾`);
|
||||
// Streak-Cache invalidieren
|
||||
try { localStorage.removeItem('w3_streak_' + dog.id); } catch {}
|
||||
// JETZT-Welt neu rendern für aktuellen Streak
|
||||
setTimeout(() => _renderJetzt(), 300);
|
||||
} catch (err) {
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.innerHTML = '<svg class="ph-icon" style="width:1.2rem;height:1.2rem"><use href="/icons/phosphor.svg#check"></use></svg> Eintragen';
|
||||
UI.toast?.error('Fehler beim Eintragen. Bitte erneut versuchen.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ── CHIP-KONFIGURATION ──────────────────────────────────────
|
||||
// Alle verfügbaren Chips mit Metadaten
|
||||
|
||||
const _ALL_CHIPS = [
|
||||
{ icon:'note-pencil', label:'Notizblock', page:'notes' },
|
||||
{ icon:'currency-eur', label:'Ausgaben', page:'expenses' },
|
||||
{ icon:'first-aid', label:'Erste Hilfe', page:'erste-hilfe' },
|
||||
{ icon:'handshake', label:'Playdate', page:'playdate' },
|
||||
{ icon:'chat-circle-dots', label:'Nachrichten', page:'chat' },
|
||||
{ icon:'sun', label:'Wetter', page:'wetter' },
|
||||
{ icon:'note-pencil', label:'Notizblock', page:'notes',
|
||||
fab:[{ icon:'note-pencil', color:'#10B981', label:'Neue Notiz', sub:'Schnellnotiz erstellen', page:'notes', action:'openNew' }] },
|
||||
{ icon:'currency-eur', label:'Ausgaben', page:'expenses',
|
||||
fab:[{ icon:'currency-eur', color:'#3B82F6', label:'Ausgabe eintragen', sub:'Einmalig oder Dauerauftrag', page:'expenses', action:'openNew' }] },
|
||||
{ icon:'first-aid', label:'Erste Hilfe', page:'erste-hilfe' },
|
||||
{ icon:'handshake', label:'Playdate', page:'playdate',
|
||||
fab:[{ icon:'handshake', color:'#F59E0B', label:'Playdate anfragen', sub:'Treffen mit anderen Hunden', page:'playdate', action:'openNew' }] },
|
||||
{ icon:'chat-circle-dots', label:'Nachrichten', page:'chat' },
|
||||
{ icon:'sun', label:'Wetter', page:'wetter' },
|
||||
|
||||
{ icon:'book-open', label:'Tagebuch', page:'diary' },
|
||||
{ icon:'heartbeat', label:'Gesundheit', page:'health' },
|
||||
{ icon:'target', label:'Übungen', page:'uebungen' },
|
||||
{ icon:'list-checks', label:'Trainings-\npläne',page:'trainingsplaene'},
|
||||
{ icon:'heart', label:'Adoption', page:'adoption' },
|
||||
{ icon:'house-line', label:'Sitting', page:'sitting' },
|
||||
{ icon:'books', label:'Wiki', page:'wiki' },
|
||||
{ icon:'scales', label:'Wurfbörse', page:'wurfboerse' },
|
||||
{ icon:'map-trifold', label:'Karte', page:'map' },
|
||||
{ icon:'push-pin', label:'Forum', page:'forum' },
|
||||
{ icon:'users', label:'Freunde', page:'friends' },
|
||||
{ icon:'paw-print', label:'Gassi', page:'walks' },
|
||||
{ icon:'skull', label:'Giftköder', page:'poison' },
|
||||
{ icon:'warning-circle', label:'Rückrufe', page:'recalls' },
|
||||
{ icon:'dog', label:'Verlorene', page:'lost' },
|
||||
{ icon:'path', label:'Routen', page:'routes' },
|
||||
{ icon:'calendar-dots', label:'Events', page:'events' },
|
||||
{ icon:'sparkle', label:'Jobs', page:'jobs' },
|
||||
{ icon:'book-open', label:'Knigge', page:'knigge' },
|
||||
{ icon:'film-slate', label:'Filme', page:'movies' },
|
||||
{ icon:'tree-structure', label:'Zucht-\nkartei', page:'zuchthunde', role:'breeder' },
|
||||
{ icon:'notebook', label:'Wurfverw.', page:'litters', role:'breeder' },
|
||||
{ icon:'sparkle', label:'Social', page:'social', role:'social' },
|
||||
{ icon:'shield-check', label:'Moderation', page:'moderation', role:'mod' },
|
||||
{ icon:'gear', label:'Admin', page:'admin', role:'admin' },
|
||||
{ icon:'book-open', label:'Tagebuch', page:'diary',
|
||||
fab:[{ icon:'book-open', color:'#8B5CF6', label:'Tagebucheintrag', sub:'Erlebnis, Foto oder Notiz', page:'diary', action:'openNew' }] },
|
||||
{ icon:'heartbeat', label:'Gesundheit', page:'health',
|
||||
fab:[{ icon:'heartbeat', color:'#EF4444', label:'Tierarztbesuch', sub:'Befund oder Impfung eintragen', page:'health' },
|
||||
{ icon:'wave-sine', color:'#06B6D4', label:'Gewicht messen', sub:'Aktuelles Gewicht eintragen', page:'health' }] },
|
||||
{ icon:'target', label:'Übungen', page:'uebungen',
|
||||
fab:[{ icon:'target', color:'#F59E0B', label:'Training aufzeichnen', sub:'Übung absolviert', page:'uebungen' }] },
|
||||
{ icon:'list-checks', label:'Trainings-\npläne', page:'trainingsplaene',
|
||||
fab:[{ icon:'list-checks', color:'#10B981', label:'Plan erstellen', sub:'Neuen Trainingsplan anlegen', page:'trainingsplaene', action:'openNew' }] },
|
||||
{ icon:'heart', label:'Adoption', page:'adoption',
|
||||
fab:[{ icon:'heart', color:'#EF4444', label:'Hund anbieten', sub:'Zur Adoption freigeben', page:'adoption', action:'openNew' }] },
|
||||
{ icon:'house-line', label:'Sitting', page:'sitting',
|
||||
fab:[{ icon:'house-line', color:'#8B5CF6', label:'Sitter anfragen', sub:'Betreuung buchen', page:'sitting', action:'openNew' }] },
|
||||
{ icon:'books', label:'Wiki', page:'wiki' },
|
||||
{ icon:'scales', label:'Wurfbörse', page:'wurfboerse' },
|
||||
{ icon:'map-trifold', label:'Karte', page:'map',
|
||||
fab:[{ icon:'map-pin', color:'#10B981', label:'Ort vorschlagen', sub:'Neuen POI auf der Karte', page:'map' }] },
|
||||
{ icon:'push-pin', label:'Forum', page:'forum',
|
||||
fab:[{ icon:'push-pin', color:'#8B5CF6', label:'Forum-Beitrag', sub:'Thema oder Frage erstellen', page:'forum', action:'openNew' }] },
|
||||
{ icon:'users', label:'Freunde', page:'friends',
|
||||
fab:[{ icon:'users', color:'#3B82F6', label:'Freund einladen', sub:'Per Link einladen', page:'friends', action:'openNew' }] },
|
||||
{ icon:'paw-print', label:'Gassi', page:'walks',
|
||||
fab:[{ icon:'paw-print', color:'#F59E0B', label:'Gassirunde', sub:'Neue Runde starten', page:'walks', action:'openNew' },
|
||||
{ icon:'paw-print', color:'#10B981', label:'Schnell-Gassi', sub:'Kurze Runde ohne GPS eintragen', page:'walks', action:'quickGassi' }] },
|
||||
{ icon:'skull', label:'Giftköder', page:'poison',
|
||||
fab:[{ icon:'skull', color:'#EF4444', label:'Giftköder melden', sub:'Warnung für andere Hundebesitzer', page:'poison' }] },
|
||||
{ icon:'warning-circle', label:'Rückrufe', page:'recalls',
|
||||
fab:[{ icon:'warning-circle', color:'#EF4444', label:'Rückruf melden', sub:'Produkt oder Futter', page:'recalls', action:'openNew' }] },
|
||||
{ icon:'dog', label:'Verlorene', page:'lost',
|
||||
fab:[{ icon:'dog', color:'#3B82F6', label:'Verlorenen melden', sub:'Hilf beim Wiederfinden', page:'lost' }] },
|
||||
{ icon:'path', label:'Routen', page:'routes',
|
||||
fab:[{ icon:'path', color:'#10B981', label:'Route aufzeichnen', sub:'GPS-Tracking starten', page:'routes', action:'openNew' }] },
|
||||
{ icon:'calendar-dots', label:'Events', page:'events',
|
||||
fab:[{ icon:'calendar-dots', color:'#06B6D4', label:'Event erstellen', sub:'Veranstaltung ankündigen', page:'events', action:'openNew' }] },
|
||||
{ icon:'sparkle', label:'Jobs', page:'jobs' },
|
||||
{ icon:'book-open', label:'Knigge', page:'knigge' },
|
||||
{ icon:'film-slate', label:'Filme', page:'movies' },
|
||||
{ icon:'tree-structure', label:'Zucht-\nkartei', page:'zuchthunde', role:'breeder',
|
||||
fab:[{ icon:'tree-structure', color:'#8B5CF6', label:'Zuchthund eintragen', sub:'Neuen Hund anlegen', page:'zuchthunde', action:'openNew' }] },
|
||||
{ icon:'notebook', label:'Wurfverw.', page:'litters', role:'breeder',
|
||||
fab:[{ icon:'notebook', color:'#10B981', label:'Wurf anlegen', sub:'Neuen Wurf eintragen', page:'litters', action:'openNew' }] },
|
||||
{ icon:'sparkle', label:'Social', page:'social', role:'social',
|
||||
fab:[{ icon:'sparkle', color:'#EC4899', label:'Social-Post', sub:'Beitrag erstellen', page:'social', action:'openNew' }] },
|
||||
{ icon:'shield-check', label:'Moderation', page:'moderation', role:'mod' },
|
||||
{ icon:'gear', label:'Admin', page:'admin', role:'admin' },
|
||||
];
|
||||
|
||||
const _DEFAULT_CONFIG = {
|
||||
|
|
@ -618,18 +766,13 @@ window.Worlds = (() => {
|
|||
|
||||
async function _loadDailyImage(dog) {
|
||||
if (!dog) return null;
|
||||
const todayKey = 'bg_' + new Date().toISOString().slice(0, 10);
|
||||
const todayKey = 'bg3_' + new Date().toISOString().slice(0, 10);
|
||||
const cached = _wLoad(todayKey);
|
||||
if (cached?.data) return cached.data;
|
||||
try {
|
||||
const r = await _cachedGet(`diary_${dog.id}`, `/dogs/${dog.id}/diary?limit=30`);
|
||||
const entries = r.data?.entries || r.data || [];
|
||||
const withPhotos = entries.filter(e => (e.foto_urls?.length || e.foto_url));
|
||||
if (!withPhotos.length) { const u = dog.foto_url || null; if(u) _wSave(todayKey, u); return u; }
|
||||
const day = Math.floor(Date.now() / 86400000);
|
||||
const entry = withPhotos[day % withPhotos.length];
|
||||
const url = (entry.foto_urls?.[0] || entry.foto_url);
|
||||
_wSave(todayKey, url);
|
||||
const dash = await API.dogs.welcomeDashboard(dog.id);
|
||||
const url = dash?.random_photo?.url || dog.foto_url || null;
|
||||
if (url) _wSave(todayKey, url);
|
||||
return url;
|
||||
} catch { return dog.foto_url || null; }
|
||||
}
|
||||
|
|
@ -669,10 +812,11 @@ window.Worlds = (() => {
|
|||
const user = _state?.user;
|
||||
el.innerHTML = _skeleton(3);
|
||||
|
||||
const [weatherRes, dogsRes, alertsRes] = await Promise.allSettled([
|
||||
const [weatherRes, dogsRes, alertsRes, achRes] = await Promise.allSettled([
|
||||
_getCachedWeather(),
|
||||
user ? _cachedGet('dogs', '/dogs') : Promise.resolve({ data: [], fromCache: false, ageMin: 0 }),
|
||||
user ? _getNearbyAlerts() : Promise.resolve([]),
|
||||
user ? _cachedGet('achievements_me', '/achievements/me') : Promise.resolve({ data: null }),
|
||||
]);
|
||||
|
||||
const weatherObj = weatherRes.value || { data: null, fromCache: false, ageMin: 0 };
|
||||
|
|
@ -681,6 +825,7 @@ window.Worlds = (() => {
|
|||
const dogList = dogsObj.data || [];
|
||||
const dog = dogList[0] || null;
|
||||
const alertList = alertsRes.value || [];
|
||||
const totalKm = achRes.value?.data?.stats?.total_km ?? null;
|
||||
const isOffline = weatherObj.fromCache && dogsObj.fromCache;
|
||||
const staleMin = Math.max(weatherObj.ageMin || 0, dogsObj.ageMin || 0);
|
||||
|
||||
|
|
@ -756,7 +901,7 @@ window.Worlds = (() => {
|
|||
<div class="world-info-title">
|
||||
${_esc(greet)}${firstName ? `, <span style="color:var(--c-primary)">${_esc(firstName)}</span>` : ''}${stale}
|
||||
</div>
|
||||
<div class="world-info-sub">${_esc(dayStr)}${weatherLine ? ' · ' + weatherLine : ''}</div>
|
||||
<div class="world-info-sub">${_esc(dayStr)}${weatherLine ? ' · ' + weatherLine : ''}${totalKm != null ? ' · ' + totalKm + ' km' : ''}</div>
|
||||
</div>
|
||||
${user ? userAvatarHtml : ''}
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue