From 64c6276153e8d361ed4d89a7ebe2b9ed2650b0d0 Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Sat, 7 Jun 2025 06:25:51 +0200 Subject: [PATCH 001/221] feat: add dropdown for guild settings and invite --- components/GuildOptionsMenu.vue | 58 +++++++++++++++++++ .../[serverId]/channels/[channelId].vue | 48 ++++++++++----- 2 files changed, 90 insertions(+), 16 deletions(-) create mode 100644 components/GuildOptionsMenu.vue diff --git a/components/GuildOptionsMenu.vue b/components/GuildOptionsMenu.vue new file mode 100644 index 0000000..d024ec8 --- /dev/null +++ b/components/GuildOptionsMenu.vue @@ -0,0 +1,58 @@ + + + + + \ No newline at end of file diff --git a/pages/servers/[serverId]/channels/[channelId].vue b/pages/servers/[serverId]/channels/[channelId].vue index c9aa8d2..b3d492a 100644 --- a/pages/servers/[serverId]/channels/[channelId].vue +++ b/pages/servers/[serverId]/channels/[channelId].vue @@ -1,21 +1,13 @@ \ No newline at end of file From 0c6cae110fb7e9b5a26621b4b16147cb1953e24b Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Mon, 7 Jul 2025 19:53:50 +0200 Subject: [PATCH 008/221] feat: add more restrictions to markdown sanitization --- components/Message.vue | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/components/Message.vue b/components/Message.vue index e8a91b5..c903012 100644 --- a/components/Message.vue +++ b/components/Message.vue @@ -60,7 +60,16 @@ const sanitized = ref(); onMounted(async () => { const parsed = await parse(props.text, { gfm: true }); - sanitized.value = DOMPurify.sanitize(parsed, { ALLOWED_TAGS: ["strong", "em", "br", "blockquote", "code", "ul", "ol", "li", "a", "h1", "h2", "h3", "h4", "h5", "h6"] }); + sanitized.value = DOMPurify.sanitize(parsed, { + ALLOWED_TAGS: [ + "strong", "em", "br", "blockquote", + "code", "ul", "ol", "li", "a", "h1", + "h2", "h3", "h4", "h5", "h6" + ], + ALLOW_DATA_ATTR: false, + ALLOW_SELF_CLOSE_IN_ATTR: false, + ALLOWED_ATTR: [] + }); console.log("adding listeners") await nextTick(); messageElement.value?.addEventListener("mouseenter", (e: Event) => { From a111180b521fbc6a4e7b6a2beb7abd11a1c31c06 Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Mon, 7 Jul 2025 20:23:47 +0200 Subject: [PATCH 009/221] feat: add word wrapping in messages --- components/Message.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/components/Message.vue b/components/Message.vue index c903012..dce8ed4 100644 --- a/components/Message.vue +++ b/components/Message.vue @@ -108,6 +108,7 @@ function getDayDifference(date1: Date, date2: Date) { align-items: center; column-gap: 1dvw; width: 100%; + overflow-wrap: anywhere; } .message:hover { From 1e0b8e2ba18c680ee626ba274de3df97b076f797 Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Mon, 7 Jul 2025 21:07:33 +0200 Subject: [PATCH 010/221] feat: add Dropdown component --- components/Dropdown.vue | 46 +++++++++++++++++++++++++++++++++++++++++ types/interfaces.ts | 6 ++++++ 2 files changed, 52 insertions(+) create mode 100644 components/Dropdown.vue diff --git a/components/Dropdown.vue b/components/Dropdown.vue new file mode 100644 index 0000000..ff03799 --- /dev/null +++ b/components/Dropdown.vue @@ -0,0 +1,46 @@ + + + + + \ No newline at end of file diff --git a/types/interfaces.ts b/types/interfaces.ts index 1aba1bc..fe58dd2 100644 --- a/types/interfaces.ts +++ b/types/interfaces.ts @@ -81,3 +81,9 @@ export interface ScrollPosition { offsetTop: number, offsetLeft: number } + +export interface DropdownOption { + name: string, + value: string | number, + callback: () => void +} From 19113f13034e9c079908024ccb130519b79821c8 Mon Sep 17 00:00:00 2001 From: JustTemmie <47639983+JustTemmie@users.noreply.github.com> Date: Tue, 8 Jul 2025 20:57:40 +0200 Subject: [PATCH 011/221] feat: implement basic home page --- layouts/client.vue | 2 +- pages/home.vue | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 pages/home.vue diff --git a/layouts/client.vue b/layouts/client.vue index a1ee86d..516658c 100644 --- a/layouts/client.vue +++ b/layouts/client.vue @@ -7,7 +7,7 @@
- +
diff --git a/pages/home.vue b/pages/home.vue new file mode 100644 index 0000000..4182eb3 --- /dev/null +++ b/pages/home.vue @@ -0,0 +1,30 @@ + + + + + \ No newline at end of file From bb5ff3750967a938ad8daec495c20893d264cbef Mon Sep 17 00:00:00 2001 From: JustTemmie <47639983+JustTemmie@users.noreply.github.com> Date: Tue, 8 Jul 2025 20:58:40 +0200 Subject: [PATCH 012/221] fix: put the home page into index.vue instead --- layouts/client.vue | 2 +- pages/home.vue | 30 ------------------------------ pages/index.vue | 15 ++++++++++++++- 3 files changed, 15 insertions(+), 32 deletions(-) delete mode 100644 pages/home.vue diff --git a/layouts/client.vue b/layouts/client.vue index 516658c..a1ee86d 100644 --- a/layouts/client.vue +++ b/layouts/client.vue @@ -7,7 +7,7 @@
- +
diff --git a/pages/home.vue b/pages/home.vue deleted file mode 100644 index 4182eb3..0000000 --- a/pages/home.vue +++ /dev/null @@ -1,30 +0,0 @@ - - - - - \ No newline at end of file diff --git a/pages/index.vue b/pages/index.vue index f970926..4182eb3 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -1,6 +1,19 @@ From bd6307f16e06cc2b53b62ab2017c9cfdf29c7ca8 Mon Sep 17 00:00:00 2001 From: JustTemmie <47639983+JustTemmie@users.noreply.github.com> Date: Tue, 8 Jul 2025 21:00:05 +0200 Subject: [PATCH 013/221] fix: rephrase sentace from "server" to "guild" --- pages/index.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/index.vue b/pages/index.vue index 4182eb3..41deadf 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -7,7 +7,7 @@ Welcome to gorb :3

- Click on a server to the left to view a guild. + Click on a guild to the left to view a guild.
Or click the button in the bottom left to join a guild.

From 8932070fcc64fae57036b9e5fc4d08398e236d68 Mon Sep 17 00:00:00 2001 From: JustTemmie <47639983+JustTemmie@users.noreply.github.com> Date: Tue, 8 Jul 2025 21:11:14 +0200 Subject: [PATCH 014/221] feat: spice up the home bar --- layouts/client.vue | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/layouts/client.vue b/layouts/client.vue index a1ee86d..9ce451e 100644 --- a/layouts/client.vue +++ b/layouts/client.vue @@ -3,7 +3,9 @@
- main bar + + gorb!!!!! +
@@ -61,6 +63,11 @@ const guilds: GuildResponse[] | undefined = await fetchWithApi("/me/guilds"); background-color: var(--topbar-background-color); padding-left: 5dvw; padding-right: 5dvw; + +} + +.homebar-item { + width: 100dvw; } #client-root>div:nth-child(-n+4) { From 730b0cb1dcece7264d81e07902e1576e7d92b1cb Mon Sep 17 00:00:00 2001 From: JustTemmie <47639983+JustTemmie@users.noreply.github.com> Date: Wed, 9 Jul 2025 00:25:52 +0200 Subject: [PATCH 015/221] refactor: change the client from table to flexbox this makes the server, channel, and member list a constant size, making the text messages take up the entire remaining width this also fixes the text wrapping you have already fixed on one of your branches this change is required if we want to make the member list toggelable, or channel list resizable --- components/Channel.vue | 2 +- layouts/client.vue | 89 ++++++++----------- .../[serverId]/channels/[channelId].vue | 13 ++- 3 files changed, 46 insertions(+), 58 deletions(-) diff --git a/components/Channel.vue b/components/Channel.vue index 0f48323..6bdc28b 100644 --- a/components/Channel.vue +++ b/components/Channel.vue @@ -30,7 +30,7 @@ const isCurrentChannel = props.uuid == props.currentUuid; .channel-list-link-container { text-align: left; display: flex; - height: 4dvh; + height: 1.5em; white-space: nowrap; align-items: center; } diff --git a/layouts/client.vue b/layouts/client.vue index a1ee86d..b98e304 100644 --- a/layouts/client.vue +++ b/layouts/client.vue @@ -6,21 +6,23 @@ main bar
-
- - - -
- - - +
+
+ + + +
+ + + + +
+ +
- - - +
-
@@ -34,11 +36,10 @@ const guilds: GuildResponse[] | undefined = await fetchWithApi("/me/guilds"); \ No newline at end of file diff --git a/pages/servers/[serverId]/channels/[channelId].vue b/pages/servers/[serverId]/channels/[channelId].vue index 6bdcc7c..b5ee86a 100644 --- a/pages/servers/[serverId]/channels/[channelId].vue +++ b/pages/servers/[serverId]/channels/[channelId].vue @@ -91,9 +91,8 @@ function handleMemberClick(member: GuildMemberResponse) { } #members-container { - padding-top: 1dvh; - padding-left: 1dvw; - padding-right: 1dvw; + min-width: 12rem; + padding-top: 1em; border-left: 1px solid var(--padding-color); } @@ -102,14 +101,14 @@ function handleMemberClick(member: GuildMemberResponse) { flex-direction: column; overflow-y: scroll; max-height: 92dvh; - padding-left: 1dvw; - padding-right: 1dvw; + padding-left: 1.3em; + padding-right: 1.3em; margin-top: 1dvh; } .member-item { display: grid; - grid-template-columns: 2dvw 1fr; + grid-template-columns: 1.5em 1fr; margin-top: .5em; margin-bottom: .5em; gap: 1em; @@ -121,7 +120,7 @@ function handleMemberClick(member: GuildMemberResponse) { #channels-list { display: flex; flex-direction: column; - gap: 1dvh; + gap: .5em; } .member-avatar { From 9a2fe8fb373c006ac074031057d0fe4e5b90fa62 Mon Sep 17 00:00:00 2001 From: JustTemmie <47639983+JustTemmie@users.noreply.github.com> Date: Wed, 9 Jul 2025 00:43:23 +0200 Subject: [PATCH 016/221] refactor: change a lot of dynamic sizes to em and rem this makes the client feel a LOT snappier --- components/Button.vue | 2 +- components/Channel.vue | 4 ++-- components/MessageArea.vue | 1 + layouts/client.vue | 20 ++++++++-------- .../[serverId]/channels/[channelId].vue | 23 ++++++++++--------- 5 files changed, 26 insertions(+), 24 deletions(-) diff --git a/components/Button.vue b/components/Button.vue index fb44cf2..66706de 100644 --- a/components/Button.vue +++ b/components/Button.vue @@ -21,7 +21,7 @@ const props = defineProps<{ background-color: var(--primary-color); color: var(--text-color); - padding: 0.7dvh 1.2dvw; + padding: 0.4em 0.75em; font-size: 1.1em; transition: background-color 0.2s; diff --git a/components/Channel.vue b/components/Channel.vue index 6bdc28b..98f210e 100644 --- a/components/Channel.vue +++ b/components/Channel.vue @@ -23,8 +23,8 @@ const isCurrentChannel = props.uuid == props.currentUuid; .channel-list-link { text-decoration: none; color: inherit; - padding-left: .5dvw; - padding-right: .5dvw; + padding-left: .25em; + padding-right: .25em; } .channel-list-link-container { diff --git a/components/MessageArea.vue b/components/MessageArea.vue index 18b9ac5..244b239 100644 --- a/components/MessageArea.vue +++ b/components/MessageArea.vue @@ -246,6 +246,7 @@ router.beforeEach((to, from, next) => { padding-left: 1dvw; padding-right: 1dvw; overflow: hidden; + flex-grow: 1; } #message-box { diff --git a/layouts/client.vue b/layouts/client.vue index b98e304..469800d 100644 --- a/layouts/client.vue +++ b/layouts/client.vue @@ -74,27 +74,27 @@ const guilds: GuildResponse[] | undefined = await fetchWithApi("/me/guilds"); #left-column { display: flex; flex-direction: column; - gap: 2dvh; - padding-left: .5dvw; - padding-right: .5dvw; + gap: .75em; + padding-left: .25em; + padding-right: .25em; border-right: 1px solid var(--padding-color); background: var(--optional-sidebar-background); background-color: var(--sidebar-background-color); - padding-top: 1.5dvh; + padding-top: .5em; } #servers-list { display: flex; flex-direction: column; - gap: 1dvh; + gap: 1em; width: 3.2rem; } #middle-left-column { - padding-left: 1dvw; - padding-right: 1dvw; + padding-left: .25em; + padding-right: .25em; border-right: 1px solid var(--padding-color); - min-width: 10rem; + min-width: 10em; overflow-y: scroll; overflow-x: hidden; } @@ -106,12 +106,12 @@ const guilds: GuildResponse[] | undefined = await fetchWithApi("/me/guilds"); #home-button { border-bottom: 1px solid var(--padding-color); - padding-bottom: 1dvh; + padding-bottom: .375em; } #settings-menu { position: absolute; - bottom: .25dvh + bottom: .25em } \ No newline at end of file diff --git a/pages/servers/[serverId]/channels/[channelId].vue b/pages/servers/[serverId]/channels/[channelId].vue index b5ee86a..04d56f9 100644 --- a/pages/servers/[serverId]/channels/[channelId].vue +++ b/pages/servers/[serverId]/channels/[channelId].vue @@ -27,6 +27,7 @@
+
@@ -83,35 +84,35 @@ function handleMemberClick(member: GuildMemberResponse) { From a6572c20f971c4f0d8e05d99f6fac86f29c59541 Mon Sep 17 00:00:00 2001 From: JustTemmie <47639983+JustTemmie@users.noreply.github.com> Date: Wed, 9 Jul 2025 01:04:37 +0200 Subject: [PATCH 018/221] fix: remove accidental duplication of member list this was for local testing, forgot to remove it --- pages/servers/[serverId]/channels/[channelId].vue | 1 - 1 file changed, 1 deletion(-) diff --git a/pages/servers/[serverId]/channels/[channelId].vue b/pages/servers/[serverId]/channels/[channelId].vue index 04d56f9..d0c702d 100644 --- a/pages/servers/[serverId]/channels/[channelId].vue +++ b/pages/servers/[serverId]/channels/[channelId].vue @@ -27,7 +27,6 @@
-
From 5c178f99ae2d9321145c21f9886fcfe0824d73f6 Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Wed, 9 Jul 2025 07:19:40 +0200 Subject: [PATCH 019/221] feat: add fetchInstanceStats and sendVerificationEmail to api composable --- composables/api.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/composables/api.ts b/composables/api.ts index 603f71f..d2ca7a0 100644 --- a/composables/api.ts +++ b/composables/api.ts @@ -1,4 +1,4 @@ -import type { ChannelResponse, GuildMemberResponse, GuildResponse, MessageResponse } from "~/types/interfaces"; +import type { ChannelResponse, GuildMemberResponse, GuildResponse, MessageResponse, StatsResponse } from "~/types/interfaces"; export const useApi = () => { async function fetchGuilds(): Promise { @@ -41,6 +41,15 @@ export const useApi = () => { return await fetchWithApi(`/channels/${channelId}/messages/${messageId}`); } + async function fetchInstanceStats(apiBase: string): Promise { + return await $fetch(`${apiBase}/stats`, { method: "GET" }); + } + + async function sendVerificationEmail(): Promise { + const email = useAuth().user.value?.email; + await fetchWithApi("/auth/verify-email", { method: "POST", body: { email } }); + } + return { fetchGuilds, fetchGuild, @@ -51,6 +60,8 @@ export const useApi = () => { fetchUsers, fetchUser, fetchMessages, - fetchMessage + fetchMessage, + fetchInstanceStats, + sendVerificationEmail } } From 04689e57ea34e936170049f3a76f7adb551c1bad Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Wed, 9 Jul 2025 07:21:16 +0200 Subject: [PATCH 020/221] feat: remove old logout and other auth functions from login/register page --- layouts/auth.vue | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/layouts/auth.vue b/layouts/auth.vue index b7d5c5e..dc65e96 100644 --- a/layouts/auth.vue +++ b/layouts/auth.vue @@ -20,30 +20,7 @@
- Instance URL is set to {{ instanceUrl }} -
-
- You're logged in! -
-
- -
- -
-
- -
-
-
- -
-
- -
-
- -
+ Instance URL is set to {{ instanceUrl }}
From 397e94798f4a0d398040c9612aa1b6e3c501ebe7 Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Wed, 9 Jul 2025 07:21:49 +0200 Subject: [PATCH 021/221] feat: remove unused type import --- layouts/auth.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/layouts/auth.vue b/layouts/auth.vue index dc65e96..d58a97f 100644 --- a/layouts/auth.vue +++ b/layouts/auth.vue @@ -28,7 +28,6 @@ \ No newline at end of file From 84aa1f95fe555a60ff0f23cb8e4e320afaf3e090 Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Wed, 9 Jul 2025 07:30:06 +0200 Subject: [PATCH 030/221] feat: add auto redirection in verify-email page --- pages/verify-email.vue | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pages/verify-email.vue b/pages/verify-email.vue index cae02ea..f160a1d 100644 --- a/pages/verify-email.vue +++ b/pages/verify-email.vue @@ -15,6 +15,12 @@ const token = useRoute().query.token; try { const res = await fetchWithApi("/auth/verify-email", { query: { token } }); console.log("hi"); + const query = useRoute().query; + if (query.redirect_to) { + await navigateTo(`/?redirect_to=${query.redirect_to}`); + } else { + await navigateTo("/"); + } } catch (error) { console.error("Error verifying email:", error); errorMessage.value = error; From 4b6dc03b136e3d19662f1f87eb09753c655d5c27 Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Wed, 9 Jul 2025 07:30:46 +0200 Subject: [PATCH 031/221] feat: refresh page when email is changed and instance requires verification --- components/Settings/UserSettings/Account.vue | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/Settings/UserSettings/Account.vue b/components/Settings/UserSettings/Account.vue index 85589e7..a08cffc 100644 --- a/components/Settings/UserSettings/Account.vue +++ b/components/Settings/UserSettings/Account.vue @@ -43,6 +43,14 @@ async function changeEmail() { body: formData }) + const apiBase = useCookie("api_base").value; + + if (apiBase) { + const stats = await useApi().fetchInstanceStats(apiBase); + if (stats.email_verification_required) { + return window.location.reload(); + } + } alert('success!!') } catch (error: any) { if (error?.response?.status !== 200) { From 7ddc2acb02aaa4c5d4bd4b3bd27903a299208d0c Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Wed, 9 Jul 2025 07:37:05 +0200 Subject: [PATCH 032/221] feat: add message id as data field of Message component --- components/Message.vue | 7 ++++--- components/MessageArea.vue | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/components/Message.vue b/components/Message.vue index 5cd7773..188960a 100644 --- a/components/Message.vue +++ b/components/Message.vue @@ -1,5 +1,5 @@ diff --git a/components/MessageArea.vue b/components/MessageArea.vue index 18b9ac5..fff4a5c 100644 --- a/components/MessageArea.vue +++ b/components/MessageArea.vue @@ -9,11 +9,28 @@
- - +
+ + + +
+ +
+
+
+
+ +
+ + + + +
@@ -106,11 +123,38 @@ function pushMessage(message: MessageResponse) { messages.value.push(message); } +function handleTextboxKeyDown(event: KeyboardEvent) { + if (event.key === "Enter" && event.shiftKey && messageTextboxInput.value) { + // this enters a newline, due to not preventing default + } else if (event.key === "Enter") { + event.preventDefault() + sendMessage(event) + } + + adjustTextboxHeight() +} + +function handleTextboxInput() { + if (messageTextboxInput.value) { + messageInput.value = messageTextboxInput.value.innerText; + } + + adjustTextboxHeight() +} + +// this technically uses pixel units, but it's still set using dynamic units +function adjustTextboxHeight() { + if (messageTextboxInput.value && messageTextboxDisplay.value) { + messageTextboxInput.value.style.height = "auto" + messageTextboxInput.value.style.height = `${messageTextboxInput.value.scrollHeight}px` + } +} + const messages = ref([]); - -const messageInput = ref(); - +const messageInput = ref(""); const messagesElement = ref(); +const messageTextboxInput = ref(); +const messageTextboxDisplay = ref(); if (messagesRes) messages.value = messagesRes; @@ -158,14 +202,21 @@ if (accessToken && apiBase) { function sendMessage(e: Event) { e.preventDefault(); - const message = { - message: messageInput.value - } - console.log("message:", message); - if (message.message) { + if (messageInput.value && messageInput.value.trim() !== "") { + const message = { + message: messageInput.value.trim().replace(/\n/g, "
") // trim, and replace \n with
+ } + + console.log("message:", message); ws.send(JSON.stringify(message)); - messageInput.value = ""; - console.log("MESSAGE SENT!!!"); + + // reset input field + messageInput.value = "" + if (messageTextboxInput.value) { + messageTextboxInput.value.innerText = "" + } + + adjustTextboxHeight() } } @@ -241,38 +292,63 @@ router.beforeEach((to, from, next) => { \ No newline at end of file diff --git a/pages/index.vue b/pages/index.vue index f970926..41deadf 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -1,6 +1,19 @@ diff --git a/pages/servers/[serverId]/channels/[channelId].vue b/pages/servers/[serverId]/channels/[channelId].vue index 6bdcc7c..5c55655 100644 --- a/pages/servers/[serverId]/channels/[channelId].vue +++ b/pages/servers/[serverId]/channels/[channelId].vue @@ -83,36 +83,36 @@ function handleMemberClick(member: GuildMemberResponse) { \ No newline at end of file From 2790772cb7c1fd9a73a3f6df766a9e9be7ff0906 Mon Sep 17 00:00:00 2001 From: JustTemmie <47639983+JustTemmie@users.noreply.github.com> Date: Thu, 10 Jul 2025 16:32:41 +0200 Subject: [PATCH 041/221] fix: some of the worst merging i've done in my life --- layouts/client.vue | 47 +--------------------------------------------- 1 file changed, 1 insertion(+), 46 deletions(-) diff --git a/layouts/client.vue b/layouts/client.vue index bd3921a..a28d6bc 100644 --- a/layouts/client.vue +++ b/layouts/client.vue @@ -25,23 +25,6 @@ -
-
- - - -
- - - - -
- - - -
- -
@@ -69,11 +52,9 @@ const guilds: GuildResponse[] | undefined = await fetchWithApi("/me/guilds"); .visible { opacity: 100%; transition: opacity 500ms; - transition: opacity 500ms; } #homebar { - min-height: 4dvh; min-height: 4dvh; display: flex; justify-content: space-evenly; @@ -81,14 +62,8 @@ const guilds: GuildResponse[] | undefined = await fetchWithApi("/me/guilds"); background: var(--optional-topbar-background); background-color: var(--topbar-background-color); border-bottom: 1px solid var(--padding-color); - border-bottom: 1px solid var(--padding-color); padding-left: 5dvw; padding-right: 5dvw; - -} - -.homebar-item { - width: 100dvw; } .homebar-item { @@ -100,9 +75,6 @@ const guilds: GuildResponse[] | undefined = await fetchWithApi("/me/guilds"); flex-direction: row; flex-grow: 1; overflow: auto; - flex-direction: row; - flex-grow: 1; - overflow: auto; } #left-column { @@ -111,13 +83,10 @@ const guilds: GuildResponse[] | undefined = await fetchWithApi("/me/guilds"); gap: .75em; padding-left: .25em; padding-right: .25em; - gap: .75em; - padding-left: .25em; - padding-right: .25em; + padding-top: .5em; border-right: 1px solid var(--padding-color); background: var(--optional-sidebar-background); background-color: var(--sidebar-background-color); - padding-top: .5em; } #servers-list { @@ -128,16 +97,7 @@ const guilds: GuildResponse[] | undefined = await fetchWithApi("/me/guilds"); padding-top: .5em; } -#servers-list { - display: flex; - flex-direction: column; - gap: 1em; - width: 3.2rem; -} - #middle-left-column { - padding-left: .25em; - padding-right: .25em; padding-left: .25em; padding-right: .25em; border-right: 1px solid var(--padding-color); @@ -154,11 +114,6 @@ const guilds: GuildResponse[] | undefined = await fetchWithApi("/me/guilds"); overflow-x: hidden; } -.sidebar-icon { - width: 3rem; - height: 3rem; -} - #home-button { border-bottom: 1px solid var(--padding-color); padding-bottom: .375em; From f59162bad596ac953d0eeba91529b3952f4eb2a8 Mon Sep 17 00:00:00 2001 From: JustTemmie <47639983+JustTemmie@users.noreply.github.com> Date: Thu, 10 Jul 2025 20:13:25 +0200 Subject: [PATCH 042/221] fix: width of icon and channel lists --- layouts/client.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layouts/client.vue b/layouts/client.vue index a28d6bc..966e60a 100644 --- a/layouts/client.vue +++ b/layouts/client.vue @@ -102,6 +102,7 @@ const guilds: GuildResponse[] | undefined = await fetchWithApi("/me/guilds"); padding-right: .25em; border-right: 1px solid var(--padding-color); min-width: 13em; + max-width: 13em; overflow-y: scroll; overflow-x: hidden; } @@ -109,7 +110,6 @@ const guilds: GuildResponse[] | undefined = await fetchWithApi("/me/guilds"); .sidebar-icon { width: 3rem; height: 3rem; - min-width: 10em; overflow-y: scroll; overflow-x: hidden; } From 04358e9c917c00b95b7debd51b7f476e2a79472c Mon Sep 17 00:00:00 2001 From: JustTemmie <47639983+JustTemmie@users.noreply.github.com> Date: Thu, 10 Jul 2025 21:04:27 +0200 Subject: [PATCH 043/221] feat: make settings menu remember your page on reload --- pages/settings.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/pages/settings.vue b/pages/settings.vue index 3aac506..6bf3c9e 100644 --- a/pages/settings.vue +++ b/pages/settings.vue @@ -98,6 +98,7 @@ let currentPage = ref(categories[0].pages[0]); let selectedPage = ref(currentPage.value.displayName); // used to highlight the current channel function selectCategory(page: Page) { + window.location.hash = page.displayName.toLowerCase() currentPage.value = page; selectedPage.value = page.displayName; }; From 71242d0543ace0b581e01cf09ab8a44d33b882d3 Mon Sep 17 00:00:00 2001 From: justtemmie Date: Thu, 10 Jul 2025 19:37:04 +0000 Subject: [PATCH 044/221] revert 04358e9c917c00b95b7debd51b7f476e2a79472c revert feat: make settings menu remember your page on reload it breaks the back button, my bad --- pages/settings.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/pages/settings.vue b/pages/settings.vue index 6bf3c9e..3aac506 100644 --- a/pages/settings.vue +++ b/pages/settings.vue @@ -98,7 +98,6 @@ let currentPage = ref(categories[0].pages[0]); let selectedPage = ref(currentPage.value.displayName); // used to highlight the current channel function selectCategory(page: Page) { - window.location.hash = page.displayName.toLowerCase() currentPage.value = page; selectedPage.value = page.displayName; }; From a90f06218126547a1e3c681515895c8f0efbd3d3 Mon Sep 17 00:00:00 2001 From: JustTemmie <47639983+JustTemmie@users.noreply.github.com> Date: Thu, 10 Jul 2025 21:53:25 +0200 Subject: [PATCH 045/221] refactor: move the homepage to /me from / --- layouts/client.vue | 2 +- pages/index.vue | 16 ++-------------- pages/me/index.vue | 30 ++++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 15 deletions(-) create mode 100644 pages/me/index.vue diff --git a/layouts/client.vue b/layouts/client.vue index 966e60a..de1e029 100644 --- a/layouts/client.vue +++ b/layouts/client.vue @@ -10,7 +10,7 @@
- +
diff --git a/pages/index.vue b/pages/index.vue index 41deadf..cb5f57e 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -1,23 +1,11 @@ + + \ No newline at end of file From b1a3ce9b00977c4bf74af610f944c885eb2ef719 Mon Sep 17 00:00:00 2001 From: JustTemmie <47639983+JustTemmie@users.noreply.github.com> Date: Thu, 10 Jul 2025 22:18:28 +0200 Subject: [PATCH 046/221] feat: update interface to include friends_since --- types/interfaces.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/types/interfaces.ts b/types/interfaces.ts index 610d007..7b9a97b 100644 --- a/types/interfaces.ts +++ b/types/interfaces.ts @@ -61,7 +61,8 @@ export interface UserResponse { pronouns: string | null, about: string | null, email?: string, - email_verified?: boolean + email_verified?: boolean, + friends_since: string | null, } export interface StatsResponse { From 8a9ecaa2e2ead30576367a2bd275c70edeb1da19 Mon Sep 17 00:00:00 2001 From: JustTemmie <47639983+JustTemmie@users.noreply.github.com> Date: Thu, 10 Jul 2025 22:44:18 +0200 Subject: [PATCH 047/221] refactor: move spacer into it's own component --- components/VerticalSpacer.vue | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 components/VerticalSpacer.vue diff --git a/components/VerticalSpacer.vue b/components/VerticalSpacer.vue new file mode 100644 index 0000000..293e9f0 --- /dev/null +++ b/components/VerticalSpacer.vue @@ -0,0 +1,21 @@ + + + + + From 5dbf21b0abb975d98ae1e825fd6edaf01fab36dc Mon Sep 17 00:00:00 2001 From: JustTemmie <47639983+JustTemmie@users.noreply.github.com> Date: Thu, 10 Jul 2025 22:44:46 +0200 Subject: [PATCH 048/221] feat: implement friends list --- components/DirectMessagesSidebar.vue | 38 ++++++++++++++++++++++++++++ components/UserEntry.vue | 35 +++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 components/DirectMessagesSidebar.vue create mode 100644 components/UserEntry.vue diff --git a/components/DirectMessagesSidebar.vue b/components/DirectMessagesSidebar.vue new file mode 100644 index 0000000..d9f677d --- /dev/null +++ b/components/DirectMessagesSidebar.vue @@ -0,0 +1,38 @@ + + + + + \ No newline at end of file diff --git a/components/UserEntry.vue b/components/UserEntry.vue new file mode 100644 index 0000000..dcea368 --- /dev/null +++ b/components/UserEntry.vue @@ -0,0 +1,35 @@ + + + + + From 15e5a21277f487174f66dcc6113edf2aae2265bd Mon Sep 17 00:00:00 2001 From: JustTemmie <47639983+JustTemmie@users.noreply.github.com> Date: Thu, 10 Jul 2025 22:47:52 +0200 Subject: [PATCH 049/221] refactor: try sorting components into sub-folders --- components/{ => Guild}/Channel.vue | 0 components/{ => Member}/MemberEntry.vue | 0 components/{ => Popups}/CropPopup.vue | 0 components/{ => Popups}/InvitePopup.vue | 0 components/{ => Popups}/Loading.vue | 0 components/{ => User}/UserEntry.vue | 0 components/{ => User}/UserPopup.vue | 0 components/UserArea.vue | 20 ------------------- components/{ => UserInterface}/Button.vue | 0 .../{ => UserInterface}/VerticalSpacer.vue | 0 10 files changed, 20 deletions(-) rename components/{ => Guild}/Channel.vue (100%) rename components/{ => Member}/MemberEntry.vue (100%) rename components/{ => Popups}/CropPopup.vue (100%) rename components/{ => Popups}/InvitePopup.vue (100%) rename components/{ => Popups}/Loading.vue (100%) rename components/{ => User}/UserEntry.vue (100%) rename components/{ => User}/UserPopup.vue (100%) delete mode 100644 components/UserArea.vue rename components/{ => UserInterface}/Button.vue (100%) rename components/{ => UserInterface}/VerticalSpacer.vue (100%) diff --git a/components/Channel.vue b/components/Guild/Channel.vue similarity index 100% rename from components/Channel.vue rename to components/Guild/Channel.vue diff --git a/components/MemberEntry.vue b/components/Member/MemberEntry.vue similarity index 100% rename from components/MemberEntry.vue rename to components/Member/MemberEntry.vue diff --git a/components/CropPopup.vue b/components/Popups/CropPopup.vue similarity index 100% rename from components/CropPopup.vue rename to components/Popups/CropPopup.vue diff --git a/components/InvitePopup.vue b/components/Popups/InvitePopup.vue similarity index 100% rename from components/InvitePopup.vue rename to components/Popups/InvitePopup.vue diff --git a/components/Loading.vue b/components/Popups/Loading.vue similarity index 100% rename from components/Loading.vue rename to components/Popups/Loading.vue diff --git a/components/UserEntry.vue b/components/User/UserEntry.vue similarity index 100% rename from components/UserEntry.vue rename to components/User/UserEntry.vue diff --git a/components/UserPopup.vue b/components/User/UserPopup.vue similarity index 100% rename from components/UserPopup.vue rename to components/User/UserPopup.vue diff --git a/components/UserArea.vue b/components/UserArea.vue deleted file mode 100644 index d922c3f..0000000 --- a/components/UserArea.vue +++ /dev/null @@ -1,20 +0,0 @@ - - - - - \ No newline at end of file diff --git a/components/Button.vue b/components/UserInterface/Button.vue similarity index 100% rename from components/Button.vue rename to components/UserInterface/Button.vue diff --git a/components/VerticalSpacer.vue b/components/UserInterface/VerticalSpacer.vue similarity index 100% rename from components/VerticalSpacer.vue rename to components/UserInterface/VerticalSpacer.vue From 59000709fe5f3ae0c3b7f3254870481094e90da2 Mon Sep 17 00:00:00 2001 From: JustTemmie <47639983+JustTemmie@users.noreply.github.com> Date: Thu, 10 Jul 2025 22:51:14 +0200 Subject: [PATCH 050/221] feat: update api --- composables/api.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/composables/api.ts b/composables/api.ts index d2ca7a0..8a37a8e 100644 --- a/composables/api.ts +++ b/composables/api.ts @@ -1,4 +1,4 @@ -import type { ChannelResponse, GuildMemberResponse, GuildResponse, MessageResponse, StatsResponse } from "~/types/interfaces"; +import type { ChannelResponse, GuildMemberResponse, GuildResponse, MessageResponse, StatsResponse, UserResponse } from "~/types/interfaces"; export const useApi = () => { async function fetchGuilds(): Promise { @@ -24,14 +24,18 @@ export const useApi = () => { async function fetchMember(guildId: string, memberId: string): Promise { return await fetchWithApi(`/guilds/${guildId}/members/${memberId}`); } - + async function fetchUsers() { return await fetchWithApi(`/users`); } - + async function fetchUser(userId: string) { return await fetchWithApi(`/users/${userId}`); } + + async function fetchFriends(): Promise { + return await fetchWithApi('/me/friends') + } async function fetchMessages(channelId: string, options?: { amount?: number, offset?: number }): Promise { return await fetchWithApi(`/channels/${channelId}/messages`, { query: { amount: options?.amount ?? 100, offset: options?.offset ?? 0 } }); @@ -59,6 +63,7 @@ export const useApi = () => { fetchMember, fetchUsers, fetchUser, + fetchFriends, fetchMessages, fetchMessage, fetchInstanceStats, From 8e69dc805e20e5feab0493b9b9aafac5a23f3c57 Mon Sep 17 00:00:00 2001 From: JustTemmie <47639983+JustTemmie@users.noreply.github.com> Date: Thu, 10 Jul 2025 22:51:56 +0200 Subject: [PATCH 051/221] chore: remove unused popups --- components/Member/MemberEntry.vue | 1 - components/Settings/UserSettings/Account.vue | 1 - components/Settings/UserSettings/Privacy.vue | 1 - pages/servers/[serverId]/channels/[channelId].vue | 1 - 4 files changed, 4 deletions(-) diff --git a/components/Member/MemberEntry.vue b/components/Member/MemberEntry.vue index ed4cd48..1ea4170 100644 --- a/components/Member/MemberEntry.vue +++ b/components/Member/MemberEntry.vue @@ -10,7 +10,6 @@ \ No newline at end of file diff --git a/components/User/UserEntry.vue b/components/User/UserEntry.vue index dcea368..b463759 100644 --- a/components/User/UserEntry.vue +++ b/components/User/UserEntry.vue @@ -24,7 +24,12 @@ const props = defineProps<{ margin-bottom: .5em; gap: .5em; - cursor: pointer; + text-decoration: none; + color: inherit; +} + +.user-item:hover { + background-color: #00000020 } .user-avatar { diff --git a/components/UserInterface/VerticalSpacer.vue b/components/UserInterface/VerticalSpacer.vue index 293e9f0..8ac1bd6 100644 --- a/components/UserInterface/VerticalSpacer.vue +++ b/components/UserInterface/VerticalSpacer.vue @@ -2,15 +2,6 @@ - - \ No newline at end of file diff --git a/components/DirectMessagesSidebar.vue b/components/Me/DirectMessagesSidebar.vue similarity index 73% rename from components/DirectMessagesSidebar.vue rename to components/Me/DirectMessagesSidebar.vue index dece975..5a0e99d 100644 --- a/components/DirectMessagesSidebar.vue +++ b/components/Me/DirectMessagesSidebar.vue @@ -5,24 +5,24 @@

Direct Messages

+ Friends +
- + :href="`/me/${user.uuid}`"/>
+ + \ No newline at end of file diff --git a/composables/api.ts b/composables/api.ts index 8a37a8e..0cd6db0 100644 --- a/composables/api.ts +++ b/composables/api.ts @@ -37,6 +37,14 @@ export const useApi = () => { return await fetchWithApi('/me/friends') } + async function addFriend(username: string): Promise { + await fetchWithApi('/me/friends', { method: "POST", body: { username } }); + } + + async function removeFriend(userId: string): Promise { + await fetchWithApi(`/me/friends/${userId}`, { method: "DELETE" }); + } + async function fetchMessages(channelId: string, options?: { amount?: number, offset?: number }): Promise { return await fetchWithApi(`/channels/${channelId}/messages`, { query: { amount: options?.amount ?? 100, offset: options?.offset ?? 0 } }); } @@ -64,6 +72,8 @@ export const useApi = () => { fetchUsers, fetchUser, fetchFriends, + addFriend, + removeFriend, fetchMessages, fetchMessage, fetchInstanceStats, diff --git a/pages/me/[userId].vue b/pages/me/[userId].vue new file mode 100644 index 0000000..d466938 --- /dev/null +++ b/pages/me/[userId].vue @@ -0,0 +1,20 @@ + + + + + \ No newline at end of file diff --git a/pages/me/friends.vue b/pages/me/friends.vue new file mode 100644 index 0000000..b284658 --- /dev/null +++ b/pages/me/friends.vue @@ -0,0 +1,82 @@ + + + + + \ No newline at end of file diff --git a/pages/me/index.vue b/pages/me/index.vue index 701481d..b075668 100644 --- a/pages/me/index.vue +++ b/pages/me/index.vue @@ -5,6 +5,8 @@ \ No newline at end of file From 2ff892b0da73a9d0e1ad5522e2dece2f74c7a16f Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Fri, 11 Jul 2025 03:31:25 +0200 Subject: [PATCH 072/221] feat: add util to create MessageReply instance --- utils/replyToMessage.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/utils/replyToMessage.ts b/utils/replyToMessage.ts index 03253d2..bbb453b 100644 --- a/utils/replyToMessage.ts +++ b/utils/replyToMessage.ts @@ -1,5 +1,14 @@ +import { render } from "vue"; +import MessageReply from "~/components/MessageReply.vue"; import type { MessageProps } from "~/types/props"; export default (element: HTMLDivElement, props: MessageProps) => { console.log("element:", element); + const messageBox = document.getElementById("message-box") as HTMLDivElement; + if (messageBox) { + const div = document.createElement("div"); + const messageReply = h(MessageReply, { author: props.author?.display_name || props.author!.username, text: props.text || "", id: props.message.uuid, replyId: props.replyMessage?.uuid || element.dataset.messageId!, maxWidth: "full" }); + messageBox.prepend(div); + render(messageReply, div); + } } From a8ee8122ee0f7d03a0e3abc65a9595d041684d56 Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Fri, 11 Jul 2025 03:33:24 +0200 Subject: [PATCH 073/221] feat: implement message replies --- components/Message.vue | 27 ++++++++++++++++++++++++--- components/MessageArea.vue | 29 ++++++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/components/Message.vue b/components/Message.vue index d3d4086..d86f0ad 100644 --- a/components/Message.vue +++ b/components/Message.vue @@ -1,5 +1,9 @@ + + \ No newline at end of file diff --git a/components/Settings/AppSettings/Appearance.vue b/components/Settings/AppSettings/Appearance.vue index a35e719..39e7410 100644 --- a/components/Settings/AppSettings/Appearance.vue +++ b/components/Settings/AppSettings/Appearance.vue @@ -17,11 +17,15 @@ -

ICONS

-
+ + +

TIME FORMAT

+
+
- -
@@ -70,6 +74,11 @@ async function fetchThemes() { } await fetchThemes() + + +async function onTimeFormatClicked(index: number) { + console.log(index) +} \ No newline at end of file From 890fbebbe9f3dd91d37ff605b1fc95aeaee1a2cc Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Sat, 12 Jul 2025 18:58:09 +0200 Subject: [PATCH 089/221] feat: use \ No newline at end of file From eb4945075646eb595404ad743b6d39be418dc728 Mon Sep 17 00:00:00 2001 From: JustTemmie <47639983+JustTemmie@users.noreply.github.com> Date: Sat, 12 Jul 2025 20:43:25 +0200 Subject: [PATCH 098/221] feat: support 12 and 24 hour formats --- components/Message.vue | 3 ++- components/MessageArea.vue | 2 +- utils/getPreferredTimeFormat.ts | 11 +++++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 utils/getPreferredTimeFormat.ts diff --git a/components/Message.vue b/components/Message.vue index a8329dd..db08258 100644 --- a/components/Message.vue +++ b/components/Message.vue @@ -46,7 +46,8 @@ Yesterday at {{ date.toLocaleDateString(undefined) }}, - {{ date.toLocaleTimeString(undefined, { timeStyle: "short" }) }} + + {{ date.toLocaleTimeString(undefined, { hour12: props.format=="12", timeStyle: "short" }) }}
diff --git a/components/MessageArea.vue b/components/MessageArea.vue index b2338f5..d59b862 100644 --- a/components/MessageArea.vue +++ b/components/MessageArea.vue @@ -49,7 +49,7 @@ const me = await fetchWithApi("/me") as UserResponse; const messageTimestamps = ref>({}); const messagesType = ref>({}); const messageGroupingMaxDifference = useRuntimeConfig().public.messageGroupingMaxDifference -const timeFormat = settingLoad("timeFormat") ?? "24" +const timeFormat = getPreferredTimeFormat() const messagesRes: MessageResponse[] | undefined = await fetchWithApi( `${props.channelUrl}/messages`, diff --git a/utils/getPreferredTimeFormat.ts b/utils/getPreferredTimeFormat.ts new file mode 100644 index 0000000..4cf03e0 --- /dev/null +++ b/utils/getPreferredTimeFormat.ts @@ -0,0 +1,11 @@ +export default (): "12" | "24" => { + const format = settingLoad("timeFormat").timeFormat ?? "auto" + + if (format == "12-hour") { + return "12" + } else if (format == "24-hour") { + return "24" + } + + return "24" +} \ No newline at end of file From 6221359a156f27e292dee3d1bcd65313d15fa89d Mon Sep 17 00:00:00 2001 From: SauceyRed Date: Sat, 12 Jul 2025 22:20:28 +0200 Subject: [PATCH 099/221] style(ui): move homebar to app.vue outside to avoid it being rerendered on route change --- app.vue | 7 +++++++ layouts/client.vue | 7 ------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app.vue b/app.vue index c4fd0dc..850f19a 100644 --- a/app.vue +++ b/app.vue @@ -1,5 +1,12 @@