diff --git a/app/static/js/path-analyzer.js b/app/static/js/path-analyzer.js index 3f4eb50..a8dd7be 100644 --- a/app/static/js/path-analyzer.js +++ b/app/static/js/path-analyzer.js @@ -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 = ``; + 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); } diff --git a/app/templates/path-analyzer.html b/app/templates/path-analyzer.html index ecde3ef..ffc72bf 100644 --- a/app/templates/path-analyzer.html +++ b/app/templates/path-analyzer.html @@ -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; + } + }
@@ -399,10 +496,10 @@