mirror of
https://github.com/open-webui/open-webui
synced 2025-04-28 10:11:34 +00:00
feat: toggleable chat bubble
This commit is contained in:
parent
db158fc9e1
commit
f2378be6f9
src/lib/components
@ -55,14 +55,47 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class=" flex w-full user-message">
|
<div class=" flex w-full user-message">
|
||||||
|
{#if !($settings?.chatBubble ?? true)}
|
||||||
|
<ProfileImage
|
||||||
|
src={message.user
|
||||||
|
? $modelfiles.find((modelfile) => modelfile.tagName === message.user)?.imageUrl ??
|
||||||
|
'/user.png'
|
||||||
|
: user?.profile_image_url ?? '/user.png'}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
<div class="w-full overflow-hidden">
|
<div class="w-full overflow-hidden">
|
||||||
|
{#if !($settings?.chatBubble ?? true)}
|
||||||
|
<div>
|
||||||
|
<Name>
|
||||||
|
{#if message.user}
|
||||||
|
{#if $modelfiles.map((modelfile) => modelfile.tagName).includes(message.user)}
|
||||||
|
{$modelfiles.find((modelfile) => modelfile.tagName === message.user)?.title}
|
||||||
|
{:else}
|
||||||
|
{$i18n.t('You')}
|
||||||
|
<span class=" text-gray-500 text-sm font-medium">{message?.user ?? ''}</span>
|
||||||
|
{/if}
|
||||||
|
{:else if $settings.showUsername}
|
||||||
|
{user.name}
|
||||||
|
{:else}
|
||||||
|
{$i18n.t('You')}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if message.timestamp}
|
||||||
|
<span class=" invisible group-hover:visible text-gray-400 text-xs font-medium">
|
||||||
|
{dayjs(message.timestamp * 1000).format($i18n.t('DD/MM/YYYY HH:mm'))}
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
</Name>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="prose chat-{message.role} w-full max-w-full flex flex-col justify-end dark:prose-invert prose-headings:my-0 prose-p:my-0 prose-p:-mb-4 prose-pre:my-0 prose-table:my-0 prose-blockquote:my-0 prose-img:my-0 prose-ul:-my-4 prose-ol:-my-4 prose-li:-my-3 prose-ul:-mb-6 prose-ol:-mb-6 prose-li:-mb-4 whitespace-pre-line"
|
class="prose chat-{message.role} w-full max-w-full flex flex-col justify-end dark:prose-invert prose-headings:my-0 prose-p:my-0 prose-p:-mb-4 prose-pre:my-0 prose-table:my-0 prose-blockquote:my-0 prose-img:my-0 prose-ul:-my-4 prose-ol:-my-4 prose-li:-my-3 prose-ul:-mb-6 prose-ol:-mb-6 prose-li:-mb-4 whitespace-pre-line"
|
||||||
>
|
>
|
||||||
{#if message.files}
|
{#if message.files}
|
||||||
<div class="mt-2.5 mb-1 w-full flex flex-col justify-end overflow-x-auto gap-1 flex-wrap">
|
<div class="mt-2.5 mb-1 w-full flex flex-col justify-end overflow-x-auto gap-1 flex-wrap">
|
||||||
{#each message.files as file}
|
{#each message.files as file}
|
||||||
<div class="self-end">
|
<div class={$settings?.chatBubble ?? true ? 'self-end' : ''}>
|
||||||
{#if file.type === 'image'}
|
{#if file.type === 'image'}
|
||||||
<img src={file.url} alt="input" class=" max-h-96 rounded-lg" draggable="false" />
|
<img src={file.url} alt="input" class=" max-h-96 rounded-lg" draggable="false" />
|
||||||
{:else if file.type === 'doc'}
|
{:else if file.type === 'doc'}
|
||||||
@ -185,17 +218,76 @@
|
|||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<div class="flex justify-end mb-2">
|
<div class="flex {$settings?.chatBubble ?? true ? 'justify-end' : ''} mb-2">
|
||||||
<div
|
<div
|
||||||
class="rounded-3xl px-5 py-2 max-w-[90%] bg-gray-50 dark:bg-gray-850 {message.files
|
class="rounded-3xl {$settings?.chatBubble ?? true
|
||||||
? 'rounded-tr-lg'
|
? `max-w-[90%] px-5 py-2 bg-gray-50 dark:bg-gray-850 ${
|
||||||
: ''}"
|
message.files ? 'rounded-tr-lg' : ''
|
||||||
|
}`
|
||||||
|
: ''} "
|
||||||
>
|
>
|
||||||
<pre id="user-message">{message.content}</pre>
|
<pre id="user-message">{message.content}</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=" flex justify-end space-x-1 text-gray-700 dark:text-gray-500">
|
<div
|
||||||
|
class=" flex {$settings?.chatBubble ?? true
|
||||||
|
? 'justify-end'
|
||||||
|
: ''} space-x-1 text-gray-700 dark:text-gray-500"
|
||||||
|
>
|
||||||
|
{#if !($settings?.chatBubble ?? true)}
|
||||||
|
{#if siblings.length > 1}
|
||||||
|
<div class="flex self-center">
|
||||||
|
<button
|
||||||
|
class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
|
||||||
|
on:click={() => {
|
||||||
|
showPreviousMessage(message);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2.5"
|
||||||
|
class="size-3.5"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M15.75 19.5 8.25 12l7.5-7.5"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="text-sm tracking-widest font-semibold self-center dark:text-gray-100">
|
||||||
|
{siblings.indexOf(message.id) + 1}/{siblings.length}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
|
||||||
|
on:click={() => {
|
||||||
|
showNextMessage(message);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2.5"
|
||||||
|
class="size-3.5"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="m8.25 4.5 7.5 7.5-7.5 7.5"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
{#if !readOnly}
|
{#if !readOnly}
|
||||||
<Tooltip content={$i18n.t('Edit')} placement="bottom">
|
<Tooltip content={$i18n.t('Edit')} placement="bottom">
|
||||||
<button
|
<button
|
||||||
@ -271,56 +363,59 @@
|
|||||||
</button>
|
</button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{/if}
|
{/if}
|
||||||
{#if siblings.length > 1}
|
|
||||||
<div class="flex self-center">
|
|
||||||
<button
|
|
||||||
class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
|
|
||||||
on:click={() => {
|
|
||||||
showPreviousMessage(message);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2.5"
|
|
||||||
class="size-3.5"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
d="M15.75 19.5 8.25 12l7.5-7.5"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div class="text-sm tracking-widest font-semibold self-center dark:text-gray-100">
|
{#if $settings?.chatBubble ?? true}
|
||||||
{siblings.indexOf(message.id) + 1}/{siblings.length}
|
{#if siblings.length > 1}
|
||||||
|
<div class="flex self-center">
|
||||||
|
<button
|
||||||
|
class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
|
||||||
|
on:click={() => {
|
||||||
|
showPreviousMessage(message);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2.5"
|
||||||
|
class="size-3.5"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M15.75 19.5 8.25 12l7.5-7.5"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="text-sm tracking-widest font-semibold self-center dark:text-gray-100">
|
||||||
|
{siblings.indexOf(message.id) + 1}/{siblings.length}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
|
||||||
|
on:click={() => {
|
||||||
|
showNextMessage(message);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2.5"
|
||||||
|
class="size-3.5"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="m8.25 4.5 7.5 7.5-7.5 7.5"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
<button
|
|
||||||
class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
|
|
||||||
on:click={() => {
|
|
||||||
showNextMessage(message);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2.5"
|
|
||||||
class="size-3.5"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
d="m8.25 4.5 7.5 7.5-7.5 7.5"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
// Interface
|
// Interface
|
||||||
let promptSuggestions = [];
|
let promptSuggestions = [];
|
||||||
let showUsername = false;
|
let showUsername = false;
|
||||||
|
let chatBubble = true;
|
||||||
|
|
||||||
const toggleSplitLargeChunks = async () => {
|
const toggleSplitLargeChunks = async () => {
|
||||||
splitLargeChunks = !splitLargeChunks;
|
splitLargeChunks = !splitLargeChunks;
|
||||||
@ -33,6 +34,11 @@
|
|||||||
saveSettings({ fullScreenMode: fullScreenMode });
|
saveSettings({ fullScreenMode: fullScreenMode });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toggleChatBubble = async () => {
|
||||||
|
chatBubble = !chatBubble;
|
||||||
|
saveSettings({ chatBubble: chatBubble });
|
||||||
|
};
|
||||||
|
|
||||||
const toggleShowUsername = async () => {
|
const toggleShowUsername = async () => {
|
||||||
showUsername = !showUsername;
|
showUsername = !showUsername;
|
||||||
saveSettings({ showUsername: showUsername });
|
saveSettings({ showUsername: showUsername });
|
||||||
@ -105,6 +111,7 @@
|
|||||||
|
|
||||||
responseAutoCopy = settings.responseAutoCopy ?? false;
|
responseAutoCopy = settings.responseAutoCopy ?? false;
|
||||||
showUsername = settings.showUsername ?? false;
|
showUsername = settings.showUsername ?? false;
|
||||||
|
chatBubble = settings.chatBubble ?? true;
|
||||||
fullScreenMode = settings.fullScreenMode ?? false;
|
fullScreenMode = settings.fullScreenMode ?? false;
|
||||||
splitLargeChunks = settings.splitLargeChunks ?? false;
|
splitLargeChunks = settings.splitLargeChunks ?? false;
|
||||||
});
|
});
|
||||||
@ -121,6 +128,26 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class=" mb-1 text-sm font-medium">{$i18n.t('WebUI Add-ons')}</div>
|
<div class=" mb-1 text-sm font-medium">{$i18n.t('WebUI Add-ons')}</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class=" py-0.5 flex w-full justify-between">
|
||||||
|
<div class=" self-center text-xs font-medium">{$i18n.t('Chat Bubble UI')}</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="p-1 px-3 text-xs flex rounded transition"
|
||||||
|
on:click={() => {
|
||||||
|
toggleChatBubble();
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
{#if chatBubble === 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 class=" self-center text-xs font-medium">{$i18n.t('Title Auto-Generation')}</div>
|
<div class=" self-center text-xs font-medium">{$i18n.t('Title Auto-Generation')}</div>
|
||||||
|
@ -85,8 +85,6 @@
|
|||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
mobile.subscribe((e) => {
|
mobile.subscribe((e) => {
|
||||||
console.log(e);
|
|
||||||
|
|
||||||
if ($showSidebar && e) {
|
if ($showSidebar && e) {
|
||||||
showSidebar.set(false);
|
showSidebar.set(false);
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,6 @@
|
|||||||
|
|
||||||
const onDrop = async (e) => {
|
const onDrop = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
console.log(e);
|
|
||||||
|
|
||||||
if (e.dataTransfer?.files) {
|
if (e.dataTransfer?.files) {
|
||||||
let reader = new FileReader();
|
let reader = new FileReader();
|
||||||
|
Loading…
Reference in New Issue
Block a user