UI: голосовой ввод/STT, TTS через OpenAI, настройки инструментов + учёт недопроверенных фич

This commit is contained in:
AidarKC
2026-05-13 02:01:51 +03:00
parent ddeaf82bfd
commit 8de4e95c6a
15 changed files with 716 additions and 5 deletions
+16 -1
View File
@@ -10,6 +10,7 @@ import {
showToast,
softHaptic,
} from '../services/channels-ux.js';
import { openSpeechInputModal } from '../components/speech-input-modal.js';
export const pageMeta = { id: 'channel-thread-view', title: 'Тред' };
@@ -229,13 +230,16 @@ function resolveNodeText(node) {
);
}
function openReplyModal({ onSubmit }) {
function openReplyModal({ onSubmit, navigate }) {
const root = document.getElementById('modal-root');
root.innerHTML = `
<div class="modal" id="thread-reply-modal">
<div class="modal-card stack">
<h3 class="modal-title">Ответ</h3>
<textarea id="thread-reply-text" class="input" rows="5" maxlength="2000" placeholder="Текст ответа"></textarea>
<div class="row wrap-row">
<button class="ghost-btn" id="thread-reply-voice" type="button">🎤 Голосом</button>
</div>
<div class="meta-muted inline-error" id="thread-reply-error"></div>
<div class="form-actions-grid">
<button class="secondary-btn" id="thread-reply-cancel" type="button">Отмена</button>
@@ -262,6 +266,15 @@ function openReplyModal({ onSubmit }) {
};
root.querySelector('#thread-reply-cancel')?.addEventListener('click', close);
root.querySelector('#thread-reply-voice')?.addEventListener('click', async () => {
await openSpeechInputModal({
navigate,
onTextReady: (text) => {
const prev = String(textEl?.value || '').trim();
if (textEl) textEl.value = prev ? `${prev} ${text}` : text;
},
});
});
root.querySelector('#thread-reply-submit')?.addEventListener('click', async () => {
if (inFlight) return;
@@ -391,6 +404,7 @@ function renderNodeCard(node, heading, handlers, localNumber, routeKey, options
animatePress(event.currentTarget);
revealCounters();
openReplyModal({
navigate: handlers.navigate,
onSubmit: async (textValue) => handlers.onReply(target, textValue),
});
});
@@ -520,6 +534,7 @@ export function render({ navigate, route }) {
};
const handlers = {
navigate,
onToggleLike: async (target, action) => {
const actionKey = makeReactionActionKey(target);
if (!actionKey) throw new Error('Некорректная ссылка на сообщение для реакции.');