Version 1.0.0 - Finalisation du composant Servers
This commit is contained in:
1450
package-lock.json
generated
1450
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite --host --port 8080",
|
||||
"build": "vue-tsc -b && vite build"
|
||||
"build": "vite build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
||||
@@ -20,5 +20,8 @@
|
||||
"vite": "^7.0.5",
|
||||
"vue": "^3.2.13",
|
||||
"vue-router": "^4.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite-plugin-vue-devtools": "^7.7.7"
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,16 @@
|
||||
<template>
|
||||
<div>
|
||||
<img :src="`https://cdn.discordapp.com/avatars/${userId}/${avatarUrl}`" alt='User Avatar'>
|
||||
<Icon v-if="tag === 'admin'" style="color: var(--main);" icon="fa-solid fa-star" class="tag" />
|
||||
<Icon v-if="tag === 'owner'" style="color: #FFAA32;" icon="fa-solid fa-crown" class="tag" />
|
||||
<Icon v-if="tag === 'mod'" style="color: #0BFF89;" icon="fa-solid fa-shield-halved" class="tag" />
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
userId: {
|
||||
type: String,
|
||||
@@ -10,8 +19,28 @@ const props = defineProps({
|
||||
avatarUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
isMod: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isOwner: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isAdmin: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
const tag = computed(() => {
|
||||
if (props.isAdmin) return 'admin';
|
||||
if (props.isOwner) return 'owner';
|
||||
if (props.isMod) return 'mod';
|
||||
return '';
|
||||
});
|
||||
|
||||
</script>
|
||||
<style scoped>
|
||||
img {
|
||||
@@ -19,5 +48,21 @@ img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
object-fit: cover;
|
||||
background-color: var(--main);
|
||||
}
|
||||
|
||||
div {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.tag {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
font-size: 0.8em;
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
padding: 2px 5px;
|
||||
}
|
||||
</style>
|
16
src/components/UI/Circle.vue
Normal file
16
src/components/UI/Circle.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<div><slot></slot></div>
|
||||
|
||||
</template>
|
||||
<style scoped>
|
||||
div {
|
||||
border-radius: 100%;
|
||||
background-color: var(--secondary);
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
</style>
|
@@ -1,16 +1,16 @@
|
||||
<template>
|
||||
<img v-if="serverIcon" :src="`https://cdn.discordapp.com/icons/${serverId}/${serverIcon}.png?`" />
|
||||
<img v-if="src" :src="src" />
|
||||
<img v-else :src="`https://cdn.discordapp.com/embed/avatars/${serverId % 5}.png`" />
|
||||
</template>
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
src: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
serverId: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
serverIcon: {
|
||||
type: String,
|
||||
default: ''
|
||||
default: null
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -18,7 +18,7 @@
|
||||
img {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
border-radius: 10px;
|
||||
background-color: var(--secondary);
|
||||
border-radius: 15px;
|
||||
background-color: var(--main);
|
||||
}
|
||||
</style>
|
@@ -2,14 +2,14 @@
|
||||
<Box no-shadow level="second" padding="closed">
|
||||
<div class="container-list">
|
||||
<div class="container-avatar">
|
||||
<ServerAvatar :server-id="server.id" :server-icon="server.icon"/>
|
||||
<ServerAvatar :server-id="server.id" :src="server.icon"/>
|
||||
<div class="info">
|
||||
<p class="name">{{ server.name }}</p>
|
||||
<p class="data"><Icon style="font-size: 10px;" :color="server.connected ? '#0BFF89' : '#FF0A0A'" icon="fa-solid fa-circle"/> {{ server.connected ? 'En ligne' : 'Hors ligne' }} - {{ server.serverMember }} membres</p>
|
||||
</div>
|
||||
</div>
|
||||
<Button @click="access()">Accéder</Button>
|
||||
|
||||
<ServerOnlinePicture class="sop" :key="server.id" v-if="server.members.length > 0" :members="server.members"/>
|
||||
<Button class="btn" @click="access()">Accéder</Button>
|
||||
</div>
|
||||
</Box>
|
||||
</template>
|
||||
@@ -20,6 +20,7 @@ import Button from '../UI/Button.vue';
|
||||
import IconAction from '../UI/IconAction.vue';
|
||||
import { useGlobalStore } from '@/stores/globalStore';
|
||||
import { useRouter } from 'vue-router';
|
||||
import ServerOnlinePicture from '@/components/Widget/ServerOnlinePicture.vue';
|
||||
const router = useRouter();
|
||||
|
||||
const globalStore = useGlobalStore();
|
||||
@@ -57,6 +58,23 @@ function access() {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.container-list {
|
||||
flex-direction: column;
|
||||
gap: 20px;;
|
||||
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sop {
|
||||
display: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.container-list {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
42
src/components/Widget/ServerOnlinePicture.vue
Normal file
42
src/components/Widget/ServerOnlinePicture.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<div>
|
||||
<Avatar v-for="member in members"
|
||||
:key="member.id"
|
||||
:user-id="member.id"
|
||||
:avatar-url="member.avatar"
|
||||
:isMod="member.isMod"
|
||||
:isOwner="member.isOwner"
|
||||
:isAdmin="member.isAdmin"
|
||||
:class="`avatar`"/>
|
||||
|
||||
<Circle style="z-index: 10;" class="avatar" v-if="length > 4">+ {{ length - 4}}</Circle>
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
<script setup>
|
||||
import Avatar from '../UI/Avatar.vue';
|
||||
import Circle from '../UI/Circle.vue';
|
||||
|
||||
const props = defineProps({
|
||||
members: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
})
|
||||
|
||||
// ne garder que les quatres premiers membres
|
||||
const length = props.members.length;
|
||||
const members = props.members.slice(0, 4);
|
||||
|
||||
</script>
|
||||
<style scoped>
|
||||
div{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
margin-left: -10px; /* Ajustez cette valeur pour contrôler le chevauchement */
|
||||
}
|
||||
</style>
|
@@ -2,6 +2,7 @@
|
||||
import DefaultSplash from '@/components/Layout/DefaultSplash.vue';
|
||||
|
||||
const defaultMessage = "On s'accorde et on prépare le concert !";
|
||||
const connectMsg = "Erreur de connexion au serveur : xhr poll error"
|
||||
|
||||
const props = defineProps({
|
||||
interuptionMessage: {
|
||||
@@ -15,8 +16,12 @@ const props = defineProps({
|
||||
<template>
|
||||
<DefaultSplash>
|
||||
<h1 v-if="!interuptionMessage" class="separate"><Icon spin-pulse icon="fa-solid fa-spinner"/> Chargement de l'interface</h1>
|
||||
<h1 v-else-if="interuptionMessage == connectMsg">Echec de connexion</h1>
|
||||
<h1 v-else><Icon icon="fa-solid fa-warning"/> Connexion interrompue</h1>
|
||||
<div class="separate-col">
|
||||
<p v-if="interuptionMessage" class="retry"><Icon spin-pulse icon="fa-solid fa-spinner"/> Tentative de reconnexion en cours</p>
|
||||
<p v-if="interuptionMessage" class="second">Contactez Raphix (raphixscrap) en cas de problème prolongé.</p>
|
||||
</div>
|
||||
<p v-if="interuptionMessage" class="error"><Icon icon="fa-solid fa-circle-xmark"/> {{ interuptionMessage }}</p>
|
||||
<p v-else>{{ defaultMessage }}</p>
|
||||
</DefaultSplash>
|
||||
@@ -37,4 +42,22 @@ const props = defineProps({
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.separate-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
|
||||
}
|
||||
|
||||
.separate-col p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.second {
|
||||
font-size: 0.8em;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
</style>
|
@@ -75,13 +75,16 @@ import { useGlobalStore } from '@/stores/globalStore';
|
||||
interuptionMessage.value = null;
|
||||
return;
|
||||
}
|
||||
setInterval(() => {
|
||||
const intervalId = setInterval(() => {
|
||||
console.log("Tentative de reconnexion au serveur...");
|
||||
if(!socket.connected || !needReload.value) {
|
||||
socket.auth.token = loginStore.token;
|
||||
socket.disconnect()
|
||||
// Avoid multiple connections attempts at the same time
|
||||
socket.connect();
|
||||
} else {
|
||||
clearInterval(this);
|
||||
console.log("Already connected, no need to reconnect.");
|
||||
clearInterval(intervalId);
|
||||
}
|
||||
}, 3000); // Essai de reconnexion après 5 secondes
|
||||
}
|
||||
|
@@ -21,8 +21,8 @@ import { watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useGlobalStore } from '@/stores/globalStore';
|
||||
import { useUserStore } from '@/stores/userStore';
|
||||
import { IOListener } from '@/utils/IORequest';
|
||||
import { onMounted } from 'vue';
|
||||
import { IOListener, IORequest } from '@/utils/IORequest';
|
||||
import { onMounted, ref } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
guildId: {
|
||||
@@ -40,9 +40,10 @@ if (!guildId) {
|
||||
const globalStore = useGlobalStore();
|
||||
const userStore = useUserStore();
|
||||
const router = useRouter();
|
||||
const alreadyLoaded = ref(false);
|
||||
|
||||
watch(() => globalStore.isLoading, (value) => {
|
||||
if(!value) {
|
||||
watch(() => globalStore.isLoading, (value, oldValue) => {
|
||||
if(!value && oldValue != value) {
|
||||
loadInteface();
|
||||
}
|
||||
})
|
||||
@@ -53,19 +54,42 @@ onMounted(() => {
|
||||
}
|
||||
});
|
||||
|
||||
watch(() => userStore.userInfo, (newValue, oldValue) => {
|
||||
if(userStore.userInfo) {
|
||||
checkGuildAvailability();
|
||||
}
|
||||
}, { immediate: true });
|
||||
|
||||
function loadInteface() {
|
||||
if(alreadyLoaded.value) return;
|
||||
console.log("Loading interface")
|
||||
console.log("Guild ID:", guildId);
|
||||
checkGuildAvailability();
|
||||
|
||||
IORequest("/USERS/LIST", (data) => {
|
||||
console.log("User list received:", data);
|
||||
})
|
||||
|
||||
alreadyLoaded.value = true;
|
||||
}
|
||||
|
||||
function checkGuildAvailability() {
|
||||
console.log("Checking guild availability for ID:", guildId);
|
||||
if(userStore.userInfo.guilds.filter(guild => guild.id === guildId).length === 0) {
|
||||
globalStore.setLastGuild(null);
|
||||
console.warn("Guild not found, redirecting to servers list.");
|
||||
router.push('/servers');
|
||||
} else {
|
||||
globalStore.setLastGuild(guildId);
|
||||
IORequest("/GUILD/JOIN", (response) => {
|
||||
if(response === true) {
|
||||
console.log("Successfully joined guild:", guildId);
|
||||
} else {
|
||||
console.error("Failed to join guild:", response);
|
||||
globalStore.setLastGuild(null);
|
||||
router.push('/servers');
|
||||
}
|
||||
}, guildId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import ReturnHomeButton from '@/components/Actions/ReturnHomeButton.vue';
|
||||
import ReturnHomeButton from '@/components/Widget/ReturnHomeButton.vue';
|
||||
import DefaultSplash from '@/components/Layout/DefaultSplash.vue';
|
||||
import Box from '@/components/UI/Box.vue';
|
||||
import Button from '@/components/UI/Button.vue';
|
||||
|
@@ -7,9 +7,10 @@ import { useRouter } from 'vue-router';
|
||||
import { useGlobalStore } from '@/stores/globalStore';
|
||||
import { useUserStore } from '@/stores/userStore';
|
||||
import Button from '@/components/UI/Button.vue';
|
||||
import ReturnHomeButton from '@/components/Actions/ReturnHomeButton.vue';
|
||||
import ReturnHomeButton from '@/components/Widget/ReturnHomeButton.vue';
|
||||
import { ref } from 'vue';
|
||||
import ServerListItem from '@/components/Features/ServerListItem.vue';
|
||||
import ServerListItem from '@/components/Widget/ServerListItem.vue';
|
||||
import Info from '@/components/UI/Info.vue';
|
||||
|
||||
const globalStore = useGlobalStore();
|
||||
const userStore = useUserStore();
|
||||
@@ -36,6 +37,8 @@ function inviteSubsonics() {
|
||||
window.open(botInviteUrl.value, '_blank');
|
||||
}
|
||||
|
||||
// Vérifier RaphX pourquoi ca plante !
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -47,8 +50,8 @@ function inviteSubsonics() {
|
||||
<div class="servers-content">
|
||||
<div class="servers-container">
|
||||
<div class="servers-list">
|
||||
<ServerListItem v-for="server in userStore.userInfo.guilds" :key="server.id" :server="server" />
|
||||
|
||||
<ServerListItem v-if="userStore.userInfo.guilds.length > 0" v-for="server in userStore.userInfo.guilds" :key="server.id" :server="server" />
|
||||
<Info class="center" v-else>Aucun de tes serveurs n'est référencé dans le bot. Invite le bot sur un serveur pour le voir ici.</Info>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -60,6 +63,8 @@ function inviteSubsonics() {
|
||||
</Splash>
|
||||
</SocketEnvironment>
|
||||
|
||||
|
||||
|
||||
</template>
|
||||
<style scoped>
|
||||
.servers-div {
|
||||
@@ -83,6 +88,12 @@ function inviteSubsonics() {
|
||||
|
||||
}
|
||||
|
||||
.center {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 10px;;
|
||||
}
|
||||
|
||||
.server-box {
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import ReturnHomeButton from '@/components/Actions/ReturnHomeButton.vue';
|
||||
import ReturnHomeButton from '@/components/Widget/ReturnHomeButton.vue';
|
||||
import DefaultSplash from '@/components/Layout/DefaultSplash.vue';
|
||||
import Box from '@/components/UI/Box.vue';
|
||||
import Button from '@/components/UI/Button.vue';
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import path from 'path'
|
||||
import VitePluginVueDevTools from 'vite-plugin-vue-devtools'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
plugins: [vue(), VitePluginVueDevTools()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, 'src'),
|
||||
|
Reference in New Issue
Block a user