Improve Bluetooth panel layout, signal bars, and add device filtering

- Rearranged layout: Proximity Radar on top, Tracker Detection and
  Signal Distribution side-by-side below for better space usage
- Made signal distribution bars thicker (16px) with gradient styling
  for better visibility
- Added device filtering with buttons: All, New, Named, Strong signal
- Filter buttons show filtered count (e.g., "5/37") when active

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Smittix
2026-01-21 19:43:09 +00:00
parent b0ab361ead
commit c5eb63ae7f
3 changed files with 192 additions and 46 deletions
+65 -10
View File
@@ -3269,8 +3269,28 @@ header h1 .tagline {
min-height: 400px;
}
.bt-layout-container .wifi-visuals {
.bt-visuals-column {
flex: 1;
display: flex;
flex-direction: column;
gap: 12px;
min-width: 0;
}
.bt-radar-panel {
flex: 1;
min-height: 0;
}
.bt-bottom-panels {
display: flex;
gap: 12px;
flex-shrink: 0;
}
.bt-compact-panel {
flex: 1;
min-width: 0;
}
.bt-device-list {
@@ -3281,33 +3301,68 @@ header h1 .tagline {
color: var(--accent-purple);
}
/* Bluetooth Device Filters */
.bt-device-filters {
display: flex;
gap: 6px;
padding: 8px 12px;
border-bottom: 1px solid var(--border-color);
flex-wrap: wrap;
}
.bt-filter-btn {
padding: 5px 12px;
font-size: 11px;
background: var(--bg-tertiary);
border: 1px solid var(--border-color);
border-radius: 4px;
color: var(--text-dim);
cursor: pointer;
transition: all 0.2s ease;
}
.bt-filter-btn:hover {
background: var(--bg-secondary);
color: var(--text-primary);
}
.bt-filter-btn.active {
background: var(--accent-purple);
border-color: var(--accent-purple);
color: white;
}
/* Bluetooth Signal Distribution */
.bt-signal-dist {
display: flex;
flex-direction: column;
gap: 8px;
font-size: 10px;
gap: 12px;
font-size: 11px;
padding: 4px 0;
}
.signal-range {
display: flex;
align-items: center;
gap: 8px;
gap: 10px;
}
.signal-range span:first-child {
width: 70px;
width: 80px;
color: var(--text-dim);
font-size: 10px;
}
.signal-range span:last-child {
width: 20px;
width: 28px;
text-align: right;
font-weight: 600;
font-size: 12px;
}
.signal-bar-bg {
flex: 1;
height: 8px;
height: 16px;
background: var(--bg-tertiary);
border-radius: 4px;
overflow: hidden;
@@ -3320,15 +3375,15 @@ header h1 .tagline {
}
.signal-bar.strong {
background: var(--accent-green);
background: linear-gradient(90deg, #22c55e, #16a34a);
}
.signal-bar.medium {
background: var(--accent-orange);
background: linear-gradient(90deg, #eab308, #ca8a04);
}
.signal-bar.weak {
background: var(--accent-red);
background: linear-gradient(90deg, #ef4444, #dc2626);
}
/* Bluetooth Device Cards */
+89 -5
View File
@@ -33,6 +33,9 @@ const BluetoothMode = (function() {
let radarInitialized = false;
let radarPaused = false;
// Device list filter
let currentDeviceFilter = 'all';
/**
* Initialize the Bluetooth mode
*/
@@ -64,10 +67,87 @@ const BluetoothMode = (function() {
// Initialize legacy heatmap (zone counts)
initHeatmap();
// Initialize device list filters
initDeviceFilters();
// Set initial panel states
updateVisualizationPanels();
}
/**
* Initialize device list filter buttons
*/
function initDeviceFilters() {
const filterContainer = document.getElementById('btDeviceFilters');
if (!filterContainer) return;
filterContainer.addEventListener('click', (e) => {
const btn = e.target.closest('.bt-filter-btn');
if (!btn) return;
const filter = btn.dataset.filter;
if (!filter) return;
// Update active state
filterContainer.querySelectorAll('.bt-filter-btn').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
// Apply filter
currentDeviceFilter = filter;
applyDeviceFilter();
});
}
/**
* Apply current filter to device list
*/
function applyDeviceFilter() {
if (!deviceContainer) return;
const cards = deviceContainer.querySelectorAll('[data-bt-device-id]');
cards.forEach(card => {
const isNew = card.dataset.isNew === 'true';
const hasName = card.dataset.hasName === 'true';
const rssi = parseInt(card.dataset.rssi) || -100;
let visible = true;
switch (currentDeviceFilter) {
case 'new':
visible = isNew;
break;
case 'named':
visible = hasName;
break;
case 'strong':
visible = rssi >= -70;
break;
case 'all':
default:
visible = true;
}
card.style.display = visible ? 'block' : 'none';
});
// Update visible count
updateFilteredCount();
}
/**
* Update the device count display based on visible devices
*/
function updateFilteredCount() {
const countEl = document.getElementById('btDeviceListCount');
if (!countEl || !deviceContainer) return;
if (currentDeviceFilter === 'all') {
countEl.textContent = devices.size;
} else {
const visible = deviceContainer.querySelectorAll('[data-bt-device-id]:not([style*="display: none"])').length;
countEl.textContent = visible + '/' + devices.size;
}
}
/**
* Initialize the new proximity radar component
*/
@@ -676,10 +756,7 @@ const BluetoothMode = (function() {
}
function updateDeviceCount() {
const countEl = document.getElementById('btDeviceListCount');
if (countEl) {
countEl.textContent = devices.size;
}
updateFilteredCount();
}
function renderDevice(device) {
@@ -697,6 +774,11 @@ const BluetoothMode = (function() {
} else {
deviceContainer.insertAdjacentHTML('afterbegin', cardHtml);
}
// Re-apply filter after rendering
if (currentDeviceFilter !== 'all') {
applyDeviceFilter();
}
}
function createSimpleDeviceCard(device) {
@@ -738,8 +820,10 @@ const BluetoothMode = (function() {
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 '<div data-bt-device-id="' + escapeHtml(device.device_id) + '" style="' + cardStyle + '" onclick="BluetoothMode.selectDevice(\'' + deviceIdEscaped + '\')" onmouseover="this.style.borderColor=\'#00d4ff\'" onmouseout="this.style.borderColor=\'#444\'">' +
return '<div data-bt-device-id="' + escapeHtml(device.device_id) + '" data-is-new="' + isNew + '" data-has-name="' + hasName + '" data-rssi="' + (rssi || -100) + '" style="' + cardStyle + '" onclick="BluetoothMode.selectDevice(\'' + deviceIdEscaped + '\')" onmouseover="this.style.borderColor=\'#00d4ff\'" onmouseout="this.style.borderColor=\'#444\'">' +
'<div style="' + headerStyle + '">' +
'<div>' + protoBadge + badgesHtml + '</div>' +
'<span style="' + statusPillStyle + '">' + (inBaseline ? '✓ Known' : '● New') + '</span>' +
+38 -31
View File
@@ -706,9 +706,9 @@
<!-- Bluetooth Layout Container (visualizations left, device cards right) -->
<div class="bt-layout-container" id="btLayoutContainer" style="display: none;">
<!-- Left: Bluetooth Visualizations -->
<div class="wifi-visuals" id="btVisuals">
<!-- Row 1: Proximity Radar + Device Types -->
<div class="wifi-visual-panel" style="grid-row: span 2;">
<div class="bt-visuals-column" id="btVisuals">
<!-- Proximity Radar -->
<div class="wifi-visual-panel bt-radar-panel">
<h5>Proximity Radar</h5>
<div id="btProximityRadar" style="display: flex; justify-content: center; padding: 8px 0;"></div>
<div id="btRadarControls" style="display: flex; gap: 6px; justify-content: center; margin-top: 8px; flex-wrap: wrap;">
@@ -717,46 +717,47 @@
<button data-filter="unapproved" class="bt-radar-filter-btn" style="padding: 4px 10px; font-size: 10px; background: var(--bg-tertiary); border: 1px solid var(--border-color); border-radius: 4px; color: #888; cursor: pointer;">Unapproved</button>
<button id="btRadarPauseBtn" style="padding: 4px 10px; font-size: 10px; background: var(--bg-tertiary); border: 1px solid var(--border-color); border-radius: 4px; color: #888; cursor: pointer;">Pause</button>
</div>
<div id="btZoneSummary" style="display: flex; justify-content: center; gap: 16px; margin-top: 12px; font-size: 11px;">
<div id="btZoneSummary" style="display: flex; justify-content: center; gap: 24px; margin-top: 12px; font-size: 11px;">
<div style="text-align: center;">
<span id="btZoneImmediate" style="font-size: 18px; font-weight: 600; color: #22c55e;">0</span>
<span id="btZoneImmediate" style="font-size: 20px; font-weight: 600; color: #22c55e;">0</span>
<div style="color: #666;">Immediate</div>
</div>
<div style="text-align: center;">
<span id="btZoneNear" style="font-size: 18px; font-weight: 600; color: #eab308;">0</span>
<span id="btZoneNear" style="font-size: 20px; font-weight: 600; color: #eab308;">0</span>
<div style="color: #666;">Near</div>
</div>
<div style="text-align: center;">
<span id="btZoneFar" style="font-size: 18px; font-weight: 600; color: #ef4444;">0</span>
<span id="btZoneFar" style="font-size: 20px; font-weight: 600; color: #ef4444;">0</span>
<div style="color: #666;">Far</div>
</div>
</div>
</div>
<!-- Row 2: Tracker Detection + Signal Analysis -->
<div class="wifi-visual-panel">
<h5>Tracker Detection</h5>
<div id="btTrackerList" style="max-height: 120px; overflow-y: auto; font-size: 11px;">
<div style="color: var(--text-dim); padding: 10px; text-align: center;">Monitoring for
AirTags, Tiles...</div>
<!-- Bottom row: Tracker Detection + Signal Distribution -->
<div class="bt-bottom-panels">
<div class="wifi-visual-panel bt-compact-panel">
<h5>Tracker Detection</h5>
<div id="btTrackerList" style="font-size: 11px;">
<div style="color: var(--text-dim); padding: 10px; text-align: center;">Monitoring for AirTags, Tiles...</div>
</div>
</div>
</div>
<div class="wifi-visual-panel">
<h5>Signal Distribution</h5>
<div class="bt-signal-dist" id="btSignalDist">
<div class="signal-range"><span>Strong (-50+)</span>
<div class="signal-bar-bg">
<div class="signal-bar strong" id="btSignalStrong" style="width: 0%;"></div>
</div><span id="btSignalStrongCount">0</span>
</div>
<div class="signal-range"><span>Medium (-70)</span>
<div class="signal-bar-bg">
<div class="signal-bar medium" id="btSignalMedium" style="width: 0%;"></div>
</div><span id="btSignalMediumCount">0</span>
</div>
<div class="signal-range"><span>Weak (-90)</span>
<div class="signal-bar-bg">
<div class="signal-bar weak" id="btSignalWeak" style="width: 0%;"></div>
</div><span id="btSignalWeakCount">0</span>
<div class="wifi-visual-panel bt-compact-panel">
<h5>Signal Distribution</h5>
<div class="bt-signal-dist" id="btSignalDist">
<div class="signal-range"><span>Strong (-50+)</span>
<div class="signal-bar-bg">
<div class="signal-bar strong" id="btSignalStrong" style="width: 0%;"></div>
</div><span id="btSignalStrongCount">0</span>
</div>
<div class="signal-range"><span>Medium (-70)</span>
<div class="signal-bar-bg">
<div class="signal-bar medium" id="btSignalMedium" style="width: 0%;"></div>
</div><span id="btSignalMediumCount">0</span>
</div>
<div class="signal-range"><span>Weak (-90)</span>
<div class="signal-bar-bg">
<div class="signal-bar weak" id="btSignalWeak" style="width: 0%;"></div>
</div><span id="btSignalWeakCount">0</span>
</div>
</div>
</div>
</div>
@@ -767,6 +768,12 @@
<h5>Bluetooth Devices</h5>
<span class="device-count">(<span id="btDeviceListCount">0</span>)</span>
</div>
<div class="bt-device-filters" id="btDeviceFilters">
<button class="bt-filter-btn active" data-filter="all">All</button>
<button class="bt-filter-btn" data-filter="new">New</button>
<button class="bt-filter-btn" data-filter="named">Named</button>
<button class="bt-filter-btn" data-filter="strong">Strong</button>
</div>
<div class="wifi-device-list-content" id="btDeviceListContent">
<div style="color: var(--text-dim); text-align: center; padding: 30px;">
Start scanning to discover Bluetooth devices