Matrix view: zoom controls so small screens can see the whole pyramid
The team pyramid overflows on phones. Add -/+/Fit zoom controls to the matrix (pyramid) view that scale it via CSS zoom, defaulting to auto-fit so the whole structure fits the screen width on load. Controls show only in pyramid mode, re-fit on resize and when the dashboard tab opens, and guard against measuring while the tab is hidden. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+30
-1
@@ -13,6 +13,7 @@
|
||||
const tp=document.getElementById('tabPitch'),td=document.getElementById('tabDash');
|
||||
if(tp)tp.classList.toggle('on',name==='pitch');
|
||||
if(td)td.classList.toggle('on',name==='dash');
|
||||
if(name==='dash'&&treeUI.mode==='pyramid')setTimeout(applyMatrixZoom,30); // fit once the matrix is visible
|
||||
}
|
||||
document.querySelectorAll('.mp-tab').forEach(t=>t.addEventListener('click',()=>{setTab(t.dataset.tab);window.scrollTo({top:0,behavior:'smooth'});}));
|
||||
function renderPitch(d){
|
||||
@@ -34,7 +35,33 @@
|
||||
|
||||
function pathId(){const m=location.pathname.match(/^\/my\/(\d+)$/);if(m)return m[1];const q=new URLSearchParams(location.search).get('id');if(q&&/^\d+$/.test(q))return q;try{return localStorage.getItem('ctb.myId')||''}catch(e){return ''}}
|
||||
|
||||
const treeUI={byId:{},parent:{},homeId:0,rootId:0,mode:'pyramid'};
|
||||
const treeUI={byId:{},parent:{},homeId:0,rootId:0,mode:'pyramid',zoom:null,_applied:1};
|
||||
// Zoom the matrix so it fits small screens. treeUI.zoom: null = auto-fit (shrink
|
||||
// to fit width, never enlarge), or a manual factor. Uses CSS `zoom` so the layout
|
||||
// reflows cleanly (no leftover box, centering + scroll keep working).
|
||||
function applyMatrixZoom(){
|
||||
const bar=document.getElementById('dZoom');
|
||||
const mtp=document.querySelector('#dTree .mtp');
|
||||
if(!mtp){if(bar)bar.classList.add('hidden');return}
|
||||
mtp.style.zoom='1';
|
||||
const availW=mtp.clientWidth;
|
||||
if(!availW){if(bar)bar.classList.add('hidden');return} // in a hidden tab — apply when it opens
|
||||
if(bar)bar.classList.remove('hidden');
|
||||
const natW=mtp.scrollWidth||1;
|
||||
let z=treeUI.zoom;
|
||||
if(z==null)z=Math.min(1,availW/natW); // Fit / default: shrink only
|
||||
z=Math.max(.4,Math.min(1.6,z));
|
||||
mtp.style.zoom=String(z);
|
||||
treeUI._applied=z;
|
||||
const lbl=document.getElementById('zLbl');if(lbl)lbl.textContent=Math.round(z*100)+'%';
|
||||
}
|
||||
(function wireZoom(){
|
||||
const out=document.getElementById('zOut'),inn=document.getElementById('zIn'),fit=document.getElementById('zFit');
|
||||
if(out)out.addEventListener('click',()=>{treeUI.zoom=Math.max(.4,(treeUI._applied||1)-0.15);applyMatrixZoom()});
|
||||
if(inn)inn.addEventListener('click',()=>{treeUI.zoom=Math.min(1.6,(treeUI._applied||1)+0.15);applyMatrixZoom()});
|
||||
if(fit)fit.addEventListener('click',()=>{treeUI.zoom=null;applyMatrixZoom()});
|
||||
let t;window.addEventListener('resize',()=>{clearTimeout(t);t=setTimeout(()=>{if(treeUI.mode==='pyramid')applyMatrixZoom()},160)});
|
||||
})();
|
||||
function indexTree(n,par){if(!n)return;treeUI.byId[n.id]=n;if(par)treeUI.parent[n.id]=par.id;indexTree(n.left,n);indexTree(n.right,n)}
|
||||
function isSpill(n){return !!(n&&treeUI.parent[n.id]&&n.referrerId&&n.referrerId!==treeUI.parent[n.id])}
|
||||
function card(n,focus){
|
||||
@@ -58,10 +85,12 @@
|
||||
nav.innerHTML=path.length>1?`<span class="micro" style="margin:0">Viewing:</span> `+path.map((id,i)=>i===path.length-1?`<strong class="mt-id">#${id}</strong>`:`<button class="btn btn-secondary btn-sm" data-tid="${id}">#${id}</button>`).join(' <span style="color:var(--muted)">›</span> ')+` <button class="btn btn-secondary btn-sm" data-tid="${treeUI.parent[treeUI.rootId]}">↑ Up one</button>`:'';
|
||||
const wire=el=>el.querySelectorAll('[data-tid]').forEach(b=>b.addEventListener('click',()=>{const t=Number(b.dataset.tid);if(t&&treeUI.byId[t]){treeUI.rootId=t;renderTree()}}));
|
||||
wire(out);wire(nav);
|
||||
applyMatrixZoom();
|
||||
}
|
||||
function renderList(){
|
||||
const out=document.getElementById('dTree');
|
||||
document.getElementById('dTreeNav').innerHTML='';
|
||||
const zb=document.getElementById('dZoom');if(zb)zb.classList.add('hidden');
|
||||
const home=treeUI.byId[treeUI.homeId];
|
||||
if(!home){out.innerHTML='<div class="empty">Team view is still indexing — check back in a few minutes.</div>';return}
|
||||
const node=(n,depth)=>{
|
||||
|
||||
Reference in New Issue
Block a user