open-webui/src/lib/components/channel/PinnedMessagesModal.svelte

151 lines
3.9 KiB
Svelte
Raw Normal View History

2025-11-28 14:58:44 +00:00
<script lang="ts">
import { toast } from 'svelte-sonner';
import { getContext, onMount } from 'svelte';
const i18n = getContext('i18n');
import Spinner from '$lib/components/common/Spinner.svelte';
import Modal from '$lib/components/common/Modal.svelte';
import UserPlusSolid from '$lib/components/icons/UserPlusSolid.svelte';
import WrenchSolid from '$lib/components/icons/WrenchSolid.svelte';
import ConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
import XMark from '$lib/components/icons/XMark.svelte';
import Hashtag from '../icons/Hashtag.svelte';
import Lock from '../icons/Lock.svelte';
import UserList from './ChannelInfoModal/UserList.svelte';
import { getChannelPinnedMessages, pinMessage } from '$lib/apis/channels';
import Message from './Messages/Message.svelte';
import { user } from '$lib/stores';
import Loader from '../common/Loader.svelte';
export let show = false;
export let channel = null;
let page = 1;
let pinnedMessages = [];
let allItemsLoaded = false;
let loading = false;
const getPinnedMessages = async () => {
if (!channel) return;
if (allItemsLoaded) return;
loading = true;
try {
const res = await getChannelPinnedMessages(localStorage.token, channel.id, page).catch(
(error) => {
toast.error(`${error}`);
return null;
}
);
if (res) {
pinnedMessages = [...pinnedMessages, ...res];
}
if (res.length === 0) {
allItemsLoaded = true;
}
} catch (error) {
console.error('Error fetching pinned messages:', error);
} finally {
loading = false;
}
};
const init = () => {
page = 1;
pinnedMessages = [];
getPinnedMessages();
};
$: if (show) {
init();
}
onMount(() => {
init();
});
</script>
{#if channel}
<Modal size="sm" bind:show>
<div>
<div class=" flex justify-between dark:text-gray-100 px-5 pt-4 mb-1.5">
<div class="self-center text-base">
<div class="flex items-center gap-0.5 shrink-0">
{$i18n.t('Pinned Messages')}
</div>
</div>
<button
class="self-center"
on:click={() => {
show = false;
}}
>
<XMark className={'size-5'} />
</button>
</div>
<div class="flex flex-col md:flex-row w-full px-4 pb-4 md:space-x-4 dark:text-gray-200">
<div class=" flex flex-col w-full sm:flex-row sm:justify-center sm:space-x-6">
<div class="flex flex-col w-full h-full pb-2 gap-1">
<div
class="flex flex-col gap-2 max-h-[60vh] overflow-y-auto scrollbar-thin scrollbar-thumb-gray-300 dark:scrollbar-thumb-gray-700 scrollbar-track-transparent py-2"
>
{#each pinnedMessages as message, messageIdx (message.id)}
<Message
className="rounded-xl px-2"
{message}
{channel}
onPin={async (message) => {
pinnedMessages = pinnedMessages.filter((m) => m.id !== message.id);
const updatedMessage = await pinMessage(
localStorage.token,
message.channel_id,
message.id,
!message.is_pinned
).catch((error) => {
toast.error(`${error}`);
return null;
});
init();
}}
onReaction={false}
onThread={false}
onReply={false}
onEdit={false}
onDelete={false}
/>
{#if messageIdx === pinnedMessages.length - 1 && !allItemsLoaded}
<Loader
on:visible={(e) => {
console.log('visible');
if (!loading) {
page += 1;
getPinnedMessages();
}
}}
>
<div
class="w-full flex justify-center py-1 text-xs animate-pulse items-center gap-2"
>
<Spinner className=" size-4" />
<div class=" ">{$i18n.t('Loading...')}</div>
</div>
</Loader>
{/if}
{/each}
</div>
</div>
</div>
</div>
</div>
</Modal>
{/if}