Compare commits
18 Commits
e3ce476788
...
main
Author | SHA1 | Date | |
---|---|---|---|
ea9cf2ce42
|
|||
b2a95c0241
|
|||
febe1f90a2
|
|||
b0ed846ef9
|
|||
a19472c6cc
|
|||
f137bd664a
|
|||
de2be3c213
|
|||
8636571eac
|
|||
807f784ca5
|
|||
595e0b9cf9
|
|||
3c9fca85e3
|
|||
bc72044270
|
|||
718c2df916
|
|||
17d91b9064
|
|||
08547bb8f3
|
|||
76017d20b2
|
|||
4eb6492247
|
|||
d54d500ebf
|
57
.gitea/workflows/deploy.yml
Normal file
57
.gitea/workflows/deploy.yml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
name: Frontend Deployment
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy-frontend:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up SSH
|
||||||
|
run: |
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
|
||||||
|
chmod 600 ~/.ssh/id_rsa
|
||||||
|
ssh-keyscan -H alpha.raphix.fr >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
- name: Deploy frontend
|
||||||
|
run: |
|
||||||
|
ssh raphix@alpha.raphix.fr "
|
||||||
|
set -e;
|
||||||
|
APP_DIR=/home/gitlab-ci/chopin-frontend;
|
||||||
|
FRONTEND_DIR=/home/gitlab-ci/frontend/dist;
|
||||||
|
REPO_URL=https://git.raphix.fr/subsonics/chopin-frontend;
|
||||||
|
BRANCH=main;
|
||||||
|
|
||||||
|
echo '[Frontend-Deploy] - START';
|
||||||
|
|
||||||
|
# Nettoyage ancien dossier temporaire
|
||||||
|
rm -rf \$APP_DIR;
|
||||||
|
mkdir -p \$APP_DIR;
|
||||||
|
|
||||||
|
echo 'Cloning repository...';
|
||||||
|
git clone -b \$BRANCH \$REPO_URL \$APP_DIR;
|
||||||
|
|
||||||
|
cd \$APP_DIR;
|
||||||
|
|
||||||
|
echo 'Installing dependencies...';
|
||||||
|
npm ci;
|
||||||
|
|
||||||
|
echo 'Building app...';
|
||||||
|
npm run build;
|
||||||
|
|
||||||
|
echo 'Deploying build to frontend/dist...';
|
||||||
|
mkdir -p \$FRONTEND_DIR;
|
||||||
|
rm -rf \$FRONTEND_DIR/*;
|
||||||
|
cp -r dist/* \$FRONTEND_DIR/;
|
||||||
|
|
||||||
|
echo 'Cleaning up temporary build directory...';
|
||||||
|
rm -rf \$APP_DIR;
|
||||||
|
|
||||||
|
echo '[Frontend-Deploy] - DONE';
|
||||||
|
"
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "chopin-frontend",
|
"name": "chopin-frontend",
|
||||||
"version": "1.0.0",
|
"version": "1.2.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host --port 8080",
|
"dev": "vite --host --port 8080",
|
||||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
@@ -5,7 +5,7 @@
|
|||||||
},
|
},
|
||||||
"backend": {
|
"backend": {
|
||||||
"development": "http://192.168.1.77:3000",
|
"development": "http://192.168.1.77:3000",
|
||||||
"production": "http://alpha.raphix.fr:3000"
|
"production": "https://backend.subsonics.raphix.fr"
|
||||||
},
|
},
|
||||||
"bot_invite": {
|
"bot_invite": {
|
||||||
"development": "https://discord.com/api/oauth2/authorize?client_id=1342913183744004158&permissions=40546675842624&scope=bot%20applications.commands",
|
"development": "https://discord.com/api/oauth2/authorize?client_id=1342913183744004158&permissions=40546675842624&scope=bot%20applications.commands",
|
||||||
|
@@ -31,8 +31,6 @@ const router = useRouter();
|
|||||||
|
|
||||||
const userSettings = ref(null);
|
const userSettings = ref(null);
|
||||||
|
|
||||||
//FIXME: Set to dispatcher
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.box {
|
.box {
|
||||||
|
@@ -25,8 +25,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="server-actions">
|
<div class="server-actions">
|
||||||
<Button v-if="gestion" @click="settings.open()"><Icon icon="fa-solid fa-gear"/>Gestion</Button>
|
<Button icon="fa-solid fa-gear" v-if="gestion" @click="settings.open()">Gestion</Button>
|
||||||
<Button :style="{width: gestion ? '' : '100%'}" @click="router.push(`/servers`)"><Icon icon="fa-solid fa-arrow-right"/>Changer de serveur</Button>
|
<Button icon="fa-solid fa-arrow-right" :style="{width: gestion ? '' : '100%'}" @click="router.push(`/servers`)">Changer de serveur</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -54,6 +54,7 @@ import GuildHeaderUsers from '../Widget/Guild/GuildHeaderUsers.vue';
|
|||||||
import GuildSettings from '../Widget/Guild/GuildSettings.vue';
|
import GuildSettings from '../Widget/Guild/GuildSettings.vue';
|
||||||
import { useUserStore } from '@/stores/userStore';
|
import { useUserStore } from '@/stores/userStore';
|
||||||
import { useGlobalStore } from '@/stores/globalStore';
|
import { useGlobalStore } from '@/stores/globalStore';
|
||||||
|
import Events from '@/utils/Events';
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
@@ -109,8 +110,13 @@ function updateServerInfo() {
|
|||||||
console.log("Server info updated");
|
console.log("Server info updated");
|
||||||
events.emit("GUILD_JOINED", data);
|
events.emit("GUILD_JOINED", data);
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Events.on("GUILD_LIST_UPDATE", (guilds) => {
|
||||||
|
server.value = guilds.find(g => g.id === globalStore.lastGuild);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
@@ -112,9 +112,6 @@ const playerOpen = ref(false);
|
|||||||
const durationBar = ref(null);
|
const durationBar = ref(null);
|
||||||
const buffering = ref(false);
|
const buffering = ref(false);
|
||||||
|
|
||||||
//TODO: Rework Animation Both Side
|
|
||||||
//FIXME: Animation weird 550px
|
|
||||||
|
|
||||||
const playerMobile = ref(null);
|
const playerMobile = ref(null);
|
||||||
const playerMobileToggle = ref(null);
|
const playerMobileToggle = ref(null);
|
||||||
const playerHeight = ref(0);
|
const playerHeight = ref(0);
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button class="add-playlist" @click="openModal()"><Icon icon="fa-add"/> Ajouter une playlist</Button>
|
<Button icon="fa-add" class="add-playlist" @click="openModal()">Ajouter une playlist</Button>
|
||||||
</div>
|
</div>
|
||||||
<Modal icon="fa-list" title="Ajouter une Playlist" ref="modal">
|
<Modal icon="fa-list" title="Ajouter une Playlist" ref="modal">
|
||||||
<div class="p-modal-content">
|
<div class="p-modal-content">
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
<label>Importer depuis Youtube</label>
|
<label>Importer depuis Youtube</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button :disabled="(!isYoutube && newPlaylistTitle.trim() === '') || (isYoutube && urlLink?.trim() === '')" @click="addPlaylist">Ajouter</Button>
|
<Button icon="fa-add" :disabled="(!isYoutube && newPlaylistTitle.trim() === '') || (isYoutube && urlLink?.trim() === '')" @click="addPlaylist">Ajouter</Button>
|
||||||
<p class="text-loading" v-if="isLoading"><Icon icon="fa-spinner" spin-pulse /> Création en cours...</p>
|
<p class="text-loading" v-if="isLoading"><Icon icon="fa-spinner" spin-pulse /> Création en cours...</p>
|
||||||
<p class="text-loading" v-if="error"><Error> {{ error }}</Error></p>
|
<p class="text-loading" v-if="error"><Error> {{ error }}</Error></p>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,7 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="search">
|
<div class="search">
|
||||||
<Icon color="#FFFFFF" icon="fa-solid fa-magnifying-glass" style="width: 20px;" />
|
<Icon color="#FFFFFF" icon="fa-solid fa-magnifying-glass" style="width: 20px;" />
|
||||||
<input name="search" ref="searchBar" type="text" placeholder="Insérer votre recherche ici" v-model="searchQuery" />
|
<div class="search-bar">
|
||||||
|
<input autocomplete="off" name="search" ref="searchBar" type="text" placeholder="Insérer votre recherche ici" v-model="searchQuery" />
|
||||||
|
<Icon color="#FFFFFF" v-if="searchQuery.trim() !== ''" icon="fa-solid fa-xmark" class="clear-icon" @click="searchQuery = ''" />
|
||||||
|
<SearchSuggestions v-if="searchQuery.trim() !== '' && suggestClose" :query="searchQuery" />
|
||||||
|
</div>
|
||||||
<div class="search-actions">
|
<div class="search-actions">
|
||||||
<IconAction
|
<IconAction
|
||||||
icon="fa-solid fa-cloud-arrow-up"
|
icon="fa-solid fa-cloud-arrow-up"
|
||||||
@@ -25,17 +29,24 @@ import { onBeforeUnmount, onMounted, ref } from 'vue';
|
|||||||
import IconAction from '../UI/IconAction.vue';
|
import IconAction from '../UI/IconAction.vue';
|
||||||
import { IORequest } from '@/utils/IORequest';
|
import { IORequest } from '@/utils/IORequest';
|
||||||
import Events from '@/utils/Events';
|
import Events from '@/utils/Events';
|
||||||
|
import SearchSuggestions from '@/components/Widget/View/Search/SearchSuggestions.vue';
|
||||||
|
|
||||||
const searchBar = ref(null);
|
const searchBar = ref(null);
|
||||||
const searchQuery = ref('');
|
const searchQuery = ref('');
|
||||||
|
const suggestClose = ref(true);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
searchBar.value.addEventListener('change', find);
|
searchBar.value.addEventListener('change', () => {
|
||||||
|
find();
|
||||||
|
suggestClose.value = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
//TODO: Faire un systême de suggestions.
|
searchBar.value.addEventListener('keydown', (event) => {
|
||||||
|
suggestClose.value = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
function find() {
|
function find(queryByResult) {
|
||||||
// If on mobile close the keyboard
|
// If on mobile close the keyboard
|
||||||
if (window.innerWidth < 768) {
|
if (window.innerWidth < 768) {
|
||||||
searchBar.value.blur();
|
searchBar.value.blur();
|
||||||
@@ -43,9 +54,15 @@ function find() {
|
|||||||
if (searchQuery.value.trim() === '') {
|
if (searchQuery.value.trim() === '') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(queryByResult == "result") {
|
||||||
|
Events.emit("SEARCH_RESULT_SENDED");
|
||||||
|
}
|
||||||
Events.emit("SEARCH_STARTED");
|
Events.emit("SEARCH_STARTED");
|
||||||
IORequest("/SEARCH", (data) => {
|
IORequest("/SEARCH", (data) => {
|
||||||
Events.emit("SEARCH_RESULT", {data: data, query: searchQuery.value});
|
Events.emit("SEARCH_RESULT", {data: data, query: searchQuery.value});
|
||||||
|
if(queryByResult == "result") {
|
||||||
|
Events.emit("SEARCH_RESULT_SENDED");
|
||||||
|
}
|
||||||
}, searchQuery.value);
|
}, searchQuery.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,6 +70,13 @@ Events.on("VIEW_CLOSED", () => {
|
|||||||
searchQuery.value = '';
|
searchQuery.value = '';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Events.on("SEARCH_RESULT_SELECTED", (result) => {
|
||||||
|
searchQuery.value = result;
|
||||||
|
suggestClose.value = false;
|
||||||
|
Events.emit("SEARCH_RESULT_SENDED");
|
||||||
|
find("result");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -68,6 +92,19 @@ Events.on("VIEW_CLOSED", () => {
|
|||||||
box-shadow: 2px 2px 10px 0px rgba(0, 0, 0, 0.50);
|
box-shadow: 2px 2px 10px 0px rgba(0, 0, 0, 0.50);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.clear-icon {
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
position: relative;
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.search input {
|
.search input {
|
||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
|
@@ -26,8 +26,6 @@ const disableClass = computed(() => {
|
|||||||
return props.disabled ? props.colorLower ? 'disabled color-lower' : 'disabled' : '';
|
return props.disabled ? props.colorLower ? 'disabled color-lower' : 'disabled' : '';
|
||||||
});
|
});
|
||||||
|
|
||||||
//TODO: Refactor every button component to use the icon prop
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
button {
|
button {
|
||||||
|
@@ -131,21 +131,23 @@ function updateSlots() {
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
if(window.innerWidth > 769 && window.innerHeight > 607) {
|
if(window.innerWidth > 769 && window.innerHeight > 607) {
|
||||||
if(actualComponent.value.props.mobile == '') {
|
if (actualComponent.value?.props?.mobile) {
|
||||||
actualIndex.value = 0; // Reset index when resizing to desktop
|
actualIndex.value = 0; // Reset index when resizing to desktop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
allSlots.value.forEach((slot, index) => {
|
allSlots.value.forEach((slot, index) => {
|
||||||
|
if(typeof slot.props?.mobile !== 'undefined') {
|
||||||
if (slot.props.mobile == '' && (window.innerWidth > 769 && window.innerHeight > 607)) {
|
if (slot.props.mobile == '' && (window.innerWidth > 769 && window.innerHeight > 607)) {
|
||||||
allSlots.value.splice(index, 1);
|
allSlots.value.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ready.value = true;
|
ready.value = true;
|
||||||
}, 100)
|
}, 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.notactive {
|
.notactive {
|
||||||
|
@@ -52,7 +52,8 @@ function getIcons(name) {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
@media screen and (max-width: 768px),
|
||||||
|
screen and (max-height: 607px) {
|
||||||
|
|
||||||
.metric {
|
.metric {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@@ -65,6 +65,7 @@ function open() {
|
|||||||
if (modal.value) {
|
if (modal.value) {
|
||||||
modal.value.style.display = 'flex';
|
modal.value.style.display = 'flex';
|
||||||
}
|
}
|
||||||
|
Events.emit('modal:open');
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
|
@@ -21,7 +21,8 @@ defineProps({
|
|||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
@media screen and (max-width: 768px),
|
||||||
|
screen and (max-height: 607px) {
|
||||||
.settings-icon {
|
.settings-icon {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup>
|
||||||
import IconAction from './IconAction.vue';
|
import IconAction from './IconAction.vue';
|
||||||
import { ref, onMounted, watch, onUnmounted } from 'vue';
|
import { ref, onMounted, watch, onUnmounted } from 'vue';
|
||||||
import { useSlots } from 'vue';
|
import { useSlots } from 'vue';
|
||||||
|
@@ -107,6 +107,7 @@ generateNotes();
|
|||||||
color: rgba(255, 255, 255, 0.2);
|
color: rgba(255, 255, 255, 0.2);
|
||||||
animation: float 10s infinite linear;
|
animation: float 10s infinite linear;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -2,7 +2,11 @@
|
|||||||
<div class="subsonics-logo">
|
<div class="subsonics-logo">
|
||||||
<LogoDark class="img" v-if="globalStore.theme == 'light'"/>
|
<LogoDark class="img" v-if="globalStore.theme == 'light'"/>
|
||||||
<LogoLight class="img" v-else/>
|
<LogoLight class="img" v-else/>
|
||||||
|
<div v-if="dev" class="text-p">
|
||||||
<h1>Subsonics</h1>
|
<h1>Subsonics</h1>
|
||||||
|
<p>Developement</p>
|
||||||
|
</div>
|
||||||
|
<h1 v-if="!dev">Subsonics</h1>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -10,6 +14,8 @@ import LogoDark from '@/assets/LogoDark.vue';
|
|||||||
import LogoLight from '@/assets/LogoLight.vue';
|
import LogoLight from '@/assets/LogoLight.vue';
|
||||||
import { useGlobalStore } from '@/stores/globalStore';
|
import { useGlobalStore } from '@/stores/globalStore';
|
||||||
|
|
||||||
|
const dev = import.meta.env.DEV;
|
||||||
|
|
||||||
const globalStore = useGlobalStore();
|
const globalStore = useGlobalStore();
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@@ -27,6 +33,25 @@ const globalStore = useGlobalStore();
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-p {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-p h1 {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-p p {
|
||||||
|
margin: 0 !important;
|
||||||
|
font-family: 'Gunship', sans-serif;
|
||||||
|
position: absolute;
|
||||||
|
bottom: -10px;
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 768px),
|
@media screen and (max-width: 768px),
|
||||||
screen and (max-height: 607px) {
|
screen and (max-height: 607px) {
|
||||||
.img {
|
.img {
|
||||||
|
@@ -3,9 +3,11 @@
|
|||||||
<ModalTree title="Utilisateurs" icon="fa-solid fa-users">
|
<ModalTree title="Utilisateurs" icon="fa-solid fa-users">
|
||||||
<GuildUsers :server="server"/>
|
<GuildUsers :server="server"/>
|
||||||
</ModalTree>
|
</ModalTree>
|
||||||
|
<ModalTree v-if="userStore.userInfo.labels.includes('ADMIN') || userStore.userInfo.identity.id == server.owner" title="Sécurité" icon="fa-solid fa-shield-halved">
|
||||||
|
<GuildSecurity :server="server"/>
|
||||||
|
</ModalTree>
|
||||||
<ModalTree title="Statistiques" icon="fa-solid fa-chart-simple">
|
<ModalTree title="Statistiques" icon="fa-solid fa-chart-simple">
|
||||||
<GuildStats :server="server"/>
|
<GuildStats :server="server"/>
|
||||||
|
|
||||||
</ModalTree>
|
</ModalTree>
|
||||||
</Modal>
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
@@ -15,13 +17,14 @@ import ModalTree from '@/components/UI/ModalTree.vue';
|
|||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import GuildUsers from './Settings/GuildUsers.vue';
|
import GuildUsers from './Settings/GuildUsers.vue';
|
||||||
import GuildStats from './Settings/GuildStats.vue';
|
import GuildStats from './Settings/GuildStats.vue';
|
||||||
|
import GuildSecurity from './Settings/GuildSecurity.vue';
|
||||||
import Events from '@/utils/Events';
|
import Events from '@/utils/Events';
|
||||||
|
import { useUserStore } from '@/stores/userStore';
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
const modal = ref(null);
|
const modal = ref(null);
|
||||||
|
|
||||||
//TODO: Ajouter la sécurité des roles pour empêcher l'utilisation publique du Bot
|
|
||||||
//TODO: Ajout de Log pour serveur
|
//TODO: Ajout de Log pour serveur
|
||||||
//TODO: Paramétérer une liste des channels autorisé !
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
server: {
|
server: {
|
||||||
|
93
src/components/Widget/Guild/Settings/GuildSecurity.vue
Normal file
93
src/components/Widget/Guild/Settings/GuildSecurity.vue
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<template>
|
||||||
|
<div class="setting">
|
||||||
|
<p class="text-secondary"><Icon icon="fa-solid fa-user-shield" /> Autoriser les utilisateurs avec un rôle spécifique</p>
|
||||||
|
<Selector v-model="roleSelected" ref="roleSelector" v-if="roles.length > 0 && modalOpen">
|
||||||
|
<Tag v-for="role in roles" :key="role.id" :value="role.id" :color="decimalToHex(role.color)">{{role.name.replace("@everyone", "Tout le monde (@everyone)")}}</Tag>
|
||||||
|
</Selector>
|
||||||
|
<Button @click="updateRole" icon="fa-solid fa-rotate">Mettre à jour</Button>
|
||||||
|
<Success v-if="roleUpdated">Rôle mis à jour avec succès !</Success>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, ref, watch } from 'vue';
|
||||||
|
import Selector from '@/components/UI/Selector.vue';
|
||||||
|
import { IORequest } from '@/utils/IORequest';
|
||||||
|
import Tag from '@/components/UI/Tag.vue';
|
||||||
|
import Events from '@/utils/Events';
|
||||||
|
import Button from '@/components/UI/Button.vue';
|
||||||
|
import Success from '@/components/UI/Success.vue';
|
||||||
|
|
||||||
|
const roles = ref([])
|
||||||
|
const roleSelector = ref(null);
|
||||||
|
const roleUpdated = ref(false);
|
||||||
|
const roleSelected = ref(null);
|
||||||
|
const modalOpen = ref(false);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
server: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//TODO: FINISH IMPLEMENTATION
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
actualizeRoles();
|
||||||
|
})
|
||||||
|
|
||||||
|
Events.on("modal:open", () => {
|
||||||
|
actualizeRoles();
|
||||||
|
modalOpen.value = true;
|
||||||
|
roleUpdated.value = false;
|
||||||
|
})
|
||||||
|
|
||||||
|
Events.on("modal:close", () => {
|
||||||
|
modalOpen.value = false;
|
||||||
|
roleSelected.value = null;
|
||||||
|
roleUpdated.value = false;
|
||||||
|
})
|
||||||
|
|
||||||
|
function actualizeRoles() {
|
||||||
|
IORequest("/OWNER/ROLES/GET", (data) => {
|
||||||
|
roles.value = data;
|
||||||
|
roleSelected.value = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateRole() {
|
||||||
|
console.log(roleSelector.value?.firstSlot());
|
||||||
|
IORequest("/OWNER/ROLES/SET", (data) => {
|
||||||
|
actualizeRoles();
|
||||||
|
roleUpdated.value = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
roleUpdated.value = false;
|
||||||
|
}, 3000);
|
||||||
|
}, roles.value.find(r => r.id === roleSelected.value) || null);
|
||||||
|
}
|
||||||
|
|
||||||
|
function decimalToHex(decimal) {
|
||||||
|
if(decimal == 0) return "var(--quaternary)"; // Default color
|
||||||
|
let hex = Number(decimal).toString(16);
|
||||||
|
hex = "000000".substring(0, 6 - hex.length) + hex;
|
||||||
|
return `#${hex}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.text-secondary {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
text-decoration: underline;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -73,7 +73,8 @@ function banUser(member) {
|
|||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
@media screen and (max-width: 768px),
|
||||||
|
screen and (max-height: 607px) {
|
||||||
|
|
||||||
.group {
|
.group {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@@ -41,7 +41,7 @@
|
|||||||
<p class="selectorp" :value="playlist.playlistId" v-for="playlist in userStore.playlists" :key="playlist.playlistId"><Icon :icon="playlist.type === 'youtube' ? 'fa-brands fa-youtube' : 'fa-solid fa-music'" /> {{ playlist.title }}</p>
|
<p class="selectorp" :value="playlist.playlistId" v-for="playlist in userStore.playlists" :key="playlist.playlistId"><Icon :icon="playlist.type === 'youtube' ? 'fa-brands fa-youtube' : 'fa-solid fa-music'" /> {{ playlist.title }}</p>
|
||||||
</Selector>
|
</Selector>
|
||||||
<p v-else class="info-no">Vous n'avez pas encore de playlist. Créez-en une pour sauvegarder ce titre.</p>
|
<p v-else class="info-no">Vous n'avez pas encore de playlist. Créez-en une pour sauvegarder ce titre.</p>
|
||||||
<Button :disabled="userStore.playlists?.length === 0" @click="Events.emit('video:add', { video: nextList[selectedIndex], playlistId: playlistSelector.firstSlot().props.value }); saveModal.close()"><Icon icon="fa-solid fa-save" /> Sauvegarder</Button>
|
<Button :disabled="userStore.playlists?.length === 0" @click="Events.emit('video:add', { video: nextList[selectedIndex], playlistId: playlistSelector.firstSlot().props.value }); saveModal.close()" icon="fa-solid fa-save">Sauvegarder</Button>
|
||||||
</Modal>
|
</Modal>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
@@ -151,7 +151,6 @@ function onDragEnd(event) {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
padding-right: 5px;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
@@ -192,6 +191,7 @@ function onDragEnd(event) {
|
|||||||
gap: 10px;
|
gap: 10px;
|
||||||
margin-top: 2.5px;
|
margin-top: 2.5px;
|
||||||
margin-bottom: 2.5px;
|
margin-bottom: 2.5px;
|
||||||
|
padding-right: 5px;
|
||||||
}
|
}
|
||||||
.allSpace {
|
.allSpace {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
@@ -30,7 +30,7 @@
|
|||||||
<p class="selectorp" :value="playlist.playlistId" v-for="playlist in userStore.playlists" :key="playlist.playlistId"><Icon :icon="playlist.type === 'youtube' ? 'fa-brands fa-youtube' : 'fa-solid fa-music'" /> {{ playlist.title }}</p>
|
<p class="selectorp" :value="playlist.playlistId" v-for="playlist in userStore.playlists" :key="playlist.playlistId"><Icon :icon="playlist.type === 'youtube' ? 'fa-brands fa-youtube' : 'fa-solid fa-music'" /> {{ playlist.title }}</p>
|
||||||
</Selector>
|
</Selector>
|
||||||
<p v-else class="info-no">Vous n'avez pas encore de playlist. Créez-en une pour sauvegarder ce titre.</p>
|
<p v-else class="info-no">Vous n'avez pas encore de playlist. Créez-en une pour sauvegarder ce titre.</p>
|
||||||
<Button :disabled="userStore.playlists?.length === 0" @click="Events.emit('video:add', { video: previousList[selectedIndex], playlistId: playlistSelector.firstSlot().props.value }); saveModal.close()"><Icon icon="fa-solid fa-save" /> Sauvegarder</Button>
|
<Button :disabled="userStore.playlists?.length === 0" @click="Events.emit('video:add', { video: previousList[selectedIndex], playlistId: playlistSelector.firstSlot().props.value }); saveModal.close()" icon="fa-solid fa-save">Sauvegarder</Button>
|
||||||
</Modal>
|
</Modal>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
@@ -5,7 +5,8 @@
|
|||||||
<ServerOnlinePicture class="sop" :key="server.id" v-if="server.members.length > 0" :members="server.members"/>
|
<ServerOnlinePicture class="sop" :key="server.id" v-if="server.members.length > 0" :members="server.members"/>
|
||||||
<section>
|
<section>
|
||||||
<Error v-if="userStore.userInfo.labels.includes('BAN_' + server.id)">Banni</Error>
|
<Error v-if="userStore.userInfo.labels.includes('BAN_' + server.id)">Banni</Error>
|
||||||
<Button color-lower :disabled="userStore.userInfo.labels.includes('BAN_' + server.id)" class="btn" @click="access()"><Icon icon="fa-solid fa-right-to-bracket"/>Accéder</Button>
|
<Error v-else-if="server.restricted">Restreint</Error>
|
||||||
|
<Button color-lower :disabled="userStore.userInfo.labels.includes('BAN_' + server.id) || server.restricted" class="btn" @click="access()" icon="fa-solid fa-right-to-bracket">Accéder</Button>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</Box>
|
</Box>
|
||||||
|
@@ -54,7 +54,7 @@ watch(showForm, (newValue) => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<p>Si vous rencontrez un problème, vous pouvez le signaler via ce formulaire. Vous pouvez être contacté en cas de besoin par Raphix pour plus d'informations.</p>
|
<p>Si vous rencontrez un problème, vous pouvez le signaler via ce formulaire. Vous pouvez être contacté en cas de besoin par Raphix pour plus d'informations.</p>
|
||||||
<Button v-if="!showForm" @click="showForm = !showForm" class="margin"><Icon icon="fa-solid fa-paper-plane" /> Faire un rapport de bug</Button>
|
<Button v-if="!showForm" @click="showForm = !showForm" class="margin" icon="fa-solid fa-paper-plane"> Faire un rapport de bug</Button>
|
||||||
<Success class="margin" v-if="sended">Votre rapport a été envoyé avec succès</Success>
|
<Success class="margin" v-if="sended">Votre rapport a été envoyé avec succès</Success>
|
||||||
<div v-if="showForm" class="report-content">
|
<div v-if="showForm" class="report-content">
|
||||||
<p>Catégorie</p>
|
<p>Catégorie</p>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<p class="privacy">Toutes les données récupérées sont à des fins <strong>strictement</strong> nécessaires au bon fonctionnement de l'application.</p>
|
<p class="privacy">Toutes les données récupérées sont à des fins <strong>strictement</strong> nécessaires au bon fonctionnement de l'application.</p>
|
||||||
|
|
||||||
<Button @click="openModal()"><Icon icon="fa-solid fa-trash"/> Supprimer mon compte</Button>
|
<Button @click="openModal()" icon="fa-solid fa-trash"> Supprimer mon compte</Button>
|
||||||
<Modal icon="fa-solid fa-trash" ref="deleteAccountModal" title="Supprimer mon compte">
|
<Modal icon="fa-solid fa-trash" ref="deleteAccountModal" title="Supprimer mon compte">
|
||||||
<p class="warning">
|
<p class="warning">
|
||||||
Êtes-vous sûr de vouloir supprimer votre compte ? <br/>
|
Êtes-vous sûr de vouloir supprimer votre compte ? <br/>
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<Video :video="video" ref="videoContainer">
|
<Video :video="video" ref="videoContainer">
|
||||||
<div ref="controls" class="controls">
|
<div ref="controls" class="controls">
|
||||||
<span v-if="globalStore.currentChannel" title="Ajouter à la liste de lecture" @click="disableAction(); playSong(false)" class="control-icon"><AddList /></span>
|
<span title="Ajouter à la liste de lecture" @click="disableAction(); playSong(false)" :class="{'control-icon': globalStore.currentChannel, 'control-icon-disable': !globalStore.currentChannel}"><AddList /></span>
|
||||||
<span v-if="globalStore.currentChannel" title="Lire maintenant" @click="disableAction(); playSong(true)" class="control-icon"><Icon icon="fa-play" /></span>
|
<span title="Lire maintenant" @click="disableAction(); playSong(true)" :class="{'control-icon': globalStore.currentChannel, 'control-icon-disable': !globalStore.currentChannel}"><Icon icon="fa-play" /></span>
|
||||||
<span v-if="!props.delete && video.type != 'attachment'" title="Enregistrer dans une playlist" @click="disableAction(); saveModal.open()" class="control-icon"><Icon icon="fa-save" /></span>
|
<span v-if="!props.delete && video.type != 'attachment'" title="Enregistrer dans une playlist" @click="disableAction(); saveModal.open()" class="control-icon"><Icon icon="fa-save" /></span>
|
||||||
<span v-if="props.delete" title="Supprimer" @click="disableAction(); Events.emit('video:delete', { video: props.video })" class="control-icon"><Icon icon="fa-trash" /></span>
|
<span v-if="props.delete" title="Supprimer" @click="disableAction(); Events.emit('video:delete', { video: props.video })" class="control-icon"><Icon icon="fa-trash" /></span>
|
||||||
</div>
|
</div>
|
||||||
@@ -10,13 +10,13 @@
|
|||||||
<Modal icon="fa-solid fa-video" title="Actions" ref="modal">
|
<Modal icon="fa-solid fa-video" title="Actions" ref="modal">
|
||||||
<Video :video="video"/>
|
<Video :video="video"/>
|
||||||
<Button v-if="globalStore.currentChannel" @click="playSong(false)"><AddList /> Ajouter à la liste de lecture</Button>
|
<Button v-if="globalStore.currentChannel" @click="playSong(false)"><AddList /> Ajouter à la liste de lecture</Button>
|
||||||
<Button v-if="globalStore.currentChannel" @click="playSong(true)"><Icon icon="fa-solid fa-play"/> Lire maintenant</Button>
|
<Button icon="fa-solid fa-play" v-if="globalStore.currentChannel" @click="playSong(true)"> Lire maintenant</Button>
|
||||||
<div v-else>
|
<div v-if="!globalStore.currentChannel" >
|
||||||
<p class="text-secondary">Connectez vous à un salon audio sur le serveur {{ globalStore.actualServer ? globalStore.actualServer.name : '' }}, pour lancer un titre</p>
|
<p class="text-secondary">Connectez vous à un salon audio sur le serveur {{ globalStore.actualServer ? globalStore.actualServer.name : '' }}, pour lancer un titre</p>
|
||||||
<ActualChannel/>
|
<ActualChannel/>
|
||||||
</div>
|
</div>
|
||||||
<Button v-if="!props.delete && video.type != 'attachment'" @click="saveModal.open()"><Icon icon="fa-solid fa-save" /> Enregistrer dans une playlist</Button>
|
<Button v-if="!props.delete && video.type != 'attachment'" @click="saveModal.open()" icon="fa-solid fa-save"> Enregistrer dans une playlist</Button>
|
||||||
<Button v-if="props.delete" @click="Events.emit('video:delete', { video: props.video })"><Icon icon="fa-solid fa-trash" /> Supprimer</Button>
|
<Button v-if="props.delete" @click="Events.emit('video:delete', { video: props.video })" icon="fa-solid fa-trash"> Supprimer</Button>
|
||||||
</Modal>
|
</Modal>
|
||||||
<Modal ref="saveModal" icon="fa-save" title="Sauvegarder dans une playlist">
|
<Modal ref="saveModal" icon="fa-save" title="Sauvegarder dans une playlist">
|
||||||
<Video class="save-video" :video="video"/>
|
<Video class="save-video" :video="video"/>
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
<p class="selectorp" :value="playlist.playlistId" v-for="playlist in userStore.playlists" :key="playlist.playlistId"><Icon :icon="playlist.type === 'youtube' ? 'fa-brands fa-youtube' : 'fa-solid fa-music'" /> {{ playlist.title }}</p>
|
<p class="selectorp" :value="playlist.playlistId" v-for="playlist in userStore.playlists" :key="playlist.playlistId"><Icon :icon="playlist.type === 'youtube' ? 'fa-brands fa-youtube' : 'fa-solid fa-music'" /> {{ playlist.title }}</p>
|
||||||
</Selector>
|
</Selector>
|
||||||
<p v-else class="info-no">Vous n'avez pas encore de playlist. Créez-en une pour sauvegarder ce titre.</p>
|
<p v-else class="info-no">Vous n'avez pas encore de playlist. Créez-en une pour sauvegarder ce titre.</p>
|
||||||
<Button :disabled="userStore.playlists?.length === 0" @click="Events.emit('video:add', { video: props.video, playlistId: playlistSelector.firstSlot().props.value }); saveModal.close()"><Icon icon="fa-solid fa-save" /> Sauvegarder</Button>
|
<Button :disabled="userStore.playlists?.length === 0" @click="Events.emit('video:add', { video: props.video, playlistId: playlistSelector.firstSlot().props.value }); saveModal.close()" icon="fa-solid fa-save" > Sauvegarder</Button>
|
||||||
</Modal>
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -64,6 +64,7 @@ const props = defineProps({
|
|||||||
let nativeVideo = {}
|
let nativeVideo = {}
|
||||||
|
|
||||||
function disableAction() {
|
function disableAction() {
|
||||||
|
if(!globalStore.currentChannel) return;
|
||||||
controls.value.style.display = "none";
|
controls.value.style.display = "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +75,7 @@ let activePointerId = null;
|
|||||||
const SLIDE_THRESHOLD = 10; // ajuster si besoin
|
const SLIDE_THRESHOLD = 10; // ajuster si besoin
|
||||||
|
|
||||||
function playSong(now) {
|
function playSong(now) {
|
||||||
|
if(!globalStore.currentChannel) return;
|
||||||
IORequest("/SEARCH/PLAY", (data) => {
|
IORequest("/SEARCH/PLAY", (data) => {
|
||||||
modal.value.close();
|
modal.value.close();
|
||||||
}, {song: nativeVideo, now: now})
|
}, {song: nativeVideo, now: now})
|
||||||
@@ -84,7 +85,7 @@ onMounted(() => {
|
|||||||
Object.assign(nativeVideo, props.video);
|
Object.assign(nativeVideo, props.video);
|
||||||
if(props.video.createdAt) {
|
if(props.video.createdAt) {
|
||||||
props.video.author = 'Ajoutée le ' + new Date(props.video.createdAt).toLocaleString()
|
props.video.author = 'Ajoutée le ' + new Date(props.video.createdAt).toLocaleString()
|
||||||
props.video.thumbnail = '/src/assets/default_thumbnail.png';
|
props.video.thumbnail = '/default_thumbnail.png';
|
||||||
nativeVideo.author = userStore.userInfo.identity.username;
|
nativeVideo.author = userStore.userInfo.identity.username;
|
||||||
}
|
}
|
||||||
if(!videoContainer.value) return
|
if(!videoContainer.value) return
|
||||||
@@ -118,9 +119,12 @@ onMounted(() => {
|
|||||||
if (activePointerId != null) videoContainer.value.releasePointerCapture(activePointerId);
|
if (activePointerId != null) videoContainer.value.releasePointerCapture(activePointerId);
|
||||||
} catch (e) { /* ignore */ }
|
} catch (e) { /* ignore */ }
|
||||||
if(!videoContainer.value) return
|
if(!videoContainer.value) return
|
||||||
|
try {
|
||||||
videoContainer.value.removeEventListener('pointermove', onPointerMove);
|
videoContainer.value.removeEventListener('pointermove', onPointerMove);
|
||||||
videoContainer.value.removeEventListener('pointerup', onPointerUp);
|
videoContainer.value.removeEventListener('pointerup', onPointerUp);
|
||||||
videoContainer.value.removeEventListener('pointercancel', onPointerCancel);
|
videoContainer.value.removeEventListener('pointercancel', onPointerCancel);
|
||||||
|
} catch (e) { console.log(videoContainer.value) }
|
||||||
|
|
||||||
activePointerId = null;
|
activePointerId = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -149,10 +153,16 @@ onMounted(() => {
|
|||||||
isSliding = false;
|
isSliding = false;
|
||||||
activePointerId = ev.pointerId;
|
activePointerId = ev.pointerId;
|
||||||
if(!videoContainer.value) return
|
if(!videoContainer.value) return
|
||||||
|
try {
|
||||||
|
thumbnailContainer.value = videoContainer.value.getThumbnailContainer();
|
||||||
|
videoContainer.value = videoContainer.value.getVideoContainer();
|
||||||
|
} catch (e) { }
|
||||||
try { videoContainer.value.setPointerCapture(activePointerId); } catch (e) { /* ignore */ }
|
try { videoContainer.value.setPointerCapture(activePointerId); } catch (e) { /* ignore */ }
|
||||||
|
try {
|
||||||
videoContainer.value.addEventListener('pointermove', onPointerMove);
|
videoContainer.value.addEventListener('pointermove', onPointerMove);
|
||||||
videoContainer.value.addEventListener('pointerup', onPointerUp);
|
videoContainer.value.addEventListener('pointerup', onPointerUp);
|
||||||
videoContainer.value.addEventListener('pointercancel', onPointerCancel);
|
videoContainer.value.addEventListener('pointercancel', onPointerCancel);
|
||||||
|
} catch (e) { console.log(videoContainer.value) }
|
||||||
};
|
};
|
||||||
|
|
||||||
videoContainer.value.addEventListener('pointerdown', onPointerDown);
|
videoContainer.value.addEventListener('pointerdown', onPointerDown);
|
||||||
@@ -218,6 +228,20 @@ onMounted(() => {
|
|||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.control-icon-disable {
|
||||||
|
font-size: 1.2em;
|
||||||
|
background-color: var(--text-inverse);
|
||||||
|
color: var(--secondary);
|
||||||
|
border-radius: 100%;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.video:hover .controls {
|
.video:hover .controls {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
@@ -1,10 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="default">
|
<div class="default">
|
||||||
<!-- <Carousel v-show="!loading" class="child"> -->
|
|
||||||
<Changelog/>
|
<Changelog/>
|
||||||
<!-- <History/>
|
|
||||||
<Advice/>
|
|
||||||
</Carousel> -->
|
|
||||||
<p v-show="loading" class="loading">
|
<p v-show="loading" class="loading">
|
||||||
<Icon icon="fa-spinner fa-solid" spin-pulse/> Chargement en cours
|
<Icon icon="fa-spinner fa-solid" spin-pulse/> Chargement en cours
|
||||||
</p>
|
</p>
|
||||||
@@ -47,18 +43,13 @@ p {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.default {
|
.default {
|
||||||
display: grid;
|
display: flex;
|
||||||
grid-template-rows: 1fr;
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 768px),
|
@media screen and (max-width: 768px),
|
||||||
screen and (max-height: 607px) {
|
screen and (max-height: 607px) {
|
||||||
.default {
|
|
||||||
grid-template-rows: 1fr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.child {
|
.child {
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
<section class="changelog">
|
<section class="changelog">
|
||||||
<Welcome/>
|
<Welcome/>
|
||||||
<h2 class="changelog-title">📝 Changelog</h2>
|
<h2 class="changelog-title">📝 Changelog</h2>
|
||||||
<div class="changelog-overflow" v-if="changelog" >
|
<div v-if="changelog" class="changelog-overflow">
|
||||||
<div class="changelog-container" v-html="changelog" ></div>
|
<div class="changelog-container" v-html="changelog" ></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="textSecond" v-else-if="!error"><Icon icon="fa-spinner fa-solid" spin-pulse/> Chargement en cours</div>
|
<div class="textSecond" v-else-if="!error"><Icon icon="fa-spinner fa-solid" spin-pulse/> Chargement en cours</div>
|
||||||
@@ -39,6 +39,8 @@ function loadChangelog() {
|
|||||||
data = data.replaceAll("-*", "</span>");
|
data = data.replaceAll("-*", "</span>");
|
||||||
data = data.replaceAll("*_", "<span class='underline'>");
|
data = data.replaceAll("*_", "<span class='underline'>");
|
||||||
data = data.replaceAll("_*", "</span>");
|
data = data.replaceAll("_*", "</span>");
|
||||||
|
data = data.replaceAll('/#', "<span class='changelog-tags'>");
|
||||||
|
data = data.replaceAll('#/', "</span>");
|
||||||
|
|
||||||
changelog.value = data;
|
changelog.value = data;
|
||||||
} else {
|
} else {
|
||||||
@@ -102,12 +104,13 @@ function loadChangelog() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.changelog-container {
|
.changelog-container {
|
||||||
display: grid;
|
display: flex;
|
||||||
grid-template-columns: 1fr;
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
overflow-y: auto;
|
||||||
|
position: absolute;
|
||||||
|
flex: 1;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
grid-template-rows: auto;
|
|
||||||
gap: 20px;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.changelog {
|
.changelog {
|
||||||
@@ -119,7 +122,10 @@ function loadChangelog() {
|
|||||||
|
|
||||||
.changelog-overflow {
|
.changelog-overflow {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
position: relative;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tags {
|
.tags {
|
||||||
@@ -225,20 +231,57 @@ function loadChangelog() {
|
|||||||
white-space: nowrap; /* Prevent line breaks */
|
white-space: nowrap; /* Prevent line breaks */
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 768px),
|
.changelog-overflow {
|
||||||
screen and (max-height: 607px) {
|
position: relative;
|
||||||
.changelog-container {
|
|
||||||
grid-template-columns: 1fr !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.changelog-container ul {
|
.changelog-container ul {
|
||||||
padding: 0
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.changelog-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 5px;
|
||||||
|
background-color: var(--quaternary);
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 768px),
|
||||||
|
screen and (max-height: 607px) {
|
||||||
|
|
||||||
|
.changelog-container ul {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.changelog-version ul li::before {
|
.changelog-version ul li::before {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.welcome-container {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-actions {
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.changelog-tags {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
<img v-if="results.thumbnail" class="search-playlist-thumbnail" :src="results.thumbnail" alt="Playlist Thumbnail" />
|
<img v-if="results.thumbnail" class="search-playlist-thumbnail" :src="results.thumbnail" alt="Playlist Thumbnail" />
|
||||||
<div v-else class="search-playlist-thumbnail"><div class="defaultIcon"><Icon icon="fa-music" /></div></div>
|
<div v-else class="search-playlist-thumbnail"><div class="defaultIcon"><Icon icon="fa-music" /></div></div>
|
||||||
<div class="search-playlist-info">
|
<div class="search-playlist-info">
|
||||||
<p class="search-playlist-title">{{ results.title }} <Icon @click="openPlaylistPage()" class="link-icon" icon="fa-solid fa-link" /></p>
|
<p class="search-playlist-title">{{ results.title }} <Icon v-if="results.url" @click="openPlaylistPage()" class="link-icon" icon="fa-solid fa-link" /></p>
|
||||||
<p class="search-playlist-stats"><Tag color="var(--text-warning)">{{ results.songs.length }} titres</Tag><Tag v-if="results.views" color="var(--text-success)">{{ results.views }} vues</Tag ><Tag v-if="results.songs.length > 0">Durée : {{ results.readduration }}</Tag></p>
|
<p class="search-playlist-stats"><Tag color="var(--text-warning)">{{ results.songs.length }} titres</Tag><Tag v-if="results.views" color="var(--text-success)">{{ results.views }} vues</Tag ><Tag v-if="results.songs.length > 0">Durée : {{ results.readduration }}</Tag></p>
|
||||||
<div @click="openAuthorPage()" class="search-playlist-author-info">
|
<div @click="openAuthorPage()" class="search-playlist-author-info">
|
||||||
<img v-if="results.authorAvatar" :src="results.authorAvatar" alt="Author Thumbnail" class="search-playlist-author" />
|
<img v-if="results.authorAvatar" :src="results.authorAvatar" alt="Author Thumbnail" class="search-playlist-author" />
|
||||||
@@ -126,6 +126,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
function openAuthorPage() {
|
function openAuthorPage() {
|
||||||
if (!props.results.authorId) return;
|
if (!props.results.authorId) return;
|
||||||
|
if(!props.results.author) return;
|
||||||
window.open(props.results.authorId, '_blank');
|
window.open(props.results.authorId, '_blank');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
116
src/components/Widget/View/Search/SearchSuggestions.vue
Normal file
116
src/components/Widget/View/Search/SearchSuggestions.vue
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
<template>
|
||||||
|
<div ref="suggestions" class="search-suggestions">
|
||||||
|
<ul>
|
||||||
|
<li class="search-suggestion" v-for="result in results" :key="result.id" @click="selectResult(result[0])">
|
||||||
|
{{ result[0] }}
|
||||||
|
<Icon class="search-icon" icon="fa-solid fa-arrow-up-right-from-square" style="float: right;"/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, ref, watch } from 'vue';
|
||||||
|
import Events from '@/utils/Events';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
query: String
|
||||||
|
});
|
||||||
|
|
||||||
|
const results = ref([]);
|
||||||
|
const suggestions = ref(null);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
window.addEventListener('click', (event) => {
|
||||||
|
if (suggestions.value && !suggestions.value.contains(event.target)) {
|
||||||
|
results.value = [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener('keydown', (event) => {
|
||||||
|
if (event.key === 'Escape') {
|
||||||
|
results.value = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
results.value = [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => props.query, (newQuery) => {
|
||||||
|
if (newQuery) {
|
||||||
|
fetchSuggest(newQuery)
|
||||||
|
.then(data => {
|
||||||
|
results.value = data[1];
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
results.value = [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function fetchSuggest(query) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const callbackName = "jsonp_callback_" + Math.random().toString(36).substr(2, 5);
|
||||||
|
|
||||||
|
window[callbackName] = function(data) {
|
||||||
|
resolve(data);
|
||||||
|
delete window[callbackName];
|
||||||
|
script.remove();
|
||||||
|
};
|
||||||
|
|
||||||
|
const script = document.createElement("script");
|
||||||
|
script.src = `https://suggestqueries.google.com/complete/search?client=youtube&ds=yt&q=${encodeURIComponent(query)}&callback=${callbackName}`;
|
||||||
|
script.onerror = reject;
|
||||||
|
document.body.appendChild(script);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectResult(result) {
|
||||||
|
Events.emit("SEARCH_RESULT_SELECTED", result);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Events.on("SEARCH_RESULT_SENDED", () => {
|
||||||
|
results.value = [];
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.search-suggestions {
|
||||||
|
position: absolute;
|
||||||
|
background: var(--secondary);
|
||||||
|
opacity: 0.95;
|
||||||
|
z-index: 1000;
|
||||||
|
width: 100%;
|
||||||
|
top: 40px;
|
||||||
|
max-height: 30vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-suggestions ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-suggestions li {
|
||||||
|
padding: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-icon {
|
||||||
|
display: none;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-suggestion:hover .search-icon {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-suggestions li:hover {
|
||||||
|
background: var(--tertiary);
|
||||||
|
}
|
||||||
|
</style>
|
@@ -4,7 +4,7 @@
|
|||||||
<h2><Icon icon="fa-folder"/> Mes fichiers</h2>
|
<h2><Icon icon="fa-folder"/> Mes fichiers</h2>
|
||||||
<Box box-class="area-container" padding="close" level="second">
|
<Box box-class="area-container" padding="close" level="second">
|
||||||
<div class="upload-area">
|
<div class="upload-area">
|
||||||
<Button :color-lower="status === 'download'" :disabled="status === 'download'" class="upload-button" @click="uploadFile()"><Icon icon="fa-upload"/> Ajouter un fichier</Button>
|
<Button :color-lower="status === 'download'" :disabled="status === 'download'" class="upload-button" @click="uploadFile()" icon="fa-upload"> Ajouter des fichiers</Button>
|
||||||
<p v-if="status === 'download'" class="upload-file-name" ref="uploadStatus"><Icon icon='fa-spinner' spin-pulse/> Téléchargement en cours...</p>
|
<p v-if="status === 'download'" class="upload-file-name" ref="uploadStatus"><Icon icon='fa-spinner' spin-pulse/> Téléchargement en cours...</p>
|
||||||
<p v-else-if="status === 'error'" class="upload-status" ref="uploadStatus"><Error>Erreur lors du téléchargement</Error></p>
|
<p v-else-if="status === 'error'" class="upload-status" ref="uploadStatus"><Error>Erreur lors du téléchargement</Error></p>
|
||||||
<p v-else-if="status === 'toohigh'" class="upload-status" ref="uploadStatus"><Error>Le fichier est trop volumineux</Error></p>
|
<p v-else-if="status === 'toohigh'" class="upload-status" ref="uploadStatus"><Error>Le fichier est trop volumineux</Error></p>
|
||||||
@@ -14,15 +14,17 @@
|
|||||||
<p class="text-secondary infosup"><Icon icon="fa-circle-info"/> Ce système n'est pas un stockage permanent de données car il dépend du CDN de Discord. Vos fichiers peuvent exprirer à tout moment.</p>
|
<p class="text-secondary infosup"><Icon icon="fa-circle-info"/> Ce système n'est pas un stockage permanent de données car il dépend du CDN de Discord. Vos fichiers peuvent exprirer à tout moment.</p>
|
||||||
</Box>
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="myFiles && myFiles.length > 0" class="uploaded-files">
|
<div v-if="myFiles && myFiles.length > 0" class="uploaded-files-container">
|
||||||
|
<div class="uploaded-files">
|
||||||
<span v-for="file in myFiles" :key="file.id"><VideoComposable :video="file" delete/></span>
|
<span v-for="file in myFiles" :key="file.id"><VideoComposable :video="file" delete/></span>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<p v-else-if="isLoading" class="none"><Icon icon="fa-spinner" spin-pulse/> Chargement des fichiers...</p>
|
<p v-else-if="isLoading" class="none"><Icon icon="fa-spinner" spin-pulse/> Chargement des fichiers...</p>
|
||||||
<p v-else class="none"><Icon icon="fa-circle-xmark"/> Aucun fichier enregistré</p>
|
<p v-else class="none"><Icon icon="fa-circle-xmark"/> Aucun fichier enregistré</p>
|
||||||
<Modal icon="fa-upload" title="Uploader un fichier" ref="uploadModal">
|
<Modal icon="fa-upload" title="Uploader un fichier" ref="uploadModal">
|
||||||
<p>Etes-vous sûr de vouloir uploader ce fichier ?</p>
|
<p>Etes-vous sûr de vouloir uploader ces fichiers ?</p>
|
||||||
<p class="text-secondary">Ce fichier sera stocké sur le CDN de Discord et sera à jamais accessible. Ne diffusez rien de sensible.</p>
|
<p class="text-secondary">Ces fichiers seront stockés sur le CDN de Discord et seront à jamais accessibles. Ne diffusez rien de sensible.</p>
|
||||||
<p v-if="fileSelected" class="upload-modal-name"><Icon icon="fa-file"/> {{ fileSelected.name }}</p>
|
<p v-if="fileSelected.length > 0" v-for="value in fileSelected" class="upload-modal-name"><Icon icon="fa-file"/> {{ value.name }}</p>
|
||||||
<div class="upload-actions">
|
<div class="upload-actions">
|
||||||
<Button @click="closeModal()">Annuler</Button>
|
<Button @click="closeModal()">Annuler</Button>
|
||||||
<Button @click="confirmUpload()">Confirmer</Button>
|
<Button @click="confirmUpload()">Confirmer</Button>
|
||||||
@@ -41,7 +43,7 @@ import { IORequest } from '@/utils/IORequest';
|
|||||||
import { onMounted, onUnmounted, ref } from 'vue';
|
import { onMounted, onUnmounted, ref } from 'vue';
|
||||||
import Events from '@/utils/Events';
|
import Events from '@/utils/Events';
|
||||||
|
|
||||||
const fileSelected = ref(null);
|
const fileSelected = ref([]);
|
||||||
const status = ref(false);
|
const status = ref(false);
|
||||||
const uploadModal = ref(null);
|
const uploadModal = ref(null);
|
||||||
const myFiles = ref([]);
|
const myFiles = ref([]);
|
||||||
@@ -66,53 +68,68 @@ function uploadFile() {
|
|||||||
const input = document.createElement('input');
|
const input = document.createElement('input');
|
||||||
input.type = 'file';
|
input.type = 'file';
|
||||||
input.accept = '.mp3,.wav,.ogg'; // Accept audio files
|
input.accept = '.mp3,.wav,.ogg'; // Accept audio files
|
||||||
|
input.multiple = true;
|
||||||
input.onchange = (event) => {
|
input.onchange = (event) => {
|
||||||
const file = event.target.files[0];
|
const files = Array.from(event.target.files);
|
||||||
if (file) {
|
if (files.length > 0) {
|
||||||
fileSelected.value = file;
|
fileSelected.value = files;
|
||||||
// Here you would typically handle the file upload to the server
|
console.log(`Files selected:`, files.map(f => f.name));
|
||||||
console.log(`File selected: ${file.name}`);
|
|
||||||
// Reset the input for future uploads
|
|
||||||
input.value = '';
|
input.value = '';
|
||||||
// destroy input
|
|
||||||
input.remove();
|
input.remove();
|
||||||
uploadModal.value.open();
|
uploadModal.value.open();
|
||||||
} else {
|
} else {
|
||||||
fileSelected.value = null;
|
fileSelected.value = [];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
input.click();
|
input.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
function confirmUpload() {
|
async function confirmUpload() {
|
||||||
console.log(`Uploading file: ${fileSelected.value.name}`);
|
if (fileSelected.value.length === 0) return;
|
||||||
status.value = 'download';
|
status.value = 'download';
|
||||||
uploadModal.value.close();
|
uploadModal.value.close();
|
||||||
if(fileSelected.value) {
|
|
||||||
// Send the file to the server
|
let errorOccurred = false;
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = () => {
|
for (const file of fileSelected.value) {
|
||||||
const fileBuffer = reader.result;
|
try {
|
||||||
// If it's higher than 300mb
|
const fileBuffer = await readFileAsArrayBuffer(file);
|
||||||
|
|
||||||
if (fileBuffer.byteLength > 300 * 1024 * 1024) {
|
if (fileBuffer.byteLength > 300 * 1024 * 1024) {
|
||||||
status.value = 'toohigh';
|
status.value = 'toohigh';
|
||||||
console.error('File is too large');
|
errorOccurred = true;
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await new Promise(resolve => {
|
||||||
IORequest('/UPLOAD/FILE', (response) => {
|
IORequest('/UPLOAD/FILE', (response) => {
|
||||||
if(!response) {
|
if (!response || response === "TOOHIGH") {
|
||||||
status.value = 'error';
|
errorOccurred = true;
|
||||||
} else if(response === "TOOHIGH") {
|
status.value = (response === "TOOHIGH") ? 'toohigh' : 'error';
|
||||||
status.value = 'toohigh';
|
|
||||||
} else {
|
|
||||||
status.value = 'success';
|
|
||||||
}
|
}
|
||||||
|
resolve();
|
||||||
|
}, { name: file.name, file: fileBuffer });
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Erreur upload fichier:", file.name, err);
|
||||||
|
errorOccurred = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status.value = errorOccurred ? status.value : 'success';
|
||||||
refreshUploadedFiles();
|
refreshUploadedFiles();
|
||||||
}, {name: fileSelected.value.name, file: fileBuffer})
|
fileSelected.value = [];
|
||||||
fileSelected.value = null;
|
|
||||||
};
|
|
||||||
reader.readAsArrayBuffer(fileSelected.value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Petite fonction utilitaire pour transformer FileReader en promesse
|
||||||
|
function readFileAsArrayBuffer(file) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = () => resolve(reader.result);
|
||||||
|
reader.onerror = reject;
|
||||||
|
reader.readAsArrayBuffer(file);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -149,6 +166,17 @@ function refreshUploadedFiles() {
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uploaded-files-container {
|
||||||
|
position: relative;
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.none {
|
.none {
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import DefaultSplash from '@/components/UI/DefaultSplash.vue';
|
import DefaultSplash from '@/components/UI/DefaultSplash.vue';
|
||||||
import MusicAnimation from '@/components/UI/MusicAnimation.vue';
|
import MusicAnimation from '@/components/UI/MusicAnimation.vue';
|
||||||
|
import { version } from '@/../package.json';
|
||||||
const defaultMessage = "On s'accorde et on prépare le concert !";
|
const defaultMessage = "On s'accorde et on prépare le concert !";
|
||||||
const connectMsg = "Erreur de connexion au serveur : xhr poll error"
|
const connectMsg = "Erreur de connexion au serveur : xhr poll error"
|
||||||
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
interuptionMessage: {
|
interuptionMessage: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -26,6 +27,7 @@ const props = defineProps({
|
|||||||
<p v-if="interuptionMessage" class="error"><Icon icon="fa-solid fa-circle-xmark"/> {{ interuptionMessage }}</p>
|
<p v-if="interuptionMessage" class="error"><Icon icon="fa-solid fa-circle-xmark"/> {{ interuptionMessage }}</p>
|
||||||
<p v-else>{{ defaultMessage }}</p>
|
<p v-else>{{ defaultMessage }}</p>
|
||||||
<MusicAnimation />
|
<MusicAnimation />
|
||||||
|
<p class="version">Version : {{ version }} - Chopin</p>
|
||||||
</DefaultSplash>
|
</DefaultSplash>
|
||||||
</template>
|
</template>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@@ -63,6 +65,12 @@ const props = defineProps({
|
|||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.version {
|
||||||
|
font-size: 0.6em;
|
||||||
|
margin-bottom: 0;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 768px),
|
@media screen and (max-width: 768px),
|
||||||
screen and (max-height: 607px) {
|
screen and (max-height: 607px) {
|
||||||
h1 {
|
h1 {
|
||||||
|
@@ -12,6 +12,7 @@ import { IOListener, IORequest } from '@/utils/IORequest';
|
|||||||
import { useUserStore } from '@/stores/userStore';
|
import { useUserStore } from '@/stores/userStore';
|
||||||
import { useGlobalStore } from '@/stores/globalStore';
|
import { useGlobalStore } from '@/stores/globalStore';
|
||||||
import events from '@/utils/Events.js';
|
import events from '@/utils/Events.js';
|
||||||
|
import Events from '@/utils/Events.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const interuptionMessage = ref(null);
|
const interuptionMessage = ref(null);
|
||||||
@@ -43,6 +44,7 @@ import events from '@/utils/Events.js';
|
|||||||
IORequest("/GUILD/LIST", (response) => {
|
IORequest("/GUILD/LIST", (response) => {
|
||||||
if(response) {
|
if(response) {
|
||||||
userStore.userInfo.guilds = response;
|
userStore.userInfo.guilds = response;
|
||||||
|
Events.emit("GUILD_LIST_UPDATE", response);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<router-link class="no-decoration" to="/">
|
<router-link class="no-decoration" to="/">
|
||||||
<Button><Icon icon="fa-solid fa-house"/> Revenir au concert</Button>
|
<Button icon="fa-solid fa-house"> Revenir au concert</Button>
|
||||||
</router-link>
|
</router-link>
|
||||||
</DefaultSplash>
|
</DefaultSplash>
|
||||||
|
|
||||||
|
@@ -103,7 +103,7 @@ onMounted(() => {
|
|||||||
</Box>
|
</Box>
|
||||||
<br/>
|
<br/>
|
||||||
<router-link class="no-decoration" to="/">
|
<router-link class="no-decoration" to="/">
|
||||||
<Button><Icon icon="fa-solid fa-house"/> Revenir au concert</Button>
|
<Button icon="fa-solid fa-house"> Revenir au concert</Button>
|
||||||
</router-link>
|
</router-link>
|
||||||
<!-- Add more content here as needed -->
|
<!-- Add more content here as needed -->
|
||||||
</DefaultSplash>
|
</DefaultSplash>
|
||||||
|
@@ -61,7 +61,7 @@ function inviteSubsonics() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button :disabled="!hasLink" @click="inviteSubsonics()"><Icon icon="fa-solid fa-user-plus"/>Inviter Subsonics</Button>
|
<Button :disabled="!hasLink" @click="inviteSubsonics()" icon="fa-solid fa-user-plus">Inviter Subsonics</Button>
|
||||||
</div>
|
</div>
|
||||||
</Box>
|
</Box>
|
||||||
<Account class="full"/>
|
<Account class="full"/>
|
||||||
|
@@ -31,7 +31,7 @@ onMounted(() => {
|
|||||||
</Box>
|
</Box>
|
||||||
<br>
|
<br>
|
||||||
<router-link class="no-decoration" to="/">
|
<router-link class="no-decoration" to="/">
|
||||||
<Button><Icon icon="fa-solid fa-house"/> Revenir au concert</Button>
|
<Button icon="fa-solid fa-house">Revenir au concert</Button>
|
||||||
</router-link>
|
</router-link>
|
||||||
<!-- Add more content here as needed -->
|
<!-- Add more content here as needed -->
|
||||||
</DefaultSplash>
|
</DefaultSplash>
|
||||||
|
@@ -3,8 +3,8 @@ import vue from '@vitejs/plugin-vue'
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import VitePluginVueDevTools from 'vite-plugin-vue-devtools'
|
import VitePluginVueDevTools from 'vite-plugin-vue-devtools'
|
||||||
|
|
||||||
// https://vite.dev/config/
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
base: '/', // <-- IMPORTANT : chemins des assets corrects
|
||||||
plugins: [vue(), VitePluginVueDevTools()],
|
plugins: [vue(), VitePluginVueDevTools()],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
|
Reference in New Issue
Block a user