Syntax Saga: neues Spiel (server-autoritativ) + 34 Seed-Missionen
Drittes Mindflux-Spiel: interaktive IT-Geschichten, in denen man den fehlenden Code (Schlüsselwörter, Operatoren, ganze Zeilen) in eine kleine Story tippt. Freitext-Eingabe, drei wählbare Stufen (Junior/Professional/ Senior), mehrere Lücken je Codeblock und mehrere gültige Antworten je Lücke (optional case-insensitive). Prüfung und Score ausschließlich serverseitig – die Lösungen verlassen nie das Backend (Anti-Cheat wie TechTacular/MindMatch). Fehler-Mechanik: bis zu 3 Versuche mit Hinweis, dann Auflösung; kein Game-Over. Inhalte DB-gestützt und im Admin pflegbar (/admin/syntaxsaga); 34 Seed- Missionen (Java/SQL/Bash/Git/HTML/Python) aus syntaxsaga/content.json. - Entities SyntaxSagaMission/Gap/Solution + Flyway V7__syntax_saga.sql - SyntaxSagaService (Story ohne Lösung / serverseitige Prüfung / Score-Recompute) - API /api/syntaxsaga (CSRF-ausgenommen) + Admin-CRUD - Frontend syntaxsaga.html/js/css (Prefix ss-, theme.css-Tokens) - Dashboard-Kachel aktiv (vorher "coming soon") Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -46,6 +46,7 @@
|
||||
<a th:href="@{/admin/users}" class="admin-card">👤 Benutzer verwalten</a>
|
||||
<a th:href="@{/admin/mindmatch}" class="admin-card">🧩 MindMatch-Decks verwalten</a>
|
||||
<a th:href="@{/admin/techtacular}" class="admin-card">🎯 TechTacular-Fragen verwalten</a>
|
||||
<a th:href="@{/admin/syntaxsaga}" class="admin-card">📜 Syntax-Saga-Missionen verwalten</a>
|
||||
</div>
|
||||
<p style="margin-top:1.1rem; color:var(--muted);">
|
||||
Hier entsteht noch Großes... ✨ Bleib dran!
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
<!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 th:text="${mission.title} + ' – Syntax Saga'">Syntax-Saga-Mission</title>
|
||||
<link rel="stylesheet" href="/css/theme.css">
|
||||
<script src="/js/theme.js"></script>
|
||||
<style>
|
||||
.ssm { max-width: 1000px; margin: 0 auto; padding: 0 1rem; width: 100%; }
|
||||
.ssm .grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0.7rem; }
|
||||
.ssm .field { margin-bottom: 0.7rem; display: flex; flex-direction: column; gap: 0.35rem; }
|
||||
.ssm .field > label { color: var(--accent); font-weight: 700; font-size: 0.85rem; }
|
||||
.ssm textarea.mf-input { font-family: monospace; resize: vertical; min-height: 4.5rem; }
|
||||
.ssm textarea.prose { font-family: inherit; }
|
||||
.ssm .gap {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-left: 4px solid var(--secondary);
|
||||
border-radius: 12px; padding: 0.9rem 1.1rem; margin-bottom: 0.7rem;
|
||||
box-shadow: var(--g-soft);
|
||||
}
|
||||
.ssm .gap-head { display: flex; align-items: center; gap: 0.6rem; justify-content: space-between; flex-wrap: wrap; }
|
||||
.ssm .pos { background: var(--glow-w); color: var(--accent); font-weight: 800; border: 1px solid var(--border-accent); border-radius: 7px; padding: 0.14rem 0.55rem; font-size: 0.85rem; }
|
||||
.ssm .meta { color: var(--muted); font-size: 0.82rem; }
|
||||
.ssm ul.sols { list-style: none; padding: 0; margin: 0.4rem 0 0; }
|
||||
.ssm ul.sols li { color: var(--secondary); font-family: monospace; padding: 0.12rem 0; }
|
||||
.ssm ul.sols li::before { content: "✓ "; }
|
||||
.ssm .gap-hint { color: var(--muted); font-size: 0.85rem; margin-top: 0.35rem; }
|
||||
.ssm .addbox { margin-top: 1.6rem; }
|
||||
.ssm .hint { color: var(--muted); font-size: 0.82rem; margin-bottom: 0.8rem; line-height: 1.5; }
|
||||
.ssm .hint code { color: var(--accent); }
|
||||
.ssm .empty { color: var(--danger); }
|
||||
.ssm .check-row { display: flex; align-items: center; gap: 0.45rem; color: var(--accent); font-size: 0.85rem; }
|
||||
@media (max-width: 600px) { .ssm .grid2 { grid-template-columns: 1fr; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="mf-theme-float"><button class="mf-theme"></button></div>
|
||||
|
||||
<div class="mf-container" style="max-width:1040px">
|
||||
|
||||
<div class="mf-page-head">
|
||||
<a th:href="@{/admin/syntaxsaga}" class="mf-back">⟵ Zurück zur Missionsliste</a>
|
||||
</div>
|
||||
|
||||
<header style="margin-bottom:1.4rem">
|
||||
<div class="mf-eyebrow">Syntax Saga · Mission</div>
|
||||
<h1 style="color:var(--heading); font-size:1.75rem; font-weight:800; margin-top:.35rem" th:text="'📜 ' + ${mission.title}">Mission</h1>
|
||||
</header>
|
||||
|
||||
<main class="ssm">
|
||||
|
||||
<!-- Mission bearbeiten -->
|
||||
<div class="mf-panel">
|
||||
<h4>Mission bearbeiten</h4>
|
||||
<form th:action="@{'/admin/syntaxsaga/missions/' + ${mission.id} + '/update'}" method="post">
|
||||
<div class="grid2">
|
||||
<div class="field">
|
||||
<label>Titel</label>
|
||||
<input class="mf-input" type="text" name="title" th:value="${mission.title}" required>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Schwierigkeit</label>
|
||||
<select class="mf-select" name="difficulty">
|
||||
<option value="junior" th:selected="${mission.difficulty == 'junior'}">Junior</option>
|
||||
<option value="professional" th:selected="${mission.difficulty == 'professional'}">Professional</option>
|
||||
<option value="senior" th:selected="${mission.difficulty == 'senior'}">Senior</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Erzähltext / Szene</label>
|
||||
<textarea class="mf-input prose" name="narrative" th:text="${mission.narrative}"></textarea>
|
||||
</div>
|
||||
<div class="grid2">
|
||||
<div class="field">
|
||||
<label>Dialog (optional)</label>
|
||||
<input class="mf-input" type="text" name="dialog" th:value="${mission.dialog}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Sprache (optional)</label>
|
||||
<input class="mf-input" type="text" name="language" th:value="${mission.language}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Code mit Lücken (<code>{{1}}</code>, <code>{{2}}</code> …)</label>
|
||||
<textarea class="mf-input" name="codeTemplate" rows="6" th:text="${mission.codeTemplate}" required></textarea>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Erfolgstext (optional)</label>
|
||||
<textarea class="mf-input prose" name="successText" th:text="${mission.successText}"></textarea>
|
||||
</div>
|
||||
<button type="submit" class="mf-btn">💾 Mission speichern</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Vorhandene Lücken -->
|
||||
<h4 style="color:var(--accent); margin:1.4rem 0 0.7rem; text-transform:uppercase; letter-spacing:.08em; font-size:.8rem">Lücken</h4>
|
||||
|
||||
<div class="gap" th:each="g : ${mission.gaps}">
|
||||
<div class="gap-head">
|
||||
<span class="pos" th:text="'Lücke {{' + ${g.position} + '}}'">Lücke {{1}}</span>
|
||||
<span class="meta">
|
||||
<span th:text="${g.points} + ' Pkt'">100 Pkt</span> ·
|
||||
<span th:text="${g.caseSensitive} ? 'Groß/Klein beachten' : 'Groß/Klein egal'">Groß/Klein</span>
|
||||
</span>
|
||||
<form th:action="@{'/admin/syntaxsaga/gaps/' + ${g.id} + '/delete'}" method="post"
|
||||
onsubmit="return confirm('Lücke löschen?');">
|
||||
<input type="hidden" name="missionId" th:value="${mission.id}">
|
||||
<button type="submit" class="mf-btn danger">✕ Lücke löschen</button>
|
||||
</form>
|
||||
</div>
|
||||
<ul class="sols">
|
||||
<li th:each="s : ${g.solutions}" th:text="${s.text}">Lösung</li>
|
||||
</ul>
|
||||
<p class="gap-hint" th:if="${g.hint}" th:text="'Hinweis: ' + ${g.hint}">Hinweis</p>
|
||||
</div>
|
||||
|
||||
<p th:if="${mission.gaps.isEmpty()}" class="empty">Noch keine Lücken – unten hinzufügen. Ohne Lücken erscheint die Mission nicht im Spiel.</p>
|
||||
|
||||
<!-- Lücke hinzufügen -->
|
||||
<div class="mf-panel accent addbox">
|
||||
<h4>Lücke hinzufügen</h4>
|
||||
<p class="hint">Die <strong>Position</strong> muss zum Marker <code>{{n}}</code> im Code passen.
|
||||
Trage die gültigen <strong>Lösungen</strong> ein – eine pro Zeile (mehrere Zeilen = mehrere akzeptierte Antworten,
|
||||
z. B. <code>192.168.0.1</code> und <code>localhost</code>).</p>
|
||||
<form th:action="@{'/admin/syntaxsaga/missions/' + ${mission.id} + '/gaps'}" method="post">
|
||||
<div class="grid2">
|
||||
<div class="field">
|
||||
<label>Position ({{n}})</label>
|
||||
<input class="mf-input" type="number" name="position" min="1" placeholder="1" required>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Punkte</label>
|
||||
<input class="mf-input" type="number" name="points" min="10" max="1000" value="100">
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid2">
|
||||
<div class="field">
|
||||
<label>Platzhalter (optional)</label>
|
||||
<input class="mf-input" type="text" name="placeholder" placeholder="z. B. Methodenname">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Hinweis (optional)</label>
|
||||
<input class="mf-input" type="text" name="hint" placeholder="kurzer Tipp nach falschem Versuch">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Gültige Lösungen (eine pro Zeile)</label>
|
||||
<textarea class="mf-input" name="solutions" rows="3" placeholder="main" required></textarea>
|
||||
</div>
|
||||
<label class="check-row" style="margin-bottom:.7rem">
|
||||
<input type="checkbox" name="caseSensitive" value="true" checked> Groß-/Kleinschreibung beachten (für Java-Bezeichner; bei SQL-Keywords abwählen)
|
||||
</label>
|
||||
<button type="submit" class="mf-btn">➕ Lücke speichern</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
</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>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,140 @@
|
||||
<!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>Syntax-Saga-Verwaltung – Admin</title>
|
||||
<link rel="stylesheet" href="/css/theme.css">
|
||||
<script src="/js/theme.js"></script>
|
||||
<style>
|
||||
.ssadmin { max-width: 1000px; margin: 0 auto; padding: 0 1rem; width: 100%; }
|
||||
.ssadmin .new-mission { margin-bottom: 1.6rem; }
|
||||
.ssadmin .grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0.7rem; }
|
||||
.ssadmin .mission {
|
||||
display: flex; align-items: center; flex-wrap: wrap; gap: 0.6rem;
|
||||
justify-content: space-between;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-left: 4px solid var(--accent);
|
||||
border-radius: 12px; padding: 0.9rem 1.1rem; margin-bottom: 0.7rem;
|
||||
box-shadow: var(--g-soft);
|
||||
}
|
||||
.ssadmin .mission.inactive { border-left-color: var(--danger); opacity: 0.7; }
|
||||
.ssadmin .mission h2 { color: var(--heading); margin: 0; font-size: 1.05rem; }
|
||||
.ssadmin .slug { color: var(--accent); font-size: 0.78rem; font-family: monospace; }
|
||||
.ssadmin .count { color: var(--muted); font-size: 0.85rem; }
|
||||
.ssadmin .badge { font-size: 0.66rem; text-transform: uppercase; padding: 0.14rem 0.45rem; border-radius: 7px; border: 1px solid var(--border-accent); color: var(--secondary); border-color: var(--secondary); }
|
||||
.ssadmin .badge.on { background: var(--glow-w); color: var(--accent); border-color: var(--border-accent); }
|
||||
.ssadmin .badge.off { background: rgba(255,95,107,.12); color: var(--danger); border-color: var(--danger); }
|
||||
.ssadmin .actions { display: flex; gap: 0.45rem; flex-wrap: wrap; align-items: center; }
|
||||
.ssadmin .field { margin-bottom: 0.7rem; display: flex; flex-direction: column; gap: 0.35rem; }
|
||||
.ssadmin .field > label { color: var(--accent); font-weight: 700; font-size: 0.85rem; }
|
||||
.ssadmin textarea.mf-input { min-height: 4.5rem; font-family: monospace; resize: vertical; }
|
||||
.ssadmin .hint { color: var(--muted); font-size: 0.82rem; margin-bottom: 0.8rem; line-height: 1.5; }
|
||||
.ssadmin .hint code { color: var(--accent); }
|
||||
.ssadmin .empty { color: var(--muted); }
|
||||
@media (max-width: 600px) { .ssadmin .grid2 { grid-template-columns: 1fr; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="mf-theme-float"><button class="mf-theme"></button></div>
|
||||
|
||||
<div class="mf-container" style="max-width:1040px">
|
||||
|
||||
<div class="mf-page-head">
|
||||
<a th:href="@{/admin}" class="mf-back">⟵ Zurück zum Admin-Dashboard</a>
|
||||
</div>
|
||||
|
||||
<header style="margin-bottom:1.4rem">
|
||||
<div class="mf-eyebrow">Syntax Saga</div>
|
||||
<h1 style="color:var(--heading); font-size:1.75rem; font-weight:800; margin-top:.35rem">📜 Syntax-Saga-Verwaltung</h1>
|
||||
</header>
|
||||
|
||||
<main class="ssadmin">
|
||||
|
||||
<div class="mf-panel accent new-mission">
|
||||
<h4>Neue Mission anlegen</h4>
|
||||
<p class="hint">Markiere die Lücken im Code mit <code>{{1}}</code>, <code>{{2}}</code> … – die Nummer
|
||||
ist die Position der Lücke. Die gültigen Lösungen trägst du nach dem Anlegen je Lücke ein.</p>
|
||||
<form th:action="@{/admin/syntaxsaga/missions}" method="post">
|
||||
<div class="grid2">
|
||||
<div class="field">
|
||||
<label>Titel</label>
|
||||
<input class="mf-input" type="text" name="title" placeholder="z. B. Hello World" required>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Schwierigkeit</label>
|
||||
<select class="mf-select" name="difficulty">
|
||||
<option value="junior">Junior (eine Lücke)</option>
|
||||
<option value="professional">Professional (mehrere Lücken)</option>
|
||||
<option value="senior">Senior (ganze Zeile)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Erzähltext / Szene</label>
|
||||
<textarea class="mf-input" name="narrative" placeholder="Worum geht es in dieser Mission?" style="font-family:inherit"></textarea>
|
||||
</div>
|
||||
<div class="grid2">
|
||||
<div class="field">
|
||||
<label>Dialog (optional)</label>
|
||||
<input class="mf-input" type="text" name="dialog" placeholder="z. B. Bitte… repariere mich…">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Sprache (optional)</label>
|
||||
<input class="mf-input" type="text" name="language" placeholder="java / sql / bash">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Code mit Lücken</label>
|
||||
<textarea class="mf-input" name="codeTemplate" rows="5" placeholder="public class Main { public static void {{1}}(String[] args) { ... } }" required></textarea>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Erfolgstext (optional)</label>
|
||||
<textarea class="mf-input" name="successText" placeholder="Was passiert, wenn alles gelöst ist?" style="font-family:inherit"></textarea>
|
||||
</div>
|
||||
<button type="submit" class="mf-btn">➕ Mission anlegen & Lücken hinzufügen</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="mission" th:each="m : ${missions}" th:classappend="${m.active} ? '' : 'inactive'">
|
||||
<div>
|
||||
<h2 th:text="${m.title}">Mission</h2>
|
||||
<span class="slug" th:text="'/' + ${m.slug}">/slug</span>
|
||||
<span class="badge" th:text="${m.difficulty}">junior</span>
|
||||
<span class="badge on" th:if="${m.active}">aktiv</span>
|
||||
<span class="badge off" th:unless="${m.active}">inaktiv</span>
|
||||
<span class="count" th:text="'· ' + ${m.gapCount} + ' Lücken'">· 0 Lücken</span>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a class="mf-btn" th:href="@{'/admin/syntaxsaga/missions/' + ${m.id}}">Lücken verwalten</a>
|
||||
<form th:action="@{'/admin/syntaxsaga/missions/' + ${m.id} + '/toggle'}" method="post">
|
||||
<button type="submit" class="mf-btn outline" th:text="${m.active} ? 'Deaktivieren' : 'Aktivieren'">Toggle</button>
|
||||
</form>
|
||||
<form th:action="@{'/admin/syntaxsaga/missions/' + ${m.id} + '/delete'}" method="post"
|
||||
onsubmit="return confirm('Mission inkl. aller Lücken löschen?');">
|
||||
<button type="submit" class="mf-btn danger">Löschen</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p th:if="${missions.isEmpty()}" class="empty">Noch keine Missionen. Lege oben die erste an.</p>
|
||||
|
||||
</main>
|
||||
|
||||
</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>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -185,7 +185,7 @@
|
||||
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'],
|
||||
['Syntax Saga','terminal','Interaktive IT-Geschichten mit Lückentexten – wie ein Textadventure zum Mitdenken.','/syntaxsaga'],
|
||||
['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'],
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de" data-theme="dark" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Syntax Saga – Mindflux</title>
|
||||
<link rel="stylesheet" href="/css/theme.css">
|
||||
<script src="/js/theme.js"></script>
|
||||
<link rel="stylesheet" href="/css/syntaxsaga.css?v=1">
|
||||
</head>
|
||||
<body class="ss-body">
|
||||
|
||||
<div class="ss-shell">
|
||||
<header class="ss-header">
|
||||
<a href="/dashboard" class="ss-back">⟵ Dashboard</a>
|
||||
<h1 class="ss-title">Syntax Saga</h1>
|
||||
<div class="ss-header-tools">
|
||||
<button type="button" class="mf-theme"></button>
|
||||
<a href="/logout" class="ss-logout">Logout</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="ss-bar">
|
||||
<div class="ss-bar-group" aria-label="Schwierigkeit wählen">
|
||||
<span class="ss-bar-label">Stufe:</span>
|
||||
<button type="button" class="ss-diff" data-diff="junior">Junior</button>
|
||||
<button type="button" class="ss-diff" data-diff="professional">Professional</button>
|
||||
<button type="button" class="ss-diff" data-diff="senior">Senior</button>
|
||||
</div>
|
||||
<div class="ss-bar-group ss-hud" aria-live="polite">
|
||||
<span class="ss-stat">Punkte <b id="ss-score">0</b></span>
|
||||
<span class="ss-stat">Mission <b id="ss-mission">– / –</b></span>
|
||||
<span class="ss-stat">Zeit <b id="ss-time">0:00</b></span>
|
||||
<span class="ss-stat">Bestwert <b id="ss-best">–</b></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main class="ss-stage">
|
||||
<section id="ss-story" class="ss-story" aria-label="Syntax-Saga-Geschichte"></section>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- Ergebnis-Overlay -->
|
||||
<div id="ss-result" class="ss-overlay" hidden>
|
||||
<div class="ss-result-card">
|
||||
<h2>Saga beendet 🎉</h2>
|
||||
<p id="ss-result-stars" class="ss-result-stars">★★★</p>
|
||||
<p class="ss-result-score">Score: <strong id="ss-result-score">0</strong> / <span id="ss-result-max">0</span></p>
|
||||
<p id="ss-result-detail" class="ss-result-detail"></p>
|
||||
<p id="ss-result-high" class="ss-result-high" hidden>🏆 Neuer Bestwert!</p>
|
||||
<div class="ss-result-actions">
|
||||
<button type="button" id="ss-again" class="ss-btn">Nochmal</button>
|
||||
<button type="button" id="ss-choose" class="ss-btn ss-btn-secondary">Andere Stufe</button>
|
||||
<a href="/dashboard" class="ss-btn ss-btn-secondary">Dashboard</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/syntaxsaga.js?v=1" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user