Polish GUI #7

Merged
justtemmie merged 10 commits from GUI-polish into main 2025-07-03 17:18:25 +00:00
7 changed files with 196 additions and 13 deletions
Showing only changes of commit 692dd6d1c7 - Show all commits

View file

@ -0,0 +1,39 @@
<template>
<div class="member-item" @click="togglePopup" @blur="hidePopup" tabindex="0">
<img v-if="props.member.user.avatar" class="member-avatar" :src="props.member.user.avatar" :alt="props.member.user.display_name ?? props.member.user.username" />
<Icon v-else class="member-avatar" name="lucide:user" />
<span class="member-display-name">{{ props.member.user.display_name ?? props.member.user.username }}</span>
<UserPopup v-if="isPopupVisible" :user="props.member.user" class="profile-popup" />
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import type { GuildMemberResponse } from '~/types/interfaces';
import UserPopup from './UserPopup.vue';
const props = defineProps<{
member: GuildMemberResponse
}>();
const isPopupVisible = ref(false);
const togglePopup = () => {
isPopupVisible.value = !isPopupVisible.value;
};
const hidePopup = () => {
isPopupVisible.value = false;
};
</script>
<style>
.member-item {
position: relative; /* Set the position to relative for absolute positioning of the popup */
}
.profile-popup {
position: absolute; /* Use absolute positioning */
left: -100px; /* Adjust this value to position the popup to the left */
}
</style>

View file

@ -81,7 +81,7 @@ onMounted(async () => {
text-align: left;
/* border: 1px solid lightcoral; */
display: grid;
grid-template-columns: 2dvw 1fr;
grid-template-columns: 2rem 1fr;
align-items: center;
column-gap: 1dvw;
width: 100%;
@ -129,10 +129,11 @@ onMounted(async () => {
}
.left-column {
min-width: 2rem;
display: flex;
justify-content: center;
text-align: center;
white-space: nowrap;
}
.author-username {

20
components/UserArea.vue Normal file
View file

@ -0,0 +1,20 @@
<template>
<div id="user-panel">
HELLO!!
</div>
</template>
<script lang="ts" setup>
import type { UserResponse } from '~/types/interfaces';
const props = defineProps<{
user: UserResponse,
}>();
</script>
<style scoped>
#user-panel {
width: 100%;
}
</style>

View file

@ -1,6 +1,8 @@
<template>
<div id="profile-popup">
<img v-if="props.user.avatar" id="avatar" :src="props.user.avatar" alt="profile avatar">
<Icon v-else id="avatar" name="lucide:user" />
<div id="cover-colour"></div>
<div id="main-body">
<p id="display-name">

View file

@ -8,12 +8,12 @@
</div>
<div id="left-column">
<NuxtLink id="home-button" href="/">
<Icon name="lucide:house" class="white" size="2rem" />
<img class="sidebar-icon" src="/public/icon.svg"/>
</NuxtLink>
<div id="servers-list">
<NuxtLink v-for="guild of guilds" :href="`/servers/${guild.uuid}`">
<img v-if="guild.icon" class="server-icon" :src="guild.icon" :alt="guild.name"/>
<Icon v-else name="lucide:server" class="server-icon white" :alt="guild.name" />
<img v-if="guild.icon" class="sidebar-icon" :src="guild.icon" :alt="guild.name"/>
<Icon v-else name="lucide:server" class="sidebar-icon white" :alt="guild.name" />
</NuxtLink>
</div>
</div>
@ -77,7 +77,7 @@ const guilds: GuildResponse[] | undefined = await fetchWithApi("/me/guilds");
padding-right: .5dvw;
}
.server-icon {
.sidebar-icon {
width: 3rem;
height: 3rem;
}

View file

@ -26,11 +26,7 @@
<MessageArea :channel-url="channelUrlPath" />
<div id="members-container">
<div id="members-list">
<div class="member-item" v-for="member of members" tabindex="0">
<img v-if="member.user.avatar" class="member-avatar" :src="member.user.avatar" :alt="member.user.display_name ?? member.user.username" />
<Icon v-else class="member-avatar" name="lucide:user" />
<span class="member-display-name">{{ member.user.display_name ?? member.user.username }}</span>
</div>
<MemberEntry v-for="member of members" :member="member" tabindex="0"/>
</div>
</div>
</NuxtLayout>
@ -50,7 +46,8 @@ const channel = ref<ChannelResponse | undefined>();
const showInvitePopup = ref(false);
import type { ChannelResponse, GuildResponse, MessageResponse } from "~/types/interfaces";
import UserPopup from "~/components/UserPopup.vue";
import type { ChannelResponse, GuildMemberResponse, GuildResponse, MessageResponse } from "~/types/interfaces";
//const servers = await fetchWithApi("/servers") as { uuid: string, name: string, description: string }[];
//console.log("channelid: servers:", servers);
@ -78,6 +75,9 @@ function toggleInvitePopup(e: Event) {
e.preventDefault();
showInvitePopup.value = !showInvitePopup.value;
}
function handleMemberClick(member: GuildMemberResponse) {
}
</script>
<style>
@ -112,7 +112,7 @@ function toggleInvitePopup(e: Event) {
gap: 1em;
align-items: center;
text-align: left;
cursor: pointer;
}
#channels-list {

121
public/icon.svg Normal file
View file

@ -0,0 +1,121 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="512"
height="512"
viewBox="0 0 512 512"
version="1.1"
id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="drawing.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="0.35399828"
inkscape:cx="2.8248725"
inkscape:cy="731.64198"
inkscape:window-width="1440"
inkscape:window-height="863"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="matrix(0.93746412,0,0,0.93746412,18.749279,18.749282)">
<g
id="g1543"
style="display:inline"
transform="matrix(3.7794744,0,0,3.7794744,-150.52528,-298.33565)">
<circle
style="fill:#000000;stroke-width:0.264583"
id="path60"
cx="106.78797"
cy="145.89536"
r="72.25267" />
<circle
style="fill:#f4741f;fill-opacity:1;stroke-width:0.257596"
id="path899"
cx="106.78797"
cy="145.89536"
r="65.485863" />
</g>
<g
id="g1460-1"
transform="matrix(4.1481001,0,0,4.1481002,45.149918,-354.52402)"
style="display:inline">
<circle
style="fill:#000000;fill-opacity:1;stroke-width:0.29496"
id="path1129-3"
cx="78.140816"
cy="136.65092"
r="17.372646" />
<circle
style="fill:#f4741f;fill-opacity:1;stroke-width:0.294225"
id="path1354-0"
cx="86.078323"
cy="136.65092"
r="11.576728" />
</g>
<g
id="g1460-1-3"
transform="matrix(4.1481001,0,0,4.1481002,-187.26754,-354.52402)"
style="display:inline">
<circle
style="fill:#000000;fill-opacity:1;stroke-width:0.29496"
id="path1129-3-4"
cx="78.140816"
cy="136.65092"
r="17.372646" />
<circle
style="fill:#f4741f;fill-opacity:1;stroke-width:0.294225"
id="path1354-0-6"
cx="86.078323"
cy="136.65092"
r="11.576728" />
</g>
<g
id="g3530"
transform="matrix(3.7794744,0,0,3.7794744,-150.52528,-294.3357)">
<path
style="fill:none;stroke:#000000;stroke-width:7;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 106.78797,168.1205 c 0,0 -17.461156,15.02392 -28.153795,0.49121"
id="path1817" />
<path
style="fill:none;stroke:#000000;stroke-width:7;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 106.78797,168.1205 c 0,0 17.46116,15.02392 28.15379,0.49121"
id="path1817-6" />
<path
style="fill:none;stroke:#000000;stroke-width:7;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 106.78797,168.1205 -5.74494,-9.7603"
id="path2191"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:7;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 106.78797,168.1205 5.74494,-9.7603"
id="path2191-6"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:7;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 101.04303,158.3602 h 11.48988"
id="path2675"
sodipodi:nodetypes="cc" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB