Commit 829e340b by michaelpastushkov

fix

parent fad46d13
...@@ -156,14 +156,12 @@ ...@@ -156,14 +156,12 @@
opacity: .98; opacity: .98;
} }
/* Sticky in-content scroll indicator (fixed to avoid overlap with composer/footer) */ /* Fixed scroll-to-bottom button (ensures visibility above composer/footer) */
#scrollDownBtn { #scrollDownBtn {
position: fixed; position: fixed;
/* changed from sticky to ensure visibility */
right: 1rem; right: 1rem;
bottom: calc(var(--footer-h) + var(--composer-h) + 1rem); bottom: calc(var(--footer-h) + var(--composer-h) + 1rem);
z-index: 1031; z-index: 1031;
/* above composer/footer */
display: none; display: none;
border: none; border: none;
border-radius: 999px; border-radius: 999px;
...@@ -261,7 +259,7 @@ ...@@ -261,7 +259,7 @@
} }
async function loadLocale(locale) { async function loadLocale(locale) {
try { try {
const res = await fetch(\`/locales/\${locale}.json\`, { cache: 'no-store' }); const res = await fetch(`/locales/${locale}.json`, { cache: 'no-store' });
if (!res.ok) throw new Error('HTTP ' + res.status); if (!res.ok) throw new Error('HTTP ' + res.status);
I18N = await res.json(); I18N = await res.json();
CURRENT_LOCALE = locale; CURRENT_LOCALE = locale;
...@@ -271,7 +269,7 @@ ...@@ -271,7 +269,7 @@
if (locale !== DEFAULT_LOCALE) await loadLocale(DEFAULT_LOCALE); if (locale !== DEFAULT_LOCALE) await loadLocale(DEFAULT_LOCALE);
} }
} }
function t(key, fallback='') { function t(key, fallback = '') {
const parts = key.split('.'); const parts = key.split('.');
let cur = I18N; let cur = I18N;
for (const p of parts) { for (const p of parts) {
...@@ -299,18 +297,18 @@ ...@@ -299,18 +297,18 @@
if (inputText) { if (inputText) {
inputText.placeholder = isRunning inputText.placeholder = isRunning
? t('status.thinking', 'Thinking…') ? t('status.thinking', 'Thinking…')
: t('composer.placeholder','What can I help you with?'); : t('composer.placeholder', 'What can I help you with?');
} }
const goBtn = document.getElementById('goBtn'); const goBtn = document.getElementById('goBtn');
if (goBtn) goBtn.textContent = t('buttons.go','Go'); if (goBtn) goBtn.textContent = t('buttons.go', 'Go');
const stopBtn = document.getElementById('stopBtn'); const stopBtn = document.getElementById('stopBtn');
if (stopBtn) stopBtn.textContent = t('buttons.stop','Stop'); if (stopBtn) stopBtn.textContent = t('buttons.stop', 'Stop');
const disclaimer = document.getElementById('disclaimer'); const disclaimer = document.getElementById('disclaimer');
if (disclaimer) disclaimer.textContent = t('footer.disclaimer','Beware: Cat can make mistakes.'); if (disclaimer) disclaimer.textContent = t('footer.disclaimer', 'Beware: Cat can make mistakes.');
const scrollDownBtn = document.getElementById('scrollDownBtn'); const scrollDownBtn = document.getElementById('scrollDownBtn');
if (scrollDownBtn) { if (scrollDownBtn) {
scrollDownBtn.setAttribute('aria-label', t('buttons.scrollDown','Scroll down')); scrollDownBtn.setAttribute('aria-label', t('buttons.scrollDown', 'Scroll down'));
scrollDownBtn.title = t('buttons.scrollDown','Scroll down'); scrollDownBtn.title = t('buttons.scrollDown', 'Scroll down');
} }
setWelcomeImage(); setWelcomeImage();
} }
...@@ -333,15 +331,15 @@ ...@@ -333,15 +331,15 @@
// --- helpers --- // --- helpers ---
function renderMarkdown(targetEl, markdownText) { function renderMarkdown(targetEl, markdownText) {
const html = marked.parse(markdownText, { breaks:true, gfm:true, headerIds:false }); const html = marked.parse(markdownText, { breaks: true, gfm: true, headerIds: false });
targetEl.innerHTML = DOMPurify.sanitize(html, { USE_PROFILES:{ html:true } }); targetEl.innerHTML = DOMPurify.sanitize(html, { USE_PROFILES: { html: true } });
} }
function showThinkingCat(targetEl) { function showThinkingCat(targetEl) {
targetEl.innerHTML = ''; targetEl.innerHTML = '';
const img = document.createElement('img'); const img = document.createElement('img');
img.className = 'thinking-cat'; img.className = 'thinking-cat';
img.src = CAT_GIF + '?t=' + Date.now(); img.src = CAT_GIF + '?t=' + Date.now();
img.alt = t('status.thinking','Thinking…'); img.alt = t('status.thinking', 'Thinking…');
targetEl.appendChild(img); targetEl.appendChild(img);
} }
function clearThinkingCatIfPresent(targetEl) { function clearThinkingCatIfPresent(targetEl) {
...@@ -372,7 +370,7 @@ ...@@ -372,7 +370,7 @@
// --- Composer lock --- // --- Composer lock ---
function setComposerLocked(locked) { function setComposerLocked(locked) {
isRunning = locked; isRunning = locked;
inputText.placeholder = locked ? t('status.thinking','Thinking…') : t('composer.placeholder','What can I help you with?'); inputText.placeholder = locked ? t('status.thinking', 'Thinking…') : t('composer.placeholder', 'What can I help you with?');
inputText.disabled = locked; inputText.disabled = locked;
goBtn.style.display = locked ? 'none' : 'inline-block'; goBtn.style.display = locked ? 'none' : 'inline-block';
stopBtn.style.display = locked ? 'inline-block' : 'none'; stopBtn.style.display = locked ? 'inline-block' : 'none';
...@@ -435,10 +433,10 @@ ...@@ -435,10 +433,10 @@
}); });
}; };
for (;;) { for (; ;) {
const { value, done } = await reader.read(); const { value, done } = await reader.read();
if (done) break; if (done) break;
const chunk = decoder.decode(value, { stream:true }); const chunk = decoder.decode(value, { stream: true });
for (const ch of chunk) rawMarkdown += ch; // char-by-char for (const ch of chunk) rawMarkdown += ch; // char-by-char
flush(); flush();
} }
...@@ -446,11 +444,11 @@ ...@@ -446,11 +444,11 @@
} catch (err) { } catch (err) {
if (err.name !== 'AbortError') { if (err.name !== 'AbortError') {
clearThinkingCatIfPresent(assistantMsg); clearThinkingCatIfPresent(assistantMsg);
renderMarkdown(assistantMsg, `\n\n ** ${ t('status.errorLabel','Error') }:** ${ err.message || err }`); renderMarkdown(assistantMsg, `\n\n**${t('status.errorLabel', 'Error')}:** ${err.message || err}`);
} else { } else {
if (assistantMsg.querySelector('img.thinking-cat')) { if (assistantMsg.querySelector('img.thinking-cat')) {
clearThinkingCatIfPresent(assistantMsg); clearThinkingCatIfPresent(assistantMsg);
renderMarkdown(assistantMsg, t('status.stopped','_Stopped._')); renderMarkdown(assistantMsg, t('status.stopped', '_Stopped._'));
} }
} }
} finally { } finally {
...@@ -462,7 +460,7 @@ ...@@ -462,7 +460,7 @@
async function stop() { async function stop() {
if (controller) controller.abort(); if (controller) controller.abort();
try { await fetch(STOPPOINT, { method: 'POST' }); } catch (_) {} try { await fetch(STOPPOINT, { method: 'POST' }); } catch (_) { }
} }
// Events // Events
...@@ -471,7 +469,7 @@ ...@@ -471,7 +469,7 @@
if (goBtn.style.display !== 'none') start(); if (goBtn.style.display !== 'none') start();
}); });
document.getElementById('inputText').addEventListener('keydown', e => { document.getElementById('inputText').addEventListener('keydown', e => {
if (e.key==='Enter' && !e.shiftKey && goBtn.style.display !== 'none') { if (e.key === 'Enter' && !e.shiftKey && goBtn.style.display !== 'none') {
e.preventDefault(); e.preventDefault();
start(); start();
} }
...@@ -480,7 +478,7 @@ ...@@ -480,7 +478,7 @@
// Init // Init
window.addEventListener('DOMContentLoaded', async () => { window.addEventListener('DOMContentLoaded', async () => {
try { await fetch('/api/clear', { method: 'GET' }); } catch (_) {} try { await fetch('/api/clear', { method: 'GET' }); } catch (_) { }
await loadLocale(CURRENT_LOCALE); await loadLocale(CURRENT_LOCALE);
document.getElementById('inputText').focus(); document.getElementById('inputText').focus();
updateScrollIndicator(); updateScrollIndicator();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment