Sprint 18: Lost-Dog CSS, Freunde-Aktivitäts-Feed, Events-Karte
This commit is contained in:
parent
cfdb3fbc19
commit
10d30bf565
8 changed files with 595 additions and 41 deletions
|
|
@ -104,6 +104,9 @@ window.Page_friends = (() => {
|
|||
<!-- Freundesliste -->
|
||||
<div id="fr-list"></div>
|
||||
|
||||
<!-- Aktivitäten-Feed -->
|
||||
<div id="fr-activity"></div>
|
||||
|
||||
</div>
|
||||
`;
|
||||
|
||||
|
|
@ -165,6 +168,113 @@ window.Page_friends = (() => {
|
|||
_renderFriends(data.friends || []);
|
||||
_updateBadge((data.incoming || []).length);
|
||||
} catch { /* silent — 401 bei abgemeldeter Session */ }
|
||||
_loadActivity();
|
||||
}
|
||||
|
||||
async function _loadActivity() {
|
||||
if (!_appState.user) return;
|
||||
const el = _container.querySelector('#fr-activity');
|
||||
if (!el) return;
|
||||
|
||||
// Ladeindikator
|
||||
el.innerHTML = `
|
||||
<div style="margin-top:var(--space-6)">
|
||||
<div class="by-section-label">Aktivitäten</div>
|
||||
<div style="text-align:center;padding:var(--space-6) 0;color:var(--c-text-muted);
|
||||
font-size:var(--text-sm)">
|
||||
<svg class="ph-icon" style="width:20px;height:20px;animation:spin 1s linear infinite"
|
||||
aria-hidden="true"><use href="/icons/phosphor.svg#spinner"></use></svg>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
try {
|
||||
const items = await API.friends.activity();
|
||||
_renderActivity(items || []);
|
||||
} catch {
|
||||
el.innerHTML = '';
|
||||
}
|
||||
}
|
||||
|
||||
function _renderActivity(items) {
|
||||
const el = _container.querySelector('#fr-activity');
|
||||
if (!el) return;
|
||||
|
||||
if (!items.length) {
|
||||
el.innerHTML = `
|
||||
<div style="margin-top:var(--space-6)">
|
||||
<div class="by-section-label">Aktivitäten</div>
|
||||
<div style="text-align:center;padding:var(--space-8) var(--space-4)">
|
||||
<svg class="ph-icon" style="width:40px;height:40px;color:var(--c-border);
|
||||
margin-bottom:var(--space-3)" aria-hidden="true">
|
||||
<use href="/icons/phosphor.svg#paw-print"></use>
|
||||
</svg>
|
||||
<p style="font-size:var(--text-sm);color:var(--c-text-secondary);margin:0">
|
||||
Noch keine Aktivitäten. Füge Freunde hinzu!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
el.innerHTML = `
|
||||
<div style="margin-top:var(--space-6)">
|
||||
<div class="by-section-label">Aktivitäten</div>
|
||||
<div class="fr-activity-timeline">
|
||||
${items.map(item => _activityItem(item)).join('')}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function _activityItem(item) {
|
||||
const ago = _timeAgo(item.created_at);
|
||||
const text = item.text || '';
|
||||
const dogLabel = item.dog_name
|
||||
? `<span class="fr-activity-dog">${_esc(item.dog_name)}</span>`
|
||||
: '';
|
||||
|
||||
const avatar = item.dog_foto
|
||||
? `<img src="${_esc(item.dog_foto)}" alt="${_esc(item.dog_name || '')}"
|
||||
class="fr-activity-avatar">`
|
||||
: item.avatar_url
|
||||
? `<img src="${_esc(item.avatar_url)}" alt="${_esc(item.user_name)}"
|
||||
class="fr-activity-avatar">`
|
||||
: `<div class="fr-activity-avatar fr-activity-avatar--initial">
|
||||
${_esc((item.user_name || '?')[0].toUpperCase())}
|
||||
</div>`;
|
||||
|
||||
return `
|
||||
<div class="fr-activity-item">
|
||||
<div class="fr-activity-avatar-wrap">
|
||||
${avatar}
|
||||
<div class="fr-activity-icon-badge">
|
||||
<svg class="ph-icon" style="width:10px;height:10px" aria-hidden="true">
|
||||
<use href="/icons/phosphor.svg#${_esc(item.icon)}"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fr-activity-body">
|
||||
<div class="fr-activity-meta">
|
||||
<span class="fr-activity-user">${_esc(item.user_name)}</span>
|
||||
${dogLabel}
|
||||
</div>
|
||||
${text ? `<div class="fr-activity-text">${_esc(text)}</div>` : ''}
|
||||
<div class="fr-activity-time">${_esc(ago)}</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function _timeAgo(iso) {
|
||||
if (!iso) return '';
|
||||
const diff = Math.floor((Date.now() - new Date(iso + (iso.endsWith('Z') ? '' : 'Z')).getTime()) / 1000);
|
||||
if (diff < 60) return 'Gerade eben';
|
||||
if (diff < 3600) return `vor ${Math.floor(diff / 60)} Min`;
|
||||
if (diff < 86400) return `vor ${Math.floor(diff / 3600)} Std`;
|
||||
if (diff < 86400 * 7) return `vor ${Math.floor(diff / 86400)} Tagen`;
|
||||
return new Date(iso).toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit' });
|
||||
}
|
||||
|
||||
function _updateBadge(count) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue