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:
+108
@@ -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>
|
||||
Reference in New Issue
Block a user