From 86ddae62b28be7274132080a1459beb7fd60be40 Mon Sep 17 00:00:00 2001
From: JustTemmie <47639983+JustTemmie@users.noreply.github.com>
Date: Sun, 13 Jul 2025 20:34:59 +0200
Subject: [PATCH 01/10] chore: sort components into subfolders
---
app.vue | 2 +-
components/{Dropdown.vue => Guild/GuildDropdown.vue} | 0
components/{ => Guild}/GuildOptionsMenu.vue | 2 +-
components/Me/AddFriend.vue | 2 +-
components/{ => Modals}/InviteModal.vue | 2 +-
components/{ => Modals}/Modal.vue | 2 +-
components/{ => UserInterface}/ContextMenu.vue | 0
components/{ => UserInterface}/MessageReply.vue | 0
layouts/client.vue | 6 +++---
pages/servers/[serverId]/channels/[channelId].vue | 5 +++--
utils/createContextMenu.ts | 2 +-
utils/replyToMessage.ts | 2 +-
12 files changed, 13 insertions(+), 12 deletions(-)
rename components/{Dropdown.vue => Guild/GuildDropdown.vue} (100%)
rename components/{ => Guild}/GuildOptionsMenu.vue (95%)
rename components/{ => Modals}/InviteModal.vue (96%)
rename components/{ => Modals}/Modal.vue (96%)
rename components/{ => UserInterface}/ContextMenu.vue (100%)
rename components/{ => UserInterface}/MessageReply.vue (100%)
diff --git a/app.vue b/app.vue
index 9aeae9d..c6db309 100644
--- a/app.vue
+++ b/app.vue
@@ -6,7 +6,7 @@
From b6b8d10d294411ccf642ef55f8a843d0582bb114 Mon Sep 17 00:00:00 2001
From: SauceyRed
Date: Mon, 14 Jul 2025 01:07:46 +0200
Subject: [PATCH 06/10] fix: automatically scrolling to bottom of chat not
working properly
---
components/MessageArea.vue | 2 ++
1 file changed, 2 insertions(+)
diff --git a/components/MessageArea.vue b/components/MessageArea.vue
index d59b862..c91efe8 100644
--- a/components/MessageArea.vue
+++ b/components/MessageArea.vue
@@ -251,6 +251,8 @@ onMounted(async () => {
if (import.meta.server) return;
console.log("[MSG] messages keys:", Object.values(messages.value));
if (messagesElement.value) {
+ await nextTick();
+ await nextTick();
scrollToBottom(messagesElement.value);
let fetched = false;
const amount = messages.value.length;
From 015b23f4e546a0bc45481588e2073e8630e8c1f5 Mon Sep 17 00:00:00 2001
From: SauceyRed
Date: Mon, 14 Jul 2025 01:11:36 +0200
Subject: [PATCH 07/10] feat: implement image embeds
---
app.vue | 1 +
components/Message.vue | 35 +++++++++++++++++++++++++--
components/MessageMedia.vue | 47 +++++++++++++++++++++++++++++++++++++
3 files changed, 81 insertions(+), 2 deletions(-)
create mode 100644 components/MessageMedia.vue
diff --git a/app.vue b/app.vue
index c6db309..9c8fb1c 100644
--- a/app.vue
+++ b/app.vue
@@ -14,6 +14,7 @@ const banner = useState("banner", () => false);
onMounted(() => {
document.removeEventListener("contextmenu", contextMenuHandler);
document.addEventListener("contextmenu", (e) => {
+ if (e.target instanceof Element && e.target.classList.contains("default-contextmenu")) return;
contextMenuHandler(e);
});
document.addEventListener("mousedown", (e) => {
diff --git a/components/Message.vue b/components/Message.vue
index 7bff711..82bc151 100644
--- a/components/Message.vue
+++ b/components/Message.vue
@@ -50,8 +50,9 @@
{{ date.toLocaleTimeString(undefined, { hour12: props.format == "12", timeStyle: "short" }) }}
-
+
+
+
@@ -71,6 +73,7 @@
import DOMPurify from 'dompurify';
import { parse } from 'marked';
import type { MessageProps } from '~/types/props';
+import MessageMedia from './MessageMedia.vue';
import MessageReply from './UserInterface/MessageReply.vue';
const props = defineProps();
@@ -86,6 +89,13 @@ console.log("[MSG] message to render:", props.message);
console.log("author:", props.author);
console.log("[MSG] reply message:", props.replyMessage);
+const linkRegex = /https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)/g;
+const linkMatches = props.message.message.matchAll(linkRegex).map(link => link[0]);
+const mediaLinks: string[] = [];
+console.log("link matches:", linkMatches);
+
+const hasEmbed = ref(false);
+
const sanitized = ref();
onMounted(async () => {
@@ -112,6 +122,27 @@ onMounted(async () => {
});
console.log("added listeners");
}
+
+ for (const link of linkMatches) {
+ console.log("link:", link);
+ try {
+ const res = await $fetch.raw(link);
+ if (res.ok && res.headers.get("content-type")?.match(/^image\/(apng|gif|jpeg|png|webp)$/)) {
+ console.log("link is image");
+ mediaLinks.push(link);
+ }
+ if (mediaLinks.length) {
+ hasEmbed.value = true
+ setTimeout(() => {
+ scrollToBottom(document.getElementById("messages") as HTMLDivElement);
+ }, 500);
+ };
+ } catch (error) {
+ console.error(error);
+ }
+}
+
+console.log("media links:", mediaLinks);
});
//function toggleTooltip(e: Event) {
diff --git a/components/MessageMedia.vue b/components/MessageMedia.vue
new file mode 100644
index 0000000..ab62387
--- /dev/null
+++ b/components/MessageMedia.vue
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
From 9d1eeff5825dfa559ed49a6d8e7bb2a1a3aabc3a Mon Sep 17 00:00:00 2001
From: SauceyRed
Date: Mon, 14 Jul 2025 18:44:18 +0200
Subject: [PATCH 08/10] feat: remove -ms-overflow-style CSS property from left
column
---
layouts/client.vue | 1 -
1 file changed, 1 deletion(-)
diff --git a/layouts/client.vue b/layouts/client.vue
index 8aeaf9c..b362156 100644
--- a/layouts/client.vue
+++ b/layouts/client.vue
@@ -262,7 +262,6 @@ function createDropdown() {
gap: 1.5dvh;
overflow-y: scroll;
scrollbar-width: none;
- -ms-overflow-style: none;
}
#left-column-top::-webkit-scrollbar, #left-column-bottom::-webkit-scrollbar {
From fc87bd4b6f5e16f143249f9fa66f2e109395b29c Mon Sep 17 00:00:00 2001
From: SauceyRed
Date: Mon, 14 Jul 2025 18:44:25 +0200
Subject: [PATCH 09/10] chore: remove unused temporary members list array
---
layouts/client.vue | 41 -----------------------------------------
1 file changed, 41 deletions(-)
diff --git a/layouts/client.vue b/layouts/client.vue
index b362156..65dd021 100644
--- a/layouts/client.vue
+++ b/layouts/client.vue
@@ -138,47 +138,6 @@ const options = [
const guilds: GuildResponse[] | undefined = await fetchWithApi("/me/guilds");
-//const servers = await fetchWithApi("/servers") as { uuid: string, name: string, description: string }[];
-//console.log("servers:", servers);
-const members = [
- {
- id: "3287484395",
- displayName: "SauceyRed"
- },
- {
- id: "3287484395",
- displayName: "SauceyRed"
- },
- {
- id: "3287484395",
- displayName: "SauceyRed"
- },
- {
- id: "3287484395",
- displayName: "SauceyRed"
- },
- {
- id: "3287484395",
- displayName: "SauceyRed"
- },
- {
- id: "3287484395",
- displayName: "SauceyRed"
- },
- {
- id: "3287484395",
- displayName: "SauceyRed"
- },
- {
- id: "3287484395",
- displayName: "SauceyRed"
- },
- {
- id: "3287484395",
- displayName: "SauceyRed"
- }
-];
-
function createDropdown() {
const dropdown = h(GuildDropdown, { options });
const div = document.createElement("div");
From a146eb001ae43f0e3bc4bb5f349afe3ffd3e31a8 Mon Sep 17 00:00:00 2001
From: JustTemmie <47639983+JustTemmie@users.noreply.github.com>
Date: Tue, 15 Jul 2025 00:16:47 +0200
Subject: [PATCH 10/10] style: manually edit the reply svg a bit
---
components/Message.vue | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/components/Message.vue b/components/Message.vue
index 82bc151..9c2c0c8 100644
--- a/components/Message.vue
+++ b/components/Message.vue
@@ -4,14 +4,10 @@
:editing.sync="props.editing" :replying-to.sync="props.replyingTo">