From 2cb62d5f34ed450d1be92580193d3acf3020a294 Mon Sep 17 00:00:00 2001 From: Smittix Date: Tue, 20 Jan 2026 22:29:28 +0000 Subject: [PATCH] Standardize all icons to uniform inline SVG format Replace emojis throughout the codebase with inline SVG icons using the Icons utility. Remove decorative icons where text labels already describe the content. Add classification dot CSS for risk indicators. - Extend Icons utility with comprehensive SVG icon set - Update navigation, header stats, and action buttons - Update playback controls and volume icons - Remove decorative device type and panel header emojis - Clean up notifications and alert messages - Add CSS for classification status dots Co-Authored-By: Claude Opus 4.5 --- static/css/modes/tscm.css | 22 ++ static/js/components/signal-cards.js | 7 +- static/js/components/signal-timeline.js | 15 +- static/js/core/audio.js | 4 +- static/js/core/utils.js | 237 ++++++++++------ static/js/modes/listening-post.js | 16 +- templates/index.html | 358 +++++++++++------------- templates/partials/modes/wifi.html | 8 +- 8 files changed, 355 insertions(+), 312 deletions(-) diff --git a/static/css/modes/tscm.css b/static/css/modes/tscm.css index a5d167f..ea742ff 100644 --- a/static/css/modes/tscm.css +++ b/static/css/modes/tscm.css @@ -1354,6 +1354,28 @@ color: var(--text-secondary); } +/* Classification Dots - replaces emoji circles for risk levels */ +.classification-dot { + display: inline-block; + width: 10px; + height: 10px; + border-radius: 50%; + vertical-align: middle; + margin-right: 4px; +} + +.classification-dot.high { + background-color: var(--accent-red); +} + +.classification-dot.review { + background-color: var(--accent-orange); +} + +.classification-dot.info { + background-color: var(--accent-green); +} + /* Device Indicators with Icons */ .device-indicator-icon { display: inline-flex; diff --git a/static/js/components/signal-cards.js b/static/js/components/signal-cards.js index 2f3187e..1cf5914 100644 --- a/static/js/components/signal-cards.js +++ b/static/js/components/signal-cards.js @@ -1072,22 +1072,19 @@ const SignalCards = (function() { const stats = getAddressStats('meter', msg.id); const seenCount = stats ? stats.count : 1; - // Determine meter type icon and color - let meterIcon = '⚡'; + // Determine meter type color let meterTypeClass = 'electric'; const meterType = (msg.type || '').toLowerCase(); if (meterType.includes('gas')) { - meterIcon = '🔥'; meterTypeClass = 'gas'; } else if (meterType.includes('water')) { - meterIcon = '💧'; meterTypeClass = 'water'; } card.innerHTML = `
- ${meterIcon} ${escapeHtml(msg.type || 'Meter')} + ${escapeHtml(msg.type || 'Meter')} ID: ${escapeHtml(msg.id || 'N/A')}
${status !== 'baseline' ? ` diff --git a/static/js/components/signal-timeline.js b/static/js/components/signal-timeline.js index c4bca50..df08dae 100644 --- a/static/js/components/signal-timeline.js +++ b/static/js/components/signal-timeline.js @@ -730,16 +730,17 @@ const SignalTimeline = (function() { container.style.display = 'block'; container.innerHTML = recentAnnotations.map(ann => { - const icons = { - new: '🆕', - burst: '⚡', - pattern: '🔄', - flagged: '🚩', - gone: '📴' + const iconFuncs = { + new: () => Icons.newBadge('icon--sm'), + burst: () => Icons.meter('icon--sm'), + pattern: () => Icons.refresh('icon--sm'), + flagged: () => Icons.flag('icon--sm'), + gone: () => Icons.offline('icon--sm') }; + const iconHtml = iconFuncs[ann.type] ? iconFuncs[ann.type]() : Icons.sensor('icon--sm'); return `
- ${icons[ann.type] || '📡'} + ${iconHtml} ${ann.message} ${formatTimeAgo(ann.timestamp)}
diff --git a/static/js/core/audio.js b/static/js/core/audio.js index 2b58c0e..b99c2df 100644 --- a/static/js/core/audio.js +++ b/static/js/core/audio.js @@ -211,7 +211,7 @@ function isMuted() { function updateMuteButton() { const btn = document.getElementById('muteBtn'); if (btn) { - btn.innerHTML = audioMuted ? '🔇 UNMUTE' : '🔊 MUTE'; + btn.innerHTML = audioMuted ? Icons.volumeOff('icon--sm') + ' UNMUTE' : Icons.volumeOn('icon--sm') + ' MUTE'; btn.classList.toggle('muted', audioMuted); } } @@ -226,7 +226,7 @@ function requestNotificationPermission() { Notification.requestPermission().then(permission => { notificationsEnabled = permission === 'granted'; if (notificationsEnabled && typeof showInfo === 'function') { - showInfo('🔔 Desktop notifications enabled'); + showInfo('Desktop notifications enabled'); } }); } diff --git a/static/js/core/utils.js b/static/js/core/utils.js index 6f9676a..d09f7a1 100644 --- a/static/js/core/utils.js +++ b/static/js/core/utils.js @@ -277,119 +277,170 @@ function mapRange(value, inMin, inMax, outMin, outMax) { // Designed for screenshot legibility - standard symbols only. const Icons = { - /** - * WiFi icon - standard arc/fan shape - */ + // ===== Signal Type Icons ===== wifi: function(className) { - return ` - - - - - - - `; + return ``; }, - - /** - * Bluetooth icon - standard rune - */ bluetooth: function(className) { - return ` - - - - `; + return ``; }, - - /** - * Cellular icon - ascending bars - */ cellular: function(className) { - return ` - - - - - - - `; + return ``; + }, + radio: function(className) { + return ``; }, - /** - * Unknown/RF signal - generic wave - */ - signalUnknown: function(className) { - return ` - - - - `; + // ===== Mode Icons ===== + pager: function(className) { + return ``; + }, + sensor: function(className) { + return ``; + }, + aircraft: function(className) { + return ``; + }, + satellite: function(className) { + return ``; + }, + location: function(className) { + return ``; + }, + search: function(className) { + return ``; + }, + meter: function(className) { + return ``; + }, + scanner: function(className) { + return ``; }, - /** - * Recording indicator - filled circle - */ + // ===== Status Icons ===== + warning: function(className) { + return ``; + }, + check: function(className) { + return ``; + }, + x: function(className) { + return ``; + }, recording: function(className) { - return ` - - - - `; + return ``; }, - - /** - * Anomaly indicator - filled circle (amber by default via CSS) - */ anomaly: function(className) { - return ` - - - - `; + return ``; + }, + flag: function(className) { + return ``; + }, + newBadge: function(className) { + return ``; + }, + offline: function(className) { + return ``; }, - /** - * Export icon - arrow out of box - */ - export: function(className) { - return ` - - - - - - `; + // ===== Device Type Icons ===== + user: function(className) { + return ``; + }, + drone: function(className) { + return ``; + }, + military: function(className) { + return ``; + }, + handshake: function(className) { + return ``; }, - /** - * Refresh icon - circular arrows - */ + // ===== Action Icons ===== refresh: function(className) { - return ` - - - - - - `; + return ``; + }, + download: function(className) { + return ``; + }, + export: function(className) { + return ``; + }, + copy: function(className) { + return ``; + }, + link: function(className) { + return ``; + }, + chart: function(className) { + return ``; + }, + star: function(className) { + return ``; + }, + target: function(className) { + return ``; + }, + settings: function(className) { + return ``; }, - /** - * Get icon by signal type - * Maps protocol names to appropriate icons - */ + // ===== Playback Controls ===== + play: function(className) { + return ``; + }, + pause: function(className) { + return ``; + }, + stop: function(className) { + return ``; + }, + headphones: function(className) { + return ``; + }, + volumeOn: function(className) { + return ``; + }, + volumeOff: function(className) { + return ``; + }, + + // ===== UI Icons ===== + sun: function(className) { + return ``; + }, + moon: function(className) { + return ``; + }, + arrowDown: function(className) { + return ``; + }, + chevronDown: function(className) { + return ``; + }, + chevronRight: function(className) { + return ``; + }, + chevronLeft: function(className) { + return ``; + }, + mail: function(className) { + return ``; + }, + loader: function(className) { + return ``; + }, + bell: function(className) { + return ``; + }, + + // ===== Helper function ===== forSignalType: function(type, className) { const t = (type || '').toLowerCase(); - if (t.includes('wifi') || t.includes('802.11')) { - return this.wifi(className); - } - if (t.includes('bluetooth') || t.includes('bt') || t.includes('ble')) { - return this.bluetooth(className); - } - if (t.includes('cellular') || t.includes('lte') || t.includes('gsm') || t.includes('5g')) { - return this.cellular(className); - } - return this.signalUnknown(className); + if (t.includes('wifi') || t.includes('802.11')) return this.wifi(className); + if (t.includes('bluetooth') || t.includes('bt') || t.includes('ble')) return this.bluetooth(className); + if (t.includes('cellular') || t.includes('lte') || t.includes('gsm') || t.includes('5g')) return this.cellular(className); + return this.radio(className); } }; diff --git a/static/js/modes/listening-post.js b/static/js/modes/listening-post.js index 1fb87fb..5f9f588 100644 --- a/static/js/modes/listening-post.js +++ b/static/js/modes/listening-post.js @@ -216,7 +216,7 @@ function startScanner() { // Update radio scan button to show STOP const radioScanBtn = document.getElementById('radioScanBtn'); if (radioScanBtn) { - radioScanBtn.innerHTML = '⏹ STOP'; + radioScanBtn.innerHTML = Icons.stop('icon--sm') + ' STOP'; radioScanBtn.style.background = 'var(--accent-red)'; radioScanBtn.style.borderColor = 'var(--accent-red)'; } @@ -268,7 +268,7 @@ function stopScanner() { const pauseBtn = document.getElementById('scannerPauseBtn'); if (pauseBtn) { pauseBtn.disabled = true; - pauseBtn.textContent = '⏸ Pause'; + pauseBtn.innerHTML = Icons.pause('icon--sm') + ' Pause'; } // Update radio scan button @@ -338,7 +338,7 @@ function pauseScanner() { .then(data => { isScannerPaused = !isScannerPaused; const pauseBtn = document.getElementById('scannerPauseBtn'); - if (pauseBtn) pauseBtn.textContent = isScannerPaused ? '▶ Resume' : '⏸ Pause'; + if (pauseBtn) pauseBtn.innerHTML = isScannerPaused ? Icons.play('icon--sm') + ' Resume' : Icons.pause('icon--sm') + ' Pause'; const statusText = document.getElementById('scannerStatusText'); if (statusText) { statusText.textContent = isScannerPaused ? 'PAUSED' : 'SCANNING'; @@ -873,7 +873,7 @@ function startAudio() { } }); - document.getElementById('audioStartBtn').textContent = '⏹ Stop Audio'; + document.getElementById('audioStartBtn').innerHTML = Icons.stop('icon--sm') + ' Stop Audio'; document.getElementById('audioStartBtn').classList.add('active'); document.getElementById('audioTunedFreq').textContent = frequency.toFixed(2) + ' MHz (' + modulation.toUpperCase() + ')'; document.getElementById('audioDeviceStatus').textContent = 'SDR ' + device; @@ -896,7 +896,7 @@ async function stopAudio() { await fetch('/listening/audio/stop', { method: 'POST' }); if (typeof releaseDevice === 'function') releaseDevice('audio'); isAudioPlaying = false; - document.getElementById('audioStartBtn').textContent = '▶ Play Audio'; + document.getElementById('audioStartBtn').innerHTML = Icons.play('icon--sm') + ' Play Audio'; document.getElementById('audioStartBtn').classList.remove('active'); document.getElementById('audioStatus').textContent = 'STOPPED'; document.getElementById('audioStatus').style.color = 'var(--text-muted)'; @@ -1741,7 +1741,7 @@ async function _startDirectListenInternal() { const listenBtn = document.getElementById('radioListenBtn'); if (listenBtn) { - listenBtn.innerHTML = '⏳ TUNING...'; + listenBtn.innerHTML = Icons.loader('icon--sm') + ' TUNING...'; listenBtn.style.background = 'var(--accent-orange)'; listenBtn.style.borderColor = 'var(--accent-orange)'; } @@ -1879,11 +1879,11 @@ function updateDirectListenUI(isPlaying, freq) { if (listenBtn) { if (isPlaying) { - listenBtn.innerHTML = '⏹ STOP'; + listenBtn.innerHTML = Icons.stop('icon--sm') + ' STOP'; listenBtn.style.background = 'var(--accent-red)'; listenBtn.style.borderColor = 'var(--accent-red)'; } else { - listenBtn.innerHTML = '🎧 LISTEN'; + listenBtn.innerHTML = Icons.headphones('icon--sm') + ' LISTEN'; listenBtn.style.background = 'var(--accent-purple)'; listenBtn.style.borderColor = 'var(--accent-purple)'; } diff --git a/templates/index.html b/templates/index.html index cbf6ad3..030fbe4 100644 --- a/templates/index.html +++ b/templates/index.html @@ -78,47 +78,47 @@

Select Mode

- ✈️ + Aircraft ADS-B tracking @@ -137,7 +137,7 @@