fix: switch overlay dismissal and port dropdown selection persistence
All checks were successful
CI / fmt (push) Successful in 34s
CI / check (push) Successful in 1m14s
CI / clippy (push) Successful in 1m19s
Publish / frontend (push) Successful in 52s
Publish / backend (push) Successful in 2m36s

- Overlay now reliably dismissed: use window.setTimeout and inline
  overlay hide instead of separate function that could lose DOM ref
- Minimum 1s duration to prevent flash for short hotkey sequences
- Port dropdown preserves user's selection across page refreshes
  by tracking selectedPort locally instead of always using device's
  active_port
- Prevent duplicate change listener on port select across remounts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-07 13:20:30 +03:00
parent 2e6f80f9ac
commit edb6853e3a

View File

@@ -56,6 +56,8 @@ export function unmountConsole() {
ws?.close() ws?.close()
ws = null ws = null
buttonMask = 0 buttonMask = 0
inputSuspended = false
portSelectWired = false
if (containerEl) containerEl.innerHTML = '' if (containerEl) containerEl.innerHTML = ''
containerEl = null containerEl = null
} }
@@ -157,6 +159,8 @@ function handleMessage(ev: MessageEvent) {
let portHotkeys: Record<number, string> = {} let portHotkeys: Record<number, string> = {}
let keyPauseDuration = 2000 let keyPauseDuration = 2000
let inputSuspended = false let inputSuspended = false
let selectedPort = -1
let portSelectWired = false
async function loadPortList() { async function loadPortList() {
try { try {
@@ -168,32 +172,39 @@ async function loadPortList() {
if (!select) return if (!select) return
select.innerHTML = '' select.innerHTML = ''
portHotkeys = {} portHotkeys = {}
// Use locally tracked selection if we've switched, otherwise use device's active port
const activePort = selectedPort >= 0 ? selectedPort : data.active_port
for (const p of data.ports) { for (const p of data.ports) {
const opt = document.createElement('option') const opt = document.createElement('option')
opt.value = String(p.index) opt.value = String(p.index)
opt.textContent = p.name || `Port ${p.index + 1}` opt.textContent = p.name || `Port ${p.index + 1}`
opt.selected = p.index === data.active_port opt.selected = p.index === activePort
select.appendChild(opt) select.appendChild(opt)
if (p.hotkey) portHotkeys[p.index] = p.hotkey if (p.hotkey) portHotkeys[p.index] = p.hotkey
} }
if (!portSelectWired) {
select.addEventListener('change', () => { select.addEventListener('change', () => {
const port = parseInt(select.value) const port = parseInt(select.value)
switchToPort(port) switchToPort(port)
}) })
portSelectWired = true
}
} catch { /* port list optional */ } } catch { /* port list optional */ }
} }
function switchToPort(port: number) { function switchToPort(port: number) {
selectedPort = port
const hotkey = portHotkeys[port] const hotkey = portHotkeys[port]
if (!hotkey || ws?.readyState !== WebSocket.OPEN) return if (!hotkey || ws?.readyState !== WebSocket.OPEN) return
// Count pause tokens to calculate total switch duration // Count pause tokens to calculate total switch duration
const pauseCount = (hotkey.match(/\*/g) || []).length const pauseCount = (hotkey.match(/\*/g) || []).length
const totalDelay = pauseCount * keyPauseDuration + 500 // +500ms buffer const totalDelay = (pauseCount * keyPauseDuration) + 500 // +500ms buffer
// Suspend input and show overlay // Suspend input and show overlay
inputSuspended = true inputSuspended = true
showSwitchOverlay(totalDelay) const duration = Math.max(totalDelay, 1000)
showSwitchOverlay(duration)
// Send the hotkey sequence // Send the hotkey sequence
const messages = parseHotkey(hotkey) const messages = parseHotkey(hotkey)
@@ -209,11 +220,12 @@ function switchToPort(port: number) {
}).catch(() => {}) }).catch(() => {})
// Resume input after the switch completes // Resume input after the switch completes
setTimeout(() => { window.setTimeout(() => {
inputSuspended = false inputSuspended = false
hideSwitchOverlay() const overlay = document.getElementById('switch-overlay')
if (overlay) overlay.hidden = true
document.getElementById('canvas')?.focus() document.getElementById('canvas')?.focus()
}, totalDelay) }, duration)
} }
function showSwitchOverlay(duration: number) { function showSwitchOverlay(duration: number) {
@@ -245,11 +257,6 @@ function showSwitchOverlay(duration: number) {
tick() tick()
} }
function hideSwitchOverlay() {
const overlay = document.getElementById('switch-overlay')
if (overlay) overlay.hidden = true
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Input handlers // Input handlers
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------