|
290 | 290 | .vbadge-branch{background:#e8f4f8;color:#1a5276;border:1px solid #aed6f1} |
291 | 291 | .vtable tbody tr{cursor:pointer} |
292 | 292 | .vtable tbody tr.ver-selected td{background:rgba(0,113,188,.1)!important} |
| 293 | + /* Hierarchical tag tree */ |
| 294 | + .vtree-group-hdr td{background:var(--bg)!important;cursor:pointer;font-size:.8rem;font-weight:700;padding:.45rem .85rem;color:var(--muted);user-select:none;border-bottom:1px solid var(--border)} |
| 295 | + .vtree-group-hdr:hover td{background:var(--border)!important} |
| 296 | + .vtree-chevron{display:inline-block;width:1rem;font-size:.7rem} |
| 297 | + .vtree-prefix{color:var(--text)} |
| 298 | + .vtree-count{margin-left:.35rem;font-size:.72rem;font-weight:400;color:var(--subtle)} |
| 299 | + .vtree-item td:first-child{padding-left:1.8rem} |
293 | 300 | /* Version pill */ |
294 | 301 | .action-card{margin-bottom:.65rem} |
295 | 302 | .ver-pill{display:flex;align-items:center;gap:.4rem;margin-top:.45rem;padding:.3rem .7rem;background:var(--bg);border:1px solid var(--border);border-radius:var(--rm)} |
|
848 | 855 | allRefsCache=allRefs.slice(0,50); |
849 | 856 | const firstTag=sortedTags.length?{name:sortedTags[0].name,kind:'tag'}:null; |
850 | 857 | curVersion=firstTag||{name:c.default_branch||'main',kind:'branch'}; |
851 | | - document.getElementById('vtbody').innerHTML=allRefsCache.length?allRefsCache.map((r,i)=>{ |
| 858 | + const hasHierTags=allRefsCache.some(r=>r.kind==='tag'&&r.name.includes('/')); |
| 859 | + document.getElementById('vtbody').innerHTML=allRefsCache.length?(hasHierTags?_renderVerTree(allRefsCache):allRefsCache.map((r,i)=>{ |
852 | 860 | const sel=curVersion&&curVersion.name===r.name&&curVersion.kind===r.kind; |
853 | | - return `<tr class="${sel?'ver-selected':''}" onclick="selectVersion(${i})"> |
| 861 | + return `<tr class="${sel?'ver-selected':''}" data-vidx="${i}" onclick="selectVersion(${i})"> |
854 | 862 | <td class="vtag-name">${esc(r.name)}${i===0&&r.kind==='tag'?'<span class="vtag-latest">latest</span>':''}</td> |
855 | 863 | <td><span class="vbadge vbadge-${r.kind}">${r.kind}</span></td> |
856 | 864 | <td class="vsha">${r.commit_sha?r.commit_sha.slice(0,10):'—'}</td> |
857 | 865 | <td style="font-size:.79rem;color:var(--subtle)">${r.date?r.date.slice(0,10):'—'}</td> |
858 | | - </tr>`;}).join(''):'<tr><td colspan="4" style="text-align:center;color:var(--subtle)">No version info</td></tr>'; |
| 866 | + </tr>`;}).join('')):'<tr><td colspan="4" style="text-align:center;color:var(--subtle)">No version info</td></tr>'; |
859 | 867 | // Snippet |
860 | 868 | document.getElementById('dSnip').innerHTML=buildSnipHtml(c,curVersion); |
861 | 869 | // Aside |
|
884 | 892 | const r=allRefsCache[i];if(!r)return; |
885 | 893 | curVersion={name:r.name,kind:r.kind}; |
886 | 894 | _replaceURL({pkg:curPkg,v:r.name,vk:r.kind}); |
887 | | - document.querySelectorAll('#vtbody tr').forEach((tr,idx)=>tr.classList.toggle('ver-selected',idx===i)); |
| 895 | + document.querySelectorAll('#vtbody tr[data-vidx]').forEach(tr=>tr.classList.toggle('ver-selected',+tr.dataset.vidx===i)); |
888 | 896 | const c=curPkg?RAW[curPkg]:null; |
889 | 897 | if(c)document.getElementById('dSnip').innerHTML=buildSnipHtml(c,curVersion); |
890 | 898 | updSelVerInfo(); |
|
896 | 904 | document.getElementById('selVerKind').textContent=curVersion.kind; |
897 | 905 | el.style.display=''; |
898 | 906 | } |
| 907 | +function _renderVerTree(refs){ |
| 908 | + // Group tags whose names contain '/' by their prefix (part before first /) |
| 909 | + const groups=new Map(); |
| 910 | + refs.forEach((r,i)=>{ |
| 911 | + if(r.kind!=='tag'||!r.name.includes('/'))return; |
| 912 | + const pfx=r.name.slice(0,r.name.indexOf('/')); |
| 913 | + if(!groups.has(pfx))groups.set(pfx,[]); |
| 914 | + groups.get(pfx).push(i); |
| 915 | + }); |
| 916 | + let html=''; |
| 917 | + // Render grouped tags — collapsed by default, open if selected version is inside |
| 918 | + groups.forEach((idxs,pfx)=>{ |
| 919 | + const open=idxs.some(i=>curVersion&&refs[i].name===curVersion.name&&refs[i].kind===curVersion.kind); |
| 920 | + html+=`<tr class="vtree-group-hdr" onclick="toggleTreeGroup(this)"><td colspan="4"><span class="vtree-chevron">${open?'▾':'▸'}</span><span class="vtree-prefix">${esc(pfx)}/</span><span class="vtree-count">(${idxs.length})</span></td></tr>`; |
| 921 | + idxs.forEach(i=>{ |
| 922 | + const r=refs[i];const sel=curVersion&&r.name===curVersion.name&&r.kind===curVersion.kind; |
| 923 | + const isLatest=i===0; |
| 924 | + html+=`<tr class="vtree-item${sel?' ver-selected':''}" data-vidx="${i}" onclick="selectVersion(${i})"${open?'':' style="display:none"'}><td class="vtag-name">${esc(r.name.slice(pfx.length+1))}${isLatest?'<span class="vtag-latest">latest</span>':''}</td><td><span class="vbadge vbadge-tag">tag</span></td><td class="vsha">${r.commit_sha?r.commit_sha.slice(0,10):'—'}</td><td style="font-size:.79rem;color:var(--subtle)">${r.date?r.date.slice(0,10):'—'}</td></tr>`; |
| 925 | + }); |
| 926 | + }); |
| 927 | + // Render ungrouped tags and branches |
| 928 | + refs.forEach((r,i)=>{ |
| 929 | + if(r.kind==='tag'&&r.name.includes('/'))return; |
| 930 | + const sel=curVersion&&r.name===curVersion.name&&r.kind===curVersion.kind; |
| 931 | + const isLatest=i===0&&r.kind==='tag'; |
| 932 | + html+=`<tr class="${sel?'ver-selected':''}" data-vidx="${i}" onclick="selectVersion(${i})"><td class="vtag-name">${esc(r.name)}${isLatest?'<span class="vtag-latest">latest</span>':''}</td><td><span class="vbadge vbadge-${r.kind}">${r.kind}</span></td><td class="vsha">${r.commit_sha?r.commit_sha.slice(0,10):'—'}</td><td style="font-size:.79rem;color:var(--subtle)">${r.date?r.date.slice(0,10):'—'}</td></tr>`; |
| 933 | + }); |
| 934 | + return html||'<tr><td colspan="4" style="text-align:center;color:var(--subtle)">No version info</td></tr>'; |
| 935 | +} |
| 936 | +function toggleTreeGroup(hdr){ |
| 937 | + const chevron=hdr.querySelector('.vtree-chevron'); |
| 938 | + const open=chevron&&chevron.textContent==='▾'; |
| 939 | + if(chevron)chevron.textContent=open?'▸':'▾'; |
| 940 | + let sib=hdr.nextElementSibling; |
| 941 | + while(sib&&sib.classList.contains('vtree-item')){sib.style.display=open?'none':'';sib=sib.nextElementSibling;} |
| 942 | +} |
899 | 943 | function switchTab(name){ |
900 | 944 | document.querySelectorAll('.tabbtn').forEach((b,i)=>{const ns=['readme','versions'];b.classList.toggle('active',ns[i]===name)}); |
901 | 945 | document.querySelectorAll('.tabcontent').forEach(el=>el.classList.remove('active')); |
|
0 commit comments