mirror of
https://github.com/open-webui/open-webui
synced 2025-05-29 09:42:12 +00:00
refac
This commit is contained in:
parent
9d39404e6c
commit
2840ff405b
@ -1,5 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toast } from 'svelte-sonner';
|
import { toast } from 'svelte-sonner';
|
||||||
|
import { Pane, PaneGroup, PaneResizer } from 'paneforge';
|
||||||
|
|
||||||
import { onDestroy, onMount, tick } from 'svelte';
|
import { onDestroy, onMount, tick } from 'svelte';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
|
||||||
@ -9,6 +11,9 @@
|
|||||||
import Messages from './Messages.svelte';
|
import Messages from './Messages.svelte';
|
||||||
import MessageInput from './MessageInput.svelte';
|
import MessageInput from './MessageInput.svelte';
|
||||||
import Navbar from './Navbar.svelte';
|
import Navbar from './Navbar.svelte';
|
||||||
|
import Drawer from '../common/Drawer.svelte';
|
||||||
|
import EllipsisVertical from '../icons/EllipsisVertical.svelte';
|
||||||
|
import Thread from './Messages/Thread.svelte';
|
||||||
|
|
||||||
export let id = '';
|
export let id = '';
|
||||||
|
|
||||||
@ -20,6 +25,8 @@
|
|||||||
let channel = null;
|
let channel = null;
|
||||||
let messages = null;
|
let messages = null;
|
||||||
|
|
||||||
|
let threadId = null;
|
||||||
|
|
||||||
let typingUsers = [];
|
let typingUsers = [];
|
||||||
let typingUsersTimeout = {};
|
let typingUsersTimeout = {};
|
||||||
|
|
||||||
@ -150,12 +157,28 @@
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mediaQuery;
|
||||||
|
let largeScreen = false;
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
if ($chatId) {
|
if ($chatId) {
|
||||||
chatId.set('');
|
chatId.set('');
|
||||||
}
|
}
|
||||||
|
|
||||||
$socket?.on('channel-events', channelEventHandler);
|
$socket?.on('channel-events', channelEventHandler);
|
||||||
|
|
||||||
|
mediaQuery = window.matchMedia('(min-width: 1024px)');
|
||||||
|
|
||||||
|
const handleMediaQuery = async (e) => {
|
||||||
|
if (e.matches) {
|
||||||
|
largeScreen = true;
|
||||||
|
} else {
|
||||||
|
largeScreen = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mediaQuery.addEventListener('change', handleMediaQuery);
|
||||||
|
handleMediaQuery(mediaQuery);
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
@ -173,40 +196,98 @@
|
|||||||
: ''} w-full max-w-full flex flex-col"
|
: ''} w-full max-w-full flex flex-col"
|
||||||
id="channel-container"
|
id="channel-container"
|
||||||
>
|
>
|
||||||
<Navbar {channel} />
|
<PaneGroup direction="horizontal" class="w-full h-full">
|
||||||
|
<Pane defaultSize={50} minSize={50} class="h-full flex flex-col w-full relative">
|
||||||
|
<Navbar {channel} />
|
||||||
|
|
||||||
<div class="flex-1 overflow-y-auto">
|
<div class="flex-1 overflow-y-auto">
|
||||||
{#if channel}
|
{#if channel}
|
||||||
<div
|
<div
|
||||||
class=" pb-2.5 max-w-full z-10 scrollbar-hidden w-full h-full pt-6 flex-1 flex flex-col-reverse overflow-auto"
|
class=" pb-2.5 max-w-full z-10 scrollbar-hidden w-full h-full pt-6 flex-1 flex flex-col-reverse overflow-auto"
|
||||||
id="messages-container"
|
id="messages-container"
|
||||||
bind:this={messagesContainerElement}
|
bind:this={messagesContainerElement}
|
||||||
on:scroll={(e) => {
|
on:scroll={(e) => {
|
||||||
scrollEnd = Math.abs(messagesContainerElement.scrollTop) <= 50;
|
scrollEnd = Math.abs(messagesContainerElement.scrollTop) <= 50;
|
||||||
}}
|
}}
|
||||||
|
>
|
||||||
|
{#key id}
|
||||||
|
<Messages
|
||||||
|
{channel}
|
||||||
|
{messages}
|
||||||
|
{top}
|
||||||
|
onThread={(id) => {
|
||||||
|
threadId = id;
|
||||||
|
}}
|
||||||
|
onLoad={async () => {
|
||||||
|
const newMessages = await getChannelMessages(
|
||||||
|
localStorage.token,
|
||||||
|
id,
|
||||||
|
messages.length
|
||||||
|
);
|
||||||
|
|
||||||
|
messages = [...messages, ...newMessages];
|
||||||
|
|
||||||
|
if (newMessages.length < 50) {
|
||||||
|
top = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/key}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class=" pb-[1rem]">
|
||||||
|
<MessageInput
|
||||||
|
{typingUsers}
|
||||||
|
{onChange}
|
||||||
|
onSubmit={submitHandler}
|
||||||
|
{scrollToBottom}
|
||||||
|
{scrollEnd}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Pane>
|
||||||
|
|
||||||
|
{#if !largeScreen}
|
||||||
|
{#if threadId !== null}
|
||||||
|
<Drawer
|
||||||
|
show={threadId !== null}
|
||||||
|
on:close={() => {
|
||||||
|
threadId = null;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class=" {threadId !== null ? ' h-screen w-screen' : 'px-6 py-4'} h-full">
|
||||||
|
<Thread
|
||||||
|
{threadId}
|
||||||
|
{channel}
|
||||||
|
onClose={() => {
|
||||||
|
threadId = null;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Drawer>
|
||||||
|
{/if}
|
||||||
|
{:else if threadId !== null}
|
||||||
|
<PaneResizer
|
||||||
|
class="relative flex w-[3px] items-center justify-center bg-background group bg-gray-50 dark:bg-gray-850"
|
||||||
>
|
>
|
||||||
{#key id}
|
<div class="z-10 flex h-7 w-5 items-center justify-center rounded-sm">
|
||||||
<Messages
|
<EllipsisVertical className="size-4 invisible group-hover:visible" />
|
||||||
|
</div>
|
||||||
|
</PaneResizer>
|
||||||
|
|
||||||
|
<Pane defaultSize={50} minSize={20} class="h-full w-full">
|
||||||
|
<div class="h-full w-full shadow-xl">
|
||||||
|
<Thread
|
||||||
|
{threadId}
|
||||||
{channel}
|
{channel}
|
||||||
{messages}
|
onClose={() => {
|
||||||
{top}
|
threadId = null;
|
||||||
onLoad={async () => {
|
|
||||||
const newMessages = await getChannelMessages(localStorage.token, id, messages.length);
|
|
||||||
|
|
||||||
messages = [...messages, ...newMessages];
|
|
||||||
|
|
||||||
if (newMessages.length < 50) {
|
|
||||||
top = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{/key}
|
</div>
|
||||||
</div>
|
</Pane>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</PaneGroup>
|
||||||
|
|
||||||
<div class=" pb-[1rem]">
|
|
||||||
<MessageInput {typingUsers} {onChange} onSubmit={submitHandler} {scrollToBottom} {scrollEnd} />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
export let top = false;
|
export let top = false;
|
||||||
|
|
||||||
export let onLoad: Function = () => {};
|
export let onLoad: Function = () => {};
|
||||||
|
export let onThread: Function = () => {};
|
||||||
|
|
||||||
let messagesLoading = false;
|
let messagesLoading = false;
|
||||||
|
|
||||||
@ -118,6 +119,9 @@
|
|||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
onThread={(id) => {
|
||||||
|
onThread(id);
|
||||||
|
}}
|
||||||
onReaction={(name) => {
|
onReaction={(name) => {
|
||||||
if (
|
if (
|
||||||
(message?.reactions ?? [])
|
(message?.reactions ?? [])
|
||||||
@ -127,7 +131,16 @@
|
|||||||
) {
|
) {
|
||||||
messages = messages.map((m) => {
|
messages = messages.map((m) => {
|
||||||
if (m.id === message.id) {
|
if (m.id === message.id) {
|
||||||
m.reactions = m.reactions.filter((reaction) => reaction.name !== name);
|
const reaction = m.reactions.find((reaction) => reaction.name === name);
|
||||||
|
|
||||||
|
if (reaction) {
|
||||||
|
reaction.user_ids = reaction.user_ids.filter((id) => id !== $user.id);
|
||||||
|
reaction.count = reaction.user_ids.length;
|
||||||
|
|
||||||
|
if (reaction.count === 0) {
|
||||||
|
m.reactions = m.reactions.filter((r) => r.name !== name);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return m;
|
return m;
|
||||||
});
|
});
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
|
|
||||||
export let onDelete: Function = () => {};
|
export let onDelete: Function = () => {};
|
||||||
export let onEdit: Function = () => {};
|
export let onEdit: Function = () => {};
|
||||||
|
export let onThread: Function = () => {};
|
||||||
export let onReaction: Function = () => {};
|
export let onReaction: Function = () => {};
|
||||||
|
|
||||||
let showButtons = false;
|
let showButtons = false;
|
||||||
@ -100,17 +101,18 @@
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</ReactionPicker>
|
</ReactionPicker>
|
||||||
|
|
||||||
<Tooltip content={$i18n.t('Reply in Thread')}>
|
{#if message?.parent_id === null}
|
||||||
<button
|
<Tooltip content={$i18n.t('Reply in Thread')}>
|
||||||
class="hover:bg-gray-100 dark:hover:bg-gray-800 transition rounded-lg p-1"
|
<button
|
||||||
on:click={() => {
|
class="hover:bg-gray-100 dark:hover:bg-gray-800 transition rounded-lg p-1"
|
||||||
edit = true;
|
on:click={() => {
|
||||||
editedContent = message.content;
|
onThread(message.id);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ChatBubbleOvalEllipsis />
|
<ChatBubbleOvalEllipsis />
|
||||||
</button>
|
</button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<Tooltip content={$i18n.t('Edit')}>
|
<Tooltip content={$i18n.t('Edit')}>
|
||||||
<button
|
<button
|
||||||
@ -288,6 +290,7 @@
|
|||||||
].toLowerCase()}.svg"
|
].toLowerCase()}.svg"
|
||||||
alt={reaction.name}
|
alt={reaction.name}
|
||||||
class=" size-4"
|
class=" size-4"
|
||||||
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<div>
|
<div>
|
||||||
|
28
src/lib/components/channel/Messages/Thread.svelte
Normal file
28
src/lib/components/channel/Messages/Thread.svelte
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import XMark from '$lib/components/icons/XMark.svelte';
|
||||||
|
|
||||||
|
export let threadId = null;
|
||||||
|
export let channel = null;
|
||||||
|
|
||||||
|
export let onClose = () => {};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex flex-col w-full h-full bg-gray-50 dark:bg-gray-900 px-3.5 py-3">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class=" font-medium text-lg">Thread</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
class="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300 p-2"
|
||||||
|
on:click={() => {
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<XMark />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{threadId}
|
||||||
|
|
||||||
|
{channel}
|
||||||
|
</div>
|
Loading…
Reference in New Issue
Block a user