ui: encryption landscape card — ring + HTML legend with counts

This commit is contained in:
2026-08-19 06:53:35 -05:00
parent 66a62ce234
commit 53e995d5a7
2 changed files with 23 additions and 11 deletions
@@ -326,6 +326,11 @@ html.dark .muted { color: #bdbdbd; }
.recon-chart-box { position: relative; flex: 1; min-height: 0; margin-top: auto; }
.recon-chart-box canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
.recon-no-data { font-style: italic; color: #787878; display: flex; justify-content: center; align-items: center; padding: 8px; text-align: center; }
.recon-enc-legend { display: flex; flex-wrap: wrap; gap: 2px 10px; margin-top: 4px; align-items: baseline; }
.recon-enc-entry { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; color: var(--text); }
.recon-enc-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.recon-enc-label { color: var(--muted); }
.recon-enc-count { font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
.recon-hs-count { font-size: 32px; font-weight: 700; line-height: 1.1; }
.recon-hs-label { color: var(--muted); font-size: 12px; margin: 1px 0 8px; }
.recon-toggle { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text); margin: 0; cursor: pointer; }
@@ -1495,16 +1495,14 @@ views.recon = (root) => {
chanBox.appendChild(chanEmpty);
const encBody = titleCard('Encryption Landscape', null);
const encValue = h('div', { class: 'recon-card-value', text: '—' });
const encSub = h('div', { class: 'recon-card-sub', text: '' });
encBody.appendChild(encValue);
encBody.appendChild(encSub);
const encBox = h('div', { class: 'recon-chart-box' });
encBody.appendChild(encBox);
const encCanvas = h('canvas', { id: 'recon-encryption' });
encBox.appendChild(encCanvas);
const encEmpty = h('div', { class: 'recon-no-data', text: 'No encryption data yet — run a scan.' });
encBox.appendChild(encEmpty);
const encLegend = h('div', { class: 'recon-enc-legend' });
encBody.appendChild(encLegend);
const hsBody = titleCard('Handshakes', '#/recon/handshakes');
const hsCount = h('span', { class: 'recon-hs-count', text: '0' });
@@ -2258,12 +2256,6 @@ views.recon = (root) => {
const b = reconEncBucket(a.encryption);
encCounts[b] = (encCounts[b] || 0) + 1;
});
let topEnc = null, topEncN = 0;
Object.keys(encCounts).forEach((k) => {
if (encCounts[k] > topEncN) { topEnc = k; topEncN = encCounts[k]; }
});
encValue.textContent = topEnc || '—';
encSub.textContent = topEnc ? topEncN + ' of ' + n + ' APs' : '';
const land = document.getElementById('recon-landscape');
if (land && typeof MiniChart !== 'undefined' && MiniChart.doughnut) {
@@ -2311,7 +2303,7 @@ views.recon = (root) => {
if (aps.length) {
MiniChart.doughnut(enc, RECON_ENC_BUCKETS.map((k, i) => ({
label: k, value: encCounts[k] || 0, color: RECON_ENC_COLORS[i]
})), { legend: true, height: 66 });
})), { legend: false, height: 120 });
enc.classList.remove('hidden');
encEmpty.classList.add('hidden');
} else {
@@ -2320,6 +2312,21 @@ views.recon = (root) => {
}
} catch (e) {}
}
const encLegend = document.getElementById('recon-enc-legend');
if (encLegend) {
encLegend.innerHTML = '';
RECON_ENC_BUCKETS.forEach((k, i) => {
const c = encCounts[k] || 0;
if (!c) return;
const entry = h('div', { class: 'recon-enc-entry' });
const dot = h('span', { class: 'recon-enc-dot' });
dot.style.background = RECON_ENC_COLORS[i];
entry.appendChild(dot);
entry.appendChild(h('span', { class: 'recon-enc-label', text: k }));
entry.appendChild(h('span', { class: 'recon-enc-count', text: String(c) }));
encLegend.appendChild(entry);
});
}
}
function detailUrl() {