enh: user status indicator

This commit is contained in:
Timothy Jaeryang Baek
2024-12-26 23:29:33 -08:00
parent c53ace3c98
commit 50534a0dcf
8 changed files with 128 additions and 22 deletions

View File

@@ -25,6 +25,7 @@
import Textarea from '$lib/components/common/Textarea.svelte';
import Image from '$lib/components/common/Image.svelte';
import FileItem from '$lib/components/common/FileItem.svelte';
import ProfilePreview from './Message/ProfilePreview.svelte';
export let message;
export let showUserProfile = true;
@@ -101,11 +102,13 @@
class={`flex-shrink-0 ${($settings?.chatDirection ?? 'LTR') === 'LTR' ? 'mr-3' : 'ml-3'} w-9`}
>
{#if showUserProfile}
<ProfileImage
src={message.user?.profile_image_url ??
($i18n.language === 'dg-DG' ? `/doge.png` : `${WEBUI_BASE_URL}/static/favicon.png`)}
className={'size-8 translate-y-1 ml-0.5'}
/>
<ProfilePreview user={message.user}>
<ProfileImage
src={message.user?.profile_image_url ??
($i18n.language === 'dg-DG' ? `/doge.png` : `${WEBUI_BASE_URL}/static/favicon.png`)}
className={'size-8 translate-y-1 ml-0.5'}
/>
</ProfilePreview>
{:else}
<!-- <div class="w-7 h-7 rounded-full bg-transparent" /> -->

View File

@@ -0,0 +1,85 @@
<script lang="ts">
import { DropdownMenu } from 'bits-ui';
import { createEventDispatcher } from 'svelte';
import { flyAndScale } from '$lib/utils/transitions';
import { WEBUI_BASE_URL } from '$lib/constants';
import { activeUserIds } from '$lib/stores';
export let side = 'right';
export let align = 'top';
export let user = null;
let show = false;
const dispatch = createEventDispatcher();
</script>
<DropdownMenu.Root
bind:open={show}
closeFocus={false}
onOpenChange={(state) => {
dispatch('change', state);
}}
typeahead={false}
>
<DropdownMenu.Trigger>
<slot />
</DropdownMenu.Trigger>
<slot name="content">
<DropdownMenu.Content
class="w-full max-w-[200px] rounded-lg z-50 bg-white dark:bg-black dark:text-white shadow-lg"
sideOffset={8}
{side}
{align}
transition={flyAndScale}
>
{#if user}
<div class=" flex flex-col gap-2 w-full rounded-lg">
<div class="py-8 relative bg-gray-900 rounded-t-lg">
<img
crossorigin="anonymous"
src={user?.profile_image_url ?? `${WEBUI_BASE_URL}/static/favicon.png`}
class=" absolute -bottom-5 left-3 size-12 ml-0.5 object-cover rounded-full -translate-y-[1px]"
alt="profile"
/>
</div>
<div class=" flex flex-col pt-4 pb-2.5 px-4">
<div class=" -mb-1">
<span class="font-medium text-sm line-clamp-1"> {user.name} </span>
</div>
<div class=" flex items-center gap-2">
{#if $activeUserIds.includes(user.id)}
<div>
<span class="relative flex size-2">
<span
class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"
/>
<span class="relative inline-flex rounded-full size-2 bg-green-500" />
</span>
</div>
<div class=" -translate-y-[1px]">
<span class="text-xs"> Active </span>
</div>
{:else}
<div>
<span class="relative flex size-2">
<span class="relative inline-flex rounded-full size-2 bg-gray-500" />
</span>
</div>
<div class=" -translate-y-[1px]">
<span class="text-xs"> Away </span>
</div>
{/if}
</div>
</div>
</div>
{/if}
</DropdownMenu.Content>
</slot>
</DropdownMenu.Root>

View File

@@ -5,6 +5,8 @@
import { flyAndScale } from '$lib/utils/transitions';
export let show = false;
export let side = 'bottom';
export let align = 'start';
const dispatch = createEventDispatcher();
</script>
@@ -24,8 +26,8 @@
<DropdownMenu.Content
class="w-full max-w-[130px] rounded-lg px-1 py-1.5 border border-gray-900 z-50 bg-gray-850 text-white"
sideOffset={8}
side="bottom"
align="start"
{side}
{align}
transition={flyAndScale}
>
<DropdownMenu.Item class="flex items-center px-3 py-2 text-sm font-medium">

View File

@@ -5,7 +5,7 @@
import { flyAndScale } from '$lib/utils/transitions';
import { goto } from '$app/navigation';
import ArchiveBox from '$lib/components/icons/ArchiveBox.svelte';
import { showSettings, activeUserCount, USAGE_POOL, mobile, showSidebar } from '$lib/stores';
import { showSettings, activeUserIds, USAGE_POOL, mobile, showSidebar } from '$lib/stores';
import { fade, slide } from 'svelte/transition';
import Tooltip from '$lib/components/common/Tooltip.svelte';
import { userSignOut } from '$lib/apis/auths';
@@ -184,7 +184,7 @@
<div class=" self-center truncate">{$i18n.t('Sign Out')}</div>
</button>
{#if $activeUserCount}
{#if $activeUserIds?.length > 0}
<hr class=" border-gray-50 dark:border-gray-850 my-1 p-0" />
<Tooltip
@@ -207,7 +207,7 @@
{$i18n.t('Active Users')}:
</span>
<span class=" font-semibold">
{$activeUserCount}
{$activeUserIds?.length}
</span>
</div>
</div>

View File

@@ -15,7 +15,7 @@ export const MODEL_DOWNLOAD_POOL = writable({});
export const mobile = writable(false);
export const socket: Writable<null | Socket> = writable(null);
export const activeUserCount: Writable<null | number> = writable(null);
export const activeUserIds: Writable<null | string[]> = writable(null);
export const USAGE_POOL: Writable<null | string[]> = writable(null);
export const theme = writable('system');

View File

@@ -14,7 +14,7 @@
WEBUI_NAME,
mobile,
socket,
activeUserCount,
activeUserIds,
USAGE_POOL,
chatId,
chats,
@@ -81,9 +81,9 @@
}
});
_socket.on('user-count', (data) => {
console.log('user-count', data);
activeUserCount.set(data.count);
_socket.on('user-list', (data) => {
console.log('user-list', data);
activeUserIds.set(data.user_ids);
});
_socket.on('usage', (data) => {