From fd9399d838f9ccc11b12bb765e01d74de5f52dcf Mon Sep 17 00:00:00 2001 From: James Smith Date: Sun, 21 Dec 2025 18:26:06 +0000 Subject: [PATCH] Add clickable drone details and improve UI cleanliness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Make drone counter clickable with detailed popup showing brand, SSID, BSSID, channel, signal, distance estimate, and detection time - Replace stats bar text labels with emoji icons and tooltips - Add collapsible sections (click header to toggle) - Slim down mode tabs with icons (📟 📡 📶 🔵) - Tighten spacing throughout (smaller padding, margins) - Add border-radius to buttons and tabs for softer look - Improve hover states and visual feedback 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- intercept.py | 215 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 174 insertions(+), 41 deletions(-) diff --git a/intercept.py b/intercept.py index b83c23f..abeb013 100755 --- a/intercept.py +++ b/intercept.py @@ -378,37 +378,57 @@ HTML_TEMPLATE = ''' } .section { - margin-bottom: 25px; + margin-bottom: 20px; } .section h3 { color: var(--accent-cyan); - margin-bottom: 15px; - padding-bottom: 10px; + margin-bottom: 12px; + padding-bottom: 8px; border-bottom: 1px solid var(--border-color); - font-size: 12px; + font-size: 11px; font-weight: 600; text-transform: uppercase; - letter-spacing: 3px; + letter-spacing: 2px; display: flex; align-items: center; - gap: 8px; + gap: 6px; + cursor: pointer; + user-select: none; } .section h3::before { - content: '//'; + content: '▼'; + font-size: 8px; color: var(--text-dim); + transition: transform 0.2s ease; + } + + .section.collapsed h3::before { + transform: rotate(-90deg); + } + + .section.collapsed > *:not(h3) { + display: none !important; + } + + .section h3:hover { + color: var(--text-primary); + } + + .section h3:hover::before { + color: var(--accent-cyan); } .form-group { - margin-bottom: 15px; + margin-bottom: 12px; } .form-group label { display: block; - margin-bottom: 6px; + margin-bottom: 4px; color: var(--text-secondary); - font-size: 11px; + font-size: 10px; text-transform: uppercase; letter-spacing: 1px; } @@ -416,12 +436,12 @@ HTML_TEMPLATE = ''' .form-group input, .form-group select { width: 100%; - padding: 12px 15px; + padding: 10px 12px; background: var(--bg-primary); border: 1px solid var(--border-color); color: var(--text-primary); font-family: 'JetBrains Mono', monospace; - font-size: 14px; + font-size: 13px; transition: all 0.2s ease; } @@ -467,16 +487,17 @@ HTML_TEMPLATE = ''' } .preset-btn { - padding: 10px 16px; + padding: 8px 14px; background: var(--bg-primary); border: 1px solid var(--border-color); color: var(--text-secondary); cursor: pointer; font-family: 'JetBrains Mono', monospace; - font-size: 12px; + font-size: 11px; text-transform: uppercase; letter-spacing: 1px; transition: all 0.2s ease; + border-radius: 3px; } .preset-btn:hover { @@ -488,20 +509,21 @@ HTML_TEMPLATE = ''' .run-btn { width: 100%; - padding: 16px; + padding: 14px; background: transparent; border: 2px solid var(--accent-green); color: var(--accent-green); font-family: 'Rajdhani', sans-serif; - font-size: 14px; + font-size: 13px; font-weight: 700; text-transform: uppercase; - letter-spacing: 4px; + letter-spacing: 3px; cursor: pointer; transition: all 0.3s ease; - margin-top: 15px; + margin-top: 12px; position: relative; overflow: hidden; + border-radius: 4px; } .run-btn::before { @@ -585,15 +607,29 @@ HTML_TEMPLATE = ''' .stats { display: flex; - gap: 25px; - font-size: 11px; + gap: 12px; + font-size: 10px; color: var(--text-secondary); font-family: 'JetBrains Mono', monospace; } + .stats > div { + display: flex; + align-items: center; + gap: 4px; + padding: 4px 8px; + background: var(--bg-primary); + border: 1px solid var(--border-color); + border-radius: 3px; + } + + .stats > div:hover { + border-color: var(--accent-cyan); + } + .stats span { color: var(--accent-cyan); - font-weight: 500; + font-weight: 600; } .output-content { @@ -872,23 +908,33 @@ HTML_TEMPLATE = ''' .mode-tabs { display: flex; gap: 0; - margin-bottom: 20px; + margin-bottom: 15px; border: 1px solid var(--border-color); + border-radius: 4px; + overflow: hidden; } .mode-tab { flex: 1; - padding: 12px 16px; + padding: 10px 8px; background: var(--bg-primary); border: none; color: var(--text-secondary); cursor: pointer; font-family: 'Rajdhani', sans-serif; - font-size: 12px; + font-size: 10px; font-weight: 600; text-transform: uppercase; - letter-spacing: 2px; + letter-spacing: 1px; transition: all 0.2s ease; + display: flex; + flex-direction: column; + align-items: center; + gap: 4px; + } + + .mode-tab .tab-icon { + font-size: 16px; } .mode-tab:not(:last-child) { @@ -1517,10 +1563,10 @@ HTML_TEMPLATE = ''' @@ -2061,6 +2107,20 @@ HTML_TEMPLATE = ''' let sensorCount = 0; let deviceList = {{ devices | tojson | safe }}; + // Make sections collapsible + document.addEventListener('DOMContentLoaded', function() { + document.querySelectorAll('.section h3').forEach(h3 => { + h3.addEventListener('click', function() { + this.parentElement.classList.toggle('collapsed'); + }); + }); + }); + + // Toggle section collapse + function toggleSection(el) { + el.closest('.section').classList.toggle('collapsed'); + } + // Mode switching function switchMode(mode) { // Stop any running scans when switching modes @@ -3489,6 +3549,79 @@ HTML_TEMPLATE = ''' document.body.appendChild(popup); } + // Show drone details popup + function showDroneDetails() { + const drones = Object.values(detectedDrones); + + if (drones.length === 0) { + showInfo('No drones detected. Drones are identified by SSID patterns and manufacturer OUI.'); + return; + } + + // Remove existing popup if any + const existing = document.getElementById('droneDetailsPopup'); + if (existing) existing.remove(); + + // Build details HTML + let html = '
'; + html += ` + + + + + + + + + `; + + drones.forEach((drone, idx) => { + const bgColor = idx % 2 === 0 ? 'rgba(255,165,0,0.1)' : 'transparent'; + const rssi = parseInt(drone.signal) || -70; + const distance = estimateDroneDistance(rssi); + const timeStr = new Date(drone.firstSeen).toLocaleTimeString(); + html += ` + + + + + + + + `; + }); + html += '
BrandSSIDBSSIDCHSignalDistanceDetected
${drone.brand || 'Unknown'}${drone.ssid || '[Hidden]'}${drone.bssid}${drone.channel || '?'}${drone.signal || '?'} dBm~${distance}m${timeStr}
'; + html += '
Detection via: SSID pattern matching and manufacturer OUI lookup
'; + + // Create popup + const popup = document.createElement('div'); + popup.id = 'droneDetailsPopup'; + popup.style.cssText = ` + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background: var(--bg-primary); + border: 1px solid var(--accent-orange); + border-radius: 8px; + padding: 16px; + z-index: 10000; + min-width: 500px; + max-width: 700px; + box-shadow: 0 4px 20px rgba(0,0,0,0.5); + `; + popup.innerHTML = ` +
+ 🚁 Detected Drones (${drones.length}) + +
+ ${html} + `; + + document.body.appendChild(popup); + } + // Update 5GHz channel graph function updateChannel5gGraph() { const bars = document.querySelectorAll('#channelGraph5g .channel-bar');