mirror of
https://github.com/open-webui/open-webui.git
synced 2025-12-14 13:25:20 +00:00
enh: formatting toolbar for chat
This commit is contained in:
parent
0acd78049d
commit
bfa42c6277
5 changed files with 256 additions and 211 deletions
|
|
@ -60,7 +60,7 @@
|
||||||
export let scrollToBottom: Function = () => {};
|
export let scrollToBottom: Function = () => {};
|
||||||
|
|
||||||
export let acceptFiles = true;
|
export let acceptFiles = true;
|
||||||
export let showFormattingButtons = true;
|
export let showFormattingToolbar = true;
|
||||||
|
|
||||||
let showInputVariablesModal = false;
|
let showInputVariablesModal = false;
|
||||||
let inputVariables: Record<string, any> = {};
|
let inputVariables: Record<string, any> = {};
|
||||||
|
|
@ -700,7 +700,7 @@
|
||||||
bind:this={chatInputElement}
|
bind:this={chatInputElement}
|
||||||
json={true}
|
json={true}
|
||||||
messageInput={true}
|
messageInput={true}
|
||||||
{showFormattingButtons}
|
{showFormattingToolbar}
|
||||||
shiftEnter={!($settings?.ctrlEnterToSend ?? false) &&
|
shiftEnter={!($settings?.ctrlEnterToSend ?? false) &&
|
||||||
(!$mobile ||
|
(!$mobile ||
|
||||||
!(
|
!(
|
||||||
|
|
|
||||||
|
|
@ -1086,6 +1086,7 @@
|
||||||
class="scrollbar-hidden rtl:text-right ltr:text-left bg-transparent dark:text-gray-100 outline-hidden w-full pt-2.5 pb-[5px] px-1 resize-none h-fit max-h-80 overflow-auto"
|
class="scrollbar-hidden rtl:text-right ltr:text-left bg-transparent dark:text-gray-100 outline-hidden w-full pt-2.5 pb-[5px] px-1 resize-none h-fit max-h-80 overflow-auto"
|
||||||
id="chat-input-container"
|
id="chat-input-container"
|
||||||
>
|
>
|
||||||
|
{#key $settings?.showFormattingToolbar ?? false}
|
||||||
<RichTextInput
|
<RichTextInput
|
||||||
bind:this={chatInputElement}
|
bind:this={chatInputElement}
|
||||||
id="chat-input"
|
id="chat-input"
|
||||||
|
|
@ -1095,7 +1096,8 @@
|
||||||
}}
|
}}
|
||||||
json={true}
|
json={true}
|
||||||
messageInput={true}
|
messageInput={true}
|
||||||
showFormattingButtons={false}
|
showFormattingToolbar={$settings?.showFormattingToolbar ?? false}
|
||||||
|
floatingMenuPlacement={'top-start'}
|
||||||
insertPromptAsRichText={$settings?.insertPromptAsRichText ?? false}
|
insertPromptAsRichText={$settings?.insertPromptAsRichText ?? false}
|
||||||
shiftEnter={!($settings?.ctrlEnterToSend ?? false) &&
|
shiftEnter={!($settings?.ctrlEnterToSend ?? false) &&
|
||||||
(!$mobile ||
|
(!$mobile ||
|
||||||
|
|
@ -1183,7 +1185,9 @@
|
||||||
commandsElement.selectUp();
|
commandsElement.selectUp();
|
||||||
|
|
||||||
const commandOptionButton = [
|
const commandOptionButton = [
|
||||||
...document.getElementsByClassName('selected-command-option-button')
|
...document.getElementsByClassName(
|
||||||
|
'selected-command-option-button'
|
||||||
|
)
|
||||||
]?.at(-1);
|
]?.at(-1);
|
||||||
commandOptionButton.scrollIntoView({ block: 'center' });
|
commandOptionButton.scrollIntoView({ block: 'center' });
|
||||||
}
|
}
|
||||||
|
|
@ -1193,7 +1197,9 @@
|
||||||
commandsElement.selectDown();
|
commandsElement.selectDown();
|
||||||
|
|
||||||
const commandOptionButton = [
|
const commandOptionButton = [
|
||||||
...document.getElementsByClassName('selected-command-option-button')
|
...document.getElementsByClassName(
|
||||||
|
'selected-command-option-button'
|
||||||
|
)
|
||||||
]?.at(-1);
|
]?.at(-1);
|
||||||
commandOptionButton.scrollIntoView({ block: 'center' });
|
commandOptionButton.scrollIntoView({ block: 'center' });
|
||||||
}
|
}
|
||||||
|
|
@ -1202,7 +1208,9 @@
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const commandOptionButton = [
|
const commandOptionButton = [
|
||||||
...document.getElementsByClassName('selected-command-option-button')
|
...document.getElementsByClassName(
|
||||||
|
'selected-command-option-button'
|
||||||
|
)
|
||||||
]?.at(-1);
|
]?.at(-1);
|
||||||
|
|
||||||
commandOptionButton?.click();
|
commandOptionButton?.click();
|
||||||
|
|
@ -1212,7 +1220,9 @@
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const commandOptionButton = [
|
const commandOptionButton = [
|
||||||
...document.getElementsByClassName('selected-command-option-button')
|
...document.getElementsByClassName(
|
||||||
|
'selected-command-option-button'
|
||||||
|
)
|
||||||
]?.at(-1);
|
]?.at(-1);
|
||||||
|
|
||||||
if (commandOptionButton) {
|
if (commandOptionButton) {
|
||||||
|
|
@ -1300,9 +1310,13 @@
|
||||||
if (text.length > PASTED_TEXT_CHARACTER_LIMIT) {
|
if (text.length > PASTED_TEXT_CHARACTER_LIMIT) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const blob = new Blob([text], { type: 'text/plain' });
|
const blob = new Blob([text], { type: 'text/plain' });
|
||||||
const file = new File([blob], `Pasted_Text_${Date.now()}.txt`, {
|
const file = new File(
|
||||||
|
[blob],
|
||||||
|
`Pasted_Text_${Date.now()}.txt`,
|
||||||
|
{
|
||||||
type: 'text/plain'
|
type: 'text/plain'
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
await uploadFileHandler(file, true);
|
await uploadFileHandler(file, true);
|
||||||
}
|
}
|
||||||
|
|
@ -1312,6 +1326,7 @@
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
{/key}
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<textarea
|
<textarea
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@
|
||||||
let detectArtifacts = true;
|
let detectArtifacts = true;
|
||||||
|
|
||||||
let richTextInput = true;
|
let richTextInput = true;
|
||||||
|
let showFormattingToolbar = false;
|
||||||
let insertPromptAsRichText = false;
|
let insertPromptAsRichText = false;
|
||||||
let promptAutocomplete = false;
|
let promptAutocomplete = false;
|
||||||
|
|
||||||
|
|
@ -228,6 +229,11 @@
|
||||||
saveSettings({ richTextInput });
|
saveSettings({ richTextInput });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toggleShowFormattingToolbar = async () => {
|
||||||
|
showFormattingToolbar = !showFormattingToolbar;
|
||||||
|
saveSettings({ showFormattingToolbar });
|
||||||
|
};
|
||||||
|
|
||||||
const toggleInsertPromptAsRichText = async () => {
|
const toggleInsertPromptAsRichText = async () => {
|
||||||
insertPromptAsRichText = !insertPromptAsRichText;
|
insertPromptAsRichText = !insertPromptAsRichText;
|
||||||
saveSettings({ insertPromptAsRichText });
|
saveSettings({ insertPromptAsRichText });
|
||||||
|
|
@ -335,6 +341,7 @@
|
||||||
chatFadeStreamingText = $settings?.chatFadeStreamingText ?? true;
|
chatFadeStreamingText = $settings?.chatFadeStreamingText ?? true;
|
||||||
|
|
||||||
richTextInput = $settings?.richTextInput ?? true;
|
richTextInput = $settings?.richTextInput ?? true;
|
||||||
|
showFormattingToolbar = $settings?.showFormattingToolbar ?? false;
|
||||||
insertPromptAsRichText = $settings?.insertPromptAsRichText ?? false;
|
insertPromptAsRichText = $settings?.insertPromptAsRichText ?? false;
|
||||||
promptAutocomplete = $settings?.promptAutocomplete ?? false;
|
promptAutocomplete = $settings?.promptAutocomplete ?? false;
|
||||||
|
|
||||||
|
|
@ -863,6 +870,29 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if richTextInput}
|
{#if richTextInput}
|
||||||
|
<div>
|
||||||
|
<div class=" py-0.5 flex w-full justify-between">
|
||||||
|
<div id="rich-input-label" class=" self-center text-xs">
|
||||||
|
{$i18n.t('Show Formatting Toolbar')}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
aria-labelledby="rich-input-label"
|
||||||
|
class="p-1 px-3 text-xs flex rounded-sm transition"
|
||||||
|
on:click={() => {
|
||||||
|
toggleShowFormattingToolbar();
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
{#if showFormattingToolbar === true}
|
||||||
|
<span class="ml-2 self-center">{$i18n.t('On')}</span>
|
||||||
|
{:else}
|
||||||
|
<span class="ml-2 self-center">{$i18n.t('Off')}</span>
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class=" py-0.5 flex w-full justify-between">
|
<div class=" py-0.5 flex w-full justify-between">
|
||||||
<div id="rich-input-label" class=" self-center text-xs">
|
<div id="rich-input-label" class=" self-center text-xs">
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,7 @@
|
||||||
export let editable = true;
|
export let editable = true;
|
||||||
export let collaboration = false;
|
export let collaboration = false;
|
||||||
|
|
||||||
export let showFormattingButtons = true;
|
export let showFormattingToolbar = true;
|
||||||
|
|
||||||
export let preserveBreaks = false;
|
export let preserveBreaks = false;
|
||||||
export let generateAutoCompletion: Function = async () => null;
|
export let generateAutoCompletion: Function = async () => null;
|
||||||
|
|
@ -1003,7 +1003,7 @@
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
|
|
||||||
...(showFormattingButtons
|
...(showFormattingToolbar
|
||||||
? [
|
? [
|
||||||
BubbleMenu.configure({
|
BubbleMenu.configure({
|
||||||
element: bubbleMenuElement,
|
element: bubbleMenuElement,
|
||||||
|
|
@ -1316,7 +1316,7 @@
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if showFormattingButtons}
|
{#if showFormattingToolbar}
|
||||||
<div bind:this={bubbleMenuElement} id="bubble-menu" class="p-0">
|
<div bind:this={bubbleMenuElement} id="bubble-menu" class="p-0">
|
||||||
<FormattingButtons {editor} />
|
<FormattingButtons {editor} />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -390,7 +390,7 @@ Based on the user's instruction, update and enhance the existing notes or select
|
||||||
bind:chatInputElement
|
bind:chatInputElement
|
||||||
acceptFiles={false}
|
acceptFiles={false}
|
||||||
inputLoading={loading}
|
inputLoading={loading}
|
||||||
showFormattingButtons={false}
|
showFormattingToolbar={false}
|
||||||
onSubmit={submitHandler}
|
onSubmit={submitHandler}
|
||||||
{onStop}
|
{onStop}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue