diff --git a/internal/server/web/static/ai.js b/internal/server/web/static/ai.js
index f836d02..fdc130b 100644
--- a/internal/server/web/static/ai.js
+++ b/internal/server/web/static/ai.js
@@ -7,7 +7,7 @@
(function () {
'use strict';
const PLANE = '';
- const STOP = '';
+ const STOP = '';
const esc = v => String(v).replace(/[&<>"]/g, c => ({'&': '&', '<': '<', '>': '>', '"': '"'}[c]));
const fab = document.createElement('button');
fab.type = 'button';
@@ -647,7 +647,6 @@
// While the model starts: a typing mark, gone with the first words.
el.querySelector('.ai-body').innerHTML = '';
ac = new AbortController();
- send.innerHTML = STOP; send.title = 'Остановить';
sendState();
let answer = '';
try {
@@ -722,7 +721,6 @@
turn = await ask(null, res);
}
ac = null;
- send.innerHTML = PLANE; send.title = 'Отправить';
sendState();
}
const form = q('.ai-form-in'), attachBtn = q('.ai-attach');
@@ -789,10 +787,23 @@
dropFiles: addPaneFiles
};
// Send shows only when there is something to send, or an answer to stop.
+ // While it fades away it keeps the look it had (a red stop stays a red
+ // stop) and becomes the plane only once hidden.
+ let sendLookTimer = 0;
+ function sendLook(stop) {
+ clearTimeout(sendLookTimer);
+ if (send.classList.contains('stop') === stop && send.dataset.look) return;
+ send.dataset.look = '1';
+ send.innerHTML = stop ? STOP : PLANE;
+ send.title = stop ? 'Остановить' : 'Отправить';
+ send.setAttribute('aria-label', send.title);
+ send.classList.toggle('stop', stop);
+ }
function sendState() {
const on = !!ac || !!input.value.trim() || attachments.length > 0;
+ if (on) sendLook(!!ac);
+ else { clearTimeout(sendLookTimer); sendLookTimer = setTimeout(() => sendLook(false), 260); }
send.classList.toggle('show', on);
- send.classList.toggle('stop', !!ac);
send.tabIndex = on ? 0 : -1;
}
input.addEventListener('input', sendState);