mirror of
https://github.com/open-webui/open-webui
synced 2024-12-29 15:25:29 +00:00
refac: styling
This commit is contained in:
parent
f4e5e5171f
commit
a165e76486
@ -20,6 +20,10 @@
|
|||||||
initHandler();
|
initHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const scrollToBottom = () => {
|
||||||
|
messagesContainerElement.scrollTop = messagesContainerElement.scrollHeight;
|
||||||
|
};
|
||||||
|
|
||||||
const initHandler = async () => {
|
const initHandler = async () => {
|
||||||
top = false;
|
top = false;
|
||||||
page = 1;
|
page = 1;
|
||||||
@ -80,13 +84,11 @@
|
|||||||
|
|
||||||
<div class="h-full md:max-w-[calc(100%-260px)] w-full max-w-full flex flex-col">
|
<div class="h-full md:max-w-[calc(100%-260px)] w-full max-w-full flex flex-col">
|
||||||
<div
|
<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 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 =
|
scrollEnd = Math.abs(messagesContainerElement.scrollTop) <= 50;
|
||||||
messagesContainerElement.scrollHeight - messagesContainerElement.scrollTop <=
|
|
||||||
messagesContainerElement.clientHeight + 5;
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{#key id}
|
{#key id}
|
||||||
@ -110,6 +112,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=" pb-[1rem]">
|
<div class=" pb-[1rem]">
|
||||||
<MessageInput onSubmit={submitHandler} />
|
<MessageInput onSubmit={submitHandler} {scrollToBottom} {scrollEnd} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
let content = '';
|
let content = '';
|
||||||
|
|
||||||
export let onSubmit: Function;
|
export let onSubmit: Function;
|
||||||
|
export let scrollEnd = true;
|
||||||
|
export let scrollToBottom: Function;
|
||||||
|
|
||||||
let submitHandler = async () => {
|
let submitHandler = async () => {
|
||||||
if (content === '') {
|
if (content === '') {
|
||||||
@ -36,6 +38,37 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<div class=" mx-auto inset-x-0 bg-transparent flex justify-center">
|
||||||
|
<div class="flex flex-col px-3 max-w-6xl w-full">
|
||||||
|
<div class="relative">
|
||||||
|
{#if scrollEnd === false}
|
||||||
|
<div class=" absolute -top-12 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={() => {
|
||||||
|
scrollEnd = 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>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="{transparentBackground ? 'bg-transparent' : 'bg-white dark:bg-gray-900'} ">
|
<div class="{transparentBackground ? 'bg-transparent' : 'bg-white dark:bg-gray-900'} ">
|
||||||
<div class="max-w-6xl px-2.5 mx-auto inset-x-0">
|
<div class="max-w-6xl px-2.5 mx-auto inset-x-0">
|
||||||
<div class="">
|
<div class="">
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
import Message from './Messages/Message.svelte';
|
import Message from './Messages/Message.svelte';
|
||||||
import Loader from '../common/Loader.svelte';
|
import Loader from '../common/Loader.svelte';
|
||||||
import Spinner from '../common/Spinner.svelte';
|
import Spinner from '../common/Spinner.svelte';
|
||||||
import { getChannelMessages } from '$lib/apis/channels';
|
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
@ -35,28 +34,32 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if messages}
|
{#if messages}
|
||||||
<div class="w-full h-full pt-2 flex-1 flex flex-col-reverse overflow-auto">
|
{@const messageList = messages.slice().reverse()}
|
||||||
<div>
|
<div>
|
||||||
{#if !top}
|
{#if !top}
|
||||||
<Loader
|
<Loader
|
||||||
on:visible={(e) => {
|
on:visible={(e) => {
|
||||||
console.log('visible');
|
console.log('visible');
|
||||||
if (!messagesLoading) {
|
if (!messagesLoading) {
|
||||||
loadMoreMessages();
|
loadMoreMessages();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div class="w-full flex justify-center py-1 text-xs animate-pulse items-center gap-2">
|
<div class="w-full flex justify-center py-1 text-xs animate-pulse items-center gap-2">
|
||||||
<Spinner className=" size-4" />
|
<Spinner className=" size-4" />
|
||||||
<div class=" ">Loading...</div>
|
<div class=" ">Loading...</div>
|
||||||
</div>
|
</div>
|
||||||
</Loader>
|
</Loader>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#each messages.slice().reverse() as message, messageIdx (message.id)}
|
{#each messageList as message, messageIdx (message.id)}
|
||||||
<Message {message} />
|
<Message
|
||||||
{/each}
|
{message}
|
||||||
</div>
|
showUserProfile={messageIdx === 0 ||
|
||||||
|
messageList.at(messageIdx + 1)?.user_id !== message.user_id}
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
<div class="pb-6" />
|
||||||
</div>
|
</div>
|
||||||
<div class="pb-6" />
|
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -1,13 +1,87 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||||
|
import isToday from 'dayjs/plugin/isToday';
|
||||||
|
import isYesterday from 'dayjs/plugin/isYesterday';
|
||||||
|
|
||||||
|
dayjs.extend(relativeTime);
|
||||||
|
dayjs.extend(isToday);
|
||||||
|
dayjs.extend(isYesterday);
|
||||||
|
|
||||||
|
import { getContext } from 'svelte';
|
||||||
|
const i18n = getContext<Writable<i18nType>>('i18n');
|
||||||
|
|
||||||
|
import { settings } from '$lib/stores';
|
||||||
|
|
||||||
|
import { WEBUI_BASE_URL } from '$lib/constants';
|
||||||
|
|
||||||
import Markdown from '$lib/components/chat/Messages/Markdown.svelte';
|
import Markdown from '$lib/components/chat/Messages/Markdown.svelte';
|
||||||
|
import ProfileImage from '$lib/components/chat/Messages/ProfileImage.svelte';
|
||||||
|
import Name from '$lib/components/chat/Messages/Name.svelte';
|
||||||
|
|
||||||
export let message;
|
export let message;
|
||||||
|
export let showUserProfile = true;
|
||||||
|
|
||||||
|
const formatDate = (inputDate) => {
|
||||||
|
const date = dayjs(inputDate);
|
||||||
|
const now = dayjs();
|
||||||
|
|
||||||
|
if (date.isToday()) {
|
||||||
|
return `Today at ${date.format('HH:mm')}`;
|
||||||
|
} else if (date.isYesterday()) {
|
||||||
|
return `Yesterday at ${date.format('HH:mm')}`;
|
||||||
|
} else {
|
||||||
|
return `${date.format('DD/MM/YYYY')} at ${date.format('HH:mm')}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if message}
|
{#if message}
|
||||||
<div>
|
<div
|
||||||
<div>
|
class="flex flex-col justify-between px-5 {showUserProfile
|
||||||
<Markdown id={message.id} content={message.content} />
|
? 'mt-3'
|
||||||
|
: ''} w-full {($settings?.widescreenMode ?? null)
|
||||||
|
? 'max-w-full'
|
||||||
|
: 'max-w-5xl'} mx-auto rounded-lg group"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class=" flex w-full message-{message.id}"
|
||||||
|
id="message-{message.id}"
|
||||||
|
dir={$settings.chatDirection}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class={`flex-shrink-0 ${($settings?.chatDirection ?? 'LTR') === 'LTR' ? 'mr-3' : 'ml-3'}`}
|
||||||
|
>
|
||||||
|
{#if showUserProfile}
|
||||||
|
<ProfileImage
|
||||||
|
src={message.user?.profile_image_url ??
|
||||||
|
($i18n.language === 'dg-DG' ? `/doge.png` : `${WEBUI_BASE_URL}/static/favicon.png`)}
|
||||||
|
className={'size-7'}
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<div class="w-7 h-7 rounded-full bg-transparent" />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-auto w-0 pl-1">
|
||||||
|
{#if showUserProfile}
|
||||||
|
<Name>
|
||||||
|
{message?.user?.name}
|
||||||
|
|
||||||
|
{#if message.created_at}
|
||||||
|
<span
|
||||||
|
class=" self-center invisible group-hover:visible text-gray-400 text-xs font-medium capitalize ml-0.5 -mt-0.5"
|
||||||
|
>
|
||||||
|
{formatDate(message.created_at / 1000000)}
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
</Name>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div class="markdown-prose">
|
||||||
|
<Markdown id={message.id} content={message.content} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
Loading…
Reference in New Issue
Block a user