/** * GeoGraSim Plattform-Standard: Mini-Onboarding * ============================================== * Für Sims, die KEIN volles Tutorial haben aber Lernenden trotzdem einen * kurzen Einstieg geben sollen: ein einfaches Modal mit Headline, Lead, * 2-4 Bullet-Schritten und optionalen Lernzielen. * * USAGE in der Sim: * * * * VERHALTEN: * - Beim 1. Besuch (kein localStorage-Key) öffnet sich das Modal automatisch. * - Schließen → localStorage merkt sich „gesehen" (key: ggs.intro.). * - Registriert automatisch `window.GGS_TUTORIAL.replay()` als Plattform-API, * damit der globale ℹ-Button im Header das Modal erneut öffnen kann. * - „Anleitung erneut öffnen" verfügbar via `GgsQuickIntro.open()` oder * `window.GGS_TUTORIAL.replay()`. * * STYLE: CSS wird automatisch injiziert. Mobile-first, iPad-tauglich, * Esc + Tap-outside schließt. * * KOMPATIBILITÄT: Pure Vanilla-JS. Funktioniert mit existierendem * Glossar-Tooltip-Pattern und GGS_TUTORIAL-Convention. */ (function () { 'use strict'; var CSS = '' + '.ggs-qi-back{position:fixed;inset:0;background:rgba(20,30,30,.55);display:flex;align-items:center;justify-content:center;z-index:9998;padding:2vw;animation:ggs-qi-fade .2s ease-out}' + '.ggs-qi-modal{background:#fff;border-radius:14px;max-width:520px;width:100%;max-height:90vh;overflow-y:auto;box-shadow:0 18px 40px rgba(0,0,0,.28);font-family:inherit;animation:ggs-qi-pop .22s ease-out;-webkit-overflow-scrolling:touch}' + '.ggs-qi-head{padding:18px 22px 8px;border-bottom:1px solid rgba(0,0,0,.05)}' + '.ggs-qi-title{font-size:1.35rem;font-weight:800;color:#1f4b37;margin:0 0 .3rem}' + '.ggs-qi-lead{font-size:.96rem;color:#3a3a3a;margin:0;line-height:1.45}' + '.ggs-qi-body{padding:14px 22px 4px;font-size:.94rem;line-height:1.5;color:#2a2a2a}' + '.ggs-qi-h3{font-size:.78rem;text-transform:uppercase;letter-spacing:.04em;color:#5a5a5a;margin:14px 0 6px;font-weight:700}' + '.ggs-qi-steps{margin:0;padding:0 0 0 1.2rem;list-style:decimal}' + '.ggs-qi-steps li{margin:.35rem 0}' + '.ggs-qi-goals{margin:0;padding:0;list-style:none}' + '.ggs-qi-goals li{padding:.28rem 0 .28rem 1.4rem;position:relative}' + '.ggs-qi-goals li::before{content:"🎯";position:absolute;left:0;font-size:.92em}' + '.ggs-qi-foot{display:flex;justify-content:flex-end;gap:.6rem;padding:14px 22px 18px;border-top:1px solid rgba(0,0,0,.05);background:#fafaf6;border-radius:0 0 14px 14px;position:sticky;bottom:0}' + '.ggs-qi-btn{font-family:inherit;font-size:.94rem;font-weight:700;padding:.55rem 1.1rem;border-radius:8px;border:0;cursor:pointer;transition:transform .08s,background .15s}' + '.ggs-qi-btn-primary{background:#1f4b37;color:#fff}' + '.ggs-qi-btn-primary:hover{background:#173527}' + '.ggs-qi-btn-primary:active{transform:scale(.97)}' + '@keyframes ggs-qi-fade{from{opacity:0}to{opacity:1}}' + '@keyframes ggs-qi-pop{from{opacity:0;transform:translateY(12px) scale(.97)}to{opacity:1;transform:none}}' + '@media (max-width:520px){.ggs-qi-modal{max-height:96vh}.ggs-qi-title{font-size:1.18rem}.ggs-qi-foot{padding-bottom:max(18px,env(safe-area-inset-bottom))}}'; var CSS_INJECTED = false; function injectCss() { if (CSS_INJECTED) return; var s = document.createElement('style'); s.id = 'ggs-quick-intro-css'; s.textContent = CSS; document.head.appendChild(s); CSS_INJECTED = true; } function escapeHtml(s) { return String(s == null ? '' : s).replace(/[<>&"]/g, function (c) { return { '<': '<', '>': '>', '&': '&', '"': '"' }[c]; }); } var _config = null; var _back = null; var _page = 1; function lsKey() { return _config && _config.simId ? 'ggs.intro.' + _config.simId : null; } function markSeen() { try { var k = lsKey(); if (k) localStorage.setItem(k, '1'); } catch (_) {} } function isSeen() { try { var k = lsKey(); return k && localStorage.getItem(k) === '1'; } catch (_) { return false; } } function close() { if (!_back) return; _back.remove(); _back = null; document.removeEventListener('keydown', onKey); } function onKey(e) { if (e.key === 'Escape') close(); } function onBackClick(e) { if (e.target === _back) { markSeen(); close(); return; } var a = e.target && e.target.dataset && e.target.dataset.action; if (a === 'next') { _page = 2; render(); } else if (a === 'back') { _page = 1; render(); } else if (a === 'start') { markSeen(); close(); } } function render() { injectCss(); var p2 = _config.page2 || null; var hasP2 = !!(p2 && (p2.html || p2.body)); var headTitle, headLead, body, foot; if (_page === 2 && hasP2) { headTitle = p2.title || _config.title || 'Mehr dazu'; headLead = ''; body = (p2.html || p2.body || ''); foot = '' + ''; } else { var steps = (_config.steps || []).map(function (s) { return '
  • ' + (s.indexOf('<') >= 0 ? s : escapeHtml(s)) + '
  • '; }).join(''); var goals = (_config.goals || []).map(function (g) { return '
  • ' + escapeHtml(g) + '
  • '; }).join(''); headTitle = _config.title || 'Anleitung'; headLead = _config.lead ? '

    ' + escapeHtml(_config.lead) + '

    ' : ''; body = (steps ? '
    Was tust du?
      ' + steps + '
    ' : '') + (goals ? '
    Was lernst du?
    ' : ''); foot = hasP2 ? '' : ''; } var html = '' + ''; if (!_back) { _back = document.createElement('div'); _back.className = 'ggs-qi-back'; _back.addEventListener('click', onBackClick); document.body.appendChild(_back); document.addEventListener('keydown', onKey); } _back.innerHTML = html; var m = _back.querySelector('.ggs-qi-modal'); if (m) m.scrollTop = 0; } function open() { if (!_config) return; // Sicherheitsnetz: alle evtl. schon vorhandenen Overlays entfernen (nie doppelt) var olds = document.querySelectorAll('.ggs-qi-back'); for (var i = 0; i < olds.length; i++) olds[i].remove(); _back = null; document.removeEventListener('keydown', onKey); _page = 1; render(); } window.GgsQuickIntro = { init: function (config) { _config = config || {}; // Plattform-Convention: GGS_TUTORIAL.replay() wird vom ℹ-Button im Header gerufen. window.GGS_TUTORIAL = { simId: _config.simId, title: _config.title, replay: function () { open(); }, }; // Beim 1. Besuch automatisch öffnen. if (!isSeen()) { // Kleiner Delay, damit Sim-Boot zuerst sein DOM aufbauen kann. setTimeout(open, 400); } }, open: open, close: close, }; })();