ggs-header Batch 2 Start: Farmer + Komponenten-Vorruestung

- Komponente: Logo-Fallback (Kreis-Logo wenn Sim keins hat), Overlay-Modus
  (data-ggs-overlay fuer Vollbild-Canvas), generische Icon-Button-Optik fuer
  Aktionen ohne .ggs-btn-ghost-Klasse, Ton-IDs erweitert (audio-toggle/btnSound).
- Farmer als erstes Bespoke-Muster: ggs-topbar -> ggs-header, schwebende Pille
  (Fallback-Logo + Titel) + Geld-KPI + Icon-Buttons; interne Fachinfo bleibt
  (data-ggs-no-glossar).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-25 14:33:53 +02:00
parent c913522a77
commit 7b1bdb8d1b
3 changed files with 63 additions and 11 deletions
+39
View File
@@ -23,6 +23,16 @@
flex-wrap: nowrap; flex-wrap: nowrap;
} }
/* Overlay-Modus: Zeile schwebt über Vollbild-Canvas (Heli, Tourismus …).
Der Sim-Canvas muss dann bis top:0 laufen; Sim-eigene Top-HUDs ggf.
nach unten schieben (siehe Kofferdetektiv). */
.ggs-header--float.ggs-header--overlay {
position: absolute;
left: 0;
right: 0;
top: 0;
}
/* --- Marken-Pille: Kreis-Logo · Titel · Level ---------------- */ /* --- Marken-Pille: Kreis-Logo · Titel · Level ---------------- */
.ggs-header--float .ggs-hpille { .ggs-header--float .ggs-hpille {
display: flex; display: flex;
@@ -61,6 +71,8 @@
font-size: .92rem; font-size: .92rem;
white-space: nowrap; white-space: nowrap;
line-height: 1; line-height: 1;
margin: 0;
padding: 0;
} }
.ggs-header--float .ggs-header-badge { .ggs-header--float .ggs-header-badge {
font-size: .6rem; font-size: .6rem;
@@ -115,6 +127,33 @@
gap: .5rem; gap: .5rem;
flex: none; flex: none;
} }
/* Bespoke-Sims: Buttons/Links in den Aktionen ohne .ggs-btn-ghost-Klasse
bekommen trotzdem die schwebende Icon-Button-Optik. */
.ggs-header--float .ggs-header-actions > button,
.ggs-header--float .ggs-header-actions > a {
width: 38px;
height: 38px;
border-radius: 12px;
border: none;
background: rgba(255, 255, 255, .96);
box-shadow: 0 2px 9px rgba(0, 0, 0, .2);
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
color: #1f4e5a;
padding: 0;
flex: none;
text-decoration: none;
font-size: 17px;
line-height: 1;
transition: background .15s, transform .1s;
}
.ggs-header--float .ggs-header-actions > button:hover,
.ggs-header--float .ggs-header-actions > a:hover {
background: #fff;
transform: translateY(-1px);
}
/* --- Tempo-Zustandsbutton (zeigt IMMER den aktuellen Speed) --- */ /* --- Tempo-Zustandsbutton (zeigt IMMER den aktuellen Speed) --- */
.ggs-header--float .ggs-tempo { position: relative; display: inline-flex; } .ggs-header--float .ggs-tempo { position: relative; display: inline-flex; }
+12 -2
View File
@@ -70,7 +70,7 @@
} }
return null; return null;
} }
var SOUND_IDS = ['btn-sound', 'btn-mute', 'btnVoiceToggle', 'btnAudioToggle', 'btnAudio', 'btn-ton', 'btn-audio']; var SOUND_IDS = ['btn-sound', 'btn-mute', 'btnVoiceToggle', 'btnAudioToggle', 'btnAudio', 'audio-toggle', 'btnSound', 'btn-ton', 'btn-audio'];
var RESET_IDS = ['btn-reset', 'btnReset', 'btn-restart', 'btn-neustart']; var RESET_IDS = ['btn-reset', 'btnReset', 'btn-restart', 'btn-neustart'];
var HELP_IDS = ['btn-info', 'btnHelp', 'btn-help', 'btn-anleitung', 'btn-hilfe']; var HELP_IDS = ['btn-info', 'btnHelp', 'btn-help', 'btn-anleitung', 'btn-hilfe'];
@@ -94,6 +94,7 @@
injectSprite(); injectSprite();
header.setAttribute('data-ggs-enhanced', '1'); header.setAttribute('data-ggs-enhanced', '1');
header.classList.add('ggs-header--float'); header.classList.add('ggs-header--float');
if (opts.overlay || header.getAttribute('data-ggs-overlay') === '1') header.classList.add('ggs-header--overlay');
var q = function (sel) { return header.querySelector(sel); }; var q = function (sel) { return header.querySelector(sel); };
var homeHref = opts.home || header.getAttribute('data-ggs-home') || '/schueler'; var homeHref = opts.home || header.getAttribute('data-ggs-home') || '/schueler';
@@ -108,10 +109,19 @@
pille.className = 'ggs-hpille'; pille.className = 'ggs-hpille';
if (logo) { if (logo) {
logo.parentNode.insertBefore(pille, logo); logo.parentNode.insertBefore(pille, logo);
pille.appendChild(logo);
} else { } else {
header.insertBefore(pille, header.firstChild); header.insertBefore(pille, header.firstChild);
// Fallback: Kreis-Logo erzeugen, falls die Sim keins im Header hat
logo = document.createElement('a');
logo.className = 'ggs-header-logo';
logo.setAttribute('href', homeHref);
var limg = document.createElement('img');
limg.className = 'ggs-header-logo-icon';
limg.src = opts.logo || header.getAttribute('data-ggs-logo') || '/assets/img/bildLogo.png';
limg.alt = '';
logo.appendChild(limg);
} }
pille.appendChild(logo);
var mod = q('.ggs-header-module'); if (mod) pille.appendChild(mod); var mod = q('.ggs-header-module'); if (mod) pille.appendChild(mod);
var badges = header.querySelectorAll('.ggs-header-badge'); var badges = header.querySelectorAll('.ggs-header-badge');
for (var i = 0; i < badges.length; i++) pille.appendChild(badges[i]); for (var i = 0; i < badges.length; i++) pille.appendChild(badges[i]);
+12 -9
View File
@@ -8,6 +8,9 @@
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""> integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="">
<link rel="stylesheet" href="../../assets/css/ggs-header.css">
<script src="../../assets/js/ggs-header.js"></script>
<style> <style>
html, body { margin: 0; padding: 0; height: 100dvh; overflow: hidden; html, body { margin: 0; padding: 0; height: 100dvh; overflow: hidden;
font-family: system-ui, -apple-system, "Segoe UI", sans-serif; font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
@@ -19,9 +22,6 @@
/* ===== Topbar ===== */ /* ===== Topbar ===== */
.ggs-topbar { .ggs-topbar {
position: absolute; top: 8px; left: 8px; z-index: 1000; position: absolute; top: 8px; left: 8px; z-index: 1000;
background: rgba(255, 255, 255, 0.95);
padding: 6px 10px; border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
display: flex; gap: 8px; align-items: center; font-size: 13px; display: flex; gap: 8px; align-items: center; font-size: 13px;
} }
.ggs-topbar a { .ggs-topbar a {
@@ -487,13 +487,16 @@
</head> </head>
<body> <body>
<div class="ggs-topbar"> <div class="ggs-topbar ggs-header" data-ggs-sim="farmer" data-ggs-no-glossar data-ggs-home="/schueler">
<h1>🌾 Landwirtschaft</h1> <h1 class="ggs-header-module">🌾 Landwirtschaft</h1>
<a href="/schueler" title="Zurück zur Schülerseite">🏠</a>
<button id="audio-toggle" title="Ton an/aus" onclick="toggleAudio()">🔊</button>
<button id="btn-info" title="Anleitung nochmal zeigen" onclick="if(window.GGS_TUTORIAL&&typeof window.GGS_TUTORIAL.replay==='function')window.GGS_TUTORIAL.replay();"></button>
<button id="glossar-btn" title="Fachinfo / Glossar" onclick="openInfoModal()">📖</button>
<div class="farmer-money" id="money-display">0 €</div> <div class="farmer-money" id="money-display">0 €</div>
<div class="ggs-header-spacer"></div>
<div class="ggs-header-actions">
<a href="/schueler" title="Zurück zur Schülerseite">🏠</a>
<button id="audio-toggle" title="Ton an/aus" onclick="toggleAudio()">🔊</button>
<button id="btn-info" title="Anleitung nochmal zeigen" onclick="if(window.GGS_TUTORIAL&&typeof window.GGS_TUTORIAL.replay==='function')window.GGS_TUTORIAL.replay();"></button>
<button id="glossar-btn" title="Fachinfo / Glossar" onclick="openInfoModal()">📖</button>
</div>
</div> </div>
<div class="farmer-year-bar"> <div class="farmer-year-bar">