feat(pathanalyzer): map view polish - channel label, auto path, 45vh map

- Show the channel name (dimmed, next to the sender) on map-view tiles
- Clicking a message now auto-selects and draws its shortest routed echo
  (fewest hops, ties -> first); re-clicking keeps the user's echo choice
- Mobile: map takes a fixed 45% of the viewport height and the path list
  gets the remaining space (was min 300px map / max 40% list)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
MarekWo
2026-07-21 21:08:19 +02:00
parent 944493a56e
commit 0d9d9ecd57
2 changed files with 40 additions and 4 deletions
+24 -2
View File
@@ -688,6 +688,18 @@ function paBuildLegend(echo) {
return legend;
}
// Default echo selection: the routed echo with the fewest hops
// (ties -> first in arrival order)
function paShortestEchoIdx(msg) {
let best = null;
msg.echoView.forEach((echo, idx) => {
if (echo.hops > 0 && (best === null || echo.hops < msg.echoView[best].hops)) {
best = idx;
}
});
return best;
}
function paRenderMapView() {
paInitMap();
paPlotBaseMarkers();
@@ -715,13 +727,21 @@ function paRenderMapView() {
const head = document.createElement('div');
head.className = 'd-flex justify-content-between gap-2';
const left = document.createElement('div');
left.className = 'd-flex align-items-baseline gap-1';
left.style.minWidth = '0';
const senderEl = document.createElement('strong');
senderEl.className = 'text-truncate';
senderEl.textContent = msg.sender || '—';
const chanEl = document.createElement('span');
chanEl.className = 'pa-map-msg-chan';
chanEl.textContent = msg.channel_name || `#${msg.channel_idx}`;
left.appendChild(senderEl);
left.appendChild(chanEl);
const timeEl = document.createElement('span');
timeEl.className = 'text-muted text-nowrap';
timeEl.textContent = paFormatTime(msg).slice(5, 16);
head.appendChild(senderEl);
head.appendChild(left);
head.appendChild(timeEl);
entry.appendChild(head);
@@ -735,7 +755,9 @@ function paRenderMapView() {
}
entry.addEventListener('click', () => {
paMapSelection = { msgId: msg.id, echoIdx: null };
// Re-clicking the selected message keeps the user's echo choice
if (paMapSelection.msgId === msg.id) return;
paMapSelection = { msgId: msg.id, echoIdx: paShortestEchoIdx(msg) };
paRenderMapView();
});
+16 -2
View File
@@ -125,11 +125,19 @@
flex-direction: column;
}
/* Message/path list gets the remaining space, the map keeps a
fixed ~45% of the viewport height */
#paMapSidebar {
width: auto;
min-width: 0;
max-height: 40%;
flex-shrink: 1;
max-height: none;
flex: 1 1 0;
min-height: 0;
}
#paMap {
flex: 0 0 45vh;
min-height: 0;
}
}
@@ -364,6 +372,12 @@
color: #6f42c1;
}
.pa-map-msg-chan {
font-size: 0.72rem;
color: var(--text-secondary, #6c757d);
white-space: nowrap;
}
.pa-map-msg-preview {
font-size: 0.75rem;
color: var(--text-secondary, #6c757d);