34b050503d
- Rechtsseiten: Impressum-Platzhalter + echte Nutzungsbedingungen/AGB, Datenschutz (DSGVO) und Richtlinien; LegalController/ImpressumController, Footer app-weit verlinkt, Seiten als permitAll freigegeben. - FinalFlux: 28 Themen / ~742 Fragen überarbeitet (plausible Distraktoren statt Dummy-Antworten, echte Erklärungen) + echte Lehrtexte je Seite; Netzwerktopologien mit Inline-SVG-Diagrammen (Stern/Bus/Ring/Mesh/Baum). - Login/Registrierung als kombiniertes Dual-Panel (Slide-Overlay + Neon-Hover- Button), ausgelagert nach auth.css; Register-Duplikat -> /?registerError. - Konto löschen repariert: @Transactional + Löschen von Spielständen, Achievements und Profilbild-Datei (DSGVO Art. 17). Impressum-Zurück-Link login-abhängig. - App-weiter Farb-Relaunch auf "Back to the Future"-Palette: Feuer-Amber primär + Flux-Blau sekundär, warmer Glow; Dark/Light bleiben. Spiele-Feedback ohne Grün: richtig = Blau + Haken, falsch = Rot + Kreuz (neue Tokens --success/--danger/--secondary). Legacy-Cyan in style.css auf Variablen. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
208 lines
14 KiB
HTML
208 lines
14 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de" data-theme="dark"
|
||
xmlns:th="http://www.thymeleaf.org"
|
||
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity6">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Mindflux Dashboard</title>
|
||
<link rel="stylesheet" href="/css/theme.css">
|
||
<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; }
|
||
.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; }
|
||
.prog-big b { color:var(--heading); font-size:2rem; font-weight:800; } .prog-big b span{ font-size:1rem; color:var(--muted); }
|
||
.xpbadge { font-size:.66rem; color:var(--accent); background:var(--surface-2); border:1px solid var(--border-accent); border-radius:6px; padding:.15rem .45rem; margin-left:auto; }
|
||
.chart svg { width:100%; height:74px; } .chart .days { display:flex; justify-content:space-between; color:var(--muted); font-size:.6rem; margin-top:.25rem; }
|
||
.cat { display:flex; align-items:center; gap:.6rem; margin:.55rem 0; font-size:.78rem; }
|
||
.cat svg { width:15px; height:15px; color:var(--accent); flex:0 0 auto; }
|
||
.cat .nm { color:var(--text); width:92px; flex:0 0 auto; }
|
||
.cat .cbar { flex:1; height:6px; border-radius:99px; background:var(--surface-2); border:1px solid var(--border); overflow:hidden; }
|
||
.cat .cbar i { display:block; height:100%; background:linear-gradient(90deg,var(--accent),var(--accent-2)); box-shadow:0 0 8px var(--glow-w); }
|
||
.cat .pct { color:var(--muted); width:30px; text-align:right; }
|
||
.challenge .ch-row { display:flex; gap:.7rem; }
|
||
.challenge .bolt { color:var(--accent); flex:0 0 auto; filter:drop-shadow(0 0 6px var(--glow-s)); }
|
||
.challenge h5 { color:var(--accent); font-size:.82rem; letter-spacing:.04em; text-transform:uppercase; margin-bottom:.3rem; }
|
||
.challenge p { color:var(--muted); font-size:.78rem; line-height:1.45; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="mf-shell">
|
||
|
||
<!-- ===== Sidebar ===== -->
|
||
<aside class="mf-sidebar">
|
||
<a th:href="@{/dashboard}" class="mf-logo">
|
||
<span class="mark"></span>
|
||
<span class="txt"><b>MINDFLUX</b><span>KNOWLEDGE. CODE. WIN.</span></span>
|
||
</a>
|
||
|
||
<nav class="mf-nav">
|
||
<a th:href="@{/dashboard}" class="active">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/></svg>
|
||
Dashboard
|
||
</a>
|
||
<a th:href="@{/admin}" sec:authorize="hasRole('ADMIN')">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2l8 4v6c0 5-3.5 8-8 10-4.5-2-8-5-8-10V6z"/><path d="M9 12l2 2 4-4"/></svg>
|
||
Admin-Dashboard
|
||
</a>
|
||
<a th:href="@{/profile/knowledge}">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18"/></svg>
|
||
Knowledge Core
|
||
</a>
|
||
<a th:href="@{/progress}">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 20V10M10 20V4M16 20v-8M22 20H2"/></svg>
|
||
Statistiken
|
||
</a>
|
||
<a th:href="@{/profile/achievements}">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="9" r="6"/><path d="M9 14l-2 8 5-3 5 3-2-8"/></svg>
|
||
Achievements
|
||
</a>
|
||
<a th:href="@{/profile/settings}">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3.2"/><path d="M19 12a7 7 0 0 0-.1-1l2-1.6-2-3.4-2.4 1a7 7 0 0 0-1.7-1L14.5 2h-4l-.3 2.5a7 7 0 0 0-1.7 1l-2.4-1-2 3.4 2 1.6a7 7 0 0 0 0 2l-2 1.6 2 3.4 2.4-1a7 7 0 0 0 1.7 1l.3 2.5h4l.3-2.5a7 7 0 0 0 1.7-1l2.4 1 2-3.4-2-1.6c.1-.3.1-.7.1-1z"/></svg>
|
||
Einstellungen
|
||
</a>
|
||
</nav>
|
||
|
||
<a th:href="@{/profile}" class="mf-profile" style="text-decoration:none">
|
||
<div class="row">
|
||
<span class="mf-avatar" th:text="${#authentication.name != null ? #authentication.name.substring(0,1).toUpperCase() : 'U'}">A</span>
|
||
<div>
|
||
<b sec:authentication="name">Alice Darkest</b>
|
||
<span class="role" sec:authorize="hasRole('ADMIN')">Administrator</span>
|
||
<span class="role" sec:authorize="!hasRole('ADMIN')">Mitglied</span>
|
||
</div>
|
||
<svg style="margin-left:auto;color:var(--muted);width:18px;height:18px" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 9l6 6 6-6"/></svg>
|
||
</div>
|
||
</a>
|
||
|
||
<div class="mf-meta">
|
||
<div class="lvl">LEVEL <b>12</b></div>
|
||
<div class="xp">3250 / 5000 XP</div>
|
||
<div class="mf-bar"><i style="width:65%"></i></div>
|
||
</div>
|
||
<div class="mf-streak">
|
||
<span class="fire">🔥</span><span><b>STREAK</b><small>7 Tage in Folge</small></span>
|
||
</div>
|
||
|
||
<div class="mf-brain">
|
||
<svg viewBox="0 0 120 110" fill="none" stroke="var(--accent)" stroke-width="1.4">
|
||
<path d="M60 12c-14-8-34-2-36 14-10 4-12 18-4 26-4 10 2 22 14 24 4 8 18 10 26 4 8 6 22 4 26-4 12-2 18-14 14-24 8-8 6-22-4-26-2-16-22-22-36-14z"/>
|
||
<path d="M60 16v82M40 30c8 4 8 14 0 18M80 30c-8 4-8 14 0 18M34 60c10 0 14 8 14 16M86 60c-10 0-14 8-14 16M48 44h24M44 76h32"/>
|
||
</svg>
|
||
</div>
|
||
</aside>
|
||
|
||
<!-- ===== Topbar ===== -->
|
||
<header class="mf-topbar">
|
||
<div class="mf-hello">
|
||
<h1>Willkommen zurück, <span class="nm" sec:authentication="name">Alice</span>! 👋</h1>
|
||
<p>Wähle ein Spielmodus, um dein Wissen auf die Probe zu stellen.</p>
|
||
</div>
|
||
<div class="mf-pulse">
|
||
<svg viewBox="0 0 200 50" fill="none" stroke="var(--accent)" stroke-width="2"><path d="M2 26h40l8-18 10 34 9-26 7 14h26l6-12 9 22 7-24h59"/></svg>
|
||
</div>
|
||
<div class="mf-tools">
|
||
<button class="mf-iconbtn" aria-label="Benachrichtigungen"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 8a6 6 0 0 0-12 0c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.7 21a2 2 0 0 1-3.4 0"/></svg></button>
|
||
<div class="mf-search"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4-4"/></svg><input placeholder="Suche..."></div>
|
||
<button class="mf-theme"></button>
|
||
<a class="mf-iconbtn" href="/logout" aria-label="Logout" style="color:var(--danger)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4M16 17l5-5-5-5M21 12H9"/></svg></a>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- ===== Spielkarten ===== -->
|
||
<main class="mf-main"><div class="mf-grid" id="grid"></div></main>
|
||
|
||
<!-- ===== 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="M60 38l16 6v12c0 11-8 17-16 20-8-3-16-9-16-20V44z" fill="none" stroke="var(--accent)" stroke-width="3"/>
|
||
<path d="M52 58l6 6 12-12" stroke="var(--accent)" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||
</svg>
|
||
<div class="ok">ALLE SYSTEME STABIL</div><div class="op">100% OPERATIONAL</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mf-panel">
|
||
<div class="prog-top"><h4 style="margin:0"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 17l6-6 4 4 8-8"/></svg> Dein Fortschritt</h4><span class="pill">Woche ▾</span></div>
|
||
<div class="op" style="color:var(--muted);font-size:.72rem;margin:.2rem 0">Gesamtfortschritt</div>
|
||
<div class="prog-big"><b>65<span>%</span></b><span class="xpbadge">+120 XP</span></div>
|
||
<div class="chart">
|
||
<svg viewBox="0 0 240 74" preserveAspectRatio="none">
|
||
<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="M0 60 L34 50 L70 56 L104 38 L140 44 L176 24 L210 30 L240 14 L240 74 L0 74 Z" fill="url(#ar)"/>
|
||
<path d="M0 60 L34 50 L70 56 L104 38 L140 44 L176 24 L210 30 L240 14" fill="none" stroke="var(--accent)" stroke-width="2" style="filter:drop-shadow(0 0 5px var(--glow-s))"/>
|
||
<circle cx="176" cy="24" r="3.5" fill="var(--accent)"/>
|
||
</svg>
|
||
<div class="days"><span>Mo</span><span>Di</span><span>Mi</span><span>Do</span><span>Fr</span><span>Sa</span><span>So</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mf-panel" id="cats">
|
||
<h4><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2l3 6 6 .5-4.5 4 1.5 6.5L12 16l-6 3 1.5-6.5L3 8.5 9 8z"/></svg> Top Kategorien</h4>
|
||
</div>
|
||
|
||
<div class="mf-panel accent challenge">
|
||
<div class="ch-row">
|
||
<svg class="bolt" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M13 2L4 14h7l-1 8 9-12h-7z"/></svg>
|
||
<div><h5>Bereit für die nächste Challenge?</h5><p>Starte jetzt ein Spiel und steigere dein Level!</p></div>
|
||
</div>
|
||
<a class="mf-btn" href="/mindmatch" style="margin-top:.8rem">LOS GEHT'S! <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14M13 6l6 6-6 6"/></svg></a>
|
||
</div>
|
||
</aside>
|
||
</div>
|
||
|
||
<footer class="mf-footer">
|
||
<a href="#">Support</a>
|
||
<a href="#">Feedback</a>
|
||
<a href="/nutzungsbedingungen">Nutzungsbedingungen</a>
|
||
<a href="/richtlinien">Richtlinien</a>
|
||
<a href="/datenschutz">Datenschutz</a>
|
||
<a href="/impressum">Impressum</a>
|
||
</footer>
|
||
|
||
<script th:inline="none">
|
||
const GI = {
|
||
brain:'<path d="M28 8c-9-5-22 0-23 11-7 2-9 12-3 18-3 7 2 15 10 16 3 6 13 7 18 2M28 8c9-5 22 0 23 11 7 2 9 12 3 18 3 7-2 15-10 16-3 6-13 7-18 2M28 8v45M16 22c6 2 6 10 0 13M40 22c-6 2-6 10 0 13M12 40c7 0 10 5 10 11M44 40c-7 0-10 5-10 11"/>',
|
||
code:'<path d="M22 16L8 28l14 12M42 16l14 12-14 12"/>',
|
||
terminal:'<rect x="6" y="10" width="52" height="44" rx="4"/><path d="M16 26l9 6-9 6M32 40h14"/>',
|
||
lock:'<rect x="12" y="28" width="40" height="28" rx="5"/><path d="M20 28v-7a12 12 0 0 1 24 0v7M32 39v6"/>',
|
||
sword:'<path d="M48 8l4 4-22 22-4-4zM26 30l8 8M30 26l8 8M22 38l-6 6 6 6 6-6M16 44l-6 6"/>',
|
||
bug:'<rect x="20" y="20" width="24" height="30" rx="12"/><path d="M32 20v-6M24 12l4 6M40 12l-4 6M20 30h-8M52 30h-8M20 40H10M54 40H44M20 50l-7 7M44 50l7 7"/>',
|
||
network:'<circle cx="32" cy="14" r="6"/><circle cx="14" cy="48" r="6"/><circle cx="50" cy="48" r="6"/><path d="M30 19L17 43M34 19l13 24M20 48h24"/>',
|
||
trophy:'<path d="M18 10h28v10a14 14 0 0 1-28 0zM18 14h-7v3a9 9 0 0 0 9 9M46 14h7v3a9 9 0 0 1-9 9M26 40h12M24 40v6h16v-6M20 56h24"/>'
|
||
};
|
||
const GAMES = [
|
||
['MindMatch','brain','Trainiere dein Gedächtnis mit IT-Begriffen in einem klassischen Memory-Spiel.','/mindmatch'],
|
||
['TechTacular','code','Das IT-Quizduell im Jeopardy-Stil – teste dein Wissen in verschiedenen Kategorien.','/techtacular'],
|
||
['Syntax Saga','terminal','Interaktive IT-Geschichten mit Lückentexten – wie ein Textadventure zum Mitdenken.','/comingsoon'],
|
||
['Code Escape Room','lock','Entkomme mit IT-Rätseln aus digitalen Räumen – sei schnell und clever.','/comingsoon'],
|
||
['Service Clash','sword','Der chaotische Admin-Alltag als Spiel – meistere Anfragen & halte Systeme am Laufen!','/comingsoon'],
|
||
['Bug Hunter','bug','Finde Fehler im Code, denke wie ein Debugger und löse knifflige Bugs.','/comingsoon'],
|
||
['Netzwerker – Das Router-Rätselspiel','network','Verbinde Netzwerke, konfiguriere IPs und löse Routing-Herausforderungen.','/comingsoon'],
|
||
['FinalFlux','trophy','Dein Power-Modul für die Prüfung – gezielt lernen, strukturiert trainieren, sicher bestehen.','/finalflux']
|
||
];
|
||
document.getElementById('grid').innerHTML = GAMES.map(([t,ic,d,href])=>`
|
||
<a class="mf-card" href="${href}">
|
||
<span class="ico"><svg viewBox="0 0 64 64" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round">${GI[ic]}</svg></span>
|
||
<h3>${t}</h3><p>${d}</p>
|
||
<span class="mf-play">SPIEL STARTEN <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span>
|
||
</a>`).join('');
|
||
|
||
const SVG={globe:'<circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18"/>',chart:'<path d="M4 20V10M10 20V4M16 20v-8M22 20H2"/>',lock:'<rect x="5" y="11" width="14" height="9" rx="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/>',grid:'<rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/>',code:'<path d="M8 7l-5 5 5 5M16 7l5 5-5 5"/>'};
|
||
const CATS=[['Netzwerk','globe',85],['Datenbanken','chart',78],['IT-Sicherheit','lock',72],['Hardware','grid',66],['Programmierung','code',60]];
|
||
document.getElementById('cats').innerHTML += CATS.map(([n,i,p])=>`<div class="cat"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${SVG[i]}</svg><span class="nm">${n}</span><span class="cbar"><i style="width:${p}%"></i></span><span class="pct">${p}%</span></div>`).join('');
|
||
</script>
|
||
</body>
|
||
</html>
|