webui: minor settings reorganization and add disable autoscroll option (#17452)

* webui: added a dedicated 'Display' settings section that groups visualization options

* webui: added a Display setting to toggle automatic chat scrolling

* chore: update webui build output
This commit is contained in:
Pascal 2025-11-23 18:42:00 +01:00 committed by GitHub
parent 96ac5a2329
commit 0c7220db56
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 61 additions and 33 deletions

Binary file not shown.

View File

@ -29,6 +29,7 @@
sendMessage, sendMessage,
stopGeneration stopGeneration
} from '$lib/stores/chat.svelte'; } from '$lib/stores/chat.svelte';
import { config } from '$lib/stores/settings.svelte';
import { import {
supportsVision, supportsVision,
supportsAudio, supportsAudio,
@ -47,6 +48,7 @@
let { showCenteredEmpty = false } = $props(); let { showCenteredEmpty = false } = $props();
let disableAutoScroll = $derived(Boolean(config().disableAutoScroll));
let autoScrollEnabled = $state(true); let autoScrollEnabled = $state(true);
let chatScrollContainer: HTMLDivElement | undefined = $state(); let chatScrollContainer: HTMLDivElement | undefined = $state();
let dragCounter = $state(0); let dragCounter = $state(0);
@ -149,7 +151,7 @@
} }
function handleScroll() { function handleScroll() {
if (!chatScrollContainer) return; if (disableAutoScroll || !chatScrollContainer) return;
const { scrollTop, scrollHeight, clientHeight } = chatScrollContainer; const { scrollTop, scrollHeight, clientHeight } = chatScrollContainer;
const distanceFromBottom = scrollHeight - scrollTop - clientHeight; const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
@ -194,8 +196,10 @@
const extras = result?.extras; const extras = result?.extras;
// Enable autoscroll for user-initiated message sending // Enable autoscroll for user-initiated message sending
if (!disableAutoScroll) {
userScrolledUp = false; userScrolledUp = false;
autoScrollEnabled = true; autoScrollEnabled = true;
}
await sendMessage(message, extras); await sendMessage(message, extras);
scrollChatToBottom(); scrollChatToBottom();
@ -241,6 +245,8 @@
} }
function scrollChatToBottom(behavior: ScrollBehavior = 'smooth') { function scrollChatToBottom(behavior: ScrollBehavior = 'smooth') {
if (disableAutoScroll) return;
chatScrollContainer?.scrollTo({ chatScrollContainer?.scrollTo({
top: chatScrollContainer?.scrollHeight, top: chatScrollContainer?.scrollHeight,
behavior behavior
@ -248,14 +254,27 @@
} }
afterNavigate(() => { afterNavigate(() => {
if (!disableAutoScroll) {
setTimeout(() => scrollChatToBottom('instant'), INITIAL_SCROLL_DELAY); setTimeout(() => scrollChatToBottom('instant'), INITIAL_SCROLL_DELAY);
}
}); });
onMount(() => { onMount(() => {
if (!disableAutoScroll) {
setTimeout(() => scrollChatToBottom('instant'), INITIAL_SCROLL_DELAY); setTimeout(() => scrollChatToBottom('instant'), INITIAL_SCROLL_DELAY);
}
}); });
$effect(() => { $effect(() => {
if (disableAutoScroll) {
autoScrollEnabled = false;
if (scrollInterval) {
clearInterval(scrollInterval);
scrollInterval = undefined;
}
return;
}
if (isCurrentConversationLoading && autoScrollEnabled) { if (isCurrentConversationLoading && autoScrollEnabled) {
scrollInterval = setInterval(scrollChatToBottom, AUTO_SCROLL_INTERVAL); scrollInterval = setInterval(scrollChatToBottom, AUTO_SCROLL_INTERVAL);
} else if (scrollInterval) { } else if (scrollInterval) {
@ -289,9 +308,11 @@
class="mb-16 md:mb-24" class="mb-16 md:mb-24"
messages={activeMessages()} messages={activeMessages()}
onUserAction={() => { onUserAction={() => {
if (!disableAutoScroll) {
userScrolledUp = false; userScrolledUp = false;
autoScrollEnabled = true; autoScrollEnabled = true;
scrollChatToBottom(); scrollChatToBottom();
}
}} }}
/> />

View File

@ -3,7 +3,6 @@
Settings, Settings,
Funnel, Funnel,
AlertTriangle, AlertTriangle,
Brain,
Code, Code,
Monitor, Monitor,
Sun, Sun,
@ -58,6 +57,33 @@
label: 'Paste long text to file length', label: 'Paste long text to file length',
type: 'input' type: 'input'
}, },
{
key: 'enableContinueGeneration',
label: 'Enable "Continue" button',
type: 'checkbox',
isExperimental: true
},
{
key: 'pdfAsImage',
label: 'Parse PDF as image',
type: 'checkbox'
},
{
key: 'askForTitleConfirmation',
label: 'Ask for confirmation before changing conversation title',
type: 'checkbox'
}
]
},
{
title: 'Display',
icon: Monitor,
fields: [
{
key: 'showThoughtInProgress',
label: 'Show thought in progress',
type: 'checkbox'
},
{ {
key: 'showMessageStats', key: 'showMessageStats',
label: 'Show message generation statistics', label: 'Show message generation statistics',
@ -79,25 +105,14 @@
type: 'checkbox' type: 'checkbox'
}, },
{ {
key: 'enableContinueGeneration', key: 'disableAutoScroll',
label: 'Enable "Continue" button', label: 'Disable automatic scroll',
type: 'checkbox',
isExperimental: true
},
{
key: 'pdfAsImage',
label: 'Parse PDF as image',
type: 'checkbox' type: 'checkbox'
}, },
{ {
key: 'renderUserContentAsMarkdown', key: 'renderUserContentAsMarkdown',
label: 'Render user content as Markdown', label: 'Render user content as Markdown',
type: 'checkbox' type: 'checkbox'
},
{
key: 'askForTitleConfirmation',
label: 'Ask for confirmation before changing conversation title',
type: 'checkbox'
} }
] ]
}, },
@ -208,17 +223,6 @@
} }
] ]
}, },
{
title: 'Reasoning',
icon: Brain,
fields: [
{
key: 'showThoughtInProgress',
label: 'Show thought in progress',
type: 'checkbox'
}
]
},
{ {
title: 'Import/Export', title: 'Import/Export',
icon: Database, icon: Database,

View File

@ -14,6 +14,7 @@ export const SETTING_CONFIG_DEFAULT: Record<string, string | number | boolean> =
pasteLongTextToFileLen: 2500, pasteLongTextToFileLen: 2500,
pdfAsImage: false, pdfAsImage: false,
showModelInfo: false, showModelInfo: false,
disableAutoScroll: false,
renderUserContentAsMarkdown: false, renderUserContentAsMarkdown: false,
modelSelectorEnabled: false, modelSelectorEnabled: false,
// make sure these default values are in sync with `common.h` // make sure these default values are in sync with `common.h`
@ -93,6 +94,8 @@ export const SETTING_CONFIG_INFO: Record<string, string> = {
'Ask for confirmation before automatically changing conversation title when editing the first message.', 'Ask for confirmation before automatically changing conversation title when editing the first message.',
pdfAsImage: 'Parse PDF as image instead of text (requires vision-capable model).', pdfAsImage: 'Parse PDF as image instead of text (requires vision-capable model).',
showModelInfo: 'Display the model name used to generate each message below the message content.', showModelInfo: 'Display the model name used to generate each message below the message content.',
disableAutoScroll:
'Disable automatic scrolling while messages stream so you can control the viewport position manually.',
renderUserContentAsMarkdown: 'Render user messages using markdown formatting in the chat.', renderUserContentAsMarkdown: 'Render user messages using markdown formatting in the chat.',
modelSelectorEnabled: modelSelectorEnabled:
'Enable the model selector in the chat input to choose the inference model. Sends the associated model field in API requests.', 'Enable the model selector in the chat input to choose the inference model. Sends the associated model field in API requests.',