fix: resolve two-window hang and sweep UI/theming updates

Fix app becoming unresponsive when two browser windows are open: the
root cause was HTTP/1.1 connection pool exhaustion (6-connection limit
per origin). VoiceAlerts was opening 3 SSE streams per window by
default, so two windows produced 8 connections and permanently starved
all regular HTTP requests.

- voice-alerts.js: default all streams to false (opt-in) to stay within
  the browser connection limit; existing user preferences in localStorage
  are preserved
- routes/alerts.py: replace direct AlertManager.stream_events() with
  sse_stream_fanout so both windows receive every alert instead of
  competing for the same queue
- routes/bluetooth_v2.py: same fanout fix via subscribe_fanout_queue,
  preserving named SSE events (device_update, scan_started, etc.)

Also includes accumulated UI/theming changes: accent-cyan CSS variable
sweep across mode CSS/JS files, standalone dashboard pages, template
updates, satellite TLE data refresh, and tile provider default rename.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
James Smith
2026-05-20 22:01:10 +01:00
parent 5100f55586
commit a3f2fa7b88
48 changed files with 1524 additions and 943 deletions
+8 -8
View File
@@ -10,15 +10,15 @@
align-items: center;
gap: 8px;
padding: 6px 12px;
background: rgba(0, 212, 255, 0.1);
border: 1px solid rgba(0, 212, 255, 0.3);
background: rgba(var(--accent-cyan-rgb), 0.1);
border: 1px solid rgba(var(--accent-cyan-rgb), 0.3);
border-radius: 20px;
cursor: pointer;
transition: all 0.2s;
}
.agent-indicator:hover {
background: rgba(0, 212, 255, 0.2);
background: rgba(var(--accent-cyan-rgb), 0.2);
border-color: var(--accent-cyan);
}
@@ -49,7 +49,7 @@
.agent-indicator-count {
font-size: 10px;
padding: 2px 6px;
background: rgba(0, 212, 255, 0.2);
background: rgba(var(--accent-cyan-rgb), 0.2);
border-radius: 10px;
color: var(--accent-cyan);
}
@@ -123,11 +123,11 @@
}
.agent-selector-item:hover {
background: rgba(0, 212, 255, 0.1);
background: rgba(var(--accent-cyan-rgb), 0.1);
}
.agent-selector-item.selected {
background: rgba(0, 212, 255, 0.15);
background: rgba(var(--accent-cyan-rgb), 0.15);
border-left: 3px solid var(--accent-cyan);
}
@@ -188,7 +188,7 @@
gap: 4px;
padding: 2px 8px;
font-size: 10px;
background: rgba(0, 212, 255, 0.1);
background: rgba(var(--accent-cyan-rgb), 0.1);
color: var(--accent-cyan);
border-radius: 10px;
font-family: var(--font-mono);
@@ -201,7 +201,7 @@
}
.agent-badge.agent-remote {
background: rgba(0, 212, 255, 0.1);
background: rgba(var(--accent-cyan-rgb), 0.1);
color: var(--accent-cyan);
}