wave3: categorized collapsible HUD (Space/Air/Sea/Earth/Context/Regional)
12+ layers in a flat list was unusable. ui.js now groups rows into ordered, collapsible category sections (scheme owned in ui.js so order is stable regardless of registration order); Regional — Australia collapsed by default; empty categories auto-hidden via :has(:empty). URL-state get/set layer APIs unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
941f5032e0
commit
3dde813d7d
@ -115,9 +115,32 @@ html, body {
|
|||||||
#layers {
|
#layers {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 2px;
|
gap: 1px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---- collapsible category sections ---- */
|
||||||
|
.cat:has(.cat-body:empty) { display: none; } /* hide unused categories */
|
||||||
|
.cat-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 4px 4px 3px;
|
||||||
|
margin-top: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
color: var(--dim);
|
||||||
|
font-size: 9.5px;
|
||||||
|
letter-spacing: 0.6px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
.cat-header:hover { color: var(--text); }
|
||||||
|
.cat-chevron { font-size: 8px; width: 8px; transition: transform 0.15s; }
|
||||||
|
.cat.collapsed .cat-chevron { transform: rotate(-90deg); }
|
||||||
|
.cat.collapsed .cat-body { display: none; }
|
||||||
|
.cat-body { display: flex; flex-direction: column; gap: 1px; }
|
||||||
|
|
||||||
.layer-row {
|
.layer-row {
|
||||||
padding: 5px 4px;
|
padding: 5px 4px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
|
|||||||
57
js/ui.js
57
js/ui.js
@ -1,9 +1,60 @@
|
|||||||
// HUD controller: layer registry, per-feed status lines, LIVE/SCRUBBED chip.
|
// HUD controller: categorized collapsible layer list, per-feed status lines,
|
||||||
|
// LIVE/SCRUBBED chip.
|
||||||
|
|
||||||
const rows = new Map();
|
const rows = new Map();
|
||||||
|
|
||||||
|
// Category scheme is owned here so HUD order is stable regardless of layer
|
||||||
|
// registration order. Categories collapsed-by-default are marked below.
|
||||||
|
const CATEGORY_ORDER = ['Space', 'Air', 'Sea', 'Earth & hazards', 'Context', 'Regional — Australia'];
|
||||||
|
const COLLAPSED_BY_DEFAULT = new Set(['Regional — Australia']);
|
||||||
|
const CATEGORY_BY_ID = {
|
||||||
|
satellites: 'Space', 'sat-paths': 'Space', launches: 'Space',
|
||||||
|
aircraft: 'Air', military: 'Air', 'aircraft-mil': 'Air',
|
||||||
|
ships: 'Sea',
|
||||||
|
quakes: 'Earth & hazards', fires: 'Earth & hazards', gdacs: 'Earth & hazards', nws: 'Earth & hazards',
|
||||||
|
infra: 'Context', events: 'Context',
|
||||||
|
rfs: 'Regional — Australia',
|
||||||
|
};
|
||||||
|
|
||||||
|
const sections = new Map(); // category → { body }
|
||||||
|
|
||||||
|
// Lazily create a category section, inserted in CATEGORY_ORDER position.
|
||||||
|
function sectionFor(category) {
|
||||||
|
if (sections.has(category)) return sections.get(category);
|
||||||
|
const wrap = document.createElement('div');
|
||||||
|
wrap.className = 'cat';
|
||||||
|
if (COLLAPSED_BY_DEFAULT.has(category)) wrap.classList.add('collapsed');
|
||||||
|
const header = document.createElement('div');
|
||||||
|
header.className = 'cat-header';
|
||||||
|
header.innerHTML = `<span class="cat-chevron">▾</span><span class="cat-name"></span>`;
|
||||||
|
header.querySelector('.cat-name').textContent = category;
|
||||||
|
header.addEventListener('click', () => wrap.classList.toggle('collapsed'));
|
||||||
|
const body = document.createElement('div');
|
||||||
|
body.className = 'cat-body';
|
||||||
|
wrap.appendChild(header);
|
||||||
|
wrap.appendChild(body);
|
||||||
|
|
||||||
|
// Insert before the existing section that is this one's immediate successor in
|
||||||
|
// CATEGORY_ORDER (smallest index greater than ours), so DOM order stays stable
|
||||||
|
// regardless of registration order. Unknown categories sort last.
|
||||||
|
const container = document.getElementById('layers');
|
||||||
|
const ord = (c) => { const i = CATEGORY_ORDER.indexOf(c); return i < 0 ? Infinity : i; };
|
||||||
|
const myOrder = ord(category);
|
||||||
|
let before = null, bestOrder = Infinity;
|
||||||
|
for (const [cat, s] of sections) {
|
||||||
|
const idx = ord(cat);
|
||||||
|
if (idx > myOrder && idx < bestOrder) { bestOrder = idx; before = s.wrap; }
|
||||||
|
}
|
||||||
|
container.insertBefore(wrap, before);
|
||||||
|
const rec = { wrap, body };
|
||||||
|
sections.set(category, rec);
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
// Register a layer row. Returns a handle so callers can flip the checkbox.
|
// Register a layer row. Returns a handle so callers can flip the checkbox.
|
||||||
export function addLayer(id, name, defaultOn, onToggle) {
|
// `category` is optional; a known id maps to a fixed category regardless.
|
||||||
|
export function addLayer(id, name, defaultOn, onToggle, category) {
|
||||||
|
const cat = CATEGORY_BY_ID[id] || category || 'Other';
|
||||||
const row = document.createElement('div');
|
const row = document.createElement('div');
|
||||||
row.className = 'layer-row';
|
row.className = 'layer-row';
|
||||||
row.innerHTML = `
|
row.innerHTML = `
|
||||||
@ -16,7 +67,7 @@ export function addLayer(id, name, defaultOn, onToggle) {
|
|||||||
row.querySelector('.lname').textContent = name;
|
row.querySelector('.lname').textContent = name;
|
||||||
const cb = row.querySelector('input');
|
const cb = row.querySelector('input');
|
||||||
cb.addEventListener('change', () => onToggle(cb.checked));
|
cb.addEventListener('change', () => onToggle(cb.checked));
|
||||||
document.getElementById('layers').appendChild(row);
|
sectionFor(cat).body.appendChild(row);
|
||||||
rows.set(id, row);
|
rows.set(id, row);
|
||||||
return { setChecked: (v) => { cb.checked = v; } };
|
return { setChecked: (v) => { cb.checked = v; } };
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user