Add buttons to scroll to start of message and copy text of message

This commit is contained in:
dimitrievgs 2026-05-03 20:10:32 +03:00
parent 58eff747a4
commit 9ae3256c35
2 changed files with 76 additions and 4 deletions

View File

@ -1,5 +1,5 @@
import LLMAgentPlugin from 'main';
import { MarkdownRenderer } from 'obsidian';
import { MarkdownRenderer, setIcon, Notice } from 'obsidian';
export class VoicePanel {
private activeTab: 'res1' | 'res2' | 'trans' = 'res1';
@ -77,6 +77,7 @@ export class VoicePanel {
}
if (this.activeTab === 'trans') {
// Для транскрибации оставляем простой текст, так как она меняется постоянно
if (body.innerText !== data.transcription) {
body.innerText = data.transcription || '';
}
@ -107,7 +108,7 @@ export class VoicePanel {
if (!existing) {
// Создаем контейнер
const msgContainer = document.createElement('div');
msgContainer.addClass('voice-message-block', 'markdown-rendered');
msgContainer.addClass('voice-message-block', 'markdown-rendered', 'group/turn-messages'); // Добавлен класс group для hover-эффекта
msgContainer.setAttr('data-id', entry.id);
// Добавляем В НАЧАЛО контейнера
@ -116,9 +117,49 @@ export class VoicePanel {
// Рендерим Markdown
await MarkdownRenderer.renderMarkdown(entry.content, msgContainer, '', this.plugin);
// Если нужно добавить разделитель (hr), в такой логике его проще
// добавить стилями CSS (border-bottom), либо вставлять внутрь msgContainer
// ДОБАВЛЯЕМ КНОПКИ (Copy и Scroll to Top)
this.createVoiceMessageToolset(msgContainer, entry.content);
}
}
}
private createVoiceMessageToolset(messageElement: HTMLElement, content: string): void {
const toolsetContainer = messageElement.createDiv({
cls: 'voice-message-toolset'
});
// Кнопка "Копировать"
const copyButton = toolsetContainer.createEl('button', {
cls: 'voice-tool-btn',
attr: { 'aria-label': 'Копировать всё' }
});
const copyIconContainer = copyButton.createSpan();
setIcon(copyIconContainer, 'copy');
copyButton.addEventListener('click', async () => {
try {
await navigator.clipboard.writeText(content);
setIcon(copyIconContainer, 'check');
setTimeout(() => setIcon(copyIconContainer, 'copy'), 1000);
} catch (err) {
new Notice('Ошибка копирования');
}
});
// Кнопка "Наверх" (перемотка к началу сообщения)
const scrollToTopButton = toolsetContainer.createEl('button', {
cls: 'voice-tool-btn',
attr: { 'aria-label': 'К началу сообщения' }
});
const scrollIconContainer = scrollToTopButton.createSpan();
setIcon(scrollIconContainer, 'arrow-up');
scrollToTopButton.addEventListener('click', () => {
// Используем встроенный метод scrollIntoView для точного позиционирования
messageElement.scrollIntoView({
behavior: 'smooth',
block: 'start' // Прокрутить так, чтобы начало элемента совпало с верхом контейнера
});
});
}
}

View File

@ -833,12 +833,43 @@
border-bottom: 1px solid var(--background-modifier-border);
padding-bottom: 10px;
margin-bottom: 10px;
position: relative; /* Для позиционирования тулсета */
scroll-margin-top: 10px;
}
/* Чтобы у последнего сообщения (самого нижнего) не было линии */
.voice-message-block:last-child {
border-bottom: none;
}
.voice-message-toolset {
display: flex;
gap: 4px;
margin-top: 8px;
transition: opacity 0.2s ease;
}
.voice-tool-btn {
background: transparent;
border: none;
cursor: pointer;
padding: 4px;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
color: var(--text-muted);
}
.voice-tool-btn:hover {
background-color: var(--background-modifier-hover);
color: var(--text-normal);
}
.voice-tool-btn svg {
width: 16px;
height: 16px;
}
.v-tabs {
display: flex;
gap: 2px;