feat: implement message replies
This commit is contained in:
parent
2ff892b0da
commit
a8ee8122ee
2 changed files with 50 additions and 6 deletions
|
@ -1,5 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-if="props.type == 'normal'" ref="messageElement" @contextmenu="createContextMenu($event, menuItems)" :id="props.last ? 'last-message' : undefined" class="message normal-message" :data-message-id="props.messageId" :editing.sync="props.editing" :replying-to.sync="props.replyingTo">
|
<div v-if="props.type == 'normal' || props.replyMessage" ref="messageElement" @contextmenu="createContextMenu($event, menuItems)" :id="props.last ? 'last-message' : undefined"
|
||||||
|
class="message normal-message" :class="{ 'mentioned': (props.replyMessage || props.isMentioned) && props.message.user.uuid != props.me.uuid }" :data-message-id="props.messageId"
|
||||||
|
:editing.sync="props.editing" :replying-to.sync="props.replyingTo">
|
||||||
|
<MessageReply v-if="props.replyMessage" :author="props.message.user.display_name || props.message.user.username" :text="props.replyMessage?.message"
|
||||||
|
:id="props.message.uuid" :reply-id="props.replyMessage.uuid" max-width="reply" />
|
||||||
<div class="left-column">
|
<div class="left-column">
|
||||||
<img v-if="props.img" class="message-author-avatar" :src="props.img" :alt="author?.display_name || author?.username" />
|
<img v-if="props.img" class="message-author-avatar" :src="props.img" :alt="author?.display_name || author?.username" />
|
||||||
<Icon v-else name="lucide:user" class="message-author-avatar" />
|
<Icon v-else name="lucide:user" class="message-author-avatar" />
|
||||||
|
@ -18,7 +22,9 @@
|
||||||
<div class="message-text" v-html="sanitized" tabindex="0"></div>
|
<div class="message-text" v-html="sanitized" tabindex="0"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else ref="messageElement" @contextmenu="createContextMenu($event, menuItems)" :id="props.last ? 'last-message' : undefined" class="message grouped-message" :class="{ 'message-margin-bottom': props.marginBottom }" :data-message-id="props.messageId" :editing.sync="props.editing" :replying-to.sync="props.replyingTo">
|
<div v-else ref="messageElement" @contextmenu="createContextMenu($event, menuItems)" :id="props.last ? 'last-message' : undefined"
|
||||||
|
class="message grouped-message" :class="{ 'message-margin-bottom': props.marginBottom, 'mentioned': props.replyMessage || props.isMentioned }"
|
||||||
|
:data-message-id="props.messageId" :editing.sync="props.editing" :replying-to.sync="props.replyingTo">
|
||||||
<div class="left-column">
|
<div class="left-column">
|
||||||
<span :class="{ 'invisible': dateHidden }" class="message-date side-message-date" :title="date.toString()">
|
<span :class="{ 'invisible': dateHidden }" class="message-date side-message-date" :title="date.toString()">
|
||||||
{{ date.toLocaleTimeString(undefined, { timeStyle: "short" }) }}
|
{{ date.toLocaleTimeString(undefined, { timeStyle: "short" }) }}
|
||||||
|
@ -44,8 +50,9 @@ const dateHidden = ref<boolean>(true);
|
||||||
const date = new Date(props.timestamp);
|
const date = new Date(props.timestamp);
|
||||||
const currentDate: Date = new Date()
|
const currentDate: Date = new Date()
|
||||||
|
|
||||||
console.log("message:", props.text);
|
console.log("[MSG] message to render:", props.message);
|
||||||
console.log("author:", props.author);
|
console.log("author:", props.author);
|
||||||
|
console.log("[MSG] reply message:", props.replyMessage);
|
||||||
|
|
||||||
const sanitized = ref<string>();
|
const sanitized = ref<string>();
|
||||||
|
|
||||||
|
@ -113,6 +120,11 @@ function getDayDifference(date1: Date, date2: Date) {
|
||||||
overflow-wrap: anywhere;
|
overflow-wrap: anywhere;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.message-reply-preview {
|
||||||
|
grid-row: 1;
|
||||||
|
grid-column: 2;
|
||||||
|
}
|
||||||
|
|
||||||
.message:hover {
|
.message:hover {
|
||||||
background-color: var(--chat-highlighted-background-color);
|
background-color: var(--chat-highlighted-background-color);
|
||||||
}
|
}
|
||||||
|
@ -142,6 +154,8 @@ function getDayDifference(date1: Date, date2: Date) {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: fit-content;
|
height: fit-content;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
grid-row: 2;
|
||||||
|
grid-column: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-author {
|
.message-author {
|
||||||
|
@ -160,6 +174,8 @@ function getDayDifference(date1: Date, date2: Date) {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
grid-row: 2;
|
||||||
|
grid-column: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.author-username {
|
.author-username {
|
||||||
|
@ -186,6 +202,11 @@ function getDayDifference(date1: Date, date2: Date) {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
.mentioned {
|
||||||
|
background-color: var(--secondary-color);
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style module>
|
<style module>
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
:text="message.message" :timestamp="messageTimestamps[message.uuid]" :img="message.user.avatar"
|
:text="message.message" :timestamp="messageTimestamps[message.uuid]" :img="message.user.avatar"
|
||||||
format="12" :type="messagesType[message.uuid]"
|
format="12" :type="messagesType[message.uuid]"
|
||||||
:margin-bottom="(messages[i + 1] && messagesType[messages[i + 1].uuid] == 'normal') ?? false"
|
:margin-bottom="(messages[i + 1] && messagesType[messages[i + 1].uuid] == 'normal') ?? false"
|
||||||
:last="i == messages.length - 1" :message-id="message.uuid" :author="message.user" :me="me" />
|
:last="i == messages.length - 1" :message-id="message.uuid" :author="message.user" :me="me"
|
||||||
|
:message="message" :is-reply="message.reply_to"
|
||||||
|
:reply-message="message.reply_to ? getReplyMessage(message.reply_to) : undefined" />
|
||||||
</div>
|
</div>
|
||||||
<div id="message-box" class="rounded-corners">
|
<div id="message-box" class="rounded-corners">
|
||||||
<form id="message-form" @submit="sendMessage">
|
<form id="message-form" @submit="sendMessage">
|
||||||
|
@ -116,6 +118,7 @@ if (messagesRes) {
|
||||||
messagesRes.reverse();
|
messagesRes.reverse();
|
||||||
console.log("messages res:", messagesRes.map(msg => msg.message));
|
console.log("messages res:", messagesRes.map(msg => msg.message));
|
||||||
for (const message of messagesRes) {
|
for (const message of messagesRes) {
|
||||||
|
console.log("[MSG] processing message:", message);
|
||||||
groupMessage(message);
|
groupMessage(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,6 +190,7 @@ if (accessToken && apiBase) {
|
||||||
console.log("event data:", event.data);
|
console.log("event data:", event.data);
|
||||||
console.log("message uuid:", event.data.uuid);
|
console.log("message uuid:", event.data.uuid);
|
||||||
const parsedData = JSON.parse(event.data);
|
const parsedData = JSON.parse(event.data);
|
||||||
|
console.log("[MSG] parsed message:", parsedData);
|
||||||
|
|
||||||
console.log("parsed message type:", messagesType.value[parsedData.uuid]);
|
console.log("parsed message type:", messagesType.value[parsedData.uuid]);
|
||||||
console.log("parsed message timestamp:", messageTimestamps.value[parsedData.uuid]);
|
console.log("parsed message timestamp:", messageTimestamps.value[parsedData.uuid]);
|
||||||
|
@ -205,11 +209,18 @@ if (accessToken && apiBase) {
|
||||||
function sendMessage(e: Event) {
|
function sendMessage(e: Event) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (messageInput.value && messageInput.value.trim() !== "") {
|
if (messageInput.value && messageInput.value.trim() !== "") {
|
||||||
const message = {
|
const message: Record<string, string> = {
|
||||||
message: messageInput.value.trim().replace(/\n/g, "<br>") // trim, and replace \n with <br>
|
message: messageInput.value.trim().replace(/\n/g, "<br>") // trim, and replace \n with <br>
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("message:", message);
|
const messageReply = document.getElementById("message-reply") as HTMLDivElement;
|
||||||
|
console.log("[MSG] message reply:", messageReply);
|
||||||
|
if (messageReply && messageReply.dataset.messageId) {
|
||||||
|
console.log("[MSG] message is a reply");
|
||||||
|
message.reply_to = messageReply.dataset.messageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("[MSG] sent message:", message);
|
||||||
ws.send(JSON.stringify(message));
|
ws.send(JSON.stringify(message));
|
||||||
|
|
||||||
// reset input field
|
// reset input field
|
||||||
|
@ -222,10 +233,22 @@ function sendMessage(e: Event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getReplyMessage(id: string) {
|
||||||
|
console.log("[REPLYMSG] id:", id);
|
||||||
|
const messagesValues = Object.values(messages.value);
|
||||||
|
console.log("[REPLYMSG] messages values:", messagesValues);
|
||||||
|
for (const message of messagesValues) {
|
||||||
|
console.log("[REPLYMSG] message:", message);
|
||||||
|
console.log("[REPLYMSG] IDs match?", message.uuid == id);
|
||||||
|
if (message.uuid == id) return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (import.meta.server) return;
|
if (import.meta.server) return;
|
||||||
|
console.log("[MSG] messages keys:", Object.values(messages.value));
|
||||||
if (messagesElement.value) {
|
if (messagesElement.value) {
|
||||||
scrollToBottom(messagesElement.value);
|
scrollToBottom(messagesElement.value);
|
||||||
let fetched = false;
|
let fetched = false;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue