mirror of
https://github.com/open-webui/open-webui.git
synced 2026-09-16 23:43:03 +00:00
feat: add scroll to top/bottom buttons in chat component
This commit is contained in:
parent
4e2240aada
commit
6ea1cfed90
2 changed files with 84 additions and 26 deletions
|
|
@ -121,9 +121,26 @@
|
|||
let messageInput: MessageInput | undefined;
|
||||
|
||||
let autoScroll = true;
|
||||
let showScrollToTop = false;
|
||||
let showScrollToBottom = false;
|
||||
let processing = '';
|
||||
let messagesContainerElement: HTMLDivElement;
|
||||
|
||||
const updateScrollButtonsState = () => {
|
||||
if (!messagesContainerElement) return;
|
||||
|
||||
const distanceFromBottom =
|
||||
messagesContainerElement.scrollHeight -
|
||||
messagesContainerElement.scrollTop -
|
||||
messagesContainerElement.clientHeight;
|
||||
const distanceFromTop = messagesContainerElement.scrollTop;
|
||||
const visibilityThreshold = Math.max(120, messagesContainerElement.clientHeight * 0.5);
|
||||
|
||||
autoScroll = distanceFromBottom <= 5;
|
||||
showScrollToBottom = distanceFromBottom > visibilityThreshold;
|
||||
showScrollToTop = !autoScroll && distanceFromTop > visibilityThreshold;
|
||||
};
|
||||
|
||||
let navbarElement;
|
||||
|
||||
let showEventConfirmation = false;
|
||||
|
|
@ -2903,13 +2920,11 @@
|
|||
<div id="chat-pane" class="flex flex-col flex-auto z-10 w-full @container overflow-auto">
|
||||
{#if ($settings?.landingPageMode === 'chat' && !$selectedFolder) || createMessagesList(history, history.currentId).length > 0}
|
||||
<div
|
||||
class=" pb-2.5 flex flex-col justify-between w-full flex-auto overflow-auto h-0 max-w-full z-10 scrollbar-hidden"
|
||||
class=" pb-2.5 flex flex-col justify-between w-full flex-auto overflow-auto h-0 max-w-full z-10"
|
||||
id="messages-container"
|
||||
bind:this={messagesContainerElement}
|
||||
on:scroll={(e) => {
|
||||
autoScroll =
|
||||
messagesContainerElement.scrollHeight - messagesContainerElement.scrollTop <=
|
||||
messagesContainerElement.clientHeight + 5;
|
||||
updateScrollButtonsState();
|
||||
}}
|
||||
>
|
||||
<div class=" h-full w-full flex flex-col">
|
||||
|
|
@ -2947,6 +2962,8 @@
|
|||
bind:files
|
||||
bind:prompt
|
||||
bind:autoScroll
|
||||
bind:showScrollToTop
|
||||
bind:showScrollToBottom
|
||||
bind:selectedToolIds
|
||||
bind:selectedFilterIds
|
||||
bind:imageGenerationEnabled
|
||||
|
|
|
|||
|
|
@ -110,6 +110,8 @@
|
|||
export let stopResponse: Function;
|
||||
|
||||
export let autoScroll = false;
|
||||
export let showScrollToTop = false;
|
||||
export let showScrollToBottom = false;
|
||||
export let generating = false;
|
||||
export let uploadPending = false;
|
||||
|
||||
|
|
@ -548,6 +550,14 @@
|
|||
});
|
||||
};
|
||||
|
||||
const scrollToTop = () => {
|
||||
const element = document.getElementById('messages-container');
|
||||
element.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
};
|
||||
|
||||
const screenCaptureHandler = async () => {
|
||||
try {
|
||||
// Request screen media
|
||||
|
|
@ -1163,30 +1173,61 @@
|
|||
: 'max-w-6xl'} w-full"
|
||||
>
|
||||
<div class="relative">
|
||||
{#if autoScroll === false && history?.currentId}
|
||||
{#if (showScrollToTop || showScrollToBottom) && history?.currentId}
|
||||
<div
|
||||
class=" absolute -top-12 left-0 right-0 flex justify-center z-30 pointer-events-none"
|
||||
class=" absolute -top-24 left-0 right-0 flex justify-center z-30 pointer-events-none"
|
||||
>
|
||||
<button
|
||||
class=" bg-white border border-gray-100 dark:border-none dark:bg-white/20 p-1.5 rounded-full pointer-events-auto"
|
||||
on:click={() => {
|
||||
autoScroll = true;
|
||||
scrollToBottom();
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
class="w-5 h-5"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 3a.75.75 0 01.75.75v10.638l3.96-4.158a.75.75 0 111.08 1.04l-5.25 5.5a.75.75 0 01-1.08 0l-5.25-5.5a.75.75 0 111.08-1.04l3.96 4.158V3.75A.75.75 0 0110 3z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="flex flex-col items-center gap-2 pointer-events-auto">
|
||||
{#if showScrollToTop}
|
||||
<button
|
||||
aria-label={$i18n.t('Go to the Top')}
|
||||
title={$i18n.t('Go to the Top')}
|
||||
class="bg-white border border-gray-100 dark:border-none dark:bg-white/20 p-1.5 rounded-full"
|
||||
on:click={() => {
|
||||
autoScroll = false;
|
||||
scrollToTop();
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
class="w-5 h-5"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 17a.75.75 0 01-.75-.75V5.612L5.29 9.77a.75.75 0 11-1.08-1.04l5.25-5.5a.75.75 0 011.08 0l5.25 5.5a.75.75 0 11-1.08 1.04l-3.96-4.158V16.25A.75.75 0 0110 17z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
{#if showScrollToBottom}
|
||||
<button
|
||||
aria-label={$i18n.t('Go to the Bottom')}
|
||||
title={$i18n.t('Go to the Bottom')}
|
||||
class="bg-white border border-gray-100 dark:border-none dark:bg-white/20 p-1.5 rounded-full"
|
||||
on:click={() => {
|
||||
autoScroll = true;
|
||||
scrollToBottom();
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
class="w-5 h-5"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 3a.75.75 0 01.75.75v10.638l3.96-4.158a.75.75 0 111.08 1.04l-5.25 5.5a.75.75 0 01-1.08 0l-5.25-5.5a.75.75 0 111.08-1.04l3.96 4.158V3.75A.75.75 0 0110 3z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue