Feature: Ratings, Lightbox, Forum-Standort, Notifications, Routen-Recording, Chat-Picker
- Bewertungssystem (ratings.py): Sterne für Sitter/Walks/Places/Routen - Admin: Server-Log-Viewer + OSM-Cache-Statistiken - Chat: "Neue Nachricht"-Button mit Freundesliste-Picker - Forum: 5 neue Kategorien, Standorteingabe (locationPicker), Absende-Toast, Lightbox - Freunde: Aktivitäts-Filter (Chips), Freundschaftsanfrage → In-App-Notification - Sitter: locationPicker statt manuelle Koordinateneingabe + ratingStars - Tagebuch: Bilder-Lightbox im Detail-View, iOS-Modal-Header-Fix (90svh) - Routen: Start/Stopp-Button wechselt Zustand, nutzt Page_map.isRecording() - Benachrichtigungen: Delete-Button sichtbar, typ-basierte Navigation, Toast-Feedback - OSM: globales Semaphore + 429-Retry-Logic; Scheduler: München-Umland, täglich - SW by-v225, APP_VER 202
This commit is contained in:
parent
aa70a838f2
commit
e56183b642
21 changed files with 648 additions and 175 deletions
|
|
@ -104,6 +104,20 @@ window.Page_admin = (() => {
|
|||
${_statCard('image', 'Media-Einträge', s.media_count, 'var(--c-text-secondary)')}
|
||||
${_statCard('map-pin', 'Routen', s.routes_total, 'var(--c-text-secondary)')}
|
||||
${_statCard('calendar', 'Events', s.events_total, 'var(--c-text-secondary)')}
|
||||
${_statCard('map-trifold', 'OSM-Marker', s.osm_total.toLocaleString('de'), 'var(--c-success)')}
|
||||
${_statCard('squares-four', 'Gecachte Tiles', s.osm_tiles.toLocaleString('de'), 'var(--c-text-secondary)')}
|
||||
</div>
|
||||
|
||||
<div class="card" style="padding:var(--space-4)">
|
||||
<p style="font-size:var(--text-sm);font-weight:600;margin:0 0 var(--space-3)">OSM-Cache nach Typ</p>
|
||||
<div style="display:flex;flex-direction:column;gap:var(--space-2)">
|
||||
${Object.entries(s.osm_by_type).map(([type, count]) => `
|
||||
<div style="display:flex;justify-content:space-between;font-size:var(--text-sm)">
|
||||
<span style="color:var(--c-text-secondary)">${type}</span>
|
||||
<span style="font-weight:600">${count.toLocaleString('de')}</span>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="padding:var(--space-4)">
|
||||
|
|
@ -543,9 +557,46 @@ window.Page_admin = (() => {
|
|||
</button>
|
||||
</div>
|
||||
<div id="adm-sys-cards">Lade…</div>
|
||||
<div style="margin-top:var(--space-5)">
|
||||
<div style="display:flex;align-items:center;gap:var(--space-3);margin-bottom:var(--space-3)">
|
||||
<span style="font-size:var(--text-sm);font-weight:600">Server-Logs</span>
|
||||
<select id="adm-log-level" class="input" style="width:auto;padding:2px 8px;font-size:var(--text-xs)">
|
||||
<option value="">Alle</option>
|
||||
<option value="INFO">INFO</option>
|
||||
<option value="WARNING">WARNING</option>
|
||||
<option value="ERROR">ERROR</option>
|
||||
</select>
|
||||
<button class="btn btn-ghost btn-sm" id="adm-log-refresh">${UI.icon('arrows-clockwise')}</button>
|
||||
</div>
|
||||
<div id="adm-log-box" style="
|
||||
background:var(--c-surface-2);border-radius:var(--radius-md);
|
||||
padding:var(--space-3);font-family:monospace;font-size:11px;
|
||||
max-height:420px;overflow-y:auto;line-height:1.6">Lade…</div>
|
||||
</div>
|
||||
`;
|
||||
el.querySelector('#adm-sys-refresh').addEventListener('click', () => _loadSystemCards(el.querySelector('#adm-sys-cards')));
|
||||
const loadLogs = async () => {
|
||||
const level = el.querySelector('#adm-log-level').value;
|
||||
const box = el.querySelector('#adm-log-box');
|
||||
box.textContent = 'Lade…';
|
||||
const rows = await API.get(`/admin/logs?lines=200${level ? '&level=' + level : ''}`);
|
||||
const COLORS = { ERROR: '#ef4444', WARNING: '#f59e0b', INFO: '#6b7280', DEBUG: '#94a3b8' };
|
||||
box.innerHTML = rows.reverse().map(r => {
|
||||
const color = COLORS[r.l] || '#6b7280';
|
||||
return `<div style="border-bottom:1px solid var(--c-border);padding:2px 0">` +
|
||||
`<span style="color:var(--c-text-muted)">${r.t}</span> ` +
|
||||
`<span style="color:${color};font-weight:600">${r.l}</span> ` +
|
||||
`<span style="color:var(--c-text-secondary)">${_esc(r.n)}</span> ` +
|
||||
`<span>${_esc(r.m)}</span></div>`;
|
||||
}).join('') || '<span style="color:var(--c-text-muted)">Keine Einträge</span>';
|
||||
};
|
||||
el.querySelector('#adm-sys-refresh').addEventListener('click', () => {
|
||||
_loadSystemCards(el.querySelector('#adm-sys-cards'));
|
||||
loadLogs();
|
||||
});
|
||||
el.querySelector('#adm-log-refresh').addEventListener('click', loadLogs);
|
||||
el.querySelector('#adm-log-level').addEventListener('change', loadLogs);
|
||||
await _loadSystemCards(el.querySelector('#adm-sys-cards'));
|
||||
await loadLogs();
|
||||
}
|
||||
|
||||
async function _loadSystemCards(el) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue