mirror of
https://github.com/Blah-IM/Weblah.git
synced 2025-08-21 03:22:40 +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
|
@ -1,7 +1,16 @@
|
|||
import { readable, type Readable } from 'svelte/store';
|
||||
import { derived, readable, type Readable } from 'svelte/store';
|
||||
import type { BlahChatServerConnection } from './blah/connection/chatServer';
|
||||
import type { BlahRichText } from './richText';
|
||||
import { messageFromBlah, type Chat, type Message } from './types';
|
||||
import { messageFromBlah, type Chat, type Message, type User } from './types';
|
||||
|
||||
const MAX_MESSAGES_PER_SECTION = 10;
|
||||
const SHOW_TIME_AFTER_SILENCE = 30 * 60 * 1000;
|
||||
|
||||
export type MessageSection = {
|
||||
sender?: User;
|
||||
messages: Message[];
|
||||
date?: Date;
|
||||
};
|
||||
|
||||
export function useChat(
|
||||
server: BlahChatServerConnection,
|
||||
|
@ -9,6 +18,7 @@ export function useChat(
|
|||
): {
|
||||
info: Readable<Chat>;
|
||||
messages: Readable<Message[]>;
|
||||
sectionedMessages: Readable<MessageSection[]>;
|
||||
sendMessage: (brt: BlahRichText) => Promise<void>;
|
||||
} {
|
||||
const info = readable<Chat>(
|
||||
|
@ -37,9 +47,41 @@ export function useChat(
|
|||
return unsubscribe;
|
||||
});
|
||||
|
||||
const sectionedMessages = derived([messages], ([messages]) => {
|
||||
const sections: MessageSection[] = [];
|
||||
|
||||
let lastMessage: Message | undefined = messages[0];
|
||||
let currentSection: MessageSection = {
|
||||
messages: [],
|
||||
sender: lastMessage?.sender,
|
||||
date: lastMessage?.date
|
||||
};
|
||||
|
||||
for (const message of messages) {
|
||||
const reachesMaxMessages = currentSection.messages.length >= MAX_MESSAGES_PER_SECTION;
|
||||
const senderChanged = message.sender.id !== lastMessage.sender.id;
|
||||
const silentForTooLong =
|
||||
message.date.getTime() - lastMessage.date.getTime() > SHOW_TIME_AFTER_SILENCE;
|
||||
if (reachesMaxMessages || senderChanged || silentForTooLong) {
|
||||
if (currentSection.messages.length > 0) {
|
||||
sections.push(currentSection);
|
||||
}
|
||||
currentSection = { messages: [], sender: message.sender };
|
||||
if (silentForTooLong) currentSection.date = message.date;
|
||||
}
|
||||
currentSection.messages.push(message);
|
||||
lastMessage = message;
|
||||
}
|
||||
|
||||
sections.push(currentSection);
|
||||
|
||||
console.log(sections);
|
||||
return sections;
|
||||
});
|
||||
|
||||
const sendMessage = async (brt: BlahRichText) => {
|
||||
await server.sendMessage(chatId, brt);
|
||||
};
|
||||
|
||||
return { info, messages, sendMessage };
|
||||
return { info, messages, sectionedMessages, sendMessage };
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
<div
|
||||
class={tw(
|
||||
'backdrop mx-4 cursor-default rounded-full px-2 py-0.5 text-center backdrop-blur-sm',
|
||||
'backdrop mx-4 inline-block cursor-default rounded-full px-2 py-0.5 text-center text-sm text-sf-secondary backdrop-blur-sm',
|
||||
className
|
||||
)}
|
||||
>
|
||||
|
|
|
@ -7,19 +7,29 @@ export function formatUnreadCount(count: number) {
|
|||
return unreadCountFormatter.format(count);
|
||||
}
|
||||
|
||||
const sameDayFormatter = new Intl.DateTimeFormat('default', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
const timeOptions: Intl.DateTimeFormatOptions = { hour: '2-digit', minute: '2-digit' };
|
||||
|
||||
const sameDayFormatter = new Intl.DateTimeFormat('default', timeOptions);
|
||||
const sameYearFormatter = new Intl.DateTimeFormat('default', {
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
});
|
||||
const sameYearWithTimeFormatter = new Intl.DateTimeFormat('default', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
...timeOptions
|
||||
});
|
||||
const otherYearFormatter = new Intl.DateTimeFormat('default', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
});
|
||||
const otherYearWithTimeFormatter = new Intl.DateTimeFormat('default', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
...timeOptions
|
||||
});
|
||||
const fullDateTimeFormatter = new Intl.DateTimeFormat('default', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
|
@ -29,9 +39,7 @@ const fullDateTimeFormatter = new Intl.DateTimeFormat('default', {
|
|||
second: '2-digit'
|
||||
});
|
||||
|
||||
export const formatMessageDate = (date: Date, full: boolean = false) => {
|
||||
if (full) return fullDateTimeFormatter.format(date);
|
||||
|
||||
export const formatMessageDate = (date: Date) => {
|
||||
const now = new Date();
|
||||
if (date.getFullYear() === now.getFullYear()) {
|
||||
if (date.getMonth() === now.getMonth() && date.getDate() === now.getDate()) {
|
||||
|
@ -43,3 +51,19 @@ export const formatMessageDate = (date: Date, full: boolean = false) => {
|
|||
return otherYearFormatter.format(date);
|
||||
}
|
||||
};
|
||||
export const formatFullMessageDate = (date: Date) => {
|
||||
return fullDateTimeFormatter.format(date);
|
||||
};
|
||||
|
||||
export const formatMessageSectionDate = (date: Date) => {
|
||||
const now = new Date();
|
||||
if (date.getFullYear() === now.getFullYear()) {
|
||||
if (date.getMonth() === now.getMonth() && date.getDate() === now.getDate()) {
|
||||
return sameDayFormatter.format(date);
|
||||
} else {
|
||||
return sameYearWithTimeFormatter.format(date);
|
||||
}
|
||||
} else {
|
||||
return otherYearWithTimeFormatter.format(date);
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue