mirror of
https://github.com/MarekWo/mc-webui.git
synced 2026-07-29 13:03:18 +02:00
fix(pathanalyzer): Messages and Repeaters views fit narrow screens
Rather than a card-per-row transform (too much scrolling for 400+ messages), narrow viewports (<=576px) keep the table but shed secondary width: - Hash, HB and Echoes columns hidden; packet hash + HB surface as a line at the top of the expanded detail row instead (still copyable) - time renders as short date/time stacked on two lines (full timestamp on wide screens) - sender/channel/message-preview columns capped with ellipsis, tighter cell padding, headers allowed to wrap - stats view: Messages and As-last-hop columns hidden on phones (Repeater, Contact, Relayed, Avg SNR remain), contact names truncated - expanded echo paths now wrap fully within the viewport, keeping every hop chip and the jump-to-map button reachable Root cause of the first attempt failing: the media block sat mid- stylesheet, so later equal-specificity base rules overrode it - it now sits last, with a comment pinning it there. Verified live via Playwright at 390px: zero horizontal overflow in Messages (incl. an expanded 20-hop path, map button on-screen) and Repeaters; desktop 1280px layout unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -263,7 +263,10 @@ function paRenderTable() {
|
||||
|
||||
const tdTime = document.createElement('td');
|
||||
tdTime.className = 'pa-time';
|
||||
tdTime.textContent = paFormatTime(msg);
|
||||
const full = paFormatTime(msg);
|
||||
tdTime.innerHTML = `<span class="pa-time-full"></span><span class="pa-time-short"></span>`;
|
||||
tdTime.querySelector('.pa-time-full').textContent = full;
|
||||
tdTime.querySelector('.pa-time-short').textContent = full === '—' ? '—' : full.slice(5, 16);
|
||||
tr.appendChild(tdTime);
|
||||
|
||||
const tdChannel = document.createElement('td');
|
||||
@@ -283,6 +286,7 @@ function paRenderTable() {
|
||||
tr.appendChild(tdContent);
|
||||
|
||||
const tdHash = document.createElement('td');
|
||||
tdHash.className = 'pa-col-hash';
|
||||
if (msg.packet_hash) {
|
||||
const span = document.createElement('span');
|
||||
span.className = 'pa-hash';
|
||||
@@ -304,13 +308,13 @@ function paRenderTable() {
|
||||
tr.appendChild(tdHops);
|
||||
|
||||
const tdHb = document.createElement('td');
|
||||
tdHb.className = 'text-end';
|
||||
tdHb.className = 'text-end pa-col-hb';
|
||||
const hbSizes = [...new Set(msg.echoView.filter(e => e.hops > 0).map(e => e.hash_size || 1))].sort();
|
||||
tdHb.textContent = hbSizes.length > 0 ? hbSizes.join(',') : '—';
|
||||
tr.appendChild(tdHb);
|
||||
|
||||
const tdEchoes = document.createElement('td');
|
||||
tdEchoes.className = 'text-end';
|
||||
tdEchoes.className = 'text-end pa-col-echoes';
|
||||
tdEchoes.textContent = msg.echoView.length;
|
||||
tr.appendChild(tdEchoes);
|
||||
|
||||
@@ -322,6 +326,23 @@ function paRenderTable() {
|
||||
const detailTd = document.createElement('td');
|
||||
detailTd.className = 'pa-echo-cell';
|
||||
detailTd.colSpan = 9;
|
||||
if (msg.packet_hash) {
|
||||
// Narrow screens hide the Hash/HB columns - surface both here
|
||||
const hashLine = document.createElement('div');
|
||||
hashLine.className = 'pa-detail-hash';
|
||||
const hashSpan = document.createElement('span');
|
||||
hashSpan.className = 'pa-hash';
|
||||
hashSpan.textContent = msg.packet_hash;
|
||||
hashSpan.title = 'Click to copy';
|
||||
hashSpan.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
paCopyText(msg.packet_hash, 'Packet hash');
|
||||
});
|
||||
hashLine.append('Hash: ');
|
||||
hashLine.appendChild(hashSpan);
|
||||
if (hbSizes.length > 0) hashLine.append(` | HB: ${hbSizes.join(',')}`);
|
||||
detailTd.appendChild(hashLine);
|
||||
}
|
||||
msg.echoView.forEach((echo, echoIdx) => {
|
||||
detailTd.appendChild(paBuildEchoLine(msg, echo, echoIdx));
|
||||
});
|
||||
@@ -438,9 +459,9 @@ function paRenderStats() {
|
||||
}
|
||||
tr.appendChild(tdContact);
|
||||
|
||||
for (const val of [s.relayed, s.messages, s.lastHop]) {
|
||||
for (const [val, cls] of [[s.relayed, ''], [s.messages, ' pa-col-msgs'], [s.lastHop, ' pa-col-lasthop']]) {
|
||||
const td = document.createElement('td');
|
||||
td.className = 'text-end';
|
||||
td.className = 'text-end' + cls;
|
||||
td.textContent = val;
|
||||
tr.appendChild(td);
|
||||
}
|
||||
|
||||
@@ -166,6 +166,18 @@
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
/* Packet hash inside the expanded detail row - narrow screens only,
|
||||
where the Hash column is hidden */
|
||||
.pa-detail-hash {
|
||||
display: none;
|
||||
font-size: 0.75rem;
|
||||
padding-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
.pa-time-short {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pa-table-wrap {
|
||||
overflow-x: auto;
|
||||
}
|
||||
@@ -324,6 +336,91 @@
|
||||
display: block;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
/* Narrow screens: drop secondary columns so rows fit the viewport
|
||||
and echo paths can wrap (keeps the jump-to-map button reachable).
|
||||
Hash and HB move into the expanded detail row. Must stay LAST in
|
||||
this stylesheet so it overrides the base rules above. */
|
||||
@media (max-width: 576px) {
|
||||
.pa-col-hash,
|
||||
.pa-col-hb,
|
||||
.pa-col-msgs,
|
||||
.pa-col-lasthop {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pa-content-preview {
|
||||
max-width: 9rem;
|
||||
}
|
||||
|
||||
.pa-time-full {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pa-time-short {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.pa-detail-hash {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.pa-echo-cell {
|
||||
padding-left: 0.75rem;
|
||||
}
|
||||
|
||||
/* Long contact names must not push the SNR column off-screen */
|
||||
#paStatsBody td:nth-child(2) {
|
||||
max-width: 8rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.pa-col-echoes {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pa-table td,
|
||||
.pa-table th {
|
||||
padding: 0.3rem 0.2rem;
|
||||
}
|
||||
|
||||
/* Truncate long channel names */
|
||||
#paTableBody td:nth-child(3) {
|
||||
max-width: 3.8rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Let long headers (Avg SNR...) wrap instead of widening columns */
|
||||
.pa-table th {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
/* Truncate long sender names */
|
||||
#paTableBody td:nth-child(4) {
|
||||
max-width: 5.5rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.pa-content-preview {
|
||||
max-width: 5.2rem;
|
||||
}
|
||||
|
||||
/* Date and time stack into two lines */
|
||||
.pa-time {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.pa-time-short {
|
||||
display: inline-block;
|
||||
width: 3.2rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -399,10 +496,10 @@
|
||||
<th>Channel</th>
|
||||
<th>Sender</th>
|
||||
<th>Message</th>
|
||||
<th>Hash</th>
|
||||
<th class="pa-col-hash">Hash</th>
|
||||
<th class="text-end">Hops</th>
|
||||
<th class="text-end" title="Path hash size in bytes per hop (from routed echoes)">HB</th>
|
||||
<th class="text-end">Echoes</th>
|
||||
<th class="text-end pa-col-hb" title="Path hash size in bytes per hop (from routed echoes)">HB</th>
|
||||
<th class="text-end pa-col-echoes">Echoes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="paTableBody"></tbody>
|
||||
@@ -416,9 +513,9 @@
|
||||
<th>Contact</th>
|
||||
<th class="text-end pa-sortable" data-sort="relayed"
|
||||
title="Echoes whose path contains this hash (anywhere)">Relayed</th>
|
||||
<th class="text-end pa-sortable" data-sort="messages"
|
||||
<th class="text-end pa-sortable pa-col-msgs" data-sort="messages"
|
||||
title="Distinct messages relayed through this hash">Messages</th>
|
||||
<th class="text-end pa-sortable" data-sort="lastHop"
|
||||
<th class="text-end pa-sortable pa-col-lasthop" data-sort="lastHop"
|
||||
title="Echoes where this hash is the final hop (heard directly by us)">As last hop</th>
|
||||
<th class="text-end pa-sortable" data-sort="avgSnr"
|
||||
title="Average echo SNR, counted only when this hash is the final hop - SNR is measured at our receiver for the last hop">Avg SNR (last hop)</th>
|
||||
|
||||
Reference in New Issue
Block a user