UX: move analytics/copy URL buttons to top of node detail; live feed close/resize more visible; VCR bar labeled

This commit is contained in:
you
2026-03-19 23:12:30 +00:00
parent 5e315e615a
commit 2539e4c098
4 changed files with 29 additions and 30 deletions
+4 -4
View File
@@ -20,9 +20,9 @@
<meta name="twitter:title" content="MeshCore Analyzer">
<meta name="twitter:description" content="Real-time MeshCore LoRa mesh network analyzer — live packet visualization, node tracking, channel decryption, and route analysis.">
<meta name="twitter:image" content="https://raw.githubusercontent.com/Kpa-clawbot/meshcore-analyzer/master/public/og-image.png">
<link rel="stylesheet" href="style.css?v=1773961528">
<link rel="stylesheet" href="style.css?v=1773961950">
<link rel="stylesheet" href="home.css">
<link rel="stylesheet" href="live.css?v=1774080600">
<link rel="stylesheet" href="live.css?v=1773961950">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin="anonymous">
@@ -81,10 +81,10 @@
<script src="packets.js?v=1773961784"></script>
<script src="map.js?v=1774079160" onerror="console.error('Failed to load:', this.src)"></script>
<script src="channels.js?v=1774079160" onerror="console.error('Failed to load:', this.src)"></script>
<script src="nodes.js?v=1773961669" onerror="console.error('Failed to load:', this.src)"></script>
<script src="nodes.js?v=1773961950" onerror="console.error('Failed to load:', this.src)"></script>
<script src="traces.js?v=1774079160" onerror="console.error('Failed to load:', this.src)"></script>
<script src="analytics.js?v=1773961035" onerror="console.error('Failed to load:', this.src)"></script>
<script src="live.js?v=1773961528" onerror="console.error('Failed to load:', this.src)"></script>
<script src="live.js?v=1773961950" onerror="console.error('Failed to load:', this.src)"></script>
<script src="observers.js?v=1774079160" onerror="console.error('Failed to load:', this.src)"></script>
<script src="node-analytics.js?v=1773961276" onerror="console.error('Failed to load:', this.src)"></script>
</body>
+15 -14
View File
@@ -379,15 +379,14 @@
.live-feed.hidden { opacity: 0; transform: translateX(-100%); pointer-events: none; visibility: hidden; }
.feed-hide-btn {
position: absolute; top: 4px; right: 4px;
background: color-mix(in srgb, var(--text) 10%, transparent); border: none; color: var(--text-muted);
width: 20px; height: 20px; border-radius: 4px; cursor: pointer;
font-size: 10px; line-height: 1; display: flex; align-items: center; justify-content: center;
opacity: 0; transition: opacity 0.2s;
position: absolute; top: 6px; right: 6px;
background: color-mix(in srgb, var(--text) 15%, transparent); border: 1px solid var(--border); color: var(--text-muted);
width: 24px; height: 24px; border-radius: 6px; cursor: pointer;
font-size: 13px; line-height: 1; display: flex; align-items: center; justify-content: center;
opacity: 0.7; transition: opacity 0.2s, background 0.2s;
z-index: 5;
}
.live-feed:hover .feed-hide-btn { opacity: 1; }
.feed-hide-btn:hover { color: var(--text); background: rgba(239,68,68,0.4); }
.feed-hide-btn:hover { opacity: 1; color: #fff; background: rgba(239,68,68,0.6); }
.feed-show-btn {
position: absolute; bottom: 12px; left: 12px; z-index: 500;
@@ -685,18 +684,20 @@
z-index: 10;
}
.feed-resize-handle::after {
content: '';
content: '';
position: absolute;
top: 50%;
right: 2px;
width: 3px;
height: 24px;
right: 0px;
width: 10px;
height: 32px;
transform: translateY(-50%);
background: color-mix(in srgb, var(--text) 18%, transparent);
border-radius: 2px;
background: color-mix(in srgb, var(--text) 25%, transparent);
border-radius: 3px;
transition: background 0.2s;
display: flex; align-items: center; justify-content: center;
font-size: 14px; color: var(--text-muted); line-height: 32px; text-align: center;
}
.feed-resize-handle:hover::after { background: rgba(59,130,246,0.5); }
.feed-resize-handle:hover::after { background: rgba(59,130,246,0.5); color: #fff; }
/* Nav pin button (#62) */
.nav-pin-btn {
+1
View File
@@ -606,6 +606,7 @@
<div class="vcr-bar" id="vcrBar">
<div class="vcr-left">
<div class="vcr-controls">
<span style="font-size:10px;color:var(--text-muted);letter-spacing:1px;text-transform:uppercase;margin-right:6px">Playback</span>
<button id="vcrRewindBtn" class="vcr-btn" title="Rewind" aria-label="Rewind">⏪</button>
<button id="vcrPauseBtn" class="vcr-btn" title="Pause/Play" aria-label="Pause">⏸</button>
<button id="vcrLiveBtn" class="vcr-btn vcr-live-btn" title="Jump to live" aria-label="Snap to Live">LIVE</button>
+9 -12
View File
@@ -117,7 +117,11 @@
<div class="node-full-card">
<div class="node-detail-name" style="font-size:20px">${escapeHtml(n.name || '(unnamed)')}</div>
<div style="margin:6px 0 12px"><span class="badge" style="background:${roleColor}20;color:${roleColor}">${n.role}</span> ${statusLabel}</div>
<div class="node-detail-key mono" style="font-size:11px;word-break:break-all;margin-bottom:12px">${n.public_key}</div>
<div class="node-detail-key mono" style="font-size:11px;word-break:break-all;margin-bottom:8px">${n.public_key}</div>
<div style="margin-bottom:12px">
<button class="btn-primary" id="copyUrlBtn" style="font-size:12px;padding:4px 10px">📋 Copy URL</button>
<a href="#/nodes/${encodeURIComponent(n.public_key)}/analytics" class="btn-primary" style="display:inline-block;margin-left:6px;text-decoration:none;font-size:12px;padding:4px 10px">📊 Analytics</a>
</div>
<div class="node-qr" id="nodeFullQrCode"></div>
</div>
@@ -166,11 +170,6 @@
</div>`;
}).join('') : '<div class="text-muted">No recent packets</div>'}
</div>
</div>
<div style="text-align:center;padding:16px">
<button class="btn-primary" id="copyUrlBtn">📋 Copy URL</button>
<a href="#/nodes/${encodeURIComponent(n.public_key)}/analytics" class="btn-primary" style="display:inline-block;margin-left:8px;text-decoration:none">📊 Analytics</a>
</div>`;
// Map
@@ -437,7 +436,10 @@
<div class="node-detail">
${hasLoc ? `<div class="node-map-container node-detail-map" id="nodeMap" style="border-radius:8px;overflow:hidden;"></div>` : ''}
<div class="node-detail-name">${escapeHtml(n.name || '(unnamed)')}</div>
<div class="node-detail-role"><span class="badge" style="background:${roleColor}20;color:${roleColor}">${n.role}</span> ${statusLabel}</div>
<div class="node-detail-role"><span class="badge" style="background:${roleColor}20;color:${roleColor}">${n.role}</span> ${statusLabel}
<button class="btn-primary" id="copyUrlBtn" style="font-size:11px;padding:2px 8px;margin-left:8px">📋 URL</button>
<a href="#/nodes/${encodeURIComponent(n.public_key)}/analytics" class="btn-primary" style="display:inline-block;margin-left:4px;text-decoration:none;font-size:11px;padding:2px 8px">📊 Analytics</a>
</div>
<div class="node-detail-section">
<h4>Public Key</h4>
@@ -468,11 +470,6 @@
</div>
</div>` : ''}
<div style="text-align:center;margin-bottom:16px">
<button class="btn-primary" id="copyUrlBtn">📋 Copy URL</button>
<a href="#/nodes/${encodeURIComponent(n.public_key)}/analytics" class="btn-primary" style="display:inline-block;margin-left:8px;text-decoration:none">📊 Analytics</a>
</div>
<div class="node-detail-section">
<h4>Recent Packets (${adverts.length})</h4>
<div id="advertTimeline">