Add scroll buttons to chat panel

This commit is contained in:
dimitrievgs 2026-05-16 17:54:24 +03:00
parent 526db6feb0
commit 89e57198ad
2 changed files with 103 additions and 2 deletions

View File

@ -39,6 +39,8 @@ export class ChatPanel {
customPromptIndicator: HTMLSpanElement | null = null;
currentStreamingNodeId: string | null;
stopButton: HTMLButtonElement;
scrollToBottomBtn: HTMLButtonElement;
scrollToTopBtn: HTMLButtonElement;
maxTokensInput: HTMLInputElement;
maxTokensResetBtn: HTMLButtonElement;
@ -446,6 +448,16 @@ export class ChatPanel {
init(): void {
this.container.innerHTML = `
<div class="llm-agent-chat-panel">
<div class="sticky-btn-wrapper">
<button class="scroll-to-top-btn" id="scroll-to-top-btn" title="Прокрутить вверх" aria-label="Прокрутить к первому сообщению">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="19" x2="12" y2="5"></line><polyline points="5 12 12 5 19 12"></polyline></svg>
</button>
<button class="scroll-to-bottom-btn" id="scroll-to-bottom-btn" title="Прокрутить вниз" aria-label="Прокрутить к последнему сообщению">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"></line><polyline points="19 12 12 19 5 12"></polyline></svg>
</button>
</div>
<div class="chat-history" id="chat-history"></div>
<div class="chat-input-container">
<div class="scroll-container">
@ -506,6 +518,9 @@ export class ChatPanel {
this.customPromptIndicator = this.container.querySelector('#custom-prompt-indicator') as HTMLSpanElement;
this.stopButton = this.container.querySelector('#stop-button') as HTMLButtonElement;
this.scrollToTopBtn = this.container.querySelector('#scroll-to-top-btn') as HTMLButtonElement;
this.scrollToBottomBtn = this.container.querySelector('#scroll-to-bottom-btn') as HTMLButtonElement;
this.attachedFilesContainer = this.container.querySelector('#attached-files-container') as HTMLDivElement;
this.tempInput = this.container.querySelector('#temp-input') as HTMLInputElement;
@ -513,7 +528,7 @@ export class ChatPanel {
this.maxTokensInput = this.container.querySelector('#max-tokens-input') as HTMLInputElement;
this.maxTokensResetBtn = this.container.querySelector('#max-tokens-reset') as HTMLButtonElement;
const defaultTemp = (this.props.plugin.settings as any).temperatureChat ?? DEFAULT_TEMPERATURE;
const defaultTemp = (this.props.plugin.settings as any).temperatureChat ?? LLM_DEFAULTS.TEMPERATURE;
this.tempInput.value = defaultTemp.toString();
// Устанавливаем дефолтное значение для токенов
@ -597,7 +612,7 @@ export class ChatPanel {
});
this.tempResetBtn.addEventListener('click', () => {
const def = (this.props.plugin.settings as any).temperatureChat ?? DEFAULT_TEMPERATURE;
const def = (this.props.plugin.settings as any).temperatureChat ?? LLM_DEFAULTS.TEMPERATURE;
this.tempInput.value = def.toString();
});
@ -611,6 +626,22 @@ export class ChatPanel {
}
});
// Логика прокрутки вверх и вниз при клике
this.scrollToTopBtn.addEventListener('click', () => {
const scrollContainer = this.container.closest('.view-content') as HTMLElement;
const historyContainer = this.container.querySelector('#chat-history') as HTMLElement;
if (scrollContainer) scrollContainer.scrollTop = 0;
if (historyContainer) historyContainer.scrollTop = 0;
});
this.scrollToBottomBtn.addEventListener('click', () => {
const scrollContainer = this.container.closest('.view-content') as HTMLElement;
const historyContainer = this.container.querySelector('#chat-history') as HTMLElement;
if (scrollContainer) scrollContainer.scrollTop = scrollContainer.scrollHeight;
if (historyContainer) historyContainer.scrollTop = historyContainer.scrollHeight;
});
// Обработчики Drag-n-Drop для внешних файлов
this.setupDragAndDrop();
}

View File

@ -171,6 +171,7 @@
display: flex;
flex-direction: column;
height: 100%;
position: relative;
}
.chat-history {
@ -501,6 +502,75 @@
display: none;
}
/* ----------------------------------------------- Кнопка прокрутки чат-панели до низа --------------------------------------------------- */
/* "Липкая" обертка, которая зависает в самом верху контейнера */
.sticky-btn-wrapper {
position: sticky;
top: 14px;
z-index: 100;
display: flex;
flex-direction: column; /* Кнопки в колонку */
align-items: flex-end; /* Прижать к правому краю */
gap: 8px; /* Расстояние между кнопками */
padding-right: 14px;
height: 0;
width: 100%;
pointer-events: none;
flex-shrink: 0;
}
/* Добавить общий стиль для обеих кнопок и специфичный для новой */
.scroll-to-bottom-btn,
.scroll-to-top-btn {
pointer-events: auto;
border: 2px solid var(--background-primary);
border-radius: 50%;
/* Жестко задаем размеры (например, 40px) */
width: 40px;
height: 40px;
min-width: 40px;
min-height: 40px;
/* Запрещаем flexbox сжимать эти элементы */
flex-shrink: 0;
/* Сбрасываем стандартные паддинги Obsidian */
padding: 0;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
color: white;
background-color: var(--button-secondary-background); /* По умолчанию тусклее */
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
opacity: 0.8;
}
.scroll-to-bottom-btn:hover,
.scroll-to-top-btn:hover {
opacity: 1;
transform: scale(1.1);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
background-color: var(--button-primary-background) !important;
}
.scroll-to-bottom-btn:active,
.scroll-to-top-btn:active {
transform: scale(0.95);
}
/* Иконки кнопок */
.scroll-to-bottom-btn svg,
.scroll-to-top-btn svg {
width: 18px;
height: 18px;
stroke-width: 3px;
}
/* ----------------------------------------------- Reference System Styles --------------------------------------------------- */
/* Reference Boxes */