From 560e829cabd4f50a669eccb87f7a4c6837bb94f0 Mon Sep 17 00:00:00 2001 From: Alois Date: Tue, 4 Aug 2026 23:51:32 +0200 Subject: [PATCH] (feat): add day date separator --- packages/chat/src/screen.tsx | 91 +++++++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 12 deletions(-) diff --git a/packages/chat/src/screen.tsx b/packages/chat/src/screen.tsx index a8a4ec0..5a3bcdd 100644 --- a/packages/chat/src/screen.tsx +++ b/packages/chat/src/screen.tsx @@ -50,6 +50,59 @@ function getMessageRenderKey(message: RawMessage | LiveMessage) { return "localId" in message ? message.localId : String(message.SendTime); } +function isSameDay(first: number | Date, second: number | Date) { + const firstDate = new Date(first); + const secondDate = new Date(second); + + return ( + firstDate.getFullYear() === secondDate.getFullYear() && + firstDate.getMonth() === secondDate.getMonth() && + firstDate.getDate() === secondDate.getDate() + ); +} + +function formatMessageDate(sendTime: number) { + const date = new Date(sendTime); + const today = new Date(); + const yesterday = new Date(today); + yesterday.setDate(yesterday.getDate() - 1); + + if (isSameDay(date, today)) { + return "Today"; + } + + if (isSameDay(date, yesterday)) { + return "Yesterday"; + } + + const day = String(date.getDate()).padStart(2, "0"); + const month = date.toLocaleString([], { month: "long" }); + return `${day} ${month} ${date.getFullYear()}`; +} + +function DateSeparator({ label }: { label: string }) { + const [visible, setVisible] = useState(false); + + useEffect(() => { + const timeout = window.setTimeout(() => setVisible(true), 100); + return () => window.clearTimeout(timeout); + }, []); + + return ( +
+
+ + {label} + +
+
+ ); +} + function buildMessageChunks( messages: Array, keyPrefix: string, @@ -483,7 +536,7 @@ export default function Screen() { className="min-h-0 flex-1 overflow-y-auto" style={{ overflowAnchor: "none", - paddingTop: "22px", + //paddingTop: "22px", transform: "scaleY(-1)", }} onScroll={handleContainerScroll} @@ -522,8 +575,15 @@ export default function Screen() { const messageIndex = chunk.startIndex + chunkMessageIndex; const lastMessage = messages[messageIndex - 1]; + const startsNewDay = + !lastMessage || + !isSameDay(lastMessage.SendTime, message.SendTime); + const dateLabel = startsNewDay + ? formatMessageDate(message.SendTime) + : null; const isGrouped = lastMessage && + !startsNewDay && !message.ReplyId && lastMessage.SenderId === message.SenderId && Math.round(lastMessage.SendTime / 10000) === @@ -535,17 +595,24 @@ export default function Screen() { userId={message.SenderId} loading={null} component={(user) => ( - - setEditingMessageId( - editing ? message.SendTime : null, - ) - } - user={user} - /> + <> + {dateLabel && ( + + )} + + setEditingMessageId( + editing ? message.SendTime : null, + ) + } + user={user} + /> + )} /> );