mirror of
https://github.com/Blah-IM/Weblah.git
synced 2025-07-08 15:05:33 +00:00
refactor: render messages in sections
This commit is contained in:
parent
4be1380d69
commit
c80b2cbf10
8 changed files with 129 additions and 36 deletions
|
@ -27,8 +27,8 @@
|
|||
|
||||
<div class="flex h-full w-full flex-col items-center justify-center">
|
||||
{#if server}
|
||||
{@const { info, messages, sendMessage } = useChat(server, roomId)}
|
||||
<ChatPage {info} {messages} on:sendMessage={(e) => sendMessage(e.detail)} />
|
||||
{@const { info, sectionedMessages, sendMessage } = useChat(server, roomId)}
|
||||
<ChatPage {info} {sectionedMessages} on:sendMessage={(e) => sendMessage(e.detail)} />
|
||||
{:else}
|
||||
<ServiceMessage>
|
||||
To view this chat, you need to connect to chat server
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
<h3 class="truncate text-sm font-semibold">{info.name}</h3>
|
||||
</div>
|
||||
<div class="sm:order-1">
|
||||
<AvatarBeam size={30} name={info.id} />
|
||||
<AvatarBeam size={32} name={info.id} />
|
||||
</div>
|
||||
|
||||
<a class="absolute inset-y-0 start-0 hidden w-2 cursor-default sm:block" href="/">
|
||||
|
|
|
@ -4,20 +4,47 @@
|
|||
import type { Message } from '$lib/types';
|
||||
import ChatMessage from './ChatMessage.svelte';
|
||||
import { tick } from 'svelte';
|
||||
import type { MessageSection } from '$lib/chat';
|
||||
import { tw } from '$lib/tw';
|
||||
import { AvatarBeam } from 'svelte-boring-avatars';
|
||||
import ServiceMessage from '$lib/components/ServiceMessage.svelte';
|
||||
import { formatMessageDate, formatMessageSectionDate } from '$lib/formatters';
|
||||
|
||||
export let messages: Message[] = [];
|
||||
export let sectionedMessages: MessageSection[] = [];
|
||||
export let mySenderId: string;
|
||||
|
||||
let ref: VList<Message> | undefined;
|
||||
let ref: VList<MessageSection> | undefined;
|
||||
|
||||
async function scrollToIndex(index: number, smooth = true) {
|
||||
await tick();
|
||||
ref?.scrollToIndex(index, { align: 'end', smooth });
|
||||
}
|
||||
|
||||
$: scrollToIndex(messages.length - 1);
|
||||
$: scrollToIndex(sectionedMessages.length - 1);
|
||||
</script>
|
||||
|
||||
<VList data={messages} let:item={message} class="size-full pt-2" bind:this={ref}>
|
||||
<ChatMessage {message} isMyself={mySenderId === message.sender.id} />
|
||||
<VList data={sectionedMessages} let:item={messageSection} class="size-full pt-2" bind:this={ref}>
|
||||
{@const isMyself = mySenderId === messageSection.sender?.id}
|
||||
|
||||
<div>
|
||||
{#if messageSection.date}
|
||||
<div class="py-0.5 text-center">
|
||||
<ServiceMessage>{formatMessageSectionDate(messageSection.date)}</ServiceMessage>
|
||||
</div>
|
||||
{/if}
|
||||
<div class={tw('flex w-full items-end px-2', isMyself && 'flex-row-reverse')}>
|
||||
<div class="sticky bottom-1.5 mb-1.5 mt-1 w-8">
|
||||
<AvatarBeam size={32} name={messageSection.sender?.id} />
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
{#each messageSection.messages as message, idx}
|
||||
<ChatMessage
|
||||
{message}
|
||||
{isMyself}
|
||||
showBubbleTail={messageSection.messages.length - 1 === idx}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</VList>
|
||||
|
|
|
@ -2,16 +2,13 @@
|
|||
import RichTextRenderer from '$lib/components/RichTextRenderer.svelte';
|
||||
import { tw } from '$lib/tw';
|
||||
import type { Message } from '$lib/types';
|
||||
import { AvatarBeam } from 'svelte-boring-avatars';
|
||||
|
||||
export let message: Message;
|
||||
export let showBubbleTail: boolean = true;
|
||||
export let isMyself: boolean;
|
||||
</script>
|
||||
|
||||
<div class={tw('mb-2 flex items-end gap-2 px-2', isMyself && 'flex-row-reverse')}>
|
||||
<div>
|
||||
<AvatarBeam size={30} name={message.sender.name} />
|
||||
</div>
|
||||
<div class={tw('mb-1.5 flex items-end gap-2 px-2', isMyself && 'flex-row-reverse')}>
|
||||
<div
|
||||
class={tw(
|
||||
'relative flex-1',
|
||||
|
@ -24,16 +21,18 @@
|
|||
<div
|
||||
class={tw(
|
||||
`relative inline-block max-w-[85%] rounded-2xl bg-[--weblah-chat-bubble-bg] shadow-sm ring-1 ring-[--weblah-chat-bubble-stroke]`,
|
||||
// ::before: Fill of chat bubble tail
|
||||
'before:absolute before:-bottom-[1px] before:box-content before:h-6 before:w-5 before:border-[--weblah-chat-bubble-bg] before:text-[--weblah-chat-bubble-stroke]',
|
||||
isMyself
|
||||
? 'before:-end-5 before:rounded-es-[16px_12px] before:border-s-[10px] before:drop-shadow-[1px_0]'
|
||||
: `before:-start-5 before:rounded-ee-[16px_12px] before:border-e-[10px] before:drop-shadow-[-1px_0]`,
|
||||
// ::after: Stroke of chat bubble tail
|
||||
'after:absolute after:-bottom-[1px] after:-z-10 after:box-content after:h-6 after:w-5 after:text-[--weblah-chat-bubble-stroke]',
|
||||
isMyself
|
||||
? 'after:-end-5 after:rounded-es-[16px_12px] after:border-s-[10px] after:drop-shadow-[0_1px]'
|
||||
: `after:-start-5 after:rounded-ee-[16px_12px] after:border-e-[10px] after:drop-shadow-[0_1px]`,
|
||||
showBubbleTail && [
|
||||
// ::before: Fill of chat bubble tail
|
||||
'before:absolute before:-bottom-[1px] before:box-content before:h-6 before:w-5 before:border-[--weblah-chat-bubble-bg] before:text-[--weblah-chat-bubble-stroke]',
|
||||
isMyself
|
||||
? 'before:-end-5 before:rounded-es-[16px_12px] before:border-s-[10px] before:drop-shadow-[1px_0]'
|
||||
: `before:-start-5 before:rounded-ee-[16px_12px] before:border-e-[10px] before:drop-shadow-[-1px_0]`,
|
||||
// ::after: Stroke of chat bubble tail
|
||||
'after:absolute after:-bottom-[1px] after:-z-10 after:box-content after:h-6 after:w-5 after:text-[--weblah-chat-bubble-stroke]',
|
||||
isMyself
|
||||
? 'after:-end-5 after:rounded-es-[16px_12px] after:border-s-[10px] after:drop-shadow-[0_1px]'
|
||||
: `after:-start-5 after:rounded-ee-[16px_12px] after:border-e-[10px] after:drop-shadow-[0_1px]`
|
||||
],
|
||||
'sm:max-w-[70%] lg:max-w-[50%]',
|
||||
isMyself && 'text-start'
|
||||
)}
|
||||
|
|
|
@ -9,9 +9,10 @@
|
|||
import ChatHistory from './ChatHistory.svelte';
|
||||
import ChatInput from './ChatInput.svelte';
|
||||
import type { BlahRichText } from '$lib/richText';
|
||||
import type { MessageSection } from '$lib/chat';
|
||||
|
||||
export let info: Readable<Chat>;
|
||||
export let messages: Readable<Message[]>;
|
||||
export let sectionedMessages: Readable<MessageSection[]>;
|
||||
|
||||
interface $$Events {
|
||||
sendMessage: CustomEvent<BlahRichText>;
|
||||
|
@ -20,6 +21,6 @@
|
|||
|
||||
<ChatHeader info={$info} outsideUnreadCount={263723} />
|
||||
<BgPattern class="w-full flex-1" pattern="charlieBrown">
|
||||
<ChatHistory messages={$messages} mySenderId={$currentKeyPair?.id} />
|
||||
<ChatHistory sectionedMessages={$sectionedMessages} mySenderId={$currentKeyPair?.id} />
|
||||
</BgPattern>
|
||||
<ChatInput on:sendMessage />
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue