+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -42,6 +52,7 @@ import { ModalBase } from '#components';
import { render } from 'vue';
import GuildDropdown from '~/components/Guild/GuildDropdown.vue';
import Button from '~/components/UserInterface/Button.vue';
+import VerticalSpacer from '~/components/UserInterface/VerticalSpacer.vue';
import type { GuildResponse } from '~/types/interfaces';
const loading = useState("loading", () => false);
@@ -243,68 +254,29 @@ function createDropdown() {
#left-column {
display: flex;
flex-direction: column;
- justify-content: space-between;
- align-items: center;
- 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);
}
-#left-column-top, #left-column-bottom {
+.left-column-segment {
display: flex;
flex-direction: column;
- justify-content: center;
- align-items: center;
- gap: 1.5dvh;
- overflow-y: scroll;
+
scrollbar-width: none;
- -ms-overflow-style: none;
}
-#left-column-top::-webkit-scrollbar, #left-column-bottom::-webkit-scrollbar {
+.left-column-segment::-webkit-scrollbar {
display: none;
}
-#left-column-bottom {
- padding-top: 1dvh;
- border-top: 1px solid var(--padding-color);
-}
-
-#middle-left-column {
- padding-left: 1dvw;
- padding-right: 1dvw;
- border-right: 1px solid var(--padding-color);
-}
-
-#home-button {
- border-bottom: 1px solid var(--padding-color);
- padding-bottom: 1dvh;
-}
-
-#servers-list {
- display: flex;
- flex-direction: column;
- gap: 1em;
- width: 3.2rem;
- padding-top: .5em;
-}
-
-#create-button {
- color: var(--primary-color);
- background-color: transparent;
- border: none;
- cursor: pointer;
- font-size: 2rem;
- padding: 0;
- display: inline-block;
-}
-
-#create-icon {
- float: left;
+#left-column-middle {
+ overflow-y: scroll;
+ flex-grow: 1;
}
#middle-left-column {
@@ -317,24 +289,27 @@ function createDropdown() {
overflow-x: hidden;
}
+#home-button {
+ height: 3em;
+}
+
.sidebar-icon {
width: 3rem;
height: 3rem;
- overflow-y: scroll;
- overflow-x: hidden;
}
-#home-button {
- border-bottom: 1px solid var(--padding-color);
- padding-bottom: .375em;
+.sidebar-bottom-buttons {
+ color: var(--primary-color);
+ background-color: transparent;
+ border: none;
+ cursor: pointer;
+ font-size: 2.4rem;
+ padding: 0;
+ display: inline-block;
}
-#settings-menu {
- color: var(--primary-color)
-}
-
-#settings-menu:hover {
- color: var(--primary-highlighted-color)
+.sidebar-bottom-buttons:hover {
+ color: var(--primary-highlighted-color);
}
diff --git a/public/themes/ash.css b/public/themes/ash.css
index 63aaa53..3f27868 100644
--- a/public/themes/ash.css
+++ b/public/themes/ash.css
@@ -11,6 +11,11 @@
--chatbox-background-color: #3a3733;
--padding-color: #e0e0e0;
+
+ --sidebar-width: 3em;
+ --standard-radius: .5em;
+ --button-radius: .6em;
+ --pfp-radius: 100%;
--primary-color: #f07028;
--primary-highlighted-color: #f28f4b;
diff --git a/public/themes/dark.css b/public/themes/dark.css
index 3673d4c..d03f07f 100644
--- a/public/themes/dark.css
+++ b/public/themes/dark.css
@@ -18,4 +18,9 @@
--secondary-highlighted-color: #8f5b2c;
--accent-color: #b35719;
--accent-highlighted-color: #c76a2e;
+
+ --sidebar-width: 3em;
+ --standard-radius: .5em;
+ --button-radius: .6em;
+ --pfp-radius: 100%;
}
\ No newline at end of file
diff --git a/public/themes/description.css b/public/themes/description.css
index 209fb36..91f6e7f 100644
--- a/public/themes/description.css
+++ b/public/themes/description.css
@@ -20,6 +20,11 @@
--accent-color: #ff218c80;
--accent-highlighted-color: #df1b6f80;
+ --sidebar-width: 3em;
+ --standard-radius: .5em;
+ --button-radius: .6em;
+ --pfp-radius: 100%;
+
--optional-body-background: ; /* background element for the body */
--optional-chat-background: ; /* background element for the chat box */
--optional-topbar-background: ; /* background element for the topbar */
diff --git a/public/themes/light.css b/public/themes/light.css
index fdd4756..44e5318 100644
--- a/public/themes/light.css
+++ b/public/themes/light.css
@@ -11,6 +11,11 @@
--chatbox-background-color: #dfdbd6;
--padding-color: #484848;
+
+ --sidebar-width: 3em;
+ --standard-radius: .5em;
+ --button-radius: .6em;
+ --pfp-radius: 100%;
--primary-color: #df5f0b;
--primary-highlighted-color: #ef6812;
diff --git a/public/themes/rainbow-capitalism.css b/public/themes/rainbow-capitalism.css
index 0e146d9..0fe2287 100644
--- a/public/themes/rainbow-capitalism.css
+++ b/public/themes/rainbow-capitalism.css
@@ -19,6 +19,11 @@
--accent-color: #ff218c80;
--accent-highlighted-color: #df1b6f80;
+ --sidebar-width: 3em;
+ --standard-radius: .5em;
+ --button-radius: .6em;
+ --pfp-radius: 100%;
+
/* --optional-body-background: background */
--optional-body-background: linear-gradient(45deg, #ed222480, #ed222480, #ed222480, #ed222480, #ed222480, #ed222480, #f35b2280, #f9962180, #f5c11e80, #f1eb1b80, #f1eb1b80, #f1eb1b80, #63c72080, #0c9b4980, #21878d80, #3954a580, #61379b80, #93288e80);
--optional-topbar-background: linear-gradient(-12.5deg, cyan, pink, white, pink, cyan);
From 06de4777f96c99b4ef90fcda7408c49dc2f4fa5b Mon Sep 17 00:00:00 2001
From: JustTemmie <47639983+JustTemmie@users.noreply.github.com>
Date: Mon, 14 Jul 2025 19:36:16 +0200
Subject: [PATCH 05/32] feat: make sidebar size adjustable by theme
---
layouts/client.vue | 14 +++-----------
public/themes/ash.css | 2 +-
public/themes/dark.css | 2 +-
public/themes/description.css | 2 +-
public/themes/light.css | 2 +-
public/themes/rainbow-capitalism.css | 2 +-
6 files changed, 8 insertions(+), 16 deletions(-)
diff --git a/layouts/client.vue b/layouts/client.vue
index e5d7907..f76b285 100644
--- a/layouts/client.vue
+++ b/layouts/client.vue
@@ -21,14 +21,6 @@
-
-
-
-
-
-
-
-
@@ -290,12 +282,12 @@ function createDropdown() {
}
#home-button {
- height: 3em;
+ height: var(--sidebar-width);
}
.sidebar-icon {
- width: 3rem;
- height: 3rem;
+ width: var(--sidebar-width);
+ height: var(--sidebar-width);
}
.sidebar-bottom-buttons {
diff --git a/public/themes/ash.css b/public/themes/ash.css
index 3f27868..d1f09c8 100644
--- a/public/themes/ash.css
+++ b/public/themes/ash.css
@@ -12,7 +12,7 @@
--padding-color: #e0e0e0;
- --sidebar-width: 3em;
+ --sidebar-width: 2.5em;
--standard-radius: .5em;
--button-radius: .6em;
--pfp-radius: 100%;
diff --git a/public/themes/dark.css b/public/themes/dark.css
index d03f07f..6160194 100644
--- a/public/themes/dark.css
+++ b/public/themes/dark.css
@@ -19,7 +19,7 @@
--accent-color: #b35719;
--accent-highlighted-color: #c76a2e;
- --sidebar-width: 3em;
+ --sidebar-width: 2.5em;
--standard-radius: .5em;
--button-radius: .6em;
--pfp-radius: 100%;
diff --git a/public/themes/description.css b/public/themes/description.css
index 91f6e7f..f3738a5 100644
--- a/public/themes/description.css
+++ b/public/themes/description.css
@@ -20,7 +20,7 @@
--accent-color: #ff218c80;
--accent-highlighted-color: #df1b6f80;
- --sidebar-width: 3em;
+ --sidebar-width: 2.5em;
--standard-radius: .5em;
--button-radius: .6em;
--pfp-radius: 100%;
diff --git a/public/themes/light.css b/public/themes/light.css
index 44e5318..d11f5f5 100644
--- a/public/themes/light.css
+++ b/public/themes/light.css
@@ -12,7 +12,7 @@
--padding-color: #484848;
- --sidebar-width: 3em;
+ --sidebar-width: 2.5em;
--standard-radius: .5em;
--button-radius: .6em;
--pfp-radius: 100%;
diff --git a/public/themes/rainbow-capitalism.css b/public/themes/rainbow-capitalism.css
index 0fe2287..1a5197b 100644
--- a/public/themes/rainbow-capitalism.css
+++ b/public/themes/rainbow-capitalism.css
@@ -19,7 +19,7 @@
--accent-color: #ff218c80;
--accent-highlighted-color: #df1b6f80;
- --sidebar-width: 3em;
+ --sidebar-width: 2.5em;
--standard-radius: .5em;
--button-radius: .6em;
--pfp-radius: 100%;
From 9bfe3310ccd4334e45436a79881c417e98c360c1 Mon Sep 17 00:00:00 2001
From: JustTemmie <47639983+JustTemmie@users.noreply.github.com>
Date: Mon, 14 Jul 2025 19:48:35 +0200
Subject: [PATCH 06/32] fix: comply with es2020 standards
---
utils/generateIrcColor.ts | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/utils/generateIrcColor.ts b/utils/generateIrcColor.ts
index d2ed643..24d4946 100644
--- a/utils/generateIrcColor.ts
+++ b/utils/generateIrcColor.ts
@@ -1,6 +1,9 @@
import xxhash from "xxhash-wasm"
-const { h64 } = await xxhash()
+let h64: CallableFunction;
+(async () => {
+ h64 = (await xxhash()).h64;
+})();
export default (seed: string): string => {
const lightness = 50
From 25cd9a397e5ef5a7cb9396fe5e0ad1d7ec9e3fd7 Mon Sep 17 00:00:00 2001
From: JustTemmie <47639983+JustTemmie@users.noreply.github.com>
Date: Mon, 14 Jul 2025 20:05:31 +0200
Subject: [PATCH 07/32] feat: implement caching for hash function
---
utils/generateIrcColor.ts | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/utils/generateIrcColor.ts b/utils/generateIrcColor.ts
index 24d4946..03a30e7 100644
--- a/utils/generateIrcColor.ts
+++ b/utils/generateIrcColor.ts
@@ -5,11 +5,9 @@ let h64: CallableFunction;
h64 = (await xxhash()).h64;
})();
-export default (seed: string): string => {
- const lightness = 50
-
- // this should probably be cached eventually
- const idHash = h64(seed)
+export default (seed: string, saturation: number = 100, lightness: number = 50): string => {
+ const idHash = useState(`h64Hash-${seed}`, () => h64(seed))
+ const hashValue: bigint = idHash.value
- return `hsl(${idHash % 360n}, 100%, ${lightness}%)`
+ return `hsl(${hashValue % 360n}, ${saturation}%, ${lightness}%)`
}
\ No newline at end of file
From b319a06749199d4baab0e9c085592b33ba0b6bec Mon Sep 17 00:00:00 2001
From: JustTemmie <47639983+JustTemmie@users.noreply.github.com>
Date: Mon, 14 Jul 2025 21:36:41 +0200
Subject: [PATCH 08/32] feat: import function from JOHN OZBAY
---
utils/isCanvasBlocked.ts | 50 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 50 insertions(+)
create mode 100644 utils/isCanvasBlocked.ts
diff --git a/utils/isCanvasBlocked.ts b/utils/isCanvasBlocked.ts
new file mode 100644
index 0000000..3bd191e
--- /dev/null
+++ b/utils/isCanvasBlocked.ts
@@ -0,0 +1,50 @@
+//
+// Canvas Blocker &
+// Firefox privacy.resistFingerprinting Detector.
+// (c) 2018 // JOHN OZBAY // CRYPT.EE
+// MIT License
+//
+export default () => {
+ // create a 1px image data
+ var blocked = false;
+ var canvas = document.createElement("canvas");
+ var ctx = canvas.getContext("2d");
+
+ // some blockers just return an undefined ctx. So let's check that first.
+ if (ctx) {
+ var imageData = ctx.createImageData(1,1);
+ var originalImageData = imageData.data;
+
+ // set pixels to RGB 128
+ originalImageData[0]=128;
+ originalImageData[1]=128;
+ originalImageData[2]=128;
+ originalImageData[3]=255;
+
+ // set this to canvas
+ ctx.putImageData(imageData,1,1);
+
+ try {
+ // now get the data back from canvas.
+ var checkData = ctx.getImageData(1, 1, 1, 1).data;
+
+ // If this is firefox, and privacy.resistFingerprinting is enabled,
+ // OR a browser extension blocking the canvas,
+ // This will return RGB all white (255,255,255) instead of the (128,128,128) we put.
+
+ // so let's check the R and G to see if they're 255 or 128 (matching what we've initially set)
+ if (originalImageData[0] !== checkData[0] && originalImageData[1] !== checkData[1]) {
+ blocked = true;
+ console.log("Canvas is blocked. Will display warning.");
+ }
+ } catch (error) {
+ // some extensions will return getImageData null. this is to account for that.
+ blocked = true;
+ console.log("Canvas is blocked. Will display warning.");
+ }
+ } else {
+ blocked = true;
+ console.log("Canvas is blocked. Will display warning.");
+ }
+ return blocked;
+}
\ No newline at end of file
From f4ddcf9d8db61d4c4704514de43cbe186fde9ac8 Mon Sep 17 00:00:00 2001
From: JustTemmie <47639983+JustTemmie@users.noreply.github.com>
Date: Mon, 14 Jul 2025 21:37:45 +0200
Subject: [PATCH 09/32] fix: prop
---
types/props.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/types/props.ts b/types/props.ts
index fe2b049..9a8e642 100644
--- a/types/props.ts
+++ b/types/props.ts
@@ -3,7 +3,7 @@ import type { MessageResponse, UserResponse } from "./interfaces";
export interface MessageProps {
class?: string,
img?: string | null,
- author?: UserResponse
+ author: UserResponse
text: string,
timestamp: number,
format: "12" | "24",
From f98e8c611092e747e267afd029cf87eeebf21cca Mon Sep 17 00:00:00 2001
From: JustTemmie <47639983+JustTemmie@users.noreply.github.com>
Date: Mon, 14 Jul 2025 21:39:00 +0200
Subject: [PATCH 10/32] feat: implement generic
component
---
components/Avatar.vue | 37 ++++++++++++++++++++++++++++++++++
components/User/UserEntry.vue | 8 +++++---
components/User/UserPopup.vue | 3 +--
layouts/client.vue | 2 +-
utils/generateDefaultIcon.ts | 38 +++++++++++++++++++++++++++++++++++
5 files changed, 82 insertions(+), 6 deletions(-)
create mode 100644 components/Avatar.vue
create mode 100644 utils/generateDefaultIcon.ts
diff --git a/components/Avatar.vue b/components/Avatar.vue
new file mode 100644
index 0000000..368316c
--- /dev/null
+++ b/components/Avatar.vue
@@ -0,0 +1,37 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/components/User/UserEntry.vue b/components/User/UserEntry.vue
index b463759..b539f2c 100644
--- a/components/User/UserEntry.vue
+++ b/components/User/UserEntry.vue
@@ -1,8 +1,8 @@
-
-
- {{ props.user.display_name || props.user.username }}
+
+
+ {{ displayName }}
@@ -12,6 +12,8 @@ import type { UserResponse } from '~/types/interfaces';
const props = defineProps<{
user: UserResponse
}>();
+
+const displayName = props.user.display_name || props.user.username
\ No newline at end of file
diff --git a/components/Message.vue b/components/Message.vue
index 166f99d..ce726fb 100644
--- a/components/Message.vue
+++ b/components/Message.vue
@@ -225,7 +225,6 @@ function getDayDifference(date1: Date, date2: Date) {
.message-author-avatar {
width: 100%;
- border-radius: 50%;
}
.left-column {
diff --git a/components/User/UserEntry.vue b/components/User/UserEntry.vue
index b539f2c..1817816 100644
--- a/components/User/UserEntry.vue
+++ b/components/User/UserEntry.vue
@@ -37,6 +37,5 @@ const displayName = props.user.display_name || props.user.username
.user-avatar {
width: 2.3em;
height: 2.3em;
- border-radius: 50%;
}
diff --git a/layouts/client.vue b/layouts/client.vue
index 112440d..2ed9e8c 100644
--- a/layouts/client.vue
+++ b/layouts/client.vue
@@ -19,16 +19,16 @@
@@ -259,8 +259,8 @@ function createDropdown() {
display: flex;
flex-direction: column;
- padding-left: .25em;
- padding-right: .25em;
+ padding-left: var(--sidebar-margin);
+ padding-right: var(--sidebar-margin);
padding-top: .5em;
background: var(--optional-sidebar-background);
@@ -281,6 +281,7 @@ function createDropdown() {
#left-column-middle {
overflow-y: scroll;
flex-grow: 1;
+ gap: var(--sidebar-icon-gap);
}
#middle-left-column {
@@ -294,12 +295,16 @@ function createDropdown() {
}
#home-button {
- height: var(--sidebar-width);
+ height: var(--sidebar-icon-width);
+}
+
+.guild-icon {
+ border-radius: var(--guild-icon-radius);
}
.sidebar-icon {
- width: var(--sidebar-width);
- height: var(--sidebar-width);
+ width: var(--sidebar-icon-width);
+ height: var(--sidebar-icon-width);
}
.sidebar-bottom-buttons {
diff --git a/public/themes/ash.css b/public/themes/ash.css
index 7a6b7a4..94f5e85 100644
--- a/public/themes/ash.css
+++ b/public/themes/ash.css
@@ -22,6 +22,7 @@
--sidebar-width: 2.5em;
--standard-radius: .5em;
--button-radius: .6em;
- --pfp-radius: 100%;
+ --guild-icon-radius: 20%;
+ --pfp-radius: 50%;
--preferred-font: Arial;
}
\ No newline at end of file
diff --git a/public/themes/dark.css b/public/themes/dark.css
index 59099c7..a228889 100644
--- a/public/themes/dark.css
+++ b/public/themes/dark.css
@@ -19,9 +19,13 @@
--accent-color: #b35719;
--accent-highlighted-color: #c76a2e;
- --sidebar-width: 2.5em;
+ --sidebar-icon-width: 2.5em;
+ --sidebar-icon-gap: .25em;
+ --sidebar-margin: .5em;
+
--standard-radius: .5em;
--button-radius: .6em;
- --pfp-radius: 100%;
+ --guild-icon-radius: 15%;
+ --pfp-radius: 50%;
--preferred-font: Arial;
}
\ No newline at end of file
diff --git a/public/themes/description.css b/public/themes/description.css
index 57ade55..e30025f 100644
--- a/public/themes/description.css
+++ b/public/themes/description.css
@@ -23,7 +23,7 @@
--sidebar-width: 2.5em;
--standard-radius: .5em;
--button-radius: .6em;
- --pfp-radius: 100%;
+ --pfp-radius: 50%;
--preferred-font: Arial;
--optional-body-background: ; /* background element for the body */
diff --git a/public/themes/light.css b/public/themes/light.css
index 0b24214..556b64d 100644
--- a/public/themes/light.css
+++ b/public/themes/light.css
@@ -22,6 +22,6 @@
--sidebar-width: 2.5em;
--standard-radius: .5em;
--button-radius: .6em;
- --pfp-radius: 100%;
+ --pfp-radius: 50%;
--preferred-font: Arial;
}
\ No newline at end of file
diff --git a/public/themes/rainbow-capitalism.css b/public/themes/rainbow-capitalism.css
index c1c8246..ca73e1f 100644
--- a/public/themes/rainbow-capitalism.css
+++ b/public/themes/rainbow-capitalism.css
@@ -22,7 +22,7 @@
--sidebar-width: 2.5em;
--standard-radius: .5em;
--button-radius: .6em;
- --pfp-radius: 100%;
+ --pfp-radius: 50%;
--preferred-font: Arial;
/* --optional-body-background: background */
From 4ce89d980348eca29b0734ebb4c07a2334d760e0 Mon Sep 17 00:00:00 2001
From: SauceyRed
Date: Tue, 15 Jul 2025 11:24:27 +0200
Subject: [PATCH 22/32] feat: update wording of guild create/join button's alt
text
---
layouts/client.vue | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/layouts/client.vue b/layouts/client.vue
index f76b285..0018e8c 100644
--- a/layouts/client.vue
+++ b/layouts/client.vue
@@ -26,7 +26,7 @@