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);