Files
geograsim/App/admin-styleguide.html
T

333 lines
20 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GeoGraSim — Style-Guide (Admin)</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:#f7f6f3;min-height:100vh;color:#2a2a2a}
.topbar{background:#fff;padding:.6rem 1.2rem;display:flex;align-items:center;gap:.8rem;border-bottom:1px solid rgba(0,0,0,.06)}
.topbar h1{font-size:.95rem;font-weight:800;color:#4a7c8a;flex:1;display:flex;align-items:center;gap:.5rem}
.topbar h1 img{height:28px}
.btn-sm{padding:.3rem .6rem;border:1px solid rgba(0,0,0,.08);border-radius:6px;background:#fff;font-size:.68rem;font-weight:600;cursor:pointer;color:#4a4a4a;text-decoration:none}
.btn-sm:hover{background:#dae8ec;color:#4a7c8a}
.wrap{max-width:980px;margin:1rem auto;padding:0 1rem}
.card{background:#fff;border-radius:10px;padding:1.2rem 1.3rem;box-shadow:0 1px 4px rgba(0,0,0,.03);border:1px solid rgba(0,0,0,.04);margin-bottom:1rem}
.card-h{font-size:.65rem;font-weight:700;color:#4a7c8a;text-transform:uppercase;letter-spacing:.06em;margin-bottom:.65rem}
h2{font-size:1.15rem;font-weight:800;color:#1f4b37;margin-bottom:.4rem}
h3{font-size:.95rem;font-weight:700;color:#4a7c8a;margin:.9rem 0 .4rem}
p{font-size:.82rem;line-height:1.55;color:#4a4a4a;margin-bottom:.5rem}
p.lead{font-size:.78rem;color:#6a6a6a}
code{font-family:'JetBrains Mono','Fira Code',monospace;font-size:.78rem;background:#f0ede4;padding:.05rem .35rem;border-radius:4px;color:#1f4b37}
pre{font-family:'JetBrains Mono','Fira Code',monospace;font-size:.74rem;background:#f0ede4;padding:.7rem .9rem;border-radius:7px;color:#1f4b37;line-height:1.5;white-space:pre-wrap;word-break:break-word;margin:.4rem 0}
.copy-block{position:relative}
.copy-btn{position:absolute;top:.45rem;right:.5rem;font-size:.6rem;padding:.2rem .55rem;border:1.5px solid rgba(0,0,0,.1);border-radius:5px;background:#fff;cursor:pointer;font-weight:600;color:#4a7c8a}
.copy-btn:hover{background:#dae8ec}
.copy-btn.ok{background:#dceadd;color:#5a8a5e;border-color:#5a8a5e}
.swatches{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:.7rem;margin:.5rem 0}
.sw{border:1px solid rgba(0,0,0,.06);border-radius:7px;overflow:hidden;cursor:pointer;background:#fff;transition:transform .12s}
.sw:hover{transform:translateY(-1px);border-color:#4a7c8a}
.sw-color{height:60px}
.sw-meta{padding:.45rem .55rem;font-size:.68rem}
.sw-meta strong{display:block;color:#1f4b37}
.sw-meta span{color:#8a8a8a;font-family:'JetBrains Mono',monospace;font-size:.66rem}
.pill{display:inline-block;padding:.18rem .55rem;border-radius:999px;font-size:.65rem;font-weight:600;background:#dae8ec;color:#1f4e5a;margin-right:.3rem}
.pill.warn{background:#fde8d0;color:#a05a2b}
.pill.bad{background:#f2ddd8;color:#a04a3a}
table{width:100%;border-collapse:collapse;font-size:.76rem;margin:.4rem 0}
th{text-align:left;background:#f7f6f3;padding:.4rem .55rem;font-weight:700;color:#4a4a4a;border-bottom:2px solid rgba(0,0,0,.06)}
td{padding:.4rem .55rem;border-bottom:1px solid rgba(0,0,0,.04);vertical-align:top}
ul{margin:.3rem 0 .6rem 1.3rem;font-size:.82rem;line-height:1.55;color:#4a4a4a}
ul li{margin-bottom:.2rem}
.toc{display:flex;flex-wrap:wrap;gap:.4rem;margin-bottom:1rem}
.toc a{padding:.3rem .65rem;background:#fff;border:1.5px solid rgba(0,0,0,.06);border-radius:6px;font-size:.7rem;color:#4a7c8a;text-decoration:none;font-weight:600}
.toc a:hover{background:#dae8ec;border-color:#4a7c8a}
</style>
</head>
<body>
<div class="topbar">
<h1><img src="assets/img/geograsim_t.svg" alt="GeoGraSim"> Style-Guide (Admin)</h1>
<a href="admin-licenses.html" class="btn-sm">🔑 Lizenzen</a>
<a href="admin-modules.html" class="btn-sm">🧩 Module</a>
<a href="admin-levels.html" class="btn-sm">🎮 Level</a>
<a href="admin-accounts.html" class="btn-sm">👤 Admins</a>
<a href="admin.html" class="btn-sm">Logout</a>
</div>
<div class="wrap">
<div class="toc">
<a href="#bildstil">🎨 Bildstil</a>
<a href="#farben-bild">🌿 Bild-Farbpalette</a>
<a href="#farben-ui">🧩 UI-Farbtokens</a>
<a href="#layout">📐 Layout &amp; Spacing</a>
<a href="#typo">🔤 Typografie</a>
<a href="#bilder">🖼️ Bildformate</a>
<a href="#ipad">📱 iPad-Patterns</a>
<a href="#sprache">🗣️ Sprache</a>
</div>
<div class="card">
<h2>Style-Guide</h2>
<p class="lead">Verbindliche Stil-Referenz für alle GeoGraSim-Module. Klick auf Farbfelder oder „Kopieren" überträgt den Wert in die Zwischenablage. Diese Seite ist die Single-Source-of-Truth — wenn du etwas änderst, musst du es hier auch aktualisieren.</p>
</div>
<!-- ============================================================== -->
<div class="card" id="bildstil">
<div class="card-h">DALL-E / Bildgenerierung</div>
<h3>Offizieller Prompt-Block</h3>
<p>Verbatim verwenden, NICHT umformulieren. Bei jedem Bild diesen Block voranstellen, danach nur den Szenen-Teil ergänzen.</p>
<div class="copy-block">
<button class="copy-btn" data-copy="prompt-base">Kopieren</button>
<pre id="prompt-base">Flat Scandinavian illustration, wide panoramic landscape filling the entire 16:9 frame edge-to-edge, painted style with clean vector shapes, dark forest green (#1f4b37) and sage green (#4a7c4e) tones, yellow-mustard (#e8c547) accents, beige (#e8e4d8) buildings and valleys, white highlights. No text, no watermark, no logos, no borders, no frame.</pre>
</div>
<h3>Eckdaten</h3>
<table>
<tr><th>Feld</th><th>Wert</th></tr>
<tr><td>Modell</td><td><code>dall-e-3</code></td></tr>
<tr><td>Splash-Auflösung</td><td>1792 × 1024 (16:9 panoramisch)</td></tr>
<tr><td>Glossar-Bilder</td><td>1792 × 1024, standard quality</td></tr>
<tr><td>Avatar-Bilder</td><td>1024 × 1024, kreisrund maskiert via CSS</td></tr>
<tr><td>Format</td><td>PNG</td></tr>
<tr><td>API-Key</td><td><code>OPENAI_API_KEY</code> in <code>App/.env.local</code> (nicht im Git)</td></tr>
</table>
<h3>Tabu</h3>
<p>
<span class="pill bad">keine Schrift im Bild</span>
<span class="pill bad">keine Logos</span>
<span class="pill bad">keine Wasserzeichen</span>
<span class="pill bad">keine Rahmen / Borders</span>
</p>
<h3>Single-Source-of-Truth</h3>
<p>Lauffähiger Referenz-Generator: <code>App/sims/logistik/scripts/generate-splash-images.sh</code> (Variable <code>PROMPT_BASE</code>). Bei Pipeline-Fragen dort als Vorlage abschauen.</p>
<h3>Why</h3>
<p>Konsistenz über alle Module. Die Sims stehen auf der Schülerseite nebeneinander; wenn ein Modul aus dem Stil ausbricht, fällt es sofort auf. Gilt nicht nur für Splashes, sondern auch für Spielfeld-Hintergründe, Sprites, Marker-Icons, Bewertungs-Visuals.</p>
</div>
<!-- ============================================================== -->
<div class="card" id="farben-bild">
<div class="card-h">Bild-Farbpalette (verbindlich für DALL-E + Sprites + SVGs)</div>
<p>Klick auf eine Karte kopiert den Hex-Wert.</p>
<div class="swatches">
<div class="sw" data-copy-text="#1f4b37"><div class="sw-color" style="background:#1f4b37"></div><div class="sw-meta"><strong>Forest green</strong><span>#1f4b37</span></div></div>
<div class="sw" data-copy-text="#4a7c4e"><div class="sw-color" style="background:#4a7c4e"></div><div class="sw-meta"><strong>Sage green</strong><span>#4a7c4e</span></div></div>
<div class="sw" data-copy-text="#e8c547"><div class="sw-color" style="background:#e8c547"></div><div class="sw-meta"><strong>Yellow-mustard</strong><span>#e8c547</span></div></div>
<div class="sw" data-copy-text="#e8e4d8"><div class="sw-color" style="background:#e8e4d8"></div><div class="sw-meta"><strong>Beige</strong><span>#e8e4d8</span></div></div>
<div class="sw" data-copy-text="#ffffff"><div class="sw-color" style="background:#ffffff;border:1px solid #ccc"></div><div class="sw-meta"><strong>Weiß-Highlights</strong><span>#ffffff</span></div></div>
</div>
</div>
<!-- ============================================================== -->
<div class="card" id="farben-ui">
<div class="card-h">UI-Farbtokens (CSS-Variablen aus design-system.css)</div>
<p>Diese Tokens nutzen alle Plattform-UIs (Cockpits, Admin, Wrapper, Modale). In Sims als <code>var(--ggs-fjord)</code> referenzieren.</p>
<h3>Akzent (Fjord)</h3>
<div class="swatches">
<div class="sw" data-copy-text="#4a7c8a"><div class="sw-color" style="background:#4a7c8a"></div><div class="sw-meta"><strong>--ggs-fjord</strong><span>#4a7c8a</span></div></div>
<div class="sw" data-copy-text="#1f4e5a"><div class="sw-color" style="background:#1f4e5a"></div><div class="sw-meta"><strong>--ggs-fjord-dark</strong><span>#1f4e5a</span></div></div>
<div class="sw" data-copy-text="#dae8ec"><div class="sw-color" style="background:#dae8ec"></div><div class="sw-meta"><strong>--ggs-fjord-light</strong><span>#dae8ec</span></div></div>
</div>
<h3>Erfolg (Moss)</h3>
<div class="swatches">
<div class="sw" data-copy-text="#5a8a5e"><div class="sw-color" style="background:#5a8a5e"></div><div class="sw-meta"><strong>--ggs-moss</strong><span>#5a8a5e</span></div></div>
<div class="sw" data-copy-text="#3a6b3e"><div class="sw-color" style="background:#3a6b3e"></div><div class="sw-meta"><strong>--ggs-moss-dark</strong><span>#3a6b3e</span></div></div>
<div class="sw" data-copy-text="#dcead0"><div class="sw-color" style="background:#dcead0"></div><div class="sw-meta"><strong>--ggs-moss-light</strong><span>#dcead0</span></div></div>
</div>
<h3>Warnung &amp; Fehler</h3>
<div class="swatches">
<div class="sw" data-copy-text="#e8833a"><div class="sw-color" style="background:#e8833a"></div><div class="sw-meta"><strong>--ggs-orange / warning</strong><span>#e8833a</span></div></div>
<div class="sw" data-copy-text="#c85c4a"><div class="sw-color" style="background:#c85c4a"></div><div class="sw-meta"><strong>--ggs-coral / danger</strong><span>#c85c4a</span></div></div>
<div class="sw" data-copy-text="#f0d0ca"><div class="sw-color" style="background:#f0d0ca"></div><div class="sw-meta"><strong>--ggs-coral-light</strong><span>#f0d0ca</span></div></div>
</div>
<h3>Neutral &amp; Sand</h3>
<div class="swatches">
<div class="sw" data-copy-text="#f5f2eb"><div class="sw-color" style="background:#f5f2eb;border:1px solid #ddd"></div><div class="sw-meta"><strong>--ggs-bg</strong><span>#f5f2eb</span></div></div>
<div class="sw" data-copy-text="#e8e4d8"><div class="sw-color" style="background:#e8e4d8;border:1px solid #ddd"></div><div class="sw-meta"><strong>--ggs-bg-dark</strong><span>#e8e4d8</span></div></div>
<div class="sw" data-copy-text="#e8d5b5"><div class="sw-color" style="background:#e8d5b5"></div><div class="sw-meta"><strong>--ggs-sand</strong><span>#e8d5b5</span></div></div>
<div class="sw" data-copy-text="#c4a97a"><div class="sw-color" style="background:#c4a97a"></div><div class="sw-meta"><strong>--ggs-sand-dark</strong><span>#c4a97a</span></div></div>
<div class="sw" data-copy-text="#e0ddd4"><div class="sw-color" style="background:#e0ddd4"></div><div class="sw-meta"><strong>--ggs-border</strong><span>#e0ddd4</span></div></div>
</div>
<h3>Text</h3>
<div class="swatches">
<div class="sw" data-copy-text="#2a2a2a"><div class="sw-color" style="background:#2a2a2a"></div><div class="sw-meta"><strong>--ggs-text</strong><span>#2a2a2a</span></div></div>
<div class="sw" data-copy-text="#8a8a8a"><div class="sw-color" style="background:#8a8a8a"></div><div class="sw-meta"><strong>--ggs-text-muted</strong><span>#8a8a8a</span></div></div>
<div class="sw" data-copy-text="#b0b0b0"><div class="sw-color" style="background:#b0b0b0"></div><div class="sw-meta"><strong>--ggs-text-light</strong><span>#b0b0b0</span></div></div>
</div>
<h3>Komplette CSS-Variable als Block</h3>
<div class="copy-block">
<button class="copy-btn" data-copy="css-tokens">Kopieren</button>
<pre id="css-tokens">--ggs-fjord: #4a7c8a;
--ggs-fjord-dark: #1f4e5a;
--ggs-fjord-light: #dae8ec;
--ggs-moss: #5a8a5e;
--ggs-moss-dark: #3a6b3e;
--ggs-moss-light: #dcead0;
--ggs-sand: #e8d5b5;
--ggs-sand-dark: #c4a97a;
--ggs-coral: #c85c4a;
--ggs-coral-light: #f0d0ca;
--ggs-orange: #e8833a;
--ggs-bg: #f5f2eb;
--ggs-bg-dark: #e8e4d8;
--ggs-white: #ffffff;
--ggs-text: #2a2a2a;
--ggs-text-muted: #8a8a8a;
--ggs-text-light: #b0b0b0;
--ggs-border: #e0ddd4;
--ggs-success: #5a8a5e;
--ggs-warning: #e8833a;
--ggs-danger: #c85c4a;
--ggs-info: #4a7c8a;</pre>
</div>
</div>
<!-- ============================================================== -->
<div class="card" id="layout">
<div class="card-h">Layout &amp; Spacing</div>
<table>
<tr><th>Token</th><th>Wert</th><th>Verwendung</th></tr>
<tr><td><code>--ggs-gap-xs</code></td><td>4 px</td><td>Inline-Abstände, Pill-Padding</td></tr>
<tr><td><code>--ggs-gap-sm</code></td><td>8 px</td><td>Button-Innenabstand, Form-Felder</td></tr>
<tr><td><code>--ggs-gap-md</code></td><td>16 px</td><td>Card-Innenabstand, Standard-Layout</td></tr>
<tr><td><code>--ggs-gap-lg</code></td><td>24 px</td><td>Sektion-Abstand</td></tr>
<tr><td><code>--ggs-gap-xl</code></td><td>32 px</td><td>Hero-Bereiche</td></tr>
<tr><td><code>--ggs-radius-sm</code></td><td>6 px</td><td>Pills, kleine Buttons</td></tr>
<tr><td><code>--ggs-radius-md</code></td><td>12 px</td><td>Karten, Modale</td></tr>
<tr><td><code>--ggs-radius-lg</code></td><td>16 px</td><td>Hero-Cards, große Modale</td></tr>
<tr><td><code>--ggs-radius-pill</code></td><td>999 px</td><td>Pills, Avatar-Kreise</td></tr>
<tr><td><code>--ggs-shadow-sm</code></td><td><code>0 1px 3px rgba(0,0,0,.08)</code></td><td>Karten</td></tr>
<tr><td><code>--ggs-shadow-md</code></td><td><code>0 2px 8px rgba(0,0,0,.12)</code></td><td>Modale, schwebende Layers</td></tr>
<tr><td><code>--ggs-shadow-lg</code></td><td><code>0 4px 16px rgba(0,0,0,.16)</code></td><td>Tooltips, Spectator-Banner</td></tr>
</table>
</div>
<!-- ============================================================== -->
<div class="card" id="typo">
<div class="card-h">Typografie</div>
<table>
<tr><th>Token</th><th>Wert</th></tr>
<tr><td><code>--ggs-font</code></td><td><code>'Inter', system-ui, -apple-system, sans-serif</code></td></tr>
<tr><td><code>--ggs-font-mono</code></td><td><code>'JetBrains Mono', 'Fira Code', monospace</code></td></tr>
</table>
<h3>Größenrichtlinien</h3>
<ul>
<li><strong>0.62 rem</strong> — Card-Header (uppercase, letter-spacing .05em)</li>
<li><strong>0.7 rem</strong> — Hilfstexte, Subtitles</li>
<li><strong>0.78 rem</strong> — Body-Text in Karten</li>
<li><strong>0.85 rem</strong> — Modul-Namen, Tabs</li>
<li><strong>0.95 rem</strong> — H3 / Section-Titel</li>
<li><strong>1.15 rem</strong> — H2 / Page-Titel</li>
</ul>
</div>
<!-- ============================================================== -->
<div class="card" id="bilder">
<div class="card-h">Bildformate &amp; Pfade</div>
<table>
<tr><th>Typ</th><th>Maße</th><th>Pfad</th></tr>
<tr><td>Modul-Card-Image (Cockpit)</td><td>≈ 800 × 450 (16:9)</td><td><code>App/assets/img/sim-NN-&lt;slug&gt;.png</code></td></tr>
<tr><td>Glossar-Bild</td><td>1792 × 1024</td><td><code>App/assets/img/glossar/&lt;slug&gt;.png</code></td></tr>
<tr><td>Glossar-SVG (Schemata)</td><td>vektor</td><td><code>App/assets/img/glossar/&lt;slug&gt;-schema.svg</code></td></tr>
<tr><td>Splash (Sim-Intro)</td><td>1792 × 1024</td><td><code>App/sims/&lt;slug&gt;/assets/splash-*.png</code></td></tr>
<tr><td>Avatar (User)</td><td>1024 × 1024</td><td><code>App/assets/img/avatars/avatar-&lt;slug&gt;.png</code></td></tr>
<tr><td>Logo (SVG)</td><td>vektor</td><td><code>App/assets/img/geograsim_t.svg</code></td></tr>
</table>
<h3>Avatar-Slugs (30 Stück, 3 Gruppen)</h3>
<ul>
<li><strong>Geo-Welt:</strong> pilotin · pilot · kartografin · geologe · meteorologin · stadtplaner · forscherin · forscher · taucherin · astronaut</li>
<li><strong>Cool &amp; lustig:</strong> coole-girl · coole-boy · lustige-girl · lustige-boy · nerd-girl · sportlich-boy · kuenstlerin · musiker · gaertnerin · abenteurer</li>
<li><strong>Tier-Begleiter:</strong> fuchs-explorer · eule-prof · baer-foerster · pinguin-polar · affe-tropen · delfin-meer · adler-pilot · schildkroete-w · katze-stadt · biene-natur</li>
</ul>
</div>
<!-- ============================================================== -->
<div class="card" id="ipad">
<div class="card-h">iPad-Patterns (Hauptzielgerät: iPad Landscape 1180 × 820)</div>
<ul>
<li><strong>Touch-Ziele</strong> ≥ 36 px Höhe, idealerweise 44 px für primäre Aktionen</li>
<li><strong>Kein Hover-Kleber</strong> — alle Interaktionen müssen ohne Hover funktionieren</li>
<li><strong>Modale nutzen</strong> <code>height: 100dvh</code> + <code>safe-area-inset-bottom</code></li>
<li><strong>Sticky Aktions-Buttons</strong> unten im Modal — nicht außerhalb scrollen lassen</li>
<li><strong>Float-✕ oben rechts</strong> bei Modalen, damit „Schließen" immer erreichbar ist</li>
<li><strong>Layout breit statt hoch</strong> — Badges horizontal, 2-Spalten-Grids wo möglich</li>
<li><strong>viewport-fit=cover</strong> + <code>100dvh</code> für Vollbild-Sims</li>
</ul>
</div>
<!-- ============================================================== -->
<div class="card" id="sprache">
<div class="card-h">Sprache (Lernarbeit-Lexikon)</div>
<p>Niemals „spielen / Spiel / Spieler*in" verwenden. GeoGraSim ist Lernarbeit nach Wygotski, kein Spiel.</p>
<table>
<tr><th>Statt</th><th>Verwende</th></tr>
<tr><td>spielen</td><td>arbeiten mit · bearbeiten</td></tr>
<tr><td>Spiel</td><td>Simulation · Modul</td></tr>
<tr><td>Spieler*in</td><td>Bearbeiter*in · Schüler*in</td></tr>
<tr><td>Spielrunde</td><td>Durchgang</td></tr>
<tr><td>Game Over</td><td>Durchgang beendet</td></tr>
</table>
<p>Ausnahme: in Code-Variablen (<code>state.gameOver</code>, <code>player_progress</code>) ist „game/player" als technischer Begriff unkritisch — Hauptsache an der UI nicht sichtbar.</p>
</div>
</div>
<script>
function copyText(text, el) {
navigator.clipboard.writeText(text).then(function() {
if (el) {
var orig = el.textContent;
el.textContent = '✓ kopiert';
el.classList.add('ok');
setTimeout(function() { el.textContent = orig; el.classList.remove('ok'); }, 1100);
}
});
}
// Copy-Buttons mit data-copy=ID
document.querySelectorAll('.copy-btn[data-copy]').forEach(function(btn) {
btn.addEventListener('click', function() {
var src = document.getElementById(btn.getAttribute('data-copy'));
if (src) copyText(src.textContent, btn);
});
});
// Swatches mit data-copy-text
document.querySelectorAll('.sw[data-copy-text]').forEach(function(sw) {
sw.addEventListener('click', function() {
var txt = sw.getAttribute('data-copy-text');
copyText(txt, null);
var meta = sw.querySelector('.sw-meta strong');
if (meta) {
var orig = meta.textContent;
meta.textContent = '✓ kopiert';
setTimeout(function() { meta.textContent = orig; }, 900);
}
});
});
// Auth-Check: nur eingeloggter Admin darf hier sein
fetch('/api/admin', {
method:'POST', headers:{'Content-Type':'application/json'}, credentials:'same-origin',
body: JSON.stringify({action:'status'})
}).then(function(r) { return r.json(); }).then(function(r) {
if (!r.authenticated) location.href = 'admin.html';
}).catch(function() {});
</script>
<script src="assets/js/version-tag.js" defer></script>
</body>
</html>