This commit is contained in:
@@ -10,10 +10,21 @@
|
||||
<script src="/js/theme.js"></script>
|
||||
<style>
|
||||
/* Dashboard-spezifische Widgets (rechte Spalte) */
|
||||
.gauge { display:flex; flex-direction:column; align-items:center; gap:.2rem; }
|
||||
.gauge svg { width:130px; height:130px; }
|
||||
.gauge .ok { color:var(--accent); font-weight:800; font-size:1rem; letter-spacing:.05em; margin-top:.3rem; text-shadow:0 0 12px var(--glow-s); }
|
||||
.gauge .op { color:var(--muted); font-size:.72rem; }
|
||||
.network-status { display:grid; grid-template-columns:auto 1fr; gap:.85rem; align-items:start; }
|
||||
.network-status svg { width:54px; height:54px; color:var(--accent); filter:drop-shadow(0 0 8px var(--glow-s)); }
|
||||
.status-summary { color:var(--heading); font-size:.9rem; font-weight:800; letter-spacing:.04em; }
|
||||
.status-summary::before { content:""; display:inline-block; width:.52rem; height:.52rem; margin-right:.42rem; border-radius:50%; background:var(--muted); box-shadow:0 0 8px color-mix(in srgb,var(--muted) 60%,transparent); }
|
||||
.network-status.ready .status-summary { color:var(--accent); }
|
||||
.network-status.ready .status-summary::before { background:var(--accent); box-shadow:0 0 8px var(--glow-s); }
|
||||
.network-status.restricted .status-summary { color:#edcb4c; }
|
||||
.network-status.restricted .status-summary::before { background:#edcb4c; box-shadow:0 0 8px rgba(237,203,76,.48); }
|
||||
.status-caption { color:var(--muted); font-size:.72rem; line-height:1.45; margin:.25rem 0 0; }
|
||||
.status-details { grid-column:1 / -1; display:none; gap:.45rem; padding-top:.2rem; color:var(--muted); font-size:.72rem; }
|
||||
.status-details.open { display:grid; }
|
||||
.status-details div { display:flex; justify-content:space-between; gap:1rem; border-top:1px solid var(--border); padding-top:.45rem; }
|
||||
.status-details b { color:var(--text); font-weight:600; text-align:right; }
|
||||
.status-toggle { grid-column:1 / -1; justify-self:start; border:0; padding:0; background:transparent; color:var(--secondary); font:inherit; font-size:.72rem; cursor:pointer; }
|
||||
.status-toggle:hover { text-decoration:underline; }
|
||||
.prog-top { display:flex; justify-content:space-between; align-items:center; margin-bottom:.4rem; }
|
||||
.pill { font-size:.68rem; color:var(--muted); border:1px solid var(--border); border-radius:7px; padding:.2rem .5rem; }
|
||||
.prog-big { display:flex; align-items:baseline; gap:.5rem; }
|
||||
@@ -68,15 +79,19 @@
|
||||
<!-- ===== Rechte Spalte ===== -->
|
||||
<aside class="mf-rightbar">
|
||||
<div class="mf-panel">
|
||||
<h4><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 12h4l2-7 4 14 2-7h6"/></svg> System Status</h4>
|
||||
<div class="gauge">
|
||||
<svg viewBox="0 0 120 120" fill="none">
|
||||
<circle cx="60" cy="60" r="50" stroke="var(--line)" stroke-width="6"/>
|
||||
<circle cx="60" cy="60" r="50" stroke="var(--accent)" stroke-width="6" stroke-linecap="round" stroke-dasharray="300 314" transform="rotate(-90 60 60)" style="filter:drop-shadow(0 0 6px var(--glow-s))"/>
|
||||
<path d="M37 52l17-13 20 8-8 21-22 8-12-15zM54 39l-2 22m22-14-22 14m-8 15 8-15m14 7-14-7" stroke="var(--accent)" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="37" cy="52" r="3" fill="var(--accent)"/><circle cx="54" cy="39" r="3" fill="var(--accent)"/><circle cx="74" cy="47" r="3" fill="var(--accent)"/><circle cx="66" cy="68" r="3" fill="var(--accent)"/><circle cx="44" cy="76" r="3" fill="var(--accent)"/><circle cx="52" cy="61" r="3" fill="var(--accent)"/>
|
||||
<h4><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 12h4l2-7 4 14 2-7h6"/></svg> Lernnetz-Status</h4>
|
||||
<div class="network-status" id="platformStatus" aria-live="polite">
|
||||
<svg viewBox="0 0 64 64" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<path d="M15 26 29 14l18 8-5 20-20 8-9-13zM29 14l-2 22m20-14-20 14m-5 14 5-14m15 6-15-6"/>
|
||||
<circle cx="15" cy="26" r="3" fill="currentColor"/><circle cx="29" cy="14" r="3" fill="currentColor"/><circle cx="47" cy="22" r="3" fill="currentColor"/><circle cx="42" cy="42" r="3" fill="currentColor"/><circle cx="22" cy="50" r="3" fill="currentColor"/><circle cx="27" cy="36" r="3" fill="currentColor"/>
|
||||
</svg>
|
||||
<div class="ok">ALLE SYSTEME STABIL</div><div class="op">100% OPERATIONAL</div>
|
||||
<div><div class="status-summary" data-status-summary>Lernnetz wird geprüft</div><p class="status-caption" data-status-caption>Prüfe Fortschrittsspeicher und Lernmodule …</p></div>
|
||||
<div class="status-details" data-status-details>
|
||||
<div><span>Fortschrittsspeicher</span><b data-status-storage>Wird geprüft</b></div>
|
||||
<div><span>Lernmodule</span><b data-status-modules>Wird geprüft</b></div>
|
||||
<div><span>Letzte Prüfung</span><b data-status-checked>–</b></div>
|
||||
</div>
|
||||
<button class="status-toggle" type="button" data-status-toggle aria-expanded="false">Details anzeigen</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -156,6 +171,45 @@
|
||||
const points = values.map((value, index) => `${Math.round(index * 40)} ${64 - Math.round(value / max * 54)}`);
|
||||
const line = `M${points.join(' L')}`;
|
||||
weekChart.querySelector('svg').innerHTML = `<defs><linearGradient id="ar" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="var(--accent)" stop-opacity=".35"/><stop offset="1" stop-color="var(--accent)" stop-opacity="0"/></linearGradient></defs><path d="${line} L240 74 L0 74 Z" fill="url(#ar)"/><path d="${line}" fill="none" stroke="var(--accent)" stroke-width="2" style="filter:drop-shadow(0 0 5px var(--glow-s))"/>`;
|
||||
|
||||
// Der Status prüft den Fortschrittsspeicher serverseitig. Die Modulzahl ist
|
||||
// der registrierte Lernkatalog, nicht ein erfundener Prozentwert.
|
||||
const statusCard = document.getElementById('platformStatus');
|
||||
const statusSummary = statusCard.querySelector('[data-status-summary]');
|
||||
const statusCaption = statusCard.querySelector('[data-status-caption]');
|
||||
const statusStorage = statusCard.querySelector('[data-status-storage]');
|
||||
const statusModules = statusCard.querySelector('[data-status-modules]');
|
||||
const statusChecked = statusCard.querySelector('[data-status-checked]');
|
||||
const details = statusCard.querySelector('[data-status-details]');
|
||||
const toggle = statusCard.querySelector('[data-status-toggle]');
|
||||
|
||||
toggle.addEventListener('click', () => {
|
||||
const open = details.classList.toggle('open');
|
||||
toggle.setAttribute('aria-expanded', String(open));
|
||||
toggle.textContent = open ? 'Details ausblenden' : 'Details anzeigen';
|
||||
});
|
||||
|
||||
fetch('/api/platform/status', { headers: { Accept: 'application/json' } })
|
||||
.then(async response => ({ response, status: await response.json() }))
|
||||
.then(({ response, status }) => {
|
||||
const ready = response.ok && status.storageConnected;
|
||||
statusCard.classList.toggle('ready', ready);
|
||||
statusCard.classList.toggle('restricted', !ready);
|
||||
statusSummary.textContent = ready ? 'Bereit für deine Session' : 'Lernnetz eingeschränkt';
|
||||
statusCaption.textContent = ready
|
||||
? 'Fortschritt wird sicher gespeichert.'
|
||||
: 'Fortschritt kann gerade nicht zuverlässig gespeichert werden.';
|
||||
statusStorage.textContent = ready ? 'Verbunden' : 'Nicht erreichbar';
|
||||
statusModules.textContent = `${status.registeredModules} registriert`;
|
||||
statusChecked.textContent = new Date(status.checkedAt).toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' });
|
||||
})
|
||||
.catch(() => {
|
||||
statusCard.classList.add('restricted');
|
||||
statusSummary.textContent = 'Statusprüfung nicht möglich';
|
||||
statusCaption.textContent = 'Der aktuelle Speicherzustand konnte nicht bestätigt werden.';
|
||||
statusStorage.textContent = 'Unbekannt';
|
||||
statusModules.textContent = 'Nicht bestätigt';
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user