diff --git a/app/static/css/style.css b/app/static/css/style.css index b8e6d01..7fe8cc6 100644 --- a/app/static/css/style.css +++ b/app/static/css/style.css @@ -780,11 +780,6 @@ main { position: relative; } -.dm-route-link > .path-popup { - left: auto; - right: 0; -} - .dm-delivery-popup { position: absolute; bottom: 100%; @@ -1444,7 +1439,8 @@ main { .path-popup { position: absolute; bottom: 100%; - left: 0; + right: 0; + left: auto; background-color: #333; color: #fff; padding: 0.4rem 0.6rem; @@ -1456,13 +1452,18 @@ main { margin-bottom: 4px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25); min-width: 180px; - max-width: 320px; + max-width: min(320px, calc(100vw - 1.5rem)); } .path-popup .path-entry { padding: 0.15rem 0; border-bottom: 1px solid rgba(255, 255, 255, 0.15); word-break: break-all; + cursor: pointer; +} + +.path-popup .path-entry:active { + opacity: 0.6; } .path-popup .path-entry:last-child { diff --git a/app/static/js/app.js b/app/static/js/app.js index 877b446..fdc0306 100644 --- a/app/static/js/app.js +++ b/app/static/js/app.js @@ -1504,7 +1504,6 @@ function showPathsPopup(element, encodedPaths) { const popup = document.createElement('div'); popup.className = 'path-popup'; - let html = ''; paths.forEach((p, i) => { const pChunkLen = (p.hash_size || 1) * 2; const segments = []; @@ -1514,15 +1513,34 @@ function showPathsPopup(element, encodedPaths) { } } const fullRoute = segments.join(' \u2192 '); + const commaRoute = segments.join(','); const snr = p.snr !== null && p.snr !== undefined ? `${p.snr.toFixed(1)} dB` : '?'; const hops = segments.length; - html += `
${fullRoute}SNR: ${snr} | Hops: ${hops}
`; + const entry = document.createElement('div'); + entry.className = 'path-entry'; + entry.innerHTML = `${fullRoute}SNR: ${snr} | Hops: ${hops}`; + entry.title = 'Tap to copy route'; + entry.addEventListener('click', (e) => { + e.stopPropagation(); + navigator.clipboard.writeText(commaRoute).then(() => { + const orig = entry.innerHTML; + entry.innerHTML = 'Copied!'; + setTimeout(() => { entry.innerHTML = orig; }, 1000); + }); + }); + popup.appendChild(entry); }); - popup.innerHTML = html; element.style.position = 'relative'; element.appendChild(popup); + // Adjust if popup overflows viewport + const rect = popup.getBoundingClientRect(); + if (rect.left < 4) { + popup.style.right = 'auto'; + popup.style.left = '0'; + } + // Auto-dismiss after 8 seconds or on outside tap const dismiss = () => popup.remove(); setTimeout(dismiss, 8000); diff --git a/app/static/js/dm.js b/app/static/js/dm.js index 7caf536..5e6ccc1 100644 --- a/app/static/js/dm.js +++ b/app/static/js/dm.js @@ -1455,10 +1455,25 @@ function showDmRoutePopup(element, hexPath, hashSize) { const segments = segmentHexPath(hexPath, hashSize || 1); const fullRoute = segments.join(' \u2192 '); + const commaRoute = segments.join(','); const popup = document.createElement('div'); popup.className = 'path-popup'; - popup.innerHTML = `
${fullRoute}Hops: ${segments.length}
`; + + const entry = document.createElement('div'); + entry.className = 'path-entry'; + entry.innerHTML = `${fullRoute}Hops: ${segments.length}`; + entry.title = 'Tap to copy route'; + entry.addEventListener('click', (e) => { + e.stopPropagation(); + navigator.clipboard.writeText(commaRoute).then(() => { + const orig = entry.innerHTML; + entry.innerHTML = 'Copied!'; + setTimeout(() => { entry.innerHTML = orig; }, 1000); + }); + }); + popup.appendChild(entry); + element.style.position = 'relative'; element.appendChild(popup);