Fix showing of response 1/2 tabs - now as messages

This commit is contained in:
dimitrievgs 2026-05-03 19:18:03 +03:00
parent 06949fc13e
commit 58eff747a4
2 changed files with 86 additions and 30 deletions

View File

@ -27,15 +27,19 @@ export class VoicePanel {
<button class="v-tab" data-tab="trans">Transcription</button>
</div>
</div>
<div id="v-body" class="voice-body"></div>
<div id="v-body" class="voice-body selectable"></div>
</div>
`;
this.container.querySelectorAll('.v-tab').forEach((tab) => {
tab.addEventListener('click', (e) => {
const target = e.target as HTMLElement;
this.container.querySelectorAll('.v-tab').forEach((t) => t.classList.remove('active'));
(e.target as HTMLElement).classList.add('active');
this.activeTab = (e.target as HTMLElement).dataset.tab as any;
target.classList.add('active');
this.activeTab = target.dataset.tab as any;
// При переключении вкладок очищаем контейнер, чтобы отрисовать актуальный список
const body = this.container.querySelector('#v-body') as HTMLElement;
if (body) body.empty();
});
});
@ -59,44 +63,62 @@ export class VoicePanel {
const data = await res.json();
this.updateContent(data);
} catch (e) {
console.error("Voice status fetch error", e);
console.error('Voice status fetch error', e);
}
}, 1500);
}, 500);
}
async updateContent(data: any) {
const body = this.container.querySelector('#v-body') as HTMLElement;
if (!body) return;
if (data.obsidian_settings_fetched == false) {
if (data.obsidian_settings_fetched === false) {
this.plugin.syncSettings();
}
// Выбираем контент для отображения
let contentToRender = "";
if (this.activeTab === 'trans') {
// Транскрипцию обычно выводим как простой текст (или тоже можно через МК)
body.innerText = data.transcription || "";
if (body.innerText !== data.transcription) {
body.innerText = data.transcription || '';
}
return;
}
if (this.activeTab === 'res1') {
contentToRender = data.response1 || "";
} else if (this.activeTab === 'res2') {
// Склеиваем массив ответов через горизонтальную линию Markdown
contentToRender = Array.isArray(data.response2)
? data.response2.join('\n\n---\n\n')
: (data.response2 || "");
}
// Получаем записи (они уже приходят отсортированные: новые в начале)
const entries: { id: string; content: string }[] = this.activeTab === 'res1' ? data.response1 : data.response2;
// Очищаем и рендерим Markdown
body.empty();
await MarkdownRenderer.renderMarkdown(
contentToRender,
body,
'',
this.plugin
);
// 1. Удаляем элементы, которых больше нет в данных (те, что вытеснены лимитом на беке)
const currentIds = new Set(entries.map((e) => e.id));
const domElements = body.querySelectorAll('.voice-message-block');
domElements.forEach((el) => {
const id = el.getAttr('data-id');
if (id && !currentIds.has(id)) {
el.remove();
}
});
// 2. Добавляем новые элементы.
// Важно: перебираем в ОБРАТНОМ порядке (от старых к новым),
// чтобы при использовании prepend в итоге самый новый оказался самым первым.
const reversedEntries = [...entries].reverse();
for (const entry of reversedEntries) {
let existing = body.querySelector(`[data-id="${entry.id}"]`);
if (!existing) {
// Создаем контейнер
const msgContainer = document.createElement('div');
msgContainer.addClass('voice-message-block', 'markdown-rendered');
msgContainer.setAttr('data-id', entry.id);
// Добавляем В НАЧАЛО контейнера
body.prepend(msgContainer);
// Рендерим Markdown
await MarkdownRenderer.renderMarkdown(entry.content, msgContainer, '', this.plugin);
// Если нужно добавить разделитель (hr), в такой логике его проще
// добавить стилями CSS (border-bottom), либо вставлять внутрь msgContainer
}
}
}
}

View File

@ -788,13 +788,37 @@
.voice-body {
flex: 1;
overflow-y: auto;
/* Убираем горизонтальный скролл на уровне контейнера */
overflow-x: hidden;
background-color: var(--background-primary);
border: 1px inset var(--background-modifier-border);
margin: 4px;
padding: 8px;
user-select: text;
user-select: text;
-webkit-user-select: text;
cursor: text; /* Меняет курсор на текстовый при наведении */
cursor: text;
/* Добавляем перенос слов для обычного текста */
word-wrap: break-word;
overflow-wrap: break-word;
}
.voice-body pre {
white-space: pre-wrap; /* Включает перенос строк в pre */
word-wrap: break-word; /* Перенос длинных слов */
word-break: break-word;
overflow-x: hidden; /* Запрет горизонтальной прокрутки */
background-color: var(--background-secondary-alt);
padding: 10px;
border-radius: 4px;
max-width: 100%; /* Чтобы блок не расширял родителя */
box-sizing: border-box;
}
.voice-body code {
white-space: pre-wrap; /* Перенос для inline и блочного кода */
word-break: break-word;
max-width: 100%;
}
.voice-header {
@ -805,6 +829,16 @@
border-bottom: 1px solid var(--background-modifier-border);
}
.voice-message-block {
border-bottom: 1px solid var(--background-modifier-border);
padding-bottom: 10px;
margin-bottom: 10px;
}
/* Чтобы у последнего сообщения (самого нижнего) не было линии */
.voice-message-block:last-child {
border-bottom: none;
}
.v-tabs {
display: flex;
gap: 2px;