From dc7c05b03f49968ffeccd9a0079c74ae503bb73d Mon Sep 17 00:00:00 2001 From: Smittix Date: Wed, 25 Feb 2026 23:26:47 +0000 Subject: [PATCH] Fix welcome dashboard jitter and refine Morse mode UI Fix "What's New" section shifting up/down on smaller screens (#157) by isolating the logo pulse animation to its own compositing layer, stabilizing the scrollbar gutter, and pinning the welcome container dimensions. Morse mode improvements: relocate scope and decoded output panels to the main content area, use shared SDR device controls, and reduce panel heights for better layout. Co-Authored-By: Claude Opus 4.6 --- static/css/index.css | 4 ++ static/css/modes/morse.css | 15 ++---- static/js/modes/morse.js | 35 +++++++++--- templates/index.html | 83 +++++++++++++++++++++-------- templates/partials/modes/morse.html | 18 ------- 5 files changed, 97 insertions(+), 58 deletions(-) diff --git a/static/css/index.css b/static/css/index.css index 0adb406..b10518b 100644 --- a/static/css/index.css +++ b/static/css/index.css @@ -206,6 +206,8 @@ body { max-width: 900px; z-index: 1; animation: welcomeFadeIn 0.8s ease-out; + max-height: calc(100vh - 40px); + overflow: hidden; } @keyframes welcomeFadeIn { @@ -232,6 +234,7 @@ body { .welcome-logo { animation: logoPulse 3s ease-in-out infinite; + will-change: filter; } @keyframes logoPulse { @@ -332,6 +335,7 @@ body { padding: 20px; max-height: calc(100vh - 300px); overflow-y: auto; + scrollbar-gutter: stable; } .changelog-release { diff --git a/static/css/modes/morse.css b/static/css/modes/morse.css index 4e46e09..844bf49 100644 --- a/static/css/modes/morse.css +++ b/static/css/modes/morse.css @@ -11,7 +11,7 @@ .morse-scope-container canvas { width: 100%; - height: 120px; + height: 80px; display: block; border-radius: 4px; } @@ -21,8 +21,8 @@ background: var(--bg-primary); border: 1px solid var(--border-color); border-radius: 6px; - padding: 16px; - min-height: 200px; + padding: 12px; + min-height: 120px; max-height: 400px; overflow-y: auto; font-family: var(--font-mono); @@ -30,7 +30,6 @@ line-height: 1.6; color: var(--text-primary); word-wrap: break-word; - flex: 1; } .morse-decoded-panel:empty::before { @@ -112,14 +111,6 @@ gap: 4px; } -/* Visuals container layout */ -#morseVisuals { - flex-direction: column; - gap: 12px; - padding: 16px; - height: 100%; -} - /* Word space styling */ .morse-word-space { display: inline; diff --git a/static/js/modes/morse.js b/static/js/modes/morse.js index 779e0db..b594bf6 100644 --- a/static/js/modes/morse.js +++ b/static/js/modes/morse.js @@ -67,11 +67,11 @@ var MorseMode = (function () { frequency: document.getElementById('morseFrequency').value || '14.060', gain: document.getElementById('morseGain').value || '0', ppm: document.getElementById('morsePPM').value || '0', - device: document.getElementById('morseDevice').value || '0', - sdr_type: document.getElementById('morseSdrType').value || 'rtlsdr', + device: document.getElementById('deviceSelect')?.value || '0', + sdr_type: document.getElementById('sdrTypeSelect')?.value || 'rtlsdr', tone_freq: document.getElementById('morseToneFreq').value || '700', wpm: document.getElementById('morseWpm').value || '15', - bias_t: document.getElementById('morseBiasT').checked, + bias_t: typeof getBiasTEnabled === 'function' ? getBiasTEnabled() : false, }; fetch('/morse/start', { @@ -191,6 +191,8 @@ var MorseMode = (function () { // Update count var countEl = document.getElementById('morseCharCount'); if (countEl) countEl.textContent = state.charCount + ' chars'; + var barChars = document.getElementById('morseStatusBarChars'); + if (barChars) barChars.textContent = state.charCount + ' chars decoded'; } function appendSpace() { @@ -210,6 +212,8 @@ var MorseMode = (function () { state.decodedLog = []; var countEl = document.getElementById('morseCharCount'); if (countEl) countEl.textContent = '0 chars'; + var barChars = document.getElementById('morseStatusBarChars'); + if (barChars) barChars.textContent = '0 chars decoded'; } // ---- Scope canvas ---- @@ -221,21 +225,28 @@ var MorseMode = (function () { var dpr = window.devicePixelRatio || 1; var rect = canvas.getBoundingClientRect(); canvas.width = rect.width * dpr; - canvas.height = 120 * dpr; - canvas.style.height = '120px'; + canvas.height = 80 * dpr; + canvas.style.height = '80px'; scopeCtx = canvas.getContext('2d'); scopeCtx.scale(dpr, dpr); scopeHistory = []; + var toneLabel = document.getElementById('morseScopeToneLabel'); + var threshLabel = document.getElementById('morseScopeThreshLabel'); + function draw() { if (!scopeCtx) return; var w = rect.width; - var h = 120; + var h = 80; - scopeCtx.fillStyle = '#0a0e14'; + scopeCtx.fillStyle = '#050510'; scopeCtx.fillRect(0, 0, w, h); + // Update header labels + if (toneLabel) toneLabel.textContent = scopeToneOn ? 'ON' : '--'; + if (threshLabel) threshLabel.textContent = scopeThreshold > 0 ? Math.round(scopeThreshold) : '--'; + if (scopeHistory.length === 0) { scopeAnim = requestAnimationFrame(draw); return; @@ -356,6 +367,16 @@ var MorseMode = (function () { if (statusText) { statusText.textContent = running ? 'Listening' : 'Standby'; } + + // Toggle scope and output panels (pager/sensor pattern) + var scopePanel = document.getElementById('morseScopePanel'); + var outputPanel = document.getElementById('morseOutputPanel'); + if (scopePanel) scopePanel.style.display = running ? 'block' : 'none'; + if (outputPanel) outputPanel.style.display = running ? 'block' : 'none'; + + var scopeStatus = document.getElementById('morseScopeStatusLabel'); + if (scopeStatus) scopeStatus.textContent = running ? 'ACTIVE' : 'IDLE'; + if (scopeStatus) scopeStatus.style.color = running ? '#0f0' : '#444'; } function setFreq(mhz) { diff --git a/templates/index.html b/templates/index.html index bd65eb3..019da83 100644 --- a/templates/index.html +++ b/templates/index.html @@ -3008,24 +3008,6 @@ - -