This commit is contained in:
@@ -38,15 +38,15 @@ body.sn-platform .mf-panel, body.sn-platform .mf-card, body.sn-platform .mf-prof
|
||||
body.sn-platform .mf-card { overflow:hidden; }
|
||||
body.sn-platform .mf-card::after { content:""; position:absolute; inset:0; pointer-events:none; opacity:.55; background:radial-gradient(circle at 90% 8%,color-mix(in srgb,var(--accent) 22%,transparent) 0 1px,transparent 2px),linear-gradient(132deg,transparent 0 45%,color-mix(in srgb,var(--accent) 12%,transparent) 45.2% 45.4%,transparent 45.6%); }
|
||||
body.sn-platform .mf-card > * { position:relative; z-index:1; }
|
||||
body.sn-platform .mf-card-mindmatch { --accent:#c078f2; --accent-2:#ebc0ff; --glow-s:rgba(192,120,242,.40); }
|
||||
body.sn-platform .mf-card-mindmatch { --accent:#df68b9; --accent-2:#ffc0e7; --glow-s:rgba(223,104,185,.40); }
|
||||
body.sn-platform .mf-card-techtacular { --accent:#d6db47; --accent-2:#f2f58a; --glow-s:rgba(214,219,71,.36); }
|
||||
body.sn-platform .mf-card-devlab { --accent:#78d7a0; --accent-2:#b4ebc8; --glow-s:rgba(120,215,160,.40); }
|
||||
body.sn-platform .mf-card-syntaxsaga { --accent:#b176ef; --accent-2:#dfbfff; --glow-s:rgba(177,118,239,.40); }
|
||||
body.sn-platform .mf-card-codeescape { --accent:#e5ae5b; --accent-2:#f8d09b; --glow-s:rgba(229,174,91,.38); }
|
||||
body.sn-platform .mf-card-syntaxsaga { --accent:#9276f0; --accent-2:#d1c8ff; --glow-s:rgba(146,118,240,.40); }
|
||||
body.sn-platform .mf-card-codeescape { --accent:#edcb4c; --accent-2:#fff0a8; --glow-s:rgba(237,203,76,.38); }
|
||||
body.sn-platform .mf-card-serviceclash { --accent:#3abec5; --accent-2:#9de9e6; --glow-s:rgba(58,190,197,.38); }
|
||||
body.sn-platform .mf-card-bughunter { --accent:#e85e68; --accent-2:#ffb6bd; --glow-s:rgba(232,94,104,.38); }
|
||||
body.sn-platform .mf-card-networker { --accent:#55bdf0; --accent-2:#b2e7ff; --glow-s:rgba(85,189,240,.38); }
|
||||
body.sn-platform .mf-card-finalprotocol { --accent:#f09043; --accent-2:#ffd0a2; --glow-s:rgba(240,144,67,.38); }
|
||||
body.sn-platform .mf-card-finalprotocol { --accent:#ed7849; --accent-2:#ffd0b5; --glow-s:rgba(237,120,73,.38); }
|
||||
body.sn-platform .mf-footer { background:rgba(3,11,13,.72); border-color:#173438; }
|
||||
body.sn-platform .mf-center { min-height:100vh; position:relative; }
|
||||
body.sn-platform .auth-container { background:linear-gradient(145deg,rgba(10,29,32,.98),rgba(4,14,17,.98)); border-color:rgba(120,215,160,.46); }
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<header style="margin-bottom:1.4rem">
|
||||
<div class="mf-eyebrow">Control Center</div>
|
||||
<h1 style="color:var(--heading); font-size:1.85rem; font-weight:800; margin-top:.35rem">✨ Admin-Dashboard ✨</h1>
|
||||
<p style="color:var(--muted); margin-top:.4rem">Hier steuerst du die Plattform und ihre Lerninhalte.</p>
|
||||
<p style="color:var(--muted); margin-top:.4rem">Hier steuerst du die verfügbaren Lerninhalte und die Benutzerverwaltung.</p>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
@@ -52,7 +52,8 @@
|
||||
<a th:href="@{/admin/bughunter}" class="admin-card">🕵️ BugHunter-Fallakten verwalten</a>
|
||||
</div>
|
||||
<p style="margin-top:1.1rem; color:var(--muted);">
|
||||
Hier entsteht noch Großes... ✨ Bleib dran!
|
||||
Für ServiceClash, NetWorker und FinalProtocol gibt es derzeit bewusst keine
|
||||
Inhaltsverwaltung: Ihre Aufgaben werden noch direkt mit der Anwendung ausgeliefert.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
<script src="/js/theme.js"></script>
|
||||
<style>
|
||||
.mf-cardbox { max-width:560px; text-align:center; }
|
||||
.mf-rocket { font-size:3rem; margin-bottom:.6rem; filter:drop-shadow(0 0 14px var(--glow-s)); }
|
||||
.mf-cardbox h1 { color:var(--heading); font-size:1.5rem; font-weight:800; margin-bottom:.5rem; }
|
||||
.mf-cardbox .slogan { color:var(--muted); font-size:.95rem; margin-bottom:1.6rem; }
|
||||
.mf-cardbox .quote { color:var(--accent); font-size:1.05rem; line-height:1.6; font-style:italic;
|
||||
@@ -23,9 +22,8 @@
|
||||
|
||||
<div class="mf-center">
|
||||
<div class="mf-cardbox">
|
||||
<div class="mf-rocket">🚀</div>
|
||||
<h1>Zukunft in Arbeit</h1>
|
||||
<p class="slogan">Hier entsteht etwas, das eure Zeitlinie verändern wird...</p>
|
||||
<h1>Bereich in Vorbereitung</h1>
|
||||
<p class="slogan">Hier entsteht ein weiterer Knoten für dein Lernnetz.</p>
|
||||
|
||||
<p class="quote">
|
||||
"Dieser Bereich wird gerade für dein Lernnetz vorbereitet."
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
<input id="reg-password2" class="mf-input" type="password" name="confirmPassword" placeholder="Passwort wiederholen" required>
|
||||
</div>
|
||||
<p id="reg-pw-msg" class="mf-alert err" style="display:none">Die Passwörter stimmen nicht überein.</p>
|
||||
<button class="neon-btn" type="submit"><span class="lock">🚀</span> Account erstellen</button>
|
||||
<button class="neon-btn" type="submit">Account erstellen</button>
|
||||
</form>
|
||||
|
||||
<p class="mobile-switch">Schon dabei? <a data-goto="login">Zum Login</a></p>
|
||||
|
||||
@@ -81,8 +81,9 @@
|
||||
|
||||
<!-- Diagramme -->
|
||||
<script th:inline="javascript">
|
||||
// Theme-Tokens auslesen, damit die Charts in Dark (Grün) & Light (Magenta) passen
|
||||
const css = getComputedStyle(document.documentElement);
|
||||
// Die Plattform-Tokens liegen auf body.sn-platform. Von dort lesen, damit die
|
||||
// Diagramme nicht auf die alte globale Akzentfarbe zurückfallen.
|
||||
const css = getComputedStyle(document.body);
|
||||
const accent = css.getPropertyValue('--accent').trim() || '#2bd96a';
|
||||
const track = css.getPropertyValue('--surface-2').trim() || '#2c2c2c';
|
||||
const tick = css.getPropertyValue('--text').trim() || '#f1f1f1';
|
||||
|
||||
Reference in New Issue
Block a user