added features and fixes
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useRef, useState, useCallback } from "react";
|
||||
import { useEffect, useRef, useState, useCallback, memo } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useConversationStore, type ConversationMessage } from "../stores/conversation.ts";
|
||||
import { useAuthStore } from "../stores/auth.ts";
|
||||
@@ -23,6 +23,19 @@ function renderDMContent(content: string) {
|
||||
pre: ({ ...props }) => <pre {...props} className="bg-gb-bg-s p-2 my-1 overflow-x-auto text-gb-fg-s" />,
|
||||
blockquote: ({ ...props }) => <blockquote {...props} className="border-l-2 border-gb-orange pl-2 my-1 text-gb-fg-s" />,
|
||||
p: ({ ...props }) => <span {...props} className="inline" />,
|
||||
img: ({ src, ...props }) => {
|
||||
const finalSrc = src?.startsWith("https://media") && src.includes(".giphy.com/")
|
||||
? `/api/v1/gifs/proxy?url=${encodeURIComponent(src)}`
|
||||
: src;
|
||||
return (
|
||||
<img
|
||||
{...props}
|
||||
src={finalSrc}
|
||||
className="max-w-[240px] max-h-[240px] object-contain rounded my-1 block"
|
||||
loading="lazy"
|
||||
/>
|
||||
);
|
||||
},
|
||||
}}
|
||||
>
|
||||
{content}
|
||||
@@ -30,6 +43,17 @@ function renderDMContent(content: string) {
|
||||
);
|
||||
}
|
||||
|
||||
const DMMessageItem = memo(({ msg }: { msg: ConversationMessage }) => {
|
||||
return (
|
||||
<div className="break-words">
|
||||
<span className="text-gb-fg-f">[{formatTime(msg.created_at)}]</span>{" "}
|
||||
<span className="text-gb-aqua"><{msg.author_username}></span>{" "}
|
||||
<span className="text-gb-fg">{renderDMContent(msg.content)}</span>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
DMMessageItem.displayName = "DMMessageItem";
|
||||
|
||||
export function DMChat() {
|
||||
const { conversationId } = useParams<{ conversationId: string }>();
|
||||
const activeId = useConversationStore((s) => s.activeConversationId);
|
||||
@@ -116,21 +140,18 @@ export function DMChat() {
|
||||
{!id && <p className="text-gb-fg-f">[select a conversation]</p>}
|
||||
{id && messages.length === 0 && <p className="text-gb-fg-f">[no messages]</p>}
|
||||
{messages.map((msg: ConversationMessage) => (
|
||||
<div key={msg.id} className="break-words">
|
||||
<span className="text-gb-fg-f">[{formatTime(msg.created_at)}]</span>{" "}
|
||||
<span className="text-gb-aqua"><{msg.author_username}></span>{" "}
|
||||
<span className="text-gb-fg">{renderDMContent(msg.content)}</span>
|
||||
</div>
|
||||
<DMMessageItem key={msg.id} msg={msg} />
|
||||
))}
|
||||
<div ref={bottomRef} />
|
||||
</div>
|
||||
{(() => {
|
||||
const convTyping = id ? (typingUsers[id] || []).filter(u => u.userId !== currentUser?.id) : [];
|
||||
if (convTyping.length === 0) return null;
|
||||
const names = convTyping.map(u => u.username);
|
||||
const text = names.length === 1 ? `${names[0]} is typing...` : names.length === 2 ? `${names[0]} and ${names[1]} are typing...` : `${names[0]} and ${names.length - 1} others are typing...`;
|
||||
return <div className="px-3 pt-1 text-xs text-gb-fg-f font-mono italic">{text}</div>;
|
||||
})()}
|
||||
<div className="px-3 pt-1 text-xs text-gb-fg-f font-mono italic h-5 select-none">
|
||||
{(() => {
|
||||
const convTyping = id ? (typingUsers[id] || []).filter(u => u.userId !== currentUser?.id) : [];
|
||||
if (convTyping.length === 0) return "\u00A0";
|
||||
const names = convTyping.map(u => u.username);
|
||||
return names.length === 1 ? `${names[0]} is typing...` : names.length === 2 ? `${names[0]} and ${names[1]} are typing...` : `${names[0]} and ${names.length - 1} others are typing...`;
|
||||
})()}
|
||||
</div>
|
||||
{error && (
|
||||
<div className="px-3 pb-1">
|
||||
<p className="text-gb-red text-xs font-mono">ERR: {error}</p>
|
||||
|
||||
Reference in New Issue
Block a user