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:
parent
06ed33ca67
commit
74e5181b7e
13
CHANGELOG.md
13
CHANGELOG.md
@ -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.
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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 */
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user