From 34f3552a40073f2d5b448067dbedfd067a3ce5ae Mon Sep 17 00:00:00 2001 From: defautluser0 Date: Sun, 18 Jan 2026 21:04:49 +0100 Subject: [PATCH] rerply --- src/components/Chatbar.tsx | 10 +++-- src/components/Icons.tsx | 9 ++++ src/components/Message.tsx | 85 +++++++++++++++++++++++++++++++++----- src/ws/index.ts | 11 ++++- 4 files changed, 100 insertions(+), 15 deletions(-) create mode 100644 src/components/Icons.tsx diff --git a/src/components/Chatbar.tsx b/src/components/Chatbar.tsx index 478a8b9..9f5af66 100644 --- a/src/components/Chatbar.tsx +++ b/src/components/Chatbar.tsx @@ -2,7 +2,7 @@ import { user } from "@localtypes"; import { sendChatMessage, token, self, getUsers, subscribeUsers } from "@ws"; import { useRef, useState, useSyncExternalStore, type ReactElement } from "react"; -export function Chatbar(): ReactElement { +export function Chatbar({channelName}: {channelName: string}): ReactElement { const [message, setMessage] = useState(""); const users: user[] = useSyncExternalStore( subscribeUsers, @@ -12,11 +12,11 @@ export function Chatbar(): ReactElement { const editorRef = useRef(null); function handleKeyDown(event: React.KeyboardEvent) { - if (event.key === "Enter" && !event.shiftKey) { + if (event.key === "Enter" && !event.shiftKey && message.trim().length !== 0) { event.preventDefault(); if (message.trim() !== "") { const msg = replaceMentions(message.trim()); - sendChatMessage({id: Date.now(), author: self, content: msg, timestamp: Date.now(), token: token!, hasSent: false}); + sendChatMessage({id: Date.now(), author: self, content: msg, timestamp: Date.now(), token: token!, hasSent: false, replyTo: undefined}); console.log("Sent message:", msg); setMessage(""); if (editorRef.current) { @@ -57,10 +57,12 @@ export function Chatbar(): ReactElement {
); diff --git a/src/components/Icons.tsx b/src/components/Icons.tsx new file mode 100644 index 0000000..d4baf73 --- /dev/null +++ b/src/components/Icons.tsx @@ -0,0 +1,9 @@ +import { ReactElement } from "react"; + +export function ReplyIcon(): ReactElement { + return ( + + ) +} \ No newline at end of file diff --git a/src/components/Message.tsx b/src/components/Message.tsx index a0897f5..0bc9f15 100644 --- a/src/components/Message.tsx +++ b/src/components/Message.tsx @@ -1,6 +1,7 @@ -import { RefObject, useEffect, useRef, useSyncExternalStore, type ReactElement } from "react"; -import { user, message } from "@localtypes"; -import { subscribeUsers, getUsers, subscribeMessages, getMessages, self } from "@ws"; +import { RefObject, useEffect, useRef, useState, useSyncExternalStore, type ReactElement } from "react"; +import { user, message, id } from "@localtypes"; +import { subscribeUsers, getUsers, subscribeMessages, getMessages, self, replyToMessage } from "@ws"; +import { ReplyIcon } from "@components/Icons.tsx"; function formatUnixTimestamp(ts: number) { const date = new Date(ts); @@ -23,13 +24,11 @@ function formatUnixTimestamp(ts: number) { export function RenderMessages(): ReactElement { let currentAuthor: user | null = null; - const messages: (message | null)[] = useSyncExternalStore( + const messages: (null | message)[] = useSyncExternalStore( subscribeMessages, getMessages ); - console.log(messages); - const bottomRef = useRef(null); useEffect(() => { @@ -53,11 +52,13 @@ export function RenderMessages(): ReactElement { key={message.id} author={message.author} content={message.content} - inline={inline} + id={message.id} + inline={inline && !message.replyTo} bottom={isLastMessageFromAuthor} timestamp={message.timestamp} hasSent={message.hasSent} mention={message.content.includes(`<@${self.id}>`) || message.content.includes("@everyone") || message.content.includes("@here")} + repliesTo={message.replyTo} /> ); } else return "" @@ -67,11 +68,39 @@ export function RenderMessages(): ReactElement { ); } -function Message({author, content, inline = false, bottom = false, timestamp = 0, hasSent, mention}: {author: user, content: string, inline?: boolean, bottom?: boolean, timestamp?: number, hasSent: boolean, mention: boolean}): ReactElement { +function Message({ + author, + content, + id, + inline = false, + bottom = false, + timestamp = 0, + hasSent = false, + mention, + repliesTo, + roleColor, +}: { + author: user, + content: string, + id: id, + inline?: boolean, + bottom?: boolean, + timestamp?: number, + hasSent: boolean, + mention: boolean, + repliesTo?: id, + roleColor?: string, +}): ReactElement { const users: user[] = useSyncExternalStore( subscribeUsers, getUsers ); + const messages: (message | null)[] = useSyncExternalStore( + subscribeMessages, + getMessages + ) + + const [hover, setHover] = useState(false); function formatContent(content: string): ReactElement[] { const parts = content.split('\n'); // Split the content into parts by newlines @@ -122,10 +151,28 @@ function Message({author, content, inline = false, bottom = false, timestamp = 0 } const formattedContent = formatContent(content); + let replyContent: ReactElement[] = []; + const replyTo = messages.find(msg => msg?.id === repliesTo); + if (replyTo) { + replyContent = formatContent(replyTo.content); + } + + function reply() { + console.log(id); + replyToMessage(id); + } + return ( -
+
setHover(true)} + onMouseLeave={() => setHover(false)} + > + {hover && } + {replyTo && replyContent ? : ""} {!inline ? : ""} - {!inline ?
{self.dev ? `${author.name} (${author.username}, ${author.id})` : author.name ?? author.username} {author.dev ? : ""} {author.bot && }
: ""} + {!inline ?
{self.dev ? `${author.name ?? "no name"} (${author.username}, ${author.id})` : author.name ?? author.username} {author.dev ? : ""} {author.bot && }
: ""}
{formattedContent}
) @@ -147,4 +194,22 @@ function Mention({name, username}: { name?: string, username: string }): ReactEl return (
@{name ?? username}
) +} + +function Reply({author, content}: {author: user, content: ReactElement[] | string}): ReactElement { + return ( +
+
+ {self.dev ? `${author.name ?? "no name"} (${author.username}, ${author.id})` : author.name ?? author.username} {author.dev ? : ""} {author.bot && } +
{content}
+
+ ) +} + +function MessageHoverActions({reply}: {reply: () => void}): ReactElement { + return ( +
+
+
+ ) } \ No newline at end of file diff --git a/src/ws/index.ts b/src/ws/index.ts index 7a3e5cc..9c9c220 100644 --- a/src/ws/index.ts +++ b/src/ws/index.ts @@ -1,4 +1,4 @@ -import { message, user } from "@localtypes"; +import { id, message, user } from "@localtypes"; let passwd = ""; let token = localStorage.getItem("token") ?? ""; @@ -16,6 +16,7 @@ let queue: (message | null)[] = new Array(6).fill(null); const listenersMessages = new Set<() => void>(); const listenersUsers = new Set<() => void>(); let visibleMessages: (message | null)[] = []; +let replyingTo: id | undefined = undefined; let dirty = true; function rebuildVisibleMessages() { @@ -170,6 +171,11 @@ export function getUsers(): user[] { return users; } +export function replyToMessage(id: id) { + replyingTo = id; + console.log(replyingTo); +} + export function sendChatMessage(message: message & { token?: string }) { if (queue.filter(m => m !== null).length < 6) { console.log(message); @@ -179,6 +185,9 @@ export function sendChatMessage(message: message & { token?: string }) { i = 6; } } + message.replyTo = replyingTo; + replyingTo = undefined; + console.log(replyingTo); dirty = true; notifyMessages(); ws.send(JSON.stringify({op: OpcodesServerbound.sendMessage, data: message}));