From 3df15b352008dc88fbdf5bf0d77225930f17d54e Mon Sep 17 00:00:00 2001 From: Matt Mabrey Date: Mon, 24 Aug 2026 16:09:08 -0700 Subject: [PATCH] Redesign Breadcrumbs panel: list + detail split view (option 3) --- tools/field-problem-workshop.html | 75 ++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 15 deletions(-) diff --git a/tools/field-problem-workshop.html b/tools/field-problem-workshop.html index 8d8547a..ab4061d 100644 --- a/tools/field-problem-workshop.html +++ b/tools/field-problem-workshop.html @@ -124,6 +124,19 @@ .bc-related summary{cursor:pointer; color:var(--interactive);} .bc-related li{margin-left:22px; padding:2px 0; color:var(--text-secondary);} .bc-foot{display:flex; align-items:center; gap:14px; margin-top:12px; flex-wrap:wrap;} + .bc-layout{display:grid; grid-template-columns:250px 1fr; gap:16px; align-items:start;} + .bc-nav{background:var(--layer); border:1px solid var(--border); position:sticky; top:12px; max-height:80vh; overflow-y:auto;} + .bc-nav-item{display:flex; align-items:center; gap:9px; padding:10px 12px; border-bottom:1px solid var(--border); cursor:pointer;} + .bc-nav-item:last-child{border-bottom:none;} + .bc-nav-item:hover{background:var(--layer-hover);} + .bc-nav-item.active{background:var(--layer-hover); border-left:3px solid var(--interactive); padding-left:9px;} + .bc-nav-text{flex:1; font-size:12.5px; line-height:1.35; color:var(--text-secondary);} + .bc-nav-item.active .bc-nav-text{color:var(--text); font-weight:600;} + .bc-dot{width:8px; height:8px; border-radius:50%; flex-shrink:0; background:var(--border-strong);} + .bc-dot.complete{background:var(--success);} + .bc-dot.partial{background:var(--warning);} + .bc-detail{min-width:0;} + @media (max-width:900px){ .bc-layout{grid-template-columns:1fr;} .bc-nav{position:static; max-height:none;} } .gate{display:flex; gap:12px; font-size:12.5px; flex-wrap:wrap;} .gate span{color:var(--text-helper);} .gate span.ok{color:var(--success); font-weight:600;} @@ -205,7 +218,10 @@

Root problem to value driver to capability to measurable outcome. A completed breadcrumb IS a pilot success criterion; the export builds the criteria table from every complete card. AI draft fills the fields from construction execution methodology (EVM, CII AWP, Last Planner, first-time quality); the room reviews and edits.

-
+
+ +
+
@@ -478,7 +494,9 @@ document.getElementById('panel-map').addEventListener('click', e=>{ const c = clusterById(t.dataset.cprom); if(c){ c.promoted = true; - S.breadcrumbs.push(B({prob:(c.root||c.name), related:activeMembers(c.id).map(p=>p.t)})); + const nb = B({prob:(c.root||c.name), related:activeMembers(c.id).map(p=>p.t)}); + S.breadcrumbs.push(nb); + bcSelectedId = nb.id; save(); renderAll(); toast('Promoted with ' + activeMembers(c.id).length + ' related issues'); } return; @@ -567,6 +585,8 @@ document.getElementById('newCluster').addEventListener('keydown', e=>{ if(e.key= const ADOPTION_WORDS = /implement|adopt|roll ?out|have a tool|tool exists|usage|active users?|users? active/i; const REQ = ['driver','cap','metric','method','baseline']; function bcComplete(b){ return REQ.every(f=>String(b[f]||'').trim().length>0); } +function bcStatus(b){ if(bcComplete(b)) return 'complete'; if(REQ.some(f=>String(b[f]||'').trim())) return 'partial'; return 'blank'; } +let bcSelectedId = null; function footHTML(b){ const adoptionFlag = b.type==='Outcome' && ADOPTION_WORDS.test(b.metric||''); const gate = REQ.map(f=>{ @@ -587,15 +607,10 @@ function bcSummaryHTML(){
${nInc}Incomplete
${nOut}Outcome
${S.breadcrumbs.length-nOut}Adoption
`; } -function renderBc(){ - const wrap = document.getElementById('bcList'); - document.getElementById('cntBc').textContent = S.breadcrumbs.length; - document.getElementById('bcSummary').innerHTML = bcSummaryHTML(); - if(!S.breadcrumbs.length){ wrap.innerHTML = '
Promote root problems from the map, or add a blank breadcrumb.
'; return; } - wrap.innerHTML = S.breadcrumbs.map(b=>{ - const rel = (b.related && b.related.length) - ? `` : ''; - return `
+function bcCardHTML(b){ + const rel = (b.related && b.related.length) + ? `` : ''; + return `

1Root problem statement ${b.example?'Worked example':''}

@@ -620,20 +635,48 @@ function renderBc(){
${footHTML(b)}
`; - }).join(''); } -document.getElementById('bcList').addEventListener('input', e=>{ +function bcNavRowHTML(b){ + const label = shortT(b.prob, 60) || '(blank breadcrumb)'; + return `
+ + ${esc(label)} +
`; +} +function renderBc(){ + document.getElementById('cntBc').textContent = S.breadcrumbs.length; + document.getElementById('bcSummary').innerHTML = bcSummaryHTML(); + const nav = document.getElementById('bcNav'); + const detail = document.getElementById('bcDetail'); + if(!S.breadcrumbs.length){ + nav.innerHTML = ''; + detail.innerHTML = '
Promote root problems from the map, or add a blank breadcrumb.
'; + bcSelectedId = null; + return; + } + if(!S.breadcrumbs.some(b=>b.id===bcSelectedId)) bcSelectedId = S.breadcrumbs[0].id; + nav.innerHTML = S.breadcrumbs.map(bcNavRowHTML).join(''); + const selected = S.breadcrumbs.find(b=>b.id===bcSelectedId); + detail.innerHTML = bcCardHTML(selected); +} +document.getElementById('bcNav').addEventListener('click', e=>{ + const row = e.target.closest('[data-bcnav]'); + if(row){ bcSelectedId = row.dataset.bcnav; renderBc(); } +}); +document.getElementById('bcDetail').addEventListener('input', e=>{ if(e.target.dataset.bid){ const b = S.breadcrumbs.find(x=>x.id===e.target.dataset.bid); if(b){ b[e.target.dataset.f] = e.target.value; save(); const foot = document.querySelector(`[data-foot="${b.id}"]`); if(foot) foot.innerHTML = footHTML(b); + const navRow = document.querySelector(`[data-bcnav="${b.id}"]`); + if(navRow) navRow.outerHTML = bcNavRowHTML(b); document.getElementById('bcSummary').innerHTML = bcSummaryHTML(); } } }); -document.getElementById('bcList').addEventListener('click', e=>{ +document.getElementById('bcDetail').addEventListener('click', e=>{ const tt = e.target.closest('[data-tt]'); if(tt){ const b = S.breadcrumbs.find(x=>x.id===tt.dataset.tt); @@ -647,7 +690,9 @@ document.getElementById('bcList').addEventListener('click', e=>{ } }); document.getElementById('btnAddBc').addEventListener('click', ()=>{ - S.breadcrumbs.push(B({})); + const nb = B({}); + S.breadcrumbs.push(nb); + bcSelectedId = nb.id; save(); renderBc(); });