Team-depth breakdown: members per generation on admin org panel + member dashboard

- chain.js getOrgShare now returns genCounts (breadth-first members per
  generation below the root)
- Admin "Your Organization vs. the Network" panel renders a Gen 1..N bar list
  with fill-vs-capacity (2^n slots)
- Member dashboard "Your team" card gains a Team Depth section computed from
  the subtree client-side, labeling each generation with the level whose
  upgrade pays that position (gen D pays at the level D+1 buy)
- AI chat system prompt updated to describe the new dashboard section

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-08-18 16:40:22 -05:00
parent 9dbe7eddcb
commit b66d3a50e8
5 changed files with 43 additions and 4 deletions
+11 -1
View File
@@ -73,9 +73,19 @@ async function loadOrgShare(){
`</div>`+
`<div class="progress-line" style="height:16px;margin:0 0 6px"><span style="width:${Math.min(100,d.memberPct)}%"></span></div>`+
`<p style="color:var(--muted);margin:0 0 14px;font-size:14px">Your organization rooted at <strong class="mt-id">#${d.rootId}</strong> is <strong style="color:var(--text)">${d.orgMembers} of ${d.totalMembers}</strong> members in the whole contract (${d.orgBelow} below you + your position), and has earned <strong style="color:var(--text)">${fmt(d.orgPol)} of ${fmt(d.totalPol)} POL</strong> ever paid.</p>`+
`<div class="facts" style="grid-template-columns:repeat(4,1fr)"><div class="fact"><small>Your org members</small><strong>${d.orgMembers}</strong></div><div class="fact"><small>Whole network</small><strong>${d.totalMembers}</strong></div><div class="fact"><small>Your org earned</small><strong>${fmt(d.orgPol)} POL</strong></div><div class="fact"><small>Network paid</small><strong>${fmt(d.totalPol)} POL</strong></div></div>`;
`<div class="facts" style="grid-template-columns:repeat(4,1fr)"><div class="fact"><small>Your org members</small><strong>${d.orgMembers}</strong></div><div class="fact"><small>Whole network</small><strong>${d.totalMembers}</strong></div><div class="fact"><small>Your org earned</small><strong>${fmt(d.orgPol)} POL</strong></div><div class="fact"><small>Network paid</small><strong>${fmt(d.totalPol)} POL</strong></div></div>`+
genBreakdownHtml(d.genCounts,d.rootId);
}catch(x){out.innerHTML=`<div class="empty" style="color:var(--danger)">${esc(x.message)}</div>`}
}
function genBreakdownHtml(gc,rootId){
if(!gc||!gc.length)return '';
const rows=gc.map((c,i)=>{
const cap=Math.pow(2,i+1), pctFill=Math.min(100,Math.round(100*c/cap));
const capLabel=cap<=1024?` of ${cap} slots`:'';
return `<div style="display:flex;align-items:center;gap:10px;margin:4px 0;font-size:13px"><span style="width:52px;color:var(--muted)">Gen ${i+1}</span><div class="progress-line" style="flex:1;height:10px"><span style="width:${pctFill}%"></span></div><span style="width:120px;text-align:right"><strong>${c}</strong><span style="color:var(--muted)">${capLabel}</span></span></div>`;
}).join('');
return `<div style="margin-top:16px"><small style="text-transform:uppercase;letter-spacing:.08em;color:var(--muted);font-size:11px">Depth — members per generation below #${rootId}</small><div style="margin-top:8px">${rows}</div></div>`;
}
document.getElementById('orgShareForm').addEventListener('submit',e=>{e.preventDefault();loadOrgShare()});
let incomeAutoLoaded=false;
async function loadIncome(){