Version 1.0.0 - Frontend

This commit is contained in:
2025-08-29 00:22:08 +02:00
parent b5dc2a9e37
commit 01b089f1f6
83 changed files with 5613 additions and 245 deletions

172
src/components/UI/Video.vue Normal file
View File

@@ -0,0 +1,172 @@
<template>
<div ref="videoContainer" :class="{'video': true, 'video-mobile': mobile}">
<div ref="thumbnailContainer" :class="{'thumbnail-container': true, 'thumbnail-mobile': mobile}">
<img v-if="video" class="thumbnail" :src="video.thumbnail" alt="Video Thumbnail" />
<div v-else class="thumbnail-placeholder"></div>
<p v-if="video && typeof video.duration === 'number' && video.duration != 0 && !mobile" class="duration">{{ getVideoDuration(video.duration) }}</p>
<p v-else-if="video && video.duration === 0 && !mobile" class="duration align"><Icon font-size="10px" color="red" icon="fa-solid fa-circle"></Icon> LIVE</p>
<span v-else></span>
<slot></slot>
</div>
<div :class="{'info-mobile': mobile, 'info': !mobile}">
<Marquee v-if="video && mobile"><p>{{ video.title }}</p></Marquee>
<p v-else-if="video" class="title">{{ video.title }}</p>
<p v-else class="title">Aucun titre jouée</p>
<p v-if="video" class="author">{{ video.author }}</p>
<p v-else class="author">Aucun auteur</p>
</div>
</div>
</template>
<script setup>
import { getVideoDuration } from '@/utils/TimeConverter';
import { ref } from 'vue';
import Marquee from './Marquee.vue';
const props = defineProps({
video: {
required: true,
default: null
},
mobile: {
type: Boolean,
default: false
}
});
const thumbnailContainer = ref(null);
const videoContainer = ref(null);
function getThumbnailContainer() {
return thumbnailContainer.value;
}
function getVideoContainer() {
return videoContainer.value;
}
defineExpose({
getThumbnailContainer,
getVideoContainer,
});
</script>
<style scoped>
.align {
display: flex;
align-items: center;
gap: 3px;
}
.thumbnail {
width: 100%;
height: auto;
border-radius: 10px;
user-select: none;
aspect-ratio: 16/9;
object-fit: cover;
background-color: var(--tertiary);
}
.thumbnail-container {
position: relative;
display: flex;
width: 100%;
}
.thumbnail-mobile {
width: 100% !important;
margin-left: auto;
margin-right: auto;
max-width: 350px;
}
.thumbnail-placeholder {
flex: 1;
height: auto;
border-radius: 10px;
user-select: none;
aspect-ratio: 16/9;
object-fit: cover;
background-color: var(--quaternary);
}
.duration {
position: absolute;
bottom: 0px;
right: 0px;
background-color: rgba(0, 0, 0, 0.5);
color: white;
padding: 2px 5px;
border-radius: 15px;
font-size: 0.8em;
margin: 3% 0.5% 3% 3%;
}
.info {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
gap: 5px;
overflow-wrap: break-word;
word-break: break-word;
white-space: normal;
text-align: center;
}
.info p {
margin: 0;
font-size: 0.9em;
}
.title {
font-weight: bold;
margin: 5px 0 0 0;
}
.author {
color: var(--text-secondary);
}
.video {
display: flex;
flex-direction: column;
align-items: center;
cursor: pointer;
justify-content: space-between;
gap: 5px;
}
.video-mobile {
display: flex;
flex-direction: column;
align-items: start !important;
cursor: pointer;
justify-content: space-between;
gap: 10px;
margin-left: 10px;
margin-right: 10px;
width: 100%;
}
.info-mobile {
display: flex;
flex-direction: column;
gap: 5px;
width: 100%;
}
.info-mobile p {
margin: 0;
font-size: 1.3em;
}
</style>