Fix conversation input bar hidden when mic is blocked

- Move mic-blocked warning into conv-chat-window (prepend) so it scrolls
  with the chat instead of pushing the input bar off-screen
- Remove min-height:400px from conv-chat-window; give conv-chat-panel a
  viewport-relative height so the input bar is always visible at the bottom
- loader.js: append ?v=<timestamp> to section fetches to bust browser cache
  (was serving stale s-conversation.html after updates)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
mARTin-B78 2026-05-29 14:20:52 +02:00
parent 06ed33ca67
commit 74e5181b7e
4 changed files with 29 additions and 8 deletions

View File

@ -7,6 +7,19 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi
## [Unreleased] ## [Unreleased]
### Fixed
- **Conversation input bar hidden when mic unavailable** — the mic-blocked
warning box was inserted before `conv-chat-window` inside the flex column,
pushing the input bar off-screen. Fixed by prepending the warning inside
`conv-chat-window` so it scrolls with the chat and never affects the bar.
- **Chat panel overflow / missing input bar on smaller viewports** — removed
`min-height: 400px` from `conv-chat-window` (prevented shrinking) and gave
`conv-chat-panel` a viewport-relative height (`calc(100vh - 340px)`,
min 440px) so the input bar is always anchored at the bottom.
- **Browser caches old section HTML after updates**`loader.js` now appends
`?v=<timestamp>` to every section fetch, busting the cache on each page load.
### Added ### Added
- **`scripts/release.py`** — automates version bump + CHANGELOG promotion. - **`scripts/release.py`** — automates version bump + CHANGELOG promotion.

View File

@ -143,7 +143,7 @@ $('s-import-voices-file')?.addEventListener('change', async function () {
} }
const flagsUrl = 'chrome://flags/#unsafely-treat-insecure-origin-as-secure'; const flagsUrl = 'chrome://flags/#unsafely-treat-insecure-origin-as-secure';
const warn = document.createElement('div'); const warn = document.createElement('div');
warn.style.cssText = 'background:var(--red,#c00);color:#fff;padding:12px 16px;border-radius:8px;margin:12px 0;font-size:13px;line-height:1.7'; warn.style.cssText = 'background:var(--red,#c00);color:#fff;padding:12px 16px;border-radius:8px;margin:0 0 12px;font-size:13px;line-height:1.7;flex-shrink:0';
warn.innerHTML = warn.innerHTML =
'<strong>⚠ Microphone blocked by browser</strong><br>' + '<strong>⚠ Microphone blocked by browser</strong><br>' +
'Browsers only allow microphone access on <b>secure contexts</b> (HTTPS or localhost).<br>' + 'Browsers only allow microphone access on <b>secure contexts</b> (HTTPS or localhost).<br>' +
@ -154,7 +154,9 @@ $('s-import-voices-file')?.addEventListener('change', async function () {
`<button onclick="navigator.clipboard?.writeText('${flagsUrl}').then(()=>{this.textContent='Copied!';setTimeout(()=>this.textContent='Copy',1500)})" ` + `<button onclick="navigator.clipboard?.writeText('${flagsUrl}').then(()=>{this.textContent='Copied!';setTimeout(()=>this.textContent='Copy',1500)})" ` +
'style="flex-shrink:0;background:rgba(255,255,255,.2);border:1px solid rgba(255,255,255,.45);color:#fff;border-radius:4px;padding:4px 10px;font-size:12px;cursor:pointer;font-weight:600">Copy</button>' + 'style="flex-shrink:0;background:rgba(255,255,255,.2);border:1px solid rgba(255,255,255,.45);color:#fff;border-radius:4px;padding:4px 10px;font-size:12px;cursor:pointer;font-weight:600">Copy</button>' +
'</div>'; '</div>';
chatWindow && chatWindow.parentElement && chatWindow.parentElement.insertBefore(warn, chatWindow); // Insert inside the chat window so it scrolls with the conversation and
// never pushes the input bar off-screen.
if (chatWindow) chatWindow.prepend(warn);
} }
// Restore conv LLM URL from server settings // Restore conv LLM URL from server settings

View File

@ -13,10 +13,12 @@
}); });
} }
// 1. Fetch all section partials in parallel and inject into their shells // 1. Fetch all section partials in parallel and inject into their shells.
// ?v= busts the browser cache so updated HTML is always used.
var _v = Date.now();
await Promise.all(SECTIONS.map(async function (id) { await Promise.all(SECTIONS.map(async function (id) {
try { try {
var res = await fetch('/static/sections/' + id + '.html'); var res = await fetch('/static/sections/' + id + '.html?v=' + _v);
if (!res.ok) throw new Error(res.status + ' ' + res.statusText); if (!res.ok) throw new Error(res.status + ' ' + res.statusText);
var html = await res.text(); var html = await res.text();
var el = document.getElementById(id); var el = document.getElementById(id);

View File

@ -2028,12 +2028,16 @@ code { background: var(--panel); border-radius: 4px; padding: 1px 5px; font-fami
.conv-system-textarea { flex: 1; resize: vertical; min-height: 34px; max-height: 120px; padding: 6px 10px; border: 1px solid var(--border); border-radius: var(--radius); font-size: 13px; font-family: var(--font); background: var(--surface); color: var(--text); } .conv-system-textarea { flex: 1; resize: vertical; min-height: 34px; max-height: 120px; padding: 6px 10px; border: 1px solid var(--border); border-radius: var(--radius); font-size: 13px; font-family: var(--font); background: var(--surface); color: var(--text); }
/* Layout */ /* Layout */
.conv-main { display: flex; gap: 14px; margin-top: 14px; min-height: 520px; } .conv-main { display: flex; gap: 14px; margin-top: 14px; }
.conv-chat-panel { flex: 1; display: flex; flex-direction: column; gap: 0; min-width: 0; } /* Chat panel: fixed height so the input bar never gets pushed off-screen */
.conv-chat-panel {
flex: 1; display: flex; flex-direction: column; gap: 0; min-width: 0;
height: calc(100vh - 340px); min-height: 440px;
}
.conv-stats-panel { width: 280px; flex-shrink: 0; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px; display: flex; flex-direction: column; gap: 8px; } .conv-stats-panel { width: 280px; flex-shrink: 0; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px; display: flex; flex-direction: column; gap: 8px; }
/* Chat window */ /* Chat window fills the space above the input bar; warning box scrolls inside it */
.conv-chat-window { flex: 1; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius) var(--radius) 0 0; padding: 16px; overflow-y: auto; display: flex; flex-direction: column; gap: 12px; min-height: 400px; } .conv-chat-window { flex: 1; min-height: 0; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius) var(--radius) 0 0; padding: 16px; overflow-y: auto; display: flex; flex-direction: column; gap: 12px; }
.conv-chat-welcome { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; flex: 1; color: var(--subtext); text-align: center; } .conv-chat-welcome { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; flex: 1; color: var(--subtext); text-align: center; }
/* Bubbles */ /* Bubbles */