This commit is contained in:
breitenbach76 2026-06-07 15:18:44 +02:00
parent 7af32ca038
commit 1de1110ed6
2 changed files with 56 additions and 10 deletions

View file

@ -93,6 +93,21 @@
.gateReq.ok { background:#f1faf4; color:#177a44; border:1px solid #cde6d6; }
.gateReq.bad { background:#fdf3f3; color:#b5202a; border:1px solid #f0c9c9; }
.choice[disabled] { opacity:.45; cursor:default; }
/* Rollen-Glossar als Overlay von links (Header-Button 👥 Rollen) */
#rollenList {
position: fixed; top:0; left:0; bottom:0; width: 330px; max-width: 88vw;
background: var(--panel); border-right:1px solid var(--line); padding: 14px;
overflow:auto; z-index: 30;
transform: translateX(-100%); transition: transform .22s ease;
box-shadow: 0 0 40px rgba(20,30,50,.18);
}
body.rollenOpen #rollenList { transform: translateX(0); }
body.rollenOpen .navBackdrop { opacity:1; pointer-events:auto; }
body:not(.runMode) #rollenList { display:none; }
body:not(.runMode) #rollenBtn { display:none; }
#rollenList h3 { font-size:11px; text-transform:uppercase; letter-spacing:.8px; color:var(--muted); margin:14px 0 4px; }
.rolleItem { display:flex; align-items:center; gap:10px; padding:6px 4px; font-size:13px; }
.rolleItem .rDot { width:12px; height:12px; border-radius:50%; flex:none; border:1px solid rgba(0,0,0,.18); }
.navTop { display:flex; align-items:center; justify-content:space-between; margin-bottom:8px; }
.navTop b { font-size:13px; text-transform:uppercase; letter-spacing:.6px; color:var(--muted); }
.navTop button { border:none; background:none; font-size:20px; line-height:1; color:var(--muted); cursor:pointer; padding:4px 8px; }
@ -270,6 +285,7 @@
<div id="cardBadge" class="cardBadge"></div>
<div class="spacer"></div>
<button class="ghost" id="akteBtn" title="Service-Akte (gesammelte Artefakte)">📁&nbsp;Akte</button>
<button class="ghost" id="rollenBtn" title="Rollen-Glossar (RACI)">👥&nbsp;Rollen</button>
<button class="ghost" id="stationsBtn" title="Stationsübersicht">&nbsp;Stationen</button>
<button class="ghost" id="resetBtn" title="Neue Action Card / Durchlauf zurücksetzen">Neu starten</button>
</header>
@ -279,6 +295,7 @@
<div class="layout">
<aside id="stationList"></aside>
<div id="akteList"></div>
<div id="rollenList"></div>
<main><div class="card" id="panel"></div></main>
</div>
@ -358,6 +375,16 @@ const ROLLEN = {
testmanagement:"Testmanagement", architektur:"Architektur",
lieferant:"Lieferant", operations_manager:"Betrieb (AL B&C / AL App)", dpm:"Demand Portfolio Manager"
};
// Rollen-Glossar fuer das Overlay: gruppiert/eingefaerbt nach den 6 Figuren-Kategorien
// (Farbe = Filamentfarbe der Figuren). Deckt alle ROLLEN-Eintraege ab.
const ROLLEN_GRUPPEN = [
{ label:"Governance (Entscheider)", color:"#c9a227", roles:["spm","service_owner","sor"] },
{ label:"Umfeld / Auftraggeber", color:"#7d2e3f", roles:["dpm"] },
{ label:"Management (operative Führung)", color:"#2f80c9", roles:["projektleitung","operations_manager","al_basis_cloud","al_applikationen","support_manager","problem_manager"] },
{ label:"Operative / Fachexperten", color:"#6b7686", roles:["queue_koordinator","first_level_agent","second_level_agent","testmanagement","architektur"] },
{ label:"Externe", color:"#cfd6df", roles:["lieferant"] },
{ label:"Teams (Sonderfiguren)", color:"#2f9e57", roles:["betriebsteam","service_support_team","projektteam"] }
];
const PHASEN = {
design:{label:"Design", color:"var(--design)"},
transition:{label:"Transition", color:"var(--transition)"},
@ -1075,10 +1102,26 @@ function renderAkte(){
const c = $("#akteClose"); if(c) c.onclick = ()=> document.body.classList.remove("akteOpen");
}
/* ====================== RENDER: ROLLEN-GLOSSAR (Overlay) ====================== */
function renderRollen(){
let html = `<div class="navTop"><b>👥 Rollen</b><button id="rollenClose" title="Schließen"></button></div>`;
html += `<div class="akteCount">RACI-Rollen im Lebenszyklus · Farbe = Figuren-Kategorie</div>`;
for(const g of ROLLEN_GRUPPEN){
html += `<h3>${g.label}</h3>`;
g.roles.forEach(r=>{
if(!ROLLEN[r]) return;
html += `<div class="rolleItem"><span class="rDot" style="background:${g.color}"></span><span>${ROLLEN[r]}</span></div>`;
});
}
html += `<p class="akteCount" style="margin-top:14px;line-height:1.45">Hinweis: Die <b>SOR</b> ist ein <b>Gremium</b> (SPM · Betrieb · Support-Manager · Service Owner …), das am Gate-Puck zusammenkommt — keine Einzelfigur.</p>`;
$("#rollenList").innerHTML = html;
const c = $("#rollenClose"); if(c) c.onclick = ()=> document.body.classList.remove("rollenOpen");
}
/* ====================== VIEW DISPATCH ====================== */
function draw(){
document.body.classList.toggle("runMode", S.view==="run");
if(S.view!=="run"){ document.body.classList.remove("navOpen"); document.body.classList.remove("akteOpen"); }
if(S.view!=="run"){ document.body.classList.remove("navOpen","akteOpen","rollenOpen"); }
renderCardBadge();
if(S.view==="deck") return renderDeck();
if(S.view==="classify") return renderClassify();
@ -1286,6 +1329,7 @@ function raciLegendHtml(){
function renderRun(){
renderList();
renderAkte();
renderRollen();
const st = cur();
const ph = PHASEN[st.phase];
const chip = st.typ==="gate"
@ -1319,13 +1363,13 @@ function activitySteps(st){
{ label:"Diskussion",
frage:`Diskutiert gemeinsam: Was fällt alles unter <b>„${st.name}"</b>? Was stellt ihr euch darunter vor? Nennt Beispiele.`,
auf:`<p style="margin:0 0 8px">${st.beschreibung}</p><h4 class="aufH">Das fällt darunter</h4><ul>${st.umfasst.map(u=>`<li>${u}</li>`).join("")}</ul>` },
{ label:"Beteiligte Rollen",
frage:`Welche Rollen sind an dieser Aktivität beteiligt? Stellt ihre Figuren auf die <b>Mulden des Station-Pucks</b>.`,
auf:`<h4 class="aufH">Beteiligte Rollen</h4><div class="roleChips">${st.raci.map(([r])=>`<span class="roleChip">${roleLabel(r)}</span>`).join("")}</div>` },
{ label:"Operative Rollen (R)",
frage:`Welche Rollen setzen diese Aktivität <b>operativ</b> um — wer sorgt für die <b>Umsetzung</b> (Responsible)? Stellt deren Figuren auf die <b>Mulden des Station-Pucks</b>.`,
auf:`<h4 class="aufH">Operativ verantwortlich (R)</h4><div class="roleChips">${(st.raci.filter(([r,c])=>c==="R").map(([r])=>`<span class="roleChip">${roleLabel(r)}</span>`).join("")) || '<span class="roleChip">— (keine eigene R-Rolle)</span>'}</div><p class="muted" style="margin:10px 0 0;font-size:13px">Das sind die „Macher" der Aktivität. <b>Wer</b> dafür geradesteht (A) sowie beratend (C) bzw. informiert (I) ist, klärt Schritt 3.</p>` },
{ label:"RACI",
frage:`Klärt die <b>RACI</b>: Wer ist R, A, C, I? Sortiert die Figuren ins <b>Aktiv-Feld (R·A·C·I)</b>.`,
frage:`Ergänzt nun die <b>vollständige RACI</b>: Wer ist <b>A</b>ccountable (trägt die Verantwortung), wer <b>C</b>onsulted, wer <b>I</b>nformed — zusätzlich zu den Responsible aus Schritt 2? Sortiert die Figuren ins <b>Aktiv-Feld (R·A·C·I)</b>.`,
legend: raciLegendHtml(),
auf:`<h4 class="aufH">RACI</h4>${raciTable(st)}` },
auf:`<h4 class="aufH">RACI (vollständig)</h4>${raciTable(st)}` },
{ label:"Artefakt", artefakt:true,
frage:`Welches <b>Artefakt</b> entsteht hier und kommt in die <b>Service-Akte</b>?`,
auf:`<h4 class="aufH">Artefakt</h4><p style="margin:0"><b>${st.artefakt}</b></p>` }
@ -1544,9 +1588,11 @@ function renderEnd(){
/* ====================== INIT ====================== */
(function init(){
$("#resetBtn").onclick = ()=>{ if(confirm("Neue Action Card ziehen und Durchlauf zurücksetzen?")){ S=defaultState(); save(); draw(); } };
$("#stationsBtn").onclick = ()=>{ document.body.classList.remove("akteOpen"); document.body.classList.toggle("navOpen"); };
$("#akteBtn").onclick = ()=>{ document.body.classList.remove("navOpen"); document.body.classList.toggle("akteOpen"); };
$("#navBackdrop").onclick = ()=>{ document.body.classList.remove("navOpen"); document.body.classList.remove("akteOpen"); };
const closeOverlays = ()=> document.body.classList.remove("navOpen","akteOpen","rollenOpen");
$("#stationsBtn").onclick = ()=>{ const o=document.body.classList.contains("navOpen"); closeOverlays(); if(!o) document.body.classList.add("navOpen"); };
$("#akteBtn").onclick = ()=>{ const o=document.body.classList.contains("akteOpen"); closeOverlays(); if(!o) document.body.classList.add("akteOpen"); };
$("#rollenBtn").onclick = ()=>{ const o=document.body.classList.contains("rollenOpen"); closeOverlays(); if(!o) document.body.classList.add("rollenOpen"); };
$("#navBackdrop").onclick = closeOverlays;
draw();
})();

View file

@ -1,5 +1,5 @@
/* Service Worker — SLC-Workshop Companion (App-Shell, offline-first) */
const CACHE = "slc-companion-v12";
const CACHE = "slc-companion-v14";
const SHELL = ["./", "index.html", "manifest.webmanifest", "icon.svg"];
// Action-Card-Grafiken (cards/s<service>-c<change>.png) fuer Offline vorab cachen (alle 30).
const CARDS = [];