mirror of
https://github.com/open-webui/open-webui.git
synced 2026-10-09 03:18:18 +00:00
refac
This commit is contained in:
parent
f4011ebe45
commit
7937e8a1fd
6 changed files with 112 additions and 99 deletions
|
|
@ -404,7 +404,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" pb-[1rem] px-2.5">
|
||||
<div class=" pb-3 px-3">
|
||||
<MessageInput
|
||||
id="root"
|
||||
bind:chatInputElement
|
||||
|
|
@ -460,7 +460,7 @@
|
|||
maxWidth={640}
|
||||
className="h-full"
|
||||
>
|
||||
<div class="h-full w-full shadow-xl">
|
||||
<div class="h-full w-full border-l border-gray-100/60 dark:border-gray-800/40">
|
||||
<Thread
|
||||
{threadId}
|
||||
{channel}
|
||||
|
|
|
|||
|
|
@ -894,13 +894,15 @@
|
|||
{/if}
|
||||
<div
|
||||
id="message-input-container"
|
||||
class="flex-1 flex flex-col relative w-full shadow-lg rounded-3xl border border-gray-50 dark:border-gray-850/30 hover:border-gray-100 focus-within:border-gray-100 hover:dark:border-gray-800 focus-within:dark:border-gray-800 transition px-0.5 bg-white/90 dark:bg-gray-400/5 dark:text-gray-100"
|
||||
class="flex-1 flex flex-col relative w-full shadow-sm rounded-2xl border border-gray-100/60 dark:border-gray-800/50 hover:border-gray-100 focus-within:border-gray-100 hover:dark:border-gray-800 focus-within:dark:border-gray-800 transition bg-white dark:bg-gray-400/5 dark:text-gray-100"
|
||||
dir={$settings?.chatDirection ?? 'auto'}
|
||||
>
|
||||
{#if replyToMessage !== null}
|
||||
<div class="px-3 pt-3 text-left w-full flex flex-col z-10">
|
||||
<div class="px-3 pt-2 text-left w-full flex flex-col z-10">
|
||||
<div class="flex items-center justify-between w-full">
|
||||
<div class="pl-[0.0625rem] flex items-center gap-2 text-sm">
|
||||
<div
|
||||
class="min-w-0 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400"
|
||||
>
|
||||
<div class="translate-y-[0.5px]">
|
||||
<span class=""
|
||||
>{$i18n.t('Replying to {{NAME}}', {
|
||||
|
|
@ -911,12 +913,14 @@
|
|||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="flex items-center dark:text-gray-500"
|
||||
class="flex size-6 shrink-0 items-center justify-center rounded-md text-gray-500 hover:bg-gray-50 dark:hover:bg-gray-800 dark:text-gray-400"
|
||||
aria-label={$i18n.t('Cancel')}
|
||||
type="button"
|
||||
on:click={() => {
|
||||
replyToMessage = null;
|
||||
}}
|
||||
>
|
||||
<XMark />
|
||||
<XMark className="size-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -992,6 +996,7 @@
|
|||
{#key $settings?.richTextInput && $settings?.showFormattingToolbar}
|
||||
<RichTextInput
|
||||
id="chat-input"
|
||||
className="input-prose min-h-fit h-full text-sm!"
|
||||
bind:this={chatInputElement}
|
||||
json={true}
|
||||
messageInput={true}
|
||||
|
|
@ -1087,8 +1092,8 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" flex justify-between mt-0.5 mb-2 mx-0.5 max-w-full">
|
||||
<div class="ml-1 self-end flex items-center flex-1 min-w-0">
|
||||
<div class=" flex items-center justify-between gap-2 p-1.5 pt-0.5 max-w-full">
|
||||
<div class="flex items-center flex-1 min-w-0">
|
||||
<slot name="menu">
|
||||
{#if acceptFiles}
|
||||
<InputMenu
|
||||
|
|
@ -1099,7 +1104,7 @@
|
|||
>
|
||||
<button
|
||||
id="input-menu-button"
|
||||
class="bg-transparent hover:bg-gray-100 text-gray-700 dark:text-white dark:hover:bg-gray-800 rounded-full size-[1.875rem] flex justify-center items-center outline-hidden focus:outline-hidden shrink-0"
|
||||
class="bg-transparent hover:bg-gray-100 text-gray-500 dark:text-gray-400 dark:hover:bg-gray-800 rounded-lg size-7 flex justify-center items-center outline-hidden focus:outline-hidden shrink-0"
|
||||
type="button"
|
||||
aria-label={$i18n.t('More')}
|
||||
>
|
||||
|
|
@ -1107,7 +1112,7 @@
|
|||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
class="size-5"
|
||||
class="size-4"
|
||||
>
|
||||
<path
|
||||
d="M10.75 4.75a.75.75 0 0 0-1.5 0v4.5h-4.5a.75.75 0 0 0 0 1.5h4.5v4.5a.75.75 0 0 0 1.5 0v-4.5h4.5a.75.75 0 0 0 0-1.5h-4.5v-4.5Z"
|
||||
|
|
@ -1119,12 +1124,12 @@
|
|||
</slot>
|
||||
</div>
|
||||
|
||||
<div class="self-end flex space-x-1 mr-1 shrink-0 gap-[0.03125rem]">
|
||||
<div class="flex items-center gap-1 shrink-0">
|
||||
{#if content === ''}
|
||||
<Tooltip content={$i18n.t('Record voice')}>
|
||||
<button
|
||||
id="voice-input-button"
|
||||
class=" text-gray-600 dark:text-gray-300 hover:text-gray-700 dark:hover:text-gray-200 transition rounded-full p-[0.3125rem] mr-0.5 self-center"
|
||||
class=" text-gray-600 dark:text-gray-300 hover:text-gray-700 dark:hover:text-gray-200 transition rounded-lg size-7 flex items-center justify-center"
|
||||
type="button"
|
||||
on:click={async () => {
|
||||
try {
|
||||
|
|
@ -1158,7 +1163,7 @@
|
|||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
class="w-5 h-5 translate-y-[0.5px]"
|
||||
class="size-4"
|
||||
>
|
||||
<path d="M7 4a3 3 0 016 0v6a3 3 0 11-6 0V4z" />
|
||||
<path
|
||||
|
|
@ -1175,7 +1180,7 @@
|
|||
<Tooltip content={$i18n.t('Stop')}>
|
||||
<button
|
||||
aria-label={$i18n.t('Stop')}
|
||||
class="bg-white hover:bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-800 transition rounded-full p-[0.3125rem]"
|
||||
class="bg-white hover:bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-800 transition rounded-full size-7 flex items-center justify-center"
|
||||
on:click={() => {
|
||||
onStop();
|
||||
}}
|
||||
|
|
@ -1184,7 +1189,7 @@
|
|||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
class="size-5"
|
||||
class="size-4"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
|
|
@ -1203,7 +1208,7 @@
|
|||
aria-label={$i18n.t('Send message')}
|
||||
class="{content !== '' || files.length !== 0
|
||||
? 'bg-black text-white hover:bg-gray-900 dark:bg-white dark:text-black dark:hover:bg-gray-100 '
|
||||
: 'text-white bg-gray-200 dark:text-gray-900 dark:bg-gray-700 disabled'} transition rounded-full p-[0.3125rem] self-center"
|
||||
: 'text-white bg-gray-200 dark:text-gray-900 dark:bg-gray-700 disabled'} transition rounded-full size-7 flex items-center justify-center self-center"
|
||||
type="submit"
|
||||
disabled={content === '' && files.length === 0}
|
||||
>
|
||||
|
|
@ -1211,7 +1216,7 @@
|
|||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
class="size-5"
|
||||
class="size-4"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
|
|
|
|||
|
|
@ -73,16 +73,16 @@
|
|||
</div>
|
||||
</Loader>
|
||||
{:else if !thread}
|
||||
<div class="px-5 max-w-full mx-auto">
|
||||
<div class="px-4 max-w-full mx-auto">
|
||||
{#if channel}
|
||||
<div class="flex flex-col gap-1.5 pb-5 pt-10">
|
||||
<div class="flex flex-col gap-1.5 pb-4 pt-8">
|
||||
{#if channel?.type === 'dm'}
|
||||
<div class="flex ml-[0.0625rem] mr-0.5">
|
||||
{#each channel.users.filter((u) => u.id !== $user?.id).slice(0, 2) as u, index}
|
||||
<img
|
||||
src={`${WEBUI_API_BASE_URL}/users/${u.id}/profile/image`}
|
||||
alt={u.name}
|
||||
class=" size-7.5 rounded-full border-2 border-white dark:border-gray-900 {index ===
|
||||
class=" size-7 rounded-full object-cover border-2 border-white dark:border-gray-900 {index ===
|
||||
1
|
||||
? '-ml-2.5'
|
||||
: ''}"
|
||||
|
|
@ -91,7 +91,7 @@
|
|||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="text-2xl font-normal capitalize">
|
||||
<div class="text-lg font-medium leading-6">
|
||||
{#if channel?.name}
|
||||
{channel.name}
|
||||
{:else}
|
||||
|
|
@ -102,7 +102,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
|
||||
<div class=" text-gray-500">
|
||||
<div class="text-xs leading-5 text-gray-500 dark:text-gray-400">
|
||||
{$i18n.t(
|
||||
'This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.',
|
||||
{
|
||||
|
|
@ -119,7 +119,7 @@
|
|||
{/if}
|
||||
|
||||
{#if messageList.length > 0}
|
||||
<hr class=" border-gray-50 dark:border-gray-700/20 py-2.5 w-full" />
|
||||
<hr class=" border-gray-100/60 dark:border-gray-800/40 mb-2 w-full" />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
|
@ -256,6 +256,6 @@
|
|||
/>
|
||||
{/each}
|
||||
|
||||
<div class="pb-6" />
|
||||
<div class="pb-4"></div>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
import StructuredOutputRenderer from '$lib/components/chat/Messages/StructuredOutputRenderer.svelte';
|
||||
import { buildOutputDisplayItems } from '$lib/components/chat/Messages/structuredOutput';
|
||||
import ProfileImage from '$lib/components/chat/Messages/ProfileImage.svelte';
|
||||
import Name from '$lib/components/chat/Messages/Name.svelte';
|
||||
import ConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
|
||||
import GarbageBin from '$lib/components/icons/GarbageBin.svelte';
|
||||
import Pencil from '$lib/components/icons/Pencil.svelte';
|
||||
|
|
@ -181,7 +180,7 @@
|
|||
class="swipe-reply-icon"
|
||||
class:swipe-reply-icon--active={swipeOffsetX >= SWIPE_THRESHOLD}
|
||||
>
|
||||
<ArrowUpLeftAlt className="size-5" />
|
||||
<ArrowUpLeftAlt className="size-4" />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
@ -190,17 +189,17 @@
|
|||
id="message-{renderedMessageId}"
|
||||
class="flex flex-col justify-between w-full max-w-full mx-auto group hover:bg-gray-300/5 dark:hover:bg-gray-700/5 relative {className
|
||||
? className
|
||||
: `px-5 ${
|
||||
: `px-4 ${
|
||||
replyToMessage
|
||||
? 'border-l-4 border-blue-500 bg-blue-100/10 dark:bg-blue-100/5 pl-4'
|
||||
? 'border-l-4 border-blue-500 bg-blue-100/10 dark:bg-blue-100/5 pl-3'
|
||||
: ''
|
||||
} ${
|
||||
(message?.reply_to_message?.meta?.model_id ?? message?.reply_to_message?.user_id) ===
|
||||
$user?.id
|
||||
? 'border-l-4 border-orange-500 bg-orange-100/10 dark:bg-orange-100/5 pl-4'
|
||||
? 'border-l-4 border-orange-500 bg-orange-100/10 dark:bg-orange-100/5 pl-3'
|
||||
: ''
|
||||
} ${message?.is_pinned ? 'bg-yellow-100/20 dark:bg-yellow-100/5' : ''}`} {showUserProfile
|
||||
? 'pt-1.5 pb-0.5'
|
||||
? 'pt-2.5 pb-0.5'
|
||||
: ''}"
|
||||
style="transform: translateX({swipeOffsetX}px); {swipeOffsetX > 0
|
||||
? ''
|
||||
|
|
@ -235,12 +234,13 @@
|
|||
{#if onReply}
|
||||
<Tooltip content={$i18n.t('Reply')}>
|
||||
<button
|
||||
class="hover:bg-gray-100 dark:hover:bg-gray-800 transition rounded-lg p-0.5"
|
||||
aria-label={$i18n.t('Reply')}
|
||||
class="hover:bg-gray-100 dark:hover:bg-gray-800 transition rounded-lg p-1"
|
||||
on:click={() => {
|
||||
onReply(message);
|
||||
}}
|
||||
>
|
||||
<ArrowUpLeftAlt className="size-5" />
|
||||
<ArrowUpLeftAlt className="size-4" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
|
|
@ -263,6 +263,7 @@
|
|||
{#if !thread && onThread}
|
||||
<Tooltip content={$i18n.t('Reply in Thread')}>
|
||||
<button
|
||||
aria-label={$i18n.t('Reply in Thread')}
|
||||
class="hover:bg-gray-100 dark:hover:bg-gray-800 transition rounded-lg p-1"
|
||||
on:click={() => {
|
||||
onThread(message.id);
|
||||
|
|
@ -305,7 +306,7 @@
|
|||
|
||||
{#if message?.is_pinned}
|
||||
<div class="flex {showUserProfile ? 'mb-0.5' : 'mt-0.5'}">
|
||||
<div class="ml-8.5 flex items-center gap-1 px-1 rounded-full text-xs">
|
||||
<div class="ml-8 flex items-center gap-1 text-[0.6875rem] leading-4">
|
||||
<Pin className="size-3 text-yellow-500 dark:text-yellow-300" />
|
||||
<span class="text-gray-500">{$i18n.t('Pinned')}</span>
|
||||
</div>
|
||||
|
|
@ -315,11 +316,11 @@
|
|||
{#if message?.reply_to_message?.user}
|
||||
<div class="relative text-xs mb-1">
|
||||
<div
|
||||
class="absolute h-3 w-7 left-[1.125rem] top-2 rounded-tl-lg border-t-[1.5px] border-l-[1.5px] border-gray-200 dark:border-gray-700 z-0"
|
||||
class="absolute h-3 w-5 left-3 top-2 rounded-tl-lg border-t-[1.5px] border-l-[1.5px] border-gray-200 dark:border-gray-700 z-0"
|
||||
></div>
|
||||
|
||||
<button
|
||||
class="ml-12 flex items-center space-x-2 relative z-0"
|
||||
class="ml-8 flex min-w-0 max-w-[calc(100%-2rem)] items-center gap-1.5 relative z-0"
|
||||
on:click={() => {
|
||||
const messageElement = document.getElementById(`message-${replyToMessageId}`);
|
||||
if (messageElement) {
|
||||
|
|
@ -355,13 +356,15 @@
|
|||
/>
|
||||
{/if}
|
||||
|
||||
<div class="shrink-0">
|
||||
<div class="max-w-[35%] shrink-0 truncate">
|
||||
{message?.reply_to_message.meta?.model_name ??
|
||||
message?.reply_to_message.user?.name ??
|
||||
$i18n.t('Unknown User')}
|
||||
</div>
|
||||
|
||||
<div class="italic text-sm text-gray-500 dark:text-gray-400 line-clamp-1 w-full flex-1">
|
||||
<div
|
||||
class="text-xs text-gray-500 dark:text-gray-400 line-clamp-1 min-w-0 flex-1 [&_.markdown-prose]:text-xs!"
|
||||
>
|
||||
<Markdown
|
||||
id={`${renderedMessageId}-reply-to`}
|
||||
content={message?.reply_to_message?.content}
|
||||
|
|
@ -377,13 +380,13 @@
|
|||
id="message-{renderedMessageId}"
|
||||
dir={$settings.chatDirection}
|
||||
>
|
||||
<div class={`shrink-0 mr-1 w-9`}>
|
||||
<div class="w-6 shrink-0">
|
||||
{#if showUserProfile}
|
||||
{#if message?.meta?.model_id}
|
||||
<img
|
||||
src={`${WEBUI_API_BASE_URL}/models/model/profile/image?id=${message.meta.model_id}`}
|
||||
alt={message.meta.model_name ?? message.meta.model_id}
|
||||
class="size-8 translate-y-1 ml-0.5 object-cover rounded-full"
|
||||
class="size-6 mt-0.5 object-cover rounded-full"
|
||||
on:error={(e) => {
|
||||
// LICENSE covers this Open WebUI fallback logo.
|
||||
// Do not alter, remove, obscure, or replace it except as LICENSE permits:
|
||||
|
|
@ -394,35 +397,33 @@
|
|||
{:else if message.user?.role === 'webhook'}
|
||||
<ProfileImage
|
||||
src={`${WEBUI_API_BASE_URL}/channels/webhooks/${message.user?.id}/profile/image`}
|
||||
className={'size-8 ml-0.5'}
|
||||
className={'size-6 mt-0.5 rounded-full!'}
|
||||
/>
|
||||
{:else}
|
||||
<ProfilePreview user={message.user}>
|
||||
<ProfileImage
|
||||
src={`${WEBUI_API_BASE_URL}/users/${message.user?.id}/profile/image`}
|
||||
className={'size-8 ml-0.5'}
|
||||
className={'size-6 mt-0.5 rounded-full!'}
|
||||
/>
|
||||
</ProfilePreview>
|
||||
{/if}
|
||||
{:else}
|
||||
<!-- <div class="w-7 h-7 rounded-full bg-transparent" /> -->
|
||||
|
||||
{#if message.created_at}
|
||||
<div
|
||||
class="mt-1.5 flex shrink-0 items-center text-xs self-center hover-reveal text-gray-500 font-normal first-letter:capitalize"
|
||||
>
|
||||
<Tooltip content={dayjs(message.created_at / 1000000).format('LLLL')}>
|
||||
{dayjs(message.created_at / 1000000).format('HH:mm')}
|
||||
</Tooltip>
|
||||
</div>
|
||||
{/if}
|
||||
{:else if message.created_at}
|
||||
<div
|
||||
class="-mx-1 mt-1 flex items-center justify-center text-[0.6875rem] leading-4 tabular-nums hover-reveal text-gray-500 dark:text-gray-400"
|
||||
>
|
||||
<Tooltip content={dayjs(message.created_at / 1000000).format('LLLL')}>
|
||||
{dayjs(message.created_at / 1000000).format('HH:mm')}
|
||||
</Tooltip>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="flex-auto w-0 pl-2">
|
||||
{#if showUserProfile}
|
||||
<Name>
|
||||
<div class=" self-end text-base shrink-0 font-normal truncate">
|
||||
<div class="flex min-w-0 items-baseline gap-1.5 leading-5">
|
||||
<div
|
||||
class=" min-w-0 truncate text-[0.8125rem] font-medium text-gray-900 dark:text-gray-100"
|
||||
>
|
||||
{#if message?.meta?.model_id}
|
||||
{message?.meta?.model_name ?? message?.meta?.model_id}
|
||||
{:else}
|
||||
|
|
@ -432,7 +433,7 @@
|
|||
|
||||
{#if message.created_at}
|
||||
<div
|
||||
class=" self-center text-xs text-gray-400 font-normal first-letter:capitalize ml-0.5 translate-y-[1px]"
|
||||
class=" shrink-0 text-[0.6875rem] leading-4 text-gray-500 dark:text-gray-400 font-normal first-letter:capitalize"
|
||||
>
|
||||
<Tooltip content={dayjs(message.created_at / 1000000).format('LLLL')}>
|
||||
<span class="line-clamp-1">
|
||||
|
|
@ -448,7 +449,7 @@
|
|||
</Tooltip>
|
||||
</div>
|
||||
{/if}
|
||||
</Name>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if message?.data === true}
|
||||
|
|
@ -531,7 +532,11 @@
|
|||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="min-w-full {pending ? 'opacity-50' : ''}">
|
||||
<div
|
||||
class="min-w-full [&_.markdown-prose]:text-sm! [&_.markdown-prose]:leading-[1.375rem]! {pending
|
||||
? 'opacity-50'
|
||||
: ''}"
|
||||
>
|
||||
{#if hasStructuredOutput}
|
||||
<StructuredOutputRenderer
|
||||
id={renderedMessageId}
|
||||
|
|
@ -558,7 +563,7 @@
|
|||
|
||||
{#if (message?.reactions ?? []).length > 0}
|
||||
<div>
|
||||
<div class="flex items-center flex-wrap gap-y-1.5 gap-1 mt-1 mb-2">
|
||||
<div class="flex items-center flex-wrap gap-1 mt-1 mb-1">
|
||||
{#each message.reactions as reaction}
|
||||
<Tooltip
|
||||
content={$i18n.t('{{NAMES}} reacted with {{REACTION}}', {
|
||||
|
|
@ -596,7 +601,7 @@
|
|||
>
|
||||
<button
|
||||
{disabled}
|
||||
class="flex items-center gap-1.5 transition rounded-xl px-2 py-1 cursor-pointer {reaction.users
|
||||
class="flex min-h-6 items-center gap-1.5 text-sm leading-4 transition rounded-lg px-1.5 py-0.5 cursor-pointer {reaction.users
|
||||
.map((u) => u.id)
|
||||
.includes($user?.id)
|
||||
? ' bg-blue-300/10 outline outline-blue-500/50 outline-1'
|
||||
|
|
@ -607,10 +612,12 @@
|
|||
}
|
||||
}}
|
||||
>
|
||||
<Emoji shortCode={reaction.name} />
|
||||
<Emoji className="size-3.5" shortCode={reaction.name} />
|
||||
|
||||
{#if reaction.users.length > 0}
|
||||
<div class="text-xs font-normal text-gray-500 dark:text-gray-400">
|
||||
<div
|
||||
class="text-[0.6875rem] font-normal text-gray-500 dark:text-gray-400"
|
||||
>
|
||||
{reaction.users?.length}
|
||||
</div>
|
||||
{/if}
|
||||
|
|
@ -626,7 +633,7 @@
|
|||
>
|
||||
<Tooltip content={$i18n.t('Add Reaction')}>
|
||||
<div
|
||||
class="flex items-center gap-1.5 bg-gray-500/10 hover:outline hover:outline-gray-700/30 dark:hover:outline-gray-300/30 hover:outline-1 transition rounded-xl px-1 py-1 cursor-pointer text-gray-500 dark:text-gray-400"
|
||||
class="flex items-center gap-1.5 bg-gray-500/10 hover:outline hover:outline-gray-700/30 dark:hover:outline-gray-300/30 hover:outline-1 transition rounded-lg p-1 cursor-pointer text-gray-500 dark:text-gray-400"
|
||||
>
|
||||
<FaceSmile />
|
||||
</div>
|
||||
|
|
@ -640,14 +647,14 @@
|
|||
{#if !thread && message.reply_count > 0}
|
||||
<div class="flex items-center gap-1.5 -mt-0.5 mb-1.5">
|
||||
<button
|
||||
class="flex items-center text-xs py-1 text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 transition"
|
||||
class="flex min-w-0 items-center text-[0.6875rem] py-1 text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 transition"
|
||||
on:click={() => {
|
||||
onThread(message.id);
|
||||
}}
|
||||
>
|
||||
<span class="font-normal mr-1">
|
||||
<span class="shrink-0 font-medium mr-1">
|
||||
{$i18n.t('{{COUNT}} Replies', { COUNT: message.reply_count })}</span
|
||||
><span>
|
||||
><span class="truncate">
|
||||
{' - '}{$i18n.t('Last reply')}
|
||||
{dayjs.unix(message.latest_reply_at / 1000000000).fromNow()}</span
|
||||
>
|
||||
|
|
|
|||
|
|
@ -52,19 +52,19 @@
|
|||
|
||||
<PinnedMessagesModal bind:show={showChannelPinnedMessagesModal} {channel} {onPin} />
|
||||
<ChannelInfoModal bind:show={showChannelInfoModal} {channel} {onUpdate} />
|
||||
<nav class="sticky top-0 z-30 w-full px-1.5 py-1 -mb-8 flex items-center drag-region flex flex-col">
|
||||
<nav class="sticky top-0 z-30 w-full px-3 py-1 -mb-8 flex items-center drag-region flex-col">
|
||||
<div
|
||||
id="navbar-bg-gradient-to-b"
|
||||
class=" bg-linear-to-b via-50% from-white via-white to-transparent dark:from-gray-900 dark:via-gray-900 dark:to-transparent pointer-events-none absolute inset-0 -bottom-7 z-[-1]"
|
||||
></div>
|
||||
|
||||
<div class=" flex max-w-full w-full mx-auto px-1 pt-0.5 bg-transparent">
|
||||
<div class=" flex max-w-full w-full mx-auto pt-0.5 bg-transparent">
|
||||
<div class="flex items-center w-full max-w-full">
|
||||
{#if $mobile}
|
||||
<div
|
||||
class="{$showSidebar
|
||||
? 'md:hidden'
|
||||
: ''} mr-1.5 mt-0.5 self-start flex flex-none items-center text-gray-600 dark:text-gray-400"
|
||||
: ''} mr-1.5 mt-0.5 self-center flex flex-none items-center text-gray-600 dark:text-gray-400"
|
||||
>
|
||||
<Tooltip
|
||||
content={$showSidebar ? $i18n.t('Close Sidebar') : $i18n.t('Open Sidebar')}
|
||||
|
|
@ -86,23 +86,23 @@
|
|||
{/if}
|
||||
|
||||
<div
|
||||
class="flex-1 overflow-hidden max-w-full py-0.5 flex items-center
|
||||
class="min-w-0 flex-1 overflow-hidden max-w-full py-0.5 flex items-center
|
||||
{$showSidebar ? 'ml-1' : ''}
|
||||
"
|
||||
>
|
||||
{#if channel}
|
||||
<div class="flex items-center gap-0.5 shrink-0">
|
||||
<div class="flex min-w-0 items-center gap-1.5">
|
||||
{#if channel?.type === 'dm'}
|
||||
{#if channel?.users}
|
||||
{@const channelMembers = channel.users.filter((u) => u.id !== $user?.id)}
|
||||
<div class="flex mr-1.5 relative">
|
||||
<div class="flex shrink-0 relative">
|
||||
{#each channelMembers.slice(0, 2) as u, index}
|
||||
<img
|
||||
src={`${WEBUI_API_BASE_URL}/users/${u.id}/profile/image`}
|
||||
alt={u.name}
|
||||
class=" size-6.5 rounded-full border-2 border-white dark:border-gray-900 {index ===
|
||||
class=" size-5.5 rounded-full object-cover border border-white dark:border-gray-900 {index ===
|
||||
1
|
||||
? '-ml-3'
|
||||
? '-ml-2'
|
||||
: ''}"
|
||||
/>
|
||||
{/each}
|
||||
|
|
@ -110,11 +110,6 @@
|
|||
{#if channelMembers.length === 1}
|
||||
<div class="absolute bottom-0 right-0">
|
||||
<span class="relative flex size-2">
|
||||
{#if channelMembers[0]?.is_active}
|
||||
<span
|
||||
class="absolute inline-flex h-full w-full animate-ping rounded-full bg-green-400 opacity-75"
|
||||
></span>
|
||||
{/if}
|
||||
<span
|
||||
class="relative inline-flex size-2 rounded-full {channelMembers[0]
|
||||
?.is_active
|
||||
|
|
@ -126,19 +121,21 @@
|
|||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<Users className="size-4 ml-1 mr-0.5" strokeWidth="2" />
|
||||
<Users className="size-4" strokeWidth="1.5" />
|
||||
{/if}
|
||||
{:else}
|
||||
<div class=" size-4.5 justify-center flex items-center">
|
||||
<div class=" size-4 shrink-0 justify-center flex items-center">
|
||||
{#if isPublicChannel(channel)}
|
||||
<Hashtag className="size-3.5" strokeWidth="2.5" />
|
||||
<Hashtag className="size-4" strokeWidth="1.5" />
|
||||
{:else}
|
||||
<Lock className="size-5" strokeWidth="2" />
|
||||
<Lock className="size-4" strokeWidth="1.5" />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class=" text-left self-center overflow-hidden w-full line-clamp-1 flex-1">
|
||||
<div
|
||||
class=" min-w-0 truncate text-left text-sm font-medium leading-5 text-gray-700 dark:text-gray-300"
|
||||
>
|
||||
{#if channel?.name}
|
||||
{channel.name}
|
||||
{:else}
|
||||
|
|
@ -153,19 +150,19 @@
|
|||
</div>
|
||||
|
||||
<div
|
||||
class="self-start flex flex-none items-center text-gray-600 dark:text-gray-400 gap-1 shrink-0"
|
||||
class="self-center flex flex-none items-center text-gray-600 dark:text-gray-400 gap-1 shrink-0"
|
||||
>
|
||||
{#if channel}
|
||||
<Tooltip content={$i18n.t('Pinned Messages')}>
|
||||
<button
|
||||
class=" flex cursor-pointer py-1.5 px-1.5 border dark:border-gray-850 border-gray-50 rounded-xl text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-850 transition"
|
||||
class=" flex size-7 items-center justify-center cursor-pointer rounded-lg text-gray-500 dark:text-gray-400 hover:bg-gray-50/60 dark:hover:bg-gray-800/60 transition-colors"
|
||||
aria-label={$i18n.t('Pinned Messages')}
|
||||
type="button"
|
||||
on:click={() => {
|
||||
showChannelPinnedMessagesModal = true;
|
||||
}}
|
||||
>
|
||||
<div class=" flex items-center gap-0.5 m-auto self-center shrink-0">
|
||||
<div class=" flex items-center gap-1 m-auto self-center shrink-0">
|
||||
<Pin className=" size-4" strokeWidth="1.5" />
|
||||
</div>
|
||||
</button>
|
||||
|
|
@ -174,17 +171,17 @@
|
|||
{#if channel?.user_count !== undefined}
|
||||
<Tooltip content={$i18n.t('Users')}>
|
||||
<button
|
||||
class=" flex cursor-pointer shrink-0 py-1 px-1.5 border dark:border-gray-850 border-gray-50 rounded-xl text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-850 transition"
|
||||
class=" flex h-7 items-center cursor-pointer shrink-0 px-1.5 rounded-lg text-gray-500 dark:text-gray-400 hover:bg-gray-50/60 dark:hover:bg-gray-800/60 transition-colors"
|
||||
aria-label={$i18n.t('User Count')}
|
||||
type="button"
|
||||
on:click={() => {
|
||||
showChannelInfoModal = true;
|
||||
}}
|
||||
>
|
||||
<div class=" flex items-center gap-0.5 m-auto self-center shrink-0">
|
||||
<div class=" flex items-center gap-1 m-auto self-center shrink-0">
|
||||
<UserAlt className=" size-4" strokeWidth="1.5" />
|
||||
|
||||
<div class="text-sm shrink-0">
|
||||
<div class="text-xs tabular-nums shrink-0">
|
||||
{channel.user_count}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -192,18 +192,22 @@
|
|||
</script>
|
||||
|
||||
{#if channel}
|
||||
<div class="flex flex-col w-full h-full bg-gray-50 dark:bg-gray-850">
|
||||
<div class="sticky top-0 flex items-center justify-between px-3.5 py-3">
|
||||
<div class=" font-normal text-lg">{$i18n.t('Thread')}</div>
|
||||
<div class="flex flex-col w-full h-full bg-white dark:bg-gray-900">
|
||||
<div
|
||||
class="sticky top-0 flex min-h-10 items-center justify-between border-b border-gray-100/60 px-4 py-1.5 dark:border-gray-800/40"
|
||||
>
|
||||
<div class=" font-medium text-sm">{$i18n.t('Thread')}</div>
|
||||
|
||||
<div>
|
||||
<button
|
||||
class="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300 p-2"
|
||||
type="button"
|
||||
aria-label={$i18n.t('Close')}
|
||||
class="flex size-7 items-center justify-center rounded-lg text-gray-500 hover:bg-gray-50/60 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-800/60 dark:hover:text-gray-300"
|
||||
on:click={() => {
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
<XMark />
|
||||
<XMark className="size-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -212,7 +216,7 @@
|
|||
class="flex-1 min-h-0 w-full overflow-y-auto will-change-transform"
|
||||
bind:this={messagesContainerElement}
|
||||
>
|
||||
<div class="pt-7">
|
||||
<div class="pt-3">
|
||||
{#if messages !== null}
|
||||
<Messages
|
||||
id={threadId}
|
||||
|
|
@ -252,7 +256,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" pb-[1rem] px-2.5 w-full">
|
||||
<div class=" pb-3 px-3 w-full">
|
||||
<MessageInput
|
||||
bind:replyToMessage
|
||||
bind:chatInputElement
|
||||
|
|
@ -262,7 +266,7 @@
|
|||
placeholder={!channel?.write_access
|
||||
? $i18n.t('You do not have permission to send messages in this thread.')
|
||||
: $i18n.t('Reply to thread...')}
|
||||
typingUsersClassName="from-gray-50 dark:from-gray-850"
|
||||
typingUsersClassName="from-white dark:from-gray-900"
|
||||
{typingUsers}
|
||||
userSuggestions={true}
|
||||
channelSuggestions={true}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue