Atlas: Infrastruktur + Team-Konventionen + Sprachregel Lernarbeit

- Design-System (assets/css/design-system.css) mit 21 Komponenten,
  iPad-Responsive-Breakpoints, Touch-Ziele 36px, Music-Player,
  Glossar-Tooltips
- Templates (sims/template.html + student/teacher-Dashboard)
- Docs: module-interface.md (inkl. 4a Sprachregel, 4b Leichte Sprache,
  4c iPad), content-architecture.md, crash-recovery.md, music-registry.md
- Admin-Infrastruktur: admin-modules.html + api/admin-modules.php
  (Titel, Emoji, Bild, Status, Dauer, Alter pro Modul)
- Inbox-System: _inbox/README.md + _status.md fuer Atlas + Briefings
  an Klima, Glossar, Lehrplan, Fluss
- Zentrale SFX-Pipeline (scripts/generate-sounds.py)
- DALL-E-Bilder: 8 Badges + 5 Glossar-Repraesentationsbilder (Querformat)
- Logo + Inter-Font lokal
- PHP-APIs: admin, glossar, levels, licenses, progress, waypoints,
  assignments, profile, tickets
- Spielsprache entfernt (admin-modules, admin-levels, schueler)
- Landing-Page-Bearbeitungen (Boote sichtbarer, Button-Hintergrund)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-19 11:51:14 +02:00
parent 2136bbbe62
commit 9a61f55cb1
134 changed files with 1012826 additions and 690 deletions
+108
View File
@@ -0,0 +1,108 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GeoGraSim — Administration</title>
<link rel="icon" type="image/png" href="favicon-96x96.png" sizes="96x96"><link rel="icon" type="image/svg+xml" href="favicon.svg">
<link rel="stylesheet" href="assets/fonts/inter.css">
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'Inter',sans-serif;background:#1f4e5a;min-height:100vh;display:flex;align-items:center;justify-content:center}
.card{background:#fff;border-radius:16px;padding:2rem;max-width:380px;width:90%;box-shadow:0 12px 40px rgba(0,0,0,.2)}
.logo{text-align:center;margin-bottom:1rem}
.logo img{height:36px}
.logo p{font-size:.7rem;color:#8a8a8a;margin-top:.3rem}
h2{font-size:1rem;font-weight:800;color:#1f4e5a;margin-bottom:.8rem;text-align:center}
label{display:block;font-size:.7rem;font-weight:600;color:#4a4a4a;margin-bottom:.15rem;margin-top:.6rem}
input{width:100%;padding:.55rem .7rem;border:1.5px solid rgba(0,0,0,.1);border-radius:7px;font-size:.82rem;font-family:inherit;outline:none;transition:border .15s}
input:focus{border-color:#4a7c8a}
.pin-input{text-align:center;font-size:1.5rem;font-weight:900;letter-spacing:.3em;font-family:'Courier New',monospace;color:#1f4e5a}
.btn{width:100%;padding:.6rem;border:none;border-radius:8px;background:#1f4e5a;color:#fff;font-size:.85rem;font-weight:700;cursor:pointer;margin-top:.8rem;transition:background .15s}
.btn:hover{background:#163a44}
.msg{margin-top:.6rem;font-size:.72rem;padding:.4rem .6rem;border-radius:6px;display:none}
.msg.err{display:block;background:#f2ddd8;color:#c07a6b}
.msg.ok{display:block;background:#dceadd;color:#5a8a5e}
.hidden{display:none}
.step-hint{font-size:.68rem;color:#8a8a8a;text-align:center;margin-bottom:.6rem}
</style>
</head>
<body>
<div class="card">
<div class="logo">
<img src="assets/img/geograsim_t.svg" alt="GeoGraSim">
<p>Administration</p>
</div>
<!-- Schritt 1: Login -->
<div id="step-login">
<h2>🔐 Admin-Anmeldung</h2>
<label>Benutzername</label>
<input type="text" id="a-user" autocomplete="off">
<label>Passwort</label>
<input type="password" id="a-pass">
<button class="btn" onclick="doLogin()">Anmelden</button>
</div>
<!-- Schritt 2: PIN -->
<div id="step-pin" class="hidden">
<h2>📧 PIN eingeben</h2>
<p class="step-hint">Ein 4-stelliger PIN wurde an <strong id="pin-email"></strong> gesendet.</p>
<input type="text" id="a-pin" class="pin-input" maxlength="4" placeholder="0000" autocomplete="off">
<button class="btn" onclick="doVerify()">Bestätigen</button>
</div>
<div class="msg" id="msg"></div>
</div>
<script>
var BASE = (window.__GGS__?.baseUrl) || '';
if (!BASE) { var p = location.pathname, i = p.indexOf('/geograsim'); if (i !== -1) { var rest = p.substring(i + '/geograsim'.length); BASE = rest.indexOf('/App/') === 0 ? p.substring(0, i) + '/geograsim/App' : p.substring(0, i) + '/geograsim'; } }
async function api(data) {
var r = await fetch(BASE + '/api/admin', {
method:'POST', headers:{'Content-Type':'application/json'}, credentials:'same-origin',
body: JSON.stringify(data)
});
return await r.json();
}
function showMsg(text, type) {
var m = document.getElementById('msg');
m.textContent = text; m.className = 'msg ' + type;
}
async function doLogin() {
var user = document.getElementById('a-user').value.trim();
var pass = document.getElementById('a-pass').value;
if (!user || !pass) { showMsg('Bitte ausfüllen.', 'err'); return; }
showMsg('Anmelden...', 'ok');
var r = await api({action:'login', username:user, password:pass});
if (r.error) { showMsg(r.error, 'err'); return; }
document.getElementById('pin-email').textContent = r.email || '***';
document.getElementById('step-login').classList.add('hidden');
document.getElementById('step-pin').classList.remove('hidden');
document.getElementById('msg').className = 'msg';
document.getElementById('a-pin').focus();
}
async function doVerify() {
var pin = document.getElementById('a-pin').value.trim();
if (pin.length !== 4) { showMsg('Bitte 4-stelligen PIN eingeben.', 'err'); return; }
var r = await api({action:'verify_pin', pin:pin});
if (r.error) { showMsg(r.error, 'err'); return; }
showMsg('Zugang gewährt!', 'ok');
setTimeout(function() { location.href = 'admin-licenses.html'; }, 600);
}
// Auto-redirect if already authenticated
api({action:'status'}).then(function(r) {
if (r.authenticated) location.href = 'admin-licenses.html';
});
// Enter key handling
document.getElementById('a-pass').addEventListener('keydown', function(e) { if(e.key==='Enter') doLogin(); });
document.getElementById('a-pin').addEventListener('keydown', function(e) { if(e.key==='Enter') doVerify(); });
</script>
</body>
</html>