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">
+