diff --git a/static/css/index.css b/static/css/index.css index 7244b58..ec52d18 100644 --- a/static/css/index.css +++ b/static/css/index.css @@ -3387,29 +3387,130 @@ header h1 .tagline { background: linear-gradient(90deg, #ef4444, #dc2626); } -/* Bluetooth Device Cards */ -.bt-device-card { - margin-bottom: 8px; - padding: 10px !important; - border-left-color: var(--accent-purple) !important; +/* Bluetooth Device Row - Compact Design */ +.bt-device-row { + display: flex; + flex-direction: column; + background: var(--bg-tertiary); + border: 1px solid var(--border-color); + border-left: 4px solid #666; + border-radius: 6px; + padding: 10px 12px; + margin-bottom: 6px; + cursor: pointer; + transition: all 0.15s ease; } -.bt-device-card .header { - font-size: 12px; +.bt-device-row:hover { + background: rgba(0, 212, 255, 0.05); + border-color: var(--accent-cyan); } -.bt-device-card .sensor-data { +.bt-row-main { + display: flex; + justify-content: space-between; + align-items: center; + gap: 12px; +} + +.bt-row-left { + display: flex; + align-items: center; + gap: 8px; + min-width: 0; + flex: 1; +} + +.bt-row-right { + display: flex; + align-items: center; + gap: 10px; + flex-shrink: 0; +} + +.bt-proto-badge { + display: inline-block; + padding: 2px 6px; + border-radius: 3px; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.3px; + flex-shrink: 0; +} + +.bt-proto-badge.ble { + background: rgba(59, 130, 246, 0.2); + color: #3b82f6; + border: 1px solid rgba(59, 130, 246, 0.3); +} + +.bt-proto-badge.classic { + background: rgba(139, 92, 246, 0.2); + color: #8b5cf6; + border: 1px solid rgba(139, 92, 246, 0.3); +} + +.bt-device-name { + font-size: 13px; + font-weight: 600; + color: var(--text-primary); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.bt-rssi-container { + display: flex; + align-items: center; + gap: 6px; +} + +.bt-rssi-bar-bg { + width: 50px; + height: 8px; + background: var(--bg-secondary); + border-radius: 4px; + overflow: hidden; +} + +.bt-rssi-bar { + height: 100%; + border-radius: 4px; + transition: width 0.3s ease; +} + +.bt-rssi-value { + font-family: 'JetBrains Mono', monospace; + font-size: 11px; + font-weight: 600; + min-width: 28px; + text-align: right; +} + +.bt-status-dot { + width: 8px; + height: 8px; + border-radius: 50%; + flex-shrink: 0; +} + +.bt-status-dot.new { + background: #3b82f6; + box-shadow: 0 0 6px rgba(59, 130, 246, 0.5); +} + +.bt-status-dot.known { + background: #22c55e; +} + +.bt-row-secondary { font-size: 10px; -} - -.bt-device-card.tracker { - border-left-color: var(--accent-orange) !important; - background: rgba(255, 165, 0, 0.05); -} - -.bt-device-card.findmy { - border-left-color: #007aff !important; - background: rgba(0, 122, 255, 0.05); + color: var(--text-dim); + margin-top: 4px; + padding-left: 42px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } /* Bluetooth Device Modal */ diff --git a/static/js/modes/bluetooth.js b/static/js/modes/bluetooth.js index 2f450dd..f227bcc 100644 --- a/static/js/modes/bluetooth.js +++ b/static/js/modes/bluetooth.js @@ -783,64 +783,54 @@ const BluetoothMode = (function() { function createSimpleDeviceCard(device) { const protocol = device.protocol || 'ble'; - const protoBadge = protocol === 'ble' - ? 'BLE' - : 'CLASSIC'; + const rssi = device.rssi_current; + const rssiColor = getRssiColor(rssi); + const inBaseline = device.in_baseline || false; + const isNew = !inBaseline; + const hasName = !!device.name; - const flags = device.heuristic_flags || []; - let badgesHtml = ''; - if (flags.includes('random_address')) { - badgesHtml += 'RANDOM'; - } - if (flags.includes('persistent')) { - badgesHtml += 'PERSISTENT'; - } + // Calculate RSSI bar width (0-100%) + // RSSI typically ranges from -100 (weak) to -30 (very strong) + const rssiPercent = rssi != null ? Math.max(0, Math.min(100, ((rssi + 100) / 70) * 100)) : 0; const displayName = device.name || formatDeviceId(device.address); const name = escapeHtml(displayName); const addr = escapeHtml(device.address || 'Unknown'); - const addrType = escapeHtml(device.address_type || 'unknown'); - const rssi = device.rssi_current; - const rssiStr = (rssi != null) ? rssi + ' dBm' : '--'; - const rssiColor = getRssiColor(rssi); const mfr = device.manufacturer_name ? escapeHtml(device.manufacturer_name) : ''; const seenCount = device.seen_count || 0; - const rangeBand = device.range_band || 'unknown'; - const inBaseline = device.in_baseline || false; - - const cardStyle = 'display:block;background:#1a1a2e;border:1px solid #444;border-radius:8px;padding:14px;margin-bottom:10px;cursor:pointer;transition:border-color 0.2s;'; - const headerStyle = 'display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;'; - const nameStyle = 'font-size:14px;font-weight:600;color:#e0e0e0;margin-bottom:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;'; - const addrStyle = 'font-family:monospace;font-size:11px;color:#00d4ff;'; - const rssiRowStyle = 'display:flex;justify-content:space-between;align-items:center;background:#141428;padding:10px;border-radius:6px;margin:10px 0;'; - const rssiValueStyle = 'font-family:monospace;font-size:16px;font-weight:700;color:' + rssiColor + ';'; - const rangeBandStyle = 'font-size:10px;color:#888;text-transform:uppercase;letter-spacing:0.5px;'; - const mfrStyle = 'font-size:11px;color:#888;margin-bottom:6px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;'; - const metaStyle = 'display:flex;justify-content:space-between;font-size:10px;color:#666;'; - const statusPillStyle = 'background:' + (inBaseline ? 'rgba(34,197,94,0.15)' : 'rgba(59,130,246,0.15)') + ';color:' + (inBaseline ? '#22c55e' : '#3b82f6') + ';padding:3px 10px;border-radius:12px;font-size:10px;font-weight:500;'; - const deviceIdEscaped = escapeHtml(device.device_id).replace(/'/g, "\\'"); - const isNew = !inBaseline; - const hasName = !!device.name; - return '