Update index.html
This commit is contained in:
parent
38c4a948ca
commit
246aa3b7b9
1 changed files with 115 additions and 25 deletions
|
|
@ -124,18 +124,36 @@
|
|||
.stat div b { display:block; font-size:24px; }
|
||||
.stat div span { color:var(--muted); font-size:12px; }
|
||||
.note { font-size:12px; color:var(--muted); margin-top:18px; text-align:center; }
|
||||
|
||||
/* Setup-Screens (Action Card / Startpunkt) */
|
||||
body:not(.runMode) aside { display:none; }
|
||||
body:not(.runMode) .layout { grid-template-columns: 1fr; }
|
||||
body:not(.runMode) .progress { display:none; }
|
||||
.cardBadge { display:none; align-items:center; gap:8px; font-size:13px; }
|
||||
.cardBadge .cb-svc { font-weight:600; }
|
||||
.setupHead { font-size:12px; text-transform:uppercase; letter-spacing:.8px; color:var(--muted); }
|
||||
.setupTitle { font-size:26px; margin:6px 0 4px; line-height:1.2; }
|
||||
.muted { color:var(--muted); }
|
||||
.cardForm { display:flex; gap:16px; flex-wrap:wrap; margin:18px 0; }
|
||||
.cardForm label { display:flex; flex-direction:column; gap:6px; font-size:12px; text-transform:uppercase; letter-spacing:.5px; color:var(--muted); }
|
||||
.cardForm select { font:inherit; padding:10px 12px; border-radius:10px; border:1px solid var(--line); min-width:280px; background:#fff; color:var(--ink); }
|
||||
.pickerList { margin:14px 0 4px; }
|
||||
.pickerPhase { font-size:11px; text-transform:uppercase; letter-spacing:.8px; color:var(--muted); margin:16px 0 6px; }
|
||||
.pickerItem { display:flex; align-items:center; gap:10px; padding:9px 12px; border:1px solid var(--line); border-radius:10px; margin-bottom:6px; cursor:pointer; }
|
||||
.pickerItem:hover { border-color:#c9d2dd; background:#f7f9fb; }
|
||||
.pickerItem.sel { border-color:var(--accent); box-shadow:0 0 0 2px rgba(226,0,26,.12); }
|
||||
.pickerItem .dot { width:10px; height:10px; border-radius:50%; flex:none; }
|
||||
.pickerItem .id { color:var(--muted); font-size:12px; font-variant-numeric:tabular-nums; }
|
||||
.pickerItem .gate { margin-left:auto; font-size:11px; font-weight:700; color:#fff; background:var(--ink); padding:1px 8px; border-radius:999px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="brand">SLC <b>Companion</b></div>
|
||||
<span class="tag">Prototyp · v0.4</span>
|
||||
<div class="scenario">
|
||||
<select id="serviceSel" title="Service (Action Card)"></select>
|
||||
<select id="changeSel" title="Change-Typ"></select>
|
||||
</div>
|
||||
<span class="tag">Prototyp · v0.5</span>
|
||||
<div id="cardBadge" class="cardBadge"></div>
|
||||
<div class="spacer"></div>
|
||||
<button class="ghost" id="resetBtn" title="Durchlauf zurücksetzen">Zurücksetzen</button>
|
||||
<button class="ghost" id="resetBtn" title="Neue Action Card / Durchlauf zurücksetzen">Neu starten</button>
|
||||
<button class="primary" id="debriefBtn">Debrief</button>
|
||||
</header>
|
||||
<div class="progress"><div id="progressBar" style="width:0%"></div></div>
|
||||
|
|
@ -745,7 +763,8 @@ const STATIONEN = [
|
|||
/* ====================== STATE ====================== */
|
||||
const LS_KEY = "slc-companion-proto";
|
||||
function defaultState(){
|
||||
return { service:0, change:0, index:0, stage:"discuss", quizIndex:0,
|
||||
return { view:"card", service:0, change:0, startIndex:null,
|
||||
index:0, stage:"discuss", quizIndex:0,
|
||||
picks:{}, done:{}, unclear:{} };
|
||||
}
|
||||
let S = load();
|
||||
|
|
@ -778,14 +797,92 @@ function renderList(){
|
|||
}
|
||||
$("#stationList").innerHTML = html;
|
||||
$("#stationList").querySelectorAll(".stationItem").forEach(el=>{
|
||||
el.onclick = ()=>{ S.index = +el.dataset.i; S.stage="discuss"; S.quizIndex=0; save(); render(); };
|
||||
el.onclick = ()=>{ S.index = +el.dataset.i; S.stage="discuss"; S.quizIndex=0; save(); draw(); };
|
||||
});
|
||||
const pct = Math.round(Object.keys(S.done).length / STATIONEN.length * 100);
|
||||
$("#progressBar").style.width = pct+"%";
|
||||
}
|
||||
|
||||
/* ====================== RENDER: PANEL ====================== */
|
||||
function render(){
|
||||
/* ====================== VIEW DISPATCH ====================== */
|
||||
function draw(){
|
||||
document.body.classList.toggle("runMode", S.view==="run");
|
||||
renderCardBadge();
|
||||
if(S.view==="card") return renderCardScreen();
|
||||
if(S.view==="start") return renderStartScreen();
|
||||
renderRun();
|
||||
}
|
||||
|
||||
function renderCardBadge(){
|
||||
const el = $("#cardBadge");
|
||||
if(S.view==="card"){ el.style.display="none"; el.innerHTML=""; return; }
|
||||
el.style.display="flex";
|
||||
el.innerHTML = `<span class="cb-svc">${USE_CASES[S.service].service}</span><span class="ctChip">${CHANGE_TYPES[S.change]}</span>`;
|
||||
}
|
||||
|
||||
/* ---------- Screen 1: Action Card ziehen ---------- */
|
||||
function renderCardScreen(){
|
||||
$("#panel").innerHTML = `
|
||||
<div class="setupHead">Schritt 1 · Action Card</div>
|
||||
<h2 class="setupTitle">Welches Szenario zieht ihr?</h2>
|
||||
<p class="muted">Wählt Service und Change-Typ der gezogenen Action Card – oder zieht zufällig. Diese Karte steckt im Action-Stein und wandert durch alle Stationen.</p>
|
||||
<div class="cardForm">
|
||||
<label>Service<select id="serviceSel"></select></label>
|
||||
<label>Change-Typ<select id="changeSel"></select></label>
|
||||
</div>
|
||||
<div class="ctText" id="cardTrigger">${USE_CASES[S.service].changes[S.change]}</div>
|
||||
<div class="actions">
|
||||
<button class="ghost" id="randomCard">🎲 Zufällig ziehen</button>
|
||||
<div class="spacer"></div>
|
||||
<button class="primary" id="toStart">Weiter → Startpunkt wählen</button>
|
||||
</div>`;
|
||||
const svc=$("#serviceSel"), ch=$("#changeSel");
|
||||
svc.innerHTML = USE_CASES.map((u,i)=>`<option value="${i}">${u.service}</option>`).join("");
|
||||
ch.innerHTML = CHANGE_TYPES.map((c,i)=>`<option value="${i}">${c}</option>`).join("");
|
||||
svc.value=S.service; ch.value=S.change;
|
||||
const refresh=()=>{ $("#cardTrigger").textContent=USE_CASES[S.service].changes[S.change]; };
|
||||
svc.onchange=()=>{ S.service=+svc.value; save(); refresh(); };
|
||||
ch.onchange=()=>{ S.change=+ch.value; save(); refresh(); };
|
||||
$("#randomCard").onclick=()=>{ S.service=Math.floor(Math.random()*USE_CASES.length); S.change=Math.floor(Math.random()*CHANGE_TYPES.length); save(); draw(); };
|
||||
$("#toStart").onclick=()=>{ S.view="start"; save(); draw(); };
|
||||
}
|
||||
|
||||
/* ---------- Screen 2: Startpunkt bestimmen ---------- */
|
||||
function renderStartScreen(){
|
||||
const groups={};
|
||||
STATIONEN.forEach((st,i)=>{ (groups[st.phase]=groups[st.phase]||[]).push({st,i}); });
|
||||
let list="";
|
||||
for(const ph in PHASEN){
|
||||
if(!groups[ph]) continue;
|
||||
list += `<div class="pickerPhase">${PHASEN[ph].label}</div>`;
|
||||
groups[ph].forEach(({st,i})=>{
|
||||
list += `<div class="pickerItem ${i===S.startIndex?'sel':''}" data-i="${i}">
|
||||
<span class="dot" style="background:${PHASEN[ph].color}"></span>
|
||||
<span class="id">${st.id}</span>
|
||||
<span class="nm">${st.name}</span>
|
||||
${st.typ==="gate"?`<span class="gate">Gate ${st.gateNr}</span>`:''}
|
||||
</div>`;
|
||||
});
|
||||
}
|
||||
$("#panel").innerHTML = `
|
||||
<div class="setupHead">Schritt 2 · Startpunkt</div>
|
||||
<h2 class="setupTitle">Wo startet ihr sinnvollerweise?</h2>
|
||||
<p class="muted">Das hängt vom Change-Typ ab – ein großer (Major) Change beginnt eher im Design, ein Standard- oder Emergency-Change steigt oft später ein. Diskutiert in der Gruppe und wählt das Tile, auf das der Action-Stein zuerst gestellt wird. Es gibt nicht die eine richtige Antwort.</p>
|
||||
<div class="pickerList">${list}</div>
|
||||
<div class="actions">
|
||||
<button class="ghost" id="backToCard">← Action Card</button>
|
||||
<div class="spacer"></div>
|
||||
<button class="primary" id="confirmStart" ${S.startIndex==null?'disabled':''}>Hier starten →</button>
|
||||
</div>`;
|
||||
$("#panel").querySelectorAll(".pickerItem").forEach(el=>{
|
||||
el.onclick=()=>{ S.startIndex=+el.dataset.i; save(); renderStartScreen(); };
|
||||
});
|
||||
$("#backToCard").onclick=()=>{ S.view="card"; save(); draw(); };
|
||||
const cs=$("#confirmStart");
|
||||
if(cs) cs.onclick=()=>{ if(S.startIndex==null) return; S.index=S.startIndex; S.view="run"; S.stage="discuss"; S.quizIndex=0; save(); draw(); };
|
||||
}
|
||||
|
||||
/* ====================== RENDER: RUN (Station) ====================== */
|
||||
function renderRun(){
|
||||
renderList();
|
||||
const st = cur();
|
||||
const ph = PHASEN[st.phase];
|
||||
|
|
@ -896,15 +993,15 @@ function renderReveal(st){
|
|||
/* ====================== WIRING ====================== */
|
||||
function wire(st){
|
||||
const b = id => $("#"+id);
|
||||
if(b("toQuiz")) b("toQuiz").onclick = ()=>{ S.stage="quiz"; S.quizIndex=0; save(); render(); };
|
||||
if(b("backDiscuss")) b("backDiscuss").onclick = ()=>{ S.stage="discuss"; save(); render(); };
|
||||
if(b("toQuiz")) b("toQuiz").onclick = ()=>{ S.stage="quiz"; S.quizIndex=0; save(); draw(); };
|
||||
if(b("backDiscuss")) b("backDiscuss").onclick = ()=>{ S.stage="discuss"; save(); draw(); };
|
||||
$("#panel").querySelectorAll(".opt[data-opt]").forEach(el=>{
|
||||
el.onclick = ()=>{ S.picks[pkey(st.id,S.quizIndex)] = +el.dataset.opt; save(); render(); };
|
||||
el.onclick = ()=>{ S.picks[pkey(st.id,S.quizIndex)] = +el.dataset.opt; save(); draw(); };
|
||||
});
|
||||
if(b("nextQ")) b("nextQ").onclick = ()=>{ S.quizIndex++; save(); render(); };
|
||||
if(b("toReveal")) b("toReveal").onclick = ()=>{ S.stage="reveal"; save(); render(); };
|
||||
if(b("nextQ")) b("nextQ").onclick = ()=>{ S.quizIndex++; save(); draw(); };
|
||||
if(b("toReveal")) b("toReveal").onclick = ()=>{ S.stage="reveal"; save(); draw(); };
|
||||
if(b("unclear")) b("unclear").onchange = e=>{ if(e.target.checked) S.unclear[st.id]=true; else delete S.unclear[st.id]; save(); renderList(); };
|
||||
if(b("nextStation")) b("nextStation").onclick = ()=>{ S.done[st.id]=true; S.index++; S.stage="discuss"; S.quizIndex=0; save(); render(); };
|
||||
if(b("nextStation")) b("nextStation").onclick = ()=>{ S.done[st.id]=true; S.index++; S.stage="discuss"; S.quizIndex=0; save(); draw(); };
|
||||
if(b("finish")) b("finish").onclick = ()=>{ S.done[st.id]=true; save(); openDebrief(); };
|
||||
}
|
||||
|
||||
|
|
@ -945,18 +1042,11 @@ function openDebrief(){
|
|||
|
||||
/* ====================== INIT ====================== */
|
||||
(function init(){
|
||||
const svcSel = $("#serviceSel"), chSel = $("#changeSel");
|
||||
svcSel.innerHTML = USE_CASES.map((u,i)=>`<option value="${i}">${u.service}</option>`).join("");
|
||||
chSel.innerHTML = CHANGE_TYPES.map((c,i)=>`<option value="${i}">${c}</option>`).join("");
|
||||
svcSel.value = S.service;
|
||||
chSel.value = S.change;
|
||||
svcSel.onchange = ()=>{ S.service = +svcSel.value; save(); render(); };
|
||||
chSel.onchange = ()=>{ S.change = +chSel.value; save(); render(); };
|
||||
$("#debriefBtn").onclick = openDebrief;
|
||||
$("#closeDebrief").onclick = ()=> $("#debriefDlg").close();
|
||||
$("#copyBtn").onclick = ()=> navigator.clipboard?.writeText($("#debriefText").textContent);
|
||||
$("#resetBtn").onclick = ()=>{ if(confirm("Durchlauf zurücksetzen?")){ S=defaultState(); save(); render(); } };
|
||||
render();
|
||||
$("#resetBtn").onclick = ()=>{ if(confirm("Neue Action Card ziehen und Durchlauf zurücksetzen?")){ S=defaultState(); save(); draw(); } };
|
||||
draw();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue