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>
 | 
			
		||||
    <img :src="`https://cdn.discordapp.com/avatars/${userId}/${avatarUrl}`" alt='User Avatar'>
 | 
			
		||||
    <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>
 | 
			
		||||
            <p v-if="interuptionMessage" class="retry"><Icon spin-pulse icon="fa-solid fa-spinner"/> Tentative de reconnexion en cours</p>
 | 
			
		||||
            <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