Merged PR 107: Detached into main
This commit is contained in:
@@ -2,12 +2,18 @@
|
|||||||
|
|
||||||
<v-infinite-scroll :items="contents"
|
<v-infinite-scroll :items="contents"
|
||||||
:onLoad="fetchContents"
|
:onLoad="fetchContents"
|
||||||
class="gap-2">
|
class="md:gap-2">
|
||||||
|
|
||||||
<template v-for="content in contents" :key="content">
|
<template v-for="content in contents" :key="content.id">
|
||||||
<content-card :content="content"
|
|
||||||
@content-deleted="onContentDeleted"
|
<div class="d-sm-none mb-1">
|
||||||
></content-card>
|
<content-card-sm :content="content" @content-deleted="onContentDeleted"></content-card-sm>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="d-none d-sm-flex">
|
||||||
|
<content-card-normal :content="content" @content-deleted="onContentDeleted"></content-card-normal>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-slot:empty>
|
<template v-slot:empty>
|
||||||
@@ -22,11 +28,12 @@
|
|||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
|
||||||
|
|
||||||
|
<script setup>
|
||||||
import {useClient} from '@/plugins/api.js';
|
import {useClient} from '@/plugins/api.js';
|
||||||
import {ref, watch} from 'vue';
|
import {ref, watch} from 'vue';
|
||||||
import ContentCard from "./ContentCard.vue";
|
import ContentCardNormal from "@/views/contents/contentcards/NContentCard.vue";
|
||||||
|
import ContentCardSm from "@/views/contents/contentcards/SmContentCard.vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
creatorId: {
|
creatorId: {
|
||||||
@@ -52,10 +59,8 @@ const creatorIdWatcher = watch(
|
|||||||
() => props.creatorId,
|
() => props.creatorId,
|
||||||
(newCreatorId) => {
|
(newCreatorId) => {
|
||||||
if (newCreatorId) {
|
if (newCreatorId) {
|
||||||
// Reset contents and last_id when the creatorId changes
|
|
||||||
contents.value = []
|
contents.value = []
|
||||||
last_id = null
|
last_id = null
|
||||||
// Fetch contents for the new creator
|
|
||||||
fetchContents({
|
fetchContents({
|
||||||
done: () => {
|
done: () => {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,170 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex h-[calc(100vh-118px)] -mt-2">
|
<div class="d-sm-block d-md-block d-lg-none mb-1">
|
||||||
<!-- Homemade carousel -->
|
<full-screen-content-sm></full-screen-content-sm>
|
||||||
<div class="flex-1 flex items-center justify-center bg-neutral-500 max-h-screen relative">
|
</div>
|
||||||
|
<div class="d-none d-lg-flex">
|
||||||
<!-- Blur image BG (désactivation des interactions) -->
|
<full-screen-content-md></full-screen-content-md>
|
||||||
<div class="absolute inset-0 z-0 bg-cover bg-center blur-lg pointer-events-none"
|
|
||||||
:style="{ backgroundImage: `url(${currentImage})` }"></div>
|
|
||||||
|
|
||||||
<!-- back Btn -->
|
|
||||||
<div class="absolute top-8 left-4 z-20">
|
|
||||||
<v-btn @click="goBack" variant="plain"
|
|
||||||
class="rounded-full text-white w-12 h-12 flex items-center justify-center">
|
|
||||||
<v-icon class="text-black bg-white rounded-full" size="36">mdi-close</v-icon>
|
|
||||||
</v-btn>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Left arrow collée à gauche -->
|
|
||||||
<div v-if="multipleImages" class="absolute left-0 top-1/2 transform -translate-y-1/2 z-20">
|
|
||||||
<v-btn @click="previousImage" variant="plain" class="rounded-full bg-gray-800 text-white w-12 h-12">
|
|
||||||
<v-icon size="36">mdi-chevron-left</v-icon>
|
|
||||||
</v-btn>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-center w-full h-full z-10">
|
|
||||||
<img :src="currentImage" alt="Image" class="max-w-full max-h-full object-contain" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- right arrow -->
|
|
||||||
<div v-if="multipleImages" class="absolute right-4 top-1/2 transform -translate-y-1/2 z-10">
|
|
||||||
<v-btn @click="nextImage" variant="plain" class="rounded-full bg-gray-800 text-white w-12 h-12">
|
|
||||||
<v-icon size="36">mdi-chevron-right</v-icon>
|
|
||||||
</v-btn>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Info -->
|
|
||||||
<div class="fixed-width border-l-2 p-6 bg-white overflow-y-auto max-h-screen">
|
|
||||||
|
|
||||||
<div class="border-b-2 p-6 font-sans space-y-2">
|
|
||||||
<div v-if="data && data.createdByName">
|
|
||||||
Créé par: {{ data.createdByName }}
|
|
||||||
</div>
|
|
||||||
<div v-if="data && data.title" class="font-semibold">
|
|
||||||
Titre: {{ data.title }}
|
|
||||||
</div>
|
|
||||||
<div v-if="data && data.description">
|
|
||||||
Description: {{ data.description }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex justify-around py-2">
|
|
||||||
<v-btn variant="plain" icon @click="likeContent">
|
|
||||||
<v-icon :color="'#313131'">mdi-thumb-up-outline</v-icon>
|
|
||||||
</v-btn>
|
|
||||||
<v-btn variant="plain" icon @click="dislikeContent">
|
|
||||||
<v-icon :color="'#000000'">mdi-thumb-down-outline</v-icon>
|
|
||||||
</v-btn>
|
|
||||||
|
|
||||||
<donation-button v-if="data"
|
|
||||||
:color-border="data.colorMenu"
|
|
||||||
:color-accent="data.colorAccent"
|
|
||||||
:creator-id="data.createdBy"
|
|
||||||
:creator-name="data.createdByName"
|
|
||||||
:creator-logo="data.createdByPortraitUrl"
|
|
||||||
iconColorClass="text-black"
|
|
||||||
></donation-button>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="border-b-2 p-6">
|
|
||||||
<h2 class="font-sans font-semibold">Commentaires</h2>
|
|
||||||
<message-list :subject-id="contentId"
|
|
||||||
></message-list>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="border-b-2 p-6">
|
|
||||||
<post-message :subject-id="contentId"
|
|
||||||
></post-message>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {ref, computed, onMounted, watch} from 'vue';
|
import FullScreenContentSm from "@/views/contents/contentfullscreen/FullScreenContentSm.vue";
|
||||||
import PostMessage from "@/views/messages/PostMessage.vue";
|
import FullScreenContentMd from "@/views/contents/contentfullscreen/FullScreenContentMd.vue";
|
||||||
import MessageList from "@/views/messages/MessageList.vue";
|
|
||||||
import DonationButton from "@/views/creators/DonationButton.vue";
|
|
||||||
import {useClient} from "@/plugins/api.js";
|
|
||||||
import {useRoute} from 'vue-router';
|
|
||||||
|
|
||||||
const data = ref(null);
|
|
||||||
const currentImageIndex = ref(0);
|
|
||||||
|
|
||||||
const route = useRoute();
|
|
||||||
const client = useClient();
|
|
||||||
|
|
||||||
const contentId = computed(() => {
|
|
||||||
return route.params.contentId;
|
|
||||||
});
|
|
||||||
|
|
||||||
const currentImage = computed(() => {
|
|
||||||
if (data.value && data.value.urls) {
|
|
||||||
return data.value.urls[currentImageIndex.value] || '';
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
});
|
|
||||||
|
|
||||||
// Calculer si on a plus d'une image
|
|
||||||
const multipleImages = computed(() => {
|
|
||||||
if (data.value && data.value.urls) {
|
|
||||||
return data.value.urls.length > 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
const fetchContentData = async (contentId) => {
|
|
||||||
try {
|
|
||||||
const response = await client.get(`/api/contents/${contentId}`);
|
|
||||||
data.value = response.data;
|
|
||||||
console.table(data.value)
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Error fetching content: ${error}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function goBack() {
|
|
||||||
window.history.go(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function nextImage() {
|
|
||||||
if (data.value?.urls.length > 0) {
|
|
||||||
currentImageIndex.value = (currentImageIndex.value + 1) % data.value.urls.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function previousImage() {
|
|
||||||
if (data.value?.urls.length > 0) {
|
|
||||||
currentImageIndex.value = (currentImageIndex.value - 1 + data.value.urls.length) % data.value.urls.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
fetchContentData(contentId.value);
|
|
||||||
});
|
|
||||||
|
|
||||||
watch(contentId, (newContentId) => {
|
|
||||||
fetchContentData(newContentId);
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.fixed-width {
|
|
||||||
width: 400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.v-btn {
|
|
||||||
transition: background-color 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.v-btn:hover {
|
|
||||||
background-color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
.v-btn .v-icon {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
245
src/views/contents/contentcards/NContentCard.vue
Normal file
245
src/views/contents/contentcards/NContentCard.vue
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
<template>
|
||||||
|
<div class="shadow-md rounded-2xl bg-gray-50 border custom-border w-full mb-2 ">
|
||||||
|
<div>
|
||||||
|
<v-card-title>
|
||||||
|
<div class="flex flex-row justify-between items-center">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<img
|
||||||
|
:src="props.content.createdByPortraitUrl"
|
||||||
|
alt="Profile Image"
|
||||||
|
class="rounded-full"
|
||||||
|
width="32px"
|
||||||
|
height="32px">
|
||||||
|
<div class="capitalize px-2">
|
||||||
|
{{ props.content.createdByName }}
|
||||||
|
</div>
|
||||||
|
<span class="text-subtitle-2 mt-1">
|
||||||
|
{{ time_ago(props.content.createdAt) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<v-menu>
|
||||||
|
<template v-slot:activator="{ props }">
|
||||||
|
<v-btn variant="plain" v-bind="props">
|
||||||
|
<v-icon>mdi-dots-vertical</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
|
<v-list>
|
||||||
|
<v-list-item v-if="creatorIsCurrentUser" @click="editContent">
|
||||||
|
<v-list-item-title>Modifier le contenu</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item v-if="creatorIsCurrentUser" @click="openDeleteConfirmationDialog">
|
||||||
|
<v-list-item-title>Effacer le contenu</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item @click="reportContent">
|
||||||
|
<v-list-item-title>Reporter le contenu</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
</v-list>
|
||||||
|
</v-menu>
|
||||||
|
</div>
|
||||||
|
<div class="uppercase">
|
||||||
|
{{ props.content.title }}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{{ props.content.description }}
|
||||||
|
</div>
|
||||||
|
</v-card-title>
|
||||||
|
|
||||||
|
<v-carousel
|
||||||
|
hide-delimiters
|
||||||
|
v-if="hasUrls"
|
||||||
|
:show-arrows="props.content.urls.length > 1"
|
||||||
|
:show-indicators="props.content.urls.length > 1"
|
||||||
|
>
|
||||||
|
<v-carousel-item
|
||||||
|
v-for="url in props.content.urls"
|
||||||
|
:key="url"
|
||||||
|
class="max-w-[800px]"
|
||||||
|
@click="redirectToContent"
|
||||||
|
>
|
||||||
|
<component :is="getComponent(url)" :src="url"></component>
|
||||||
|
</v-carousel-item>
|
||||||
|
</v-carousel>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="px-4">
|
||||||
|
<div class="flex justify-around py-2">
|
||||||
|
<v-btn variant="plain" icon @click="likeContent">
|
||||||
|
<v-icon>mdi-thumb-up-outline</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
<v-btn variant="plain" icon @click="dislikeContent">
|
||||||
|
<v-icon>mdi-thumb-down-outline</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
<v-btn
|
||||||
|
:class="{'comment-active': hasMessages}"
|
||||||
|
variant="plain"
|
||||||
|
icon
|
||||||
|
@click="toggleComments">
|
||||||
|
<v-icon>mdi-comment-outline</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
|
||||||
|
<donation-button :color-border="colorMenu"
|
||||||
|
:color-accent="colorAccent"
|
||||||
|
:creator-id="creatorId"
|
||||||
|
:creator-name="creatorName"
|
||||||
|
:creator-logo="creatorLogo"
|
||||||
|
iconColorClass="text-black"
|
||||||
|
></donation-button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div :class="{'hidden': !messagesVisible}">
|
||||||
|
<h2 class="font-sans font-semibold mt-2">Commentaires</h2>
|
||||||
|
<message-list
|
||||||
|
:subject-id="props.content.id"
|
||||||
|
:messages="messages"
|
||||||
|
></message-list>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="py-2">
|
||||||
|
<post-message :subject-id="props.content.id"
|
||||||
|
@message-posted="addMessage"
|
||||||
|
></post-message>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<v-dialog v-model="openDeleteConfirmationModal" max-width="500">
|
||||||
|
<v-form>
|
||||||
|
<v-card class="text-center rounded-xl"
|
||||||
|
:style="{
|
||||||
|
border: `2px solid `
|
||||||
|
}">
|
||||||
|
<div class="flex items-center justify-between py-4 text-2xl font-bold border-b mb-2">
|
||||||
|
<div class="flex-1 text-center">
|
||||||
|
Supprimer ce contenu ?
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<v-btn icon @click="openDeleteConfirmationModal = false" class="ml-auto mr-2" variant="text">
|
||||||
|
<v-icon>mdi-close</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class=" mr-2">
|
||||||
|
Êtes-vous sûr de vouloir supprimer le contenu ?
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="py-2 space-x-3">
|
||||||
|
<v-btn variant="flat"
|
||||||
|
@click="deleteContent()" class=" mt-5">
|
||||||
|
Oui
|
||||||
|
</v-btn>
|
||||||
|
<v-btn variant="outlined"
|
||||||
|
@click="openDeleteConfirmationModal = false" class=" mt-5">
|
||||||
|
Non
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
</v-card>
|
||||||
|
</v-form>
|
||||||
|
</v-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {computed, ref} from 'vue';
|
||||||
|
import {time_ago} from "@/internal_time_ago.js";
|
||||||
|
import MessageList from "@/views/messages/MessageList.vue";
|
||||||
|
import PostMessage from "@/views/messages/PostMessage.vue";
|
||||||
|
import DonationButton from "@/views/creators/DonationButton.vue";
|
||||||
|
import YoutubePlayer from '../YoutubePlayer.vue';
|
||||||
|
import ImageViewer from '../ImageViewer.vue';
|
||||||
|
import {useClient} from "@/plugins/api.js";
|
||||||
|
import {useAuthStore} from "@/stores/authStore.js";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
content: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const openDeleteConfirmationModal = ref(false);
|
||||||
|
const emits = defineEmits(['content-deleted'])
|
||||||
|
|
||||||
|
const contentId = computed(() => props.content.id)
|
||||||
|
const creatorId = computed(() => props.content.createdBy)
|
||||||
|
const creatorName = computed(() => props.content.createdByName)
|
||||||
|
const creatorLogo = computed(() => props.content.createdByPortraitUrl)
|
||||||
|
const colorMenu = computed(() => props.content.colorMenu)
|
||||||
|
const colorAccent = computed(() => props.content.colorAccent)
|
||||||
|
|
||||||
|
const authStore = useAuthStore()
|
||||||
|
const creatorIsCurrentUser = computed(() => authStore.isAuthenticated && authStore.userId === creatorId.value)
|
||||||
|
|
||||||
|
const hasUrls = computed(() => !!props.content.urls && props.content.urls.length > 0);
|
||||||
|
const messagesVisible = ref(false);
|
||||||
|
const messages = ref([]);
|
||||||
|
const hasMessages = computed(() => messages.value.length > 0)
|
||||||
|
|
||||||
|
function openDeleteConfirmationDialog() {
|
||||||
|
openDeleteConfirmationModal.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addMessage(newMessage) {
|
||||||
|
messages.value.unshift(newMessage);
|
||||||
|
messagesVisible.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleComments() {
|
||||||
|
messagesVisible.value = !messagesVisible.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function likeContent() {
|
||||||
|
console.log('Content liked');
|
||||||
|
}
|
||||||
|
|
||||||
|
function dislikeContent() {
|
||||||
|
console.log('Content disliked');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getComponent(url) {
|
||||||
|
if (url.includes('youtube.com') || url.includes('youtu.be')) {
|
||||||
|
return YoutubePlayer;
|
||||||
|
} else if (url.match(/\.(jpeg|jpg|gif|png)$/)) {
|
||||||
|
return ImageViewer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function editContent() {
|
||||||
|
console.log('Modifier le contenu');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteContent() {
|
||||||
|
const client = useClient()
|
||||||
|
const response = await client.delete(`/api/contents/${contentId.value}`)
|
||||||
|
if (response.status >= 200 && response.status < 300) {
|
||||||
|
emits('content-deleted', contentId.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function reportContent() {
|
||||||
|
console.log('Reporter le contenu');
|
||||||
|
}
|
||||||
|
|
||||||
|
function redirectToContent() {
|
||||||
|
window.location.href = `/content/${props.content.id}`;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
|
||||||
|
.custom-border {
|
||||||
|
border-color: #EAEBEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-active .v-icon {
|
||||||
|
color: #D63DAB;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
265
src/views/contents/contentcards/SmContentCard.vue
Normal file
265
src/views/contents/contentcards/SmContentCard.vue
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
<template>
|
||||||
|
<div class="shadow-md bg-gray-50">
|
||||||
|
<div>
|
||||||
|
<v-card-title>
|
||||||
|
<div class="flex flex-row justify-between items-center">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<img
|
||||||
|
:src="props.content.createdByPortraitUrl"
|
||||||
|
alt="Profile Image"
|
||||||
|
class="rounded-full"
|
||||||
|
width="32px"
|
||||||
|
height="32px">
|
||||||
|
<div class="capitalize px-2">
|
||||||
|
{{ props.content.createdByName }}
|
||||||
|
</div>
|
||||||
|
<span class="text-subtitle-2">
|
||||||
|
{{ time_ago(props.content.createdAt) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<v-menu>
|
||||||
|
<template v-slot:activator="{ props }">
|
||||||
|
<v-btn variant="plain" v-bind="props">
|
||||||
|
<v-icon>mdi-dots-vertical</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
|
<v-list>
|
||||||
|
<v-list-item v-if="creatorIsCurrentUser" @click="editContent">
|
||||||
|
<v-list-item-title>Modifier le contenu</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item v-if="creatorIsCurrentUser" @click="openDeleteConfirmationDialog">
|
||||||
|
<v-list-item-title>Effacer le contenu</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item @click="reportContent">
|
||||||
|
<v-list-item-title>Reporter le contenu</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
</v-list>
|
||||||
|
</v-menu>
|
||||||
|
</div>
|
||||||
|
<div class="uppercase">
|
||||||
|
{{ props.content.title }}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{{ props.content.description }}
|
||||||
|
</div>
|
||||||
|
</v-card-title>
|
||||||
|
|
||||||
|
<v-carousel
|
||||||
|
hide-delimiters
|
||||||
|
v-if="hasUrls"
|
||||||
|
:show-arrows="props.content.urls.length > 1"
|
||||||
|
:show-indicators="props.content.urls.length > 1"
|
||||||
|
>
|
||||||
|
<v-carousel-item
|
||||||
|
v-for="url in props.content.urls"
|
||||||
|
:key="url"
|
||||||
|
class="image-container"
|
||||||
|
@click="redirectToContent"
|
||||||
|
>
|
||||||
|
<component :is="getComponent(url)" :src="url"></component>
|
||||||
|
</v-carousel-item>
|
||||||
|
</v-carousel>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="px-1">
|
||||||
|
<div class="flex justify-around ">
|
||||||
|
<v-btn variant="plain" icon @click="likeContent">
|
||||||
|
<v-icon>mdi-thumb-up-outline</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
<v-btn variant="plain" icon @click="dislikeContent">
|
||||||
|
<v-icon>mdi-thumb-down-outline</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
<v-btn
|
||||||
|
:class="{'comment-active': hasMessages}"
|
||||||
|
variant="plain"
|
||||||
|
icon
|
||||||
|
@click="toggleComments">
|
||||||
|
<v-icon>mdi-comment-outline</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
|
||||||
|
<donation-button :color-border="colorMenu"
|
||||||
|
:color-accent="colorAccent"
|
||||||
|
:creator-id="creatorId"
|
||||||
|
:creator-name="creatorName"
|
||||||
|
:creator-logo="creatorLogo"
|
||||||
|
iconColorClass="text-black"
|
||||||
|
></donation-button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div :class="{'hidden': !messagesVisible}">
|
||||||
|
<h2 class="font-sans font-semibold ">Commentaires</h2>
|
||||||
|
<message-list
|
||||||
|
:subject-id="props.content.id"
|
||||||
|
:messages="messages"
|
||||||
|
></message-list>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="py-1">
|
||||||
|
<post-message :subject-id="props.content.id"
|
||||||
|
@message-posted="addMessage"
|
||||||
|
></post-message>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<v-dialog v-model="openDeleteConfirmationModal" max-width="500">
|
||||||
|
<v-form>
|
||||||
|
<v-card class="text-center rounded-xl"
|
||||||
|
:style="{
|
||||||
|
border: `2px solid `
|
||||||
|
}">
|
||||||
|
<div class="flex items-center justify-between py-4 text-2xl font-bold border-b mb-2">
|
||||||
|
<div class="flex-1 text-center">
|
||||||
|
Supprimer ce contenu ?
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<v-btn icon @click="openDeleteConfirmationModal = false" class="ml-auto mr-2" variant="text">
|
||||||
|
<v-icon>mdi-close</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class=" mr-2">
|
||||||
|
Êtes-vous sûr de vouloir supprimer le contenu ?
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="py-2 space-x-3">
|
||||||
|
<v-btn variant="flat"
|
||||||
|
@click="deleteContent()" class=" mt-5">
|
||||||
|
Oui
|
||||||
|
</v-btn>
|
||||||
|
<v-btn variant="outlined"
|
||||||
|
@click="openDeleteConfirmationModal = false" class=" mt-5">
|
||||||
|
Non
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
</v-card>
|
||||||
|
</v-form>
|
||||||
|
</v-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {computed, ref} from 'vue';
|
||||||
|
import {time_ago} from "@/internal_time_ago.js";
|
||||||
|
import MessageList from "@/views/messages/MessageList.vue";
|
||||||
|
import PostMessage from "@/views/messages/PostMessage.vue";
|
||||||
|
import DonationButton from "@/views/creators/DonationButton.vue";
|
||||||
|
import YoutubePlayer from '../YoutubePlayer.vue';
|
||||||
|
import ImageViewer from '../ImageViewer.vue';
|
||||||
|
import {useClient} from "@/plugins/api.js";
|
||||||
|
import {useAuthStore} from "@/stores/authStore.js";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
content: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const openDeleteConfirmationModal = ref(false);
|
||||||
|
const emits = defineEmits(['content-deleted'])
|
||||||
|
|
||||||
|
const contentId = computed(() => props.content.id)
|
||||||
|
const creatorId = computed(() => props.content.createdBy)
|
||||||
|
const creatorName = computed(() => props.content.createdByName)
|
||||||
|
const creatorLogo = computed(() => props.content.createdByPortraitUrl)
|
||||||
|
const colorMenu = computed(() => props.content.colorMenu)
|
||||||
|
const colorAccent = computed(() => props.content.colorAccent)
|
||||||
|
|
||||||
|
const authStore = useAuthStore()
|
||||||
|
const creatorIsCurrentUser = computed(() => authStore.isAuthenticated && authStore.userId === creatorId.value)
|
||||||
|
|
||||||
|
const hasUrls = computed(() => !!props.content.urls && props.content.urls.length > 0);
|
||||||
|
const messagesVisible = ref(false);
|
||||||
|
const messages = ref([]);
|
||||||
|
const hasMessages = computed(() => messages.value.length > 0)
|
||||||
|
|
||||||
|
function openDeleteConfirmationDialog() {
|
||||||
|
openDeleteConfirmationModal.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addMessage(newMessage) {
|
||||||
|
messages.value.unshift(newMessage);
|
||||||
|
messagesVisible.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleComments() {
|
||||||
|
messagesVisible.value = !messagesVisible.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function likeContent() {
|
||||||
|
console.log('Content liked');
|
||||||
|
}
|
||||||
|
|
||||||
|
function dislikeContent() {
|
||||||
|
console.log('Content disliked');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getComponent(url) {
|
||||||
|
if (url.includes('youtube.com') || url.includes('youtu.be')) {
|
||||||
|
return YoutubePlayer;
|
||||||
|
} else if (url.match(/\.(jpeg|jpg|gif|png)$/)) {
|
||||||
|
return ImageViewer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function editContent() {
|
||||||
|
console.log('Modifier le contenu');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteContent() {
|
||||||
|
const client = useClient()
|
||||||
|
const response = await client.delete(`/api/contents/${contentId.value}`)
|
||||||
|
if (response.status >= 200 && response.status < 300) {
|
||||||
|
emits('content-deleted', contentId.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function reportContent() {
|
||||||
|
console.log('Reporter le contenu');
|
||||||
|
}
|
||||||
|
|
||||||
|
function redirectToContent() {
|
||||||
|
window.location.href = `/content/${props.content.id}`;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.image-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-container img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-border {
|
||||||
|
border-color: #EAEBEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-carousel-item {
|
||||||
|
padding: 0; /* Supprime tout padding interne */
|
||||||
|
margin: 0; /* Supprime toute marge interne */
|
||||||
|
width: 100vw; /* Assure que chaque item occupe toute la largeur de l'écran */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.comment-active .v-icon {
|
||||||
|
color: #D63DAB;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
170
src/views/contents/contentfullscreen/FullScreenContentMd.vue
Normal file
170
src/views/contents/contentfullscreen/FullScreenContentMd.vue
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex h-[calc(100vh-118px)] -mt-2">
|
||||||
|
<!-- Homemade carousel -->
|
||||||
|
<div class="flex-1 flex items-center justify-center bg-neutral-500 max-h-screen relative">
|
||||||
|
|
||||||
|
<!-- Blur image BG (désactivation des interactions) -->
|
||||||
|
<div class="absolute inset-0 z-0 bg-cover bg-center blur-lg pointer-events-none"
|
||||||
|
:style="{ backgroundImage: `url(${currentImage})` }"></div>
|
||||||
|
|
||||||
|
<!-- back Btn -->
|
||||||
|
<div class="absolute top-8 left-4 z-20">
|
||||||
|
<v-btn @click="goBack" variant="plain"
|
||||||
|
class="rounded-full text-white w-12 h-12 flex items-center justify-center">
|
||||||
|
<v-icon class="text-black bg-white rounded-full" size="36">mdi-close</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Left arrow collée à gauche -->
|
||||||
|
<div v-if="multipleImages" class="absolute left-0 top-1/2 transform -translate-y-1/2 z-20">
|
||||||
|
<v-btn @click="previousImage" variant="plain" class="rounded-full bg-gray-800 text-white w-12 h-12">
|
||||||
|
<v-icon size="36">mdi-chevron-left</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center justify-center w-full h-full z-10">
|
||||||
|
<img :src="currentImage" alt="Image" class="max-w-full max-h-full object-contain" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- right arrow -->
|
||||||
|
<div v-if="multipleImages" class="absolute right-4 top-1/2 transform -translate-y-1/2 z-10">
|
||||||
|
<v-btn @click="nextImage" variant="plain" class="rounded-full bg-gray-800 text-white w-12 h-12">
|
||||||
|
<v-icon size="36">mdi-chevron-right</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Info -->
|
||||||
|
<div class="fixed-width border-l-2 p-6 bg-white overflow-y-auto max-h-screen">
|
||||||
|
|
||||||
|
<div class="border-b-2 p-6 font-sans space-y-2">
|
||||||
|
<div v-if="data && data.createdByName">
|
||||||
|
Créé par: {{ data.createdByName }}
|
||||||
|
</div>
|
||||||
|
<div v-if="data && data.title" class="font-semibold">
|
||||||
|
Titre: {{ data.title }}
|
||||||
|
</div>
|
||||||
|
<div v-if="data && data.description">
|
||||||
|
Description: {{ data.description }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-around py-2">
|
||||||
|
<v-btn variant="plain" icon @click="likeContent">
|
||||||
|
<v-icon :color="'#313131'">mdi-thumb-up-outline</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
<v-btn variant="plain" icon @click="dislikeContent">
|
||||||
|
<v-icon :color="'#000000'">mdi-thumb-down-outline</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
|
||||||
|
<donation-button v-if="data"
|
||||||
|
:color-border="data.colorMenu"
|
||||||
|
:color-accent="data.colorAccent"
|
||||||
|
:creator-id="data.createdBy"
|
||||||
|
:creator-name="data.createdByName"
|
||||||
|
:creator-logo="data.createdByPortraitUrl"
|
||||||
|
iconColorClass="text-black"
|
||||||
|
></donation-button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="border-b-2 p-6">
|
||||||
|
<h2 class="font-sans font-semibold">Commentaires</h2>
|
||||||
|
<message-list :subject-id="contentId"
|
||||||
|
></message-list>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="border-b-2 p-6">
|
||||||
|
<post-message :subject-id="contentId"
|
||||||
|
></post-message>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {ref, computed, onMounted, watch} from 'vue';
|
||||||
|
import PostMessage from "@/views/messages/PostMessage.vue";
|
||||||
|
import MessageList from "@/views/messages/MessageList.vue";
|
||||||
|
import DonationButton from "@/views/creators/DonationButton.vue";
|
||||||
|
import {useClient} from "@/plugins/api.js";
|
||||||
|
import {useRoute} from 'vue-router';
|
||||||
|
|
||||||
|
const data = ref(null);
|
||||||
|
const currentImageIndex = ref(0);
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const client = useClient();
|
||||||
|
|
||||||
|
const contentId = computed(() => {
|
||||||
|
return route.params.contentId;
|
||||||
|
});
|
||||||
|
|
||||||
|
const currentImage = computed(() => {
|
||||||
|
if (data.value && data.value.urls) {
|
||||||
|
return data.value.urls[currentImageIndex.value] || '';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
});
|
||||||
|
|
||||||
|
// Calculer si on a plus d'une image
|
||||||
|
const multipleImages = computed(() => {
|
||||||
|
if (data.value && data.value.urls) {
|
||||||
|
return data.value.urls.length > 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchContentData = async (contentId) => {
|
||||||
|
try {
|
||||||
|
const response = await client.get(`/api/contents/${contentId}`);
|
||||||
|
data.value = response.data;
|
||||||
|
console.table(data.value)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error fetching content: ${error}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function goBack() {
|
||||||
|
window.history.go(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function nextImage() {
|
||||||
|
if (data.value?.urls.length > 0) {
|
||||||
|
currentImageIndex.value = (currentImageIndex.value + 1) % data.value.urls.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function previousImage() {
|
||||||
|
if (data.value?.urls.length > 0) {
|
||||||
|
currentImageIndex.value = (currentImageIndex.value - 1 + data.value.urls.length) % data.value.urls.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchContentData(contentId.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(contentId, (newContentId) => {
|
||||||
|
fetchContentData(newContentId);
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.fixed-width {
|
||||||
|
width: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-btn {
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-btn:hover {
|
||||||
|
background-color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-btn .v-icon {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
174
src/views/contents/contentfullscreen/FullScreenContentSm.vue
Normal file
174
src/views/contents/contentfullscreen/FullScreenContentSm.vue
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex flex-col -mt-2">
|
||||||
|
<!-- Titre en haut de l'image -->
|
||||||
|
<div class="bg-white py-4 text-center font-semibold text-lg">
|
||||||
|
<div v-if="data && data.title">
|
||||||
|
{{ data.title }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Homemade carousel -->
|
||||||
|
<div class="flex-1 flex items-center justify-center bg-neutral-500 max-h-screen relative">
|
||||||
|
|
||||||
|
<!-- Blur image BG (désactivation des interactions) -->
|
||||||
|
<div class="absolute inset-0 z-0 bg-cover bg-center blur-lg pointer-events-none"
|
||||||
|
:style="{ backgroundImage: `url(${currentImage})` }"></div>
|
||||||
|
|
||||||
|
<!-- back Btn -->
|
||||||
|
<div class="absolute top-8 left-4 z-20">
|
||||||
|
<v-btn @click="goBack" variant="plain"
|
||||||
|
class="rounded-full text-white w-12 h-12 flex items-center justify-center">
|
||||||
|
<v-icon class="text-black bg-white rounded-full" size="36">mdi-close</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Left arrow collée à gauche -->
|
||||||
|
<div v-if="multipleImages" class="absolute left-0 top-1/2 transform -translate-y-1/2 z-20">
|
||||||
|
<v-btn @click="previousImage" variant="plain" class="rounded-full bg-gray-800 text-white w-12 h-12">
|
||||||
|
<v-icon size="36">mdi-chevron-left</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center justify-center w-full h-full z-10">
|
||||||
|
<img :src="currentImage" alt="Image" class="max-w-full max-h-full object-contain" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- right arrow -->
|
||||||
|
<div v-if="multipleImages" class="absolute right-4 top-1/2 transform -translate-y-1/2 z-10">
|
||||||
|
<v-btn @click="nextImage" variant="plain" class="rounded-full bg-gray-800 text-white w-12 h-12">
|
||||||
|
<v-icon size="36">mdi-chevron-right</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Info -->
|
||||||
|
<div class="flex flex-col p-6 bg-white overflow-y-auto max-h-screen">
|
||||||
|
|
||||||
|
<div class="border-b-2 p-6 font-sans space-y-2">
|
||||||
|
<div v-if="data && data.createdByName">
|
||||||
|
Créé par: {{ data.createdByName }}
|
||||||
|
</div>
|
||||||
|
<div v-if="data && data.description">
|
||||||
|
Description: {{ data.description }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-around py-2">
|
||||||
|
<v-btn variant="plain" icon @click="likeContent">
|
||||||
|
<v-icon :color="'#313131'">mdi-thumb-up-outline</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
<v-btn variant="plain" icon @click="dislikeContent">
|
||||||
|
<v-icon :color="'#000000'">mdi-thumb-down-outline</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
|
||||||
|
<donation-button v-if="data"
|
||||||
|
:color-border="data.colorMenu"
|
||||||
|
:color-accent="data.colorAccent"
|
||||||
|
:creator-id="data.createdBy"
|
||||||
|
:creator-name="data.createdByName"
|
||||||
|
:creator-logo="data.createdByPortraitUrl"
|
||||||
|
iconColorClass="text-black"
|
||||||
|
></donation-button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="border-b-2 p-6">
|
||||||
|
<h2 class="font-sans font-semibold">Commentaires</h2>
|
||||||
|
<message-list :subject-id="contentId"
|
||||||
|
></message-list>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="border-b-2 p-6">
|
||||||
|
<post-message :subject-id="contentId"
|
||||||
|
></post-message>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {ref, computed, onMounted, watch} from 'vue';
|
||||||
|
import PostMessage from "@/views/messages/PostMessage.vue";
|
||||||
|
import MessageList from "@/views/messages/MessageList.vue";
|
||||||
|
import DonationButton from "@/views/creators/DonationButton.vue";
|
||||||
|
import {useClient} from "@/plugins/api.js";
|
||||||
|
import {useRoute} from 'vue-router';
|
||||||
|
|
||||||
|
const data = ref(null);
|
||||||
|
const currentImageIndex = ref(0);
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const client = useClient();
|
||||||
|
|
||||||
|
const contentId = computed(() => {
|
||||||
|
return route.params.contentId;
|
||||||
|
});
|
||||||
|
|
||||||
|
const currentImage = computed(() => {
|
||||||
|
if (data.value && data.value.urls) {
|
||||||
|
return data.value.urls[currentImageIndex.value] || '';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
});
|
||||||
|
|
||||||
|
// Calculer si on a plus d'une image
|
||||||
|
const multipleImages = computed(() => {
|
||||||
|
if (data.value && data.value.urls) {
|
||||||
|
return data.value.urls.length > 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchContentData = async (contentId) => {
|
||||||
|
try {
|
||||||
|
const response = await client.get(`/api/contents/${contentId}`);
|
||||||
|
data.value = response.data;
|
||||||
|
console.table(data.value)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error fetching content: ${error}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function goBack() {
|
||||||
|
window.history.go(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function nextImage() {
|
||||||
|
if (data.value?.urls.length > 0) {
|
||||||
|
currentImageIndex.value = (currentImageIndex.value + 1) % data.value.urls.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function previousImage() {
|
||||||
|
if (data.value?.urls.length > 0) {
|
||||||
|
currentImageIndex.value = (currentImageIndex.value - 1 + data.value.urls.length) % data.value.urls.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchContentData(contentId.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(contentId, (newContentId) => {
|
||||||
|
fetchContentData(newContentId);
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.fixed-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-btn {
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-btn:hover {
|
||||||
|
background-color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-btn .v-icon {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,53 +1,47 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- Bannière-->
|
<!-- Bannière-->
|
||||||
<div>
|
<div>
|
||||||
<div class="relative z-20">
|
<div class="relative z-20 -mt-2 md:mt-2">
|
||||||
<div>
|
<div>
|
||||||
<!-- Social Network-->
|
<!-- Social Network UpperPart-->
|
||||||
<div class="py-4 px-4 min-h-14 md:rounded-t-none lg:rounded-t-2xl"
|
<div class="py-4 px-4 min-h-14 md:rounded-t-2xl"
|
||||||
:style="{ backgroundColor: creator.colors.bannerTop || '#6B0065' }">
|
:style="{ backgroundColor: creator.colors.bannerTop || '#6B0065' }">
|
||||||
|
|
||||||
<div class="w-full flex justify-between lg:justify-end gap-14 mt-2">
|
<div class="w-full flex justify-end gap-6 max-h-8">
|
||||||
<a
|
<a
|
||||||
v-for="socialNetwork in GetSocialsUrls()"
|
v-for="socialNetwork in GetSocialsUrls()"
|
||||||
:href="socialNetwork.url"
|
:href="socialNetwork.url"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
class="text-white text-2xl transform transition-transform duration-200 hover:scale-125 hover:text-blue-500">
|
class="text-white text-2xl transform transition-transform duration-200 hover:scale-125 hover:text-blue-500">
|
||||||
<v-icon v-if="socialNetwork.icon.includes('mdi')">{{ socialNetwork.icon }}</v-icon>
|
<v-icon v-if="socialNetwork.icon.includes('mdi')">{{ socialNetwork.icon }}</v-icon>
|
||||||
<img v-if="socialNetwork.icon.includes('tiktok')" :src="socialNetwork.icon" class="w-9 h-9"
|
<img v-if="socialNetwork.icon.includes('tiktok')" :src="socialNetwork.icon" class="w-9 h-9"
|
||||||
alt="Tiktok">
|
alt="Tiktok">
|
||||||
<img v-if="socialNetwork.icon.includes('websiteIcon')" :src="socialNetwork.icon" class="w-9 h-9"
|
<img v-if="socialNetwork.icon.includes('websiteIcon')" :src="socialNetwork.icon" class="w-9 h-9"
|
||||||
alt="Website">
|
alt="Website">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--Banner & user info-->
|
|
||||||
<div class="relative">
|
|
||||||
<!--Banner-->
|
|
||||||
<div>
|
|
||||||
<img class=" w-full drop-shadow-[0_15px_10px_rgba(0,0,0,0.35)]"
|
|
||||||
:src="creator.images.banner"
|
|
||||||
alt="Profile Banner" style="max-height: 425px">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<banner-actions :creator="creator" @content-posted="addContent"></banner-actions>
|
<!--Banner-->
|
||||||
|
<div class="relative">
|
||||||
|
<!--Banner-->
|
||||||
|
<div>
|
||||||
|
<img class=" w-full drop-shadow-[0_15px_10px_rgba(0,0,0,0.35)]"
|
||||||
|
:src="creator.images.banner"
|
||||||
|
alt="Profile Banner" style="max-height: 425px">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!--actions - Lowerpart-->
|
||||||
|
<banner-actions :creator="creator" @content-posted="addContent"></banner-actions>
|
||||||
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import CreatorAbout from "@/views/creators/CreatorAbout.vue";
|
import BannerActions from "@/views/creators/banner/bannerlower/BannerActions.vue";
|
||||||
import SubscribeButton from "@/views/creators/SubscribeButton.vue";
|
|
||||||
import PublishContentButton from "@/views/contents/PublishContentButton.vue";
|
|
||||||
import DonationButton from "@/views/creators/DonationButton.vue";
|
|
||||||
import BannerActions from "@/views/creators/banner/BannerActions.vue";
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
creator: {type: Object, required: true},
|
creator: {type: Object, required: true},
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Fallback when user try to access a non-existing creator -->
|
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div v-if="loading">
|
<div v-if="loading">
|
||||||
<v-progress-linear indeterminate></v-progress-linear>
|
<v-progress-linear indeterminate></v-progress-linear>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import BannerActionsSm from "@/views/creators/banner/BannerActionsSm.vue";
|
import BannerActionsMd from "@/views/creators/banner/bannerlower/BannerActionsMd.vue";
|
||||||
import BannerActionsMd from "@/views/creators/banner/BannerActionsMd.vue";
|
import BannerActionsSm from "@/views/creators/banner/bannerlower/BannerActionsSm.vue";
|
||||||
import BannerActionsLg from "@/views/creators/banner/BannerActionsLg.vue";
|
import BannerActionsLg from "@/views/creators/banner/bannerlower/BannerActionsLg.vue";
|
||||||
import BannerActionsXl from "@/views/creators/banner/BannerActionsXl.vue";
|
import BannerActionsXl from "@/views/creators/banner/bannerlower/BannerActionsXl.vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
creator: { type: Object, required: true }
|
creator: { type: Object, required: true }
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="relative w-full">
|
<div class="relative w-full mb-5">
|
||||||
<div class="rounded-b-2xl"
|
<div class="rounded-b-2xl"
|
||||||
:style="{ backgroundColor: creator.colors.bannerBottom || '#A30E79' }">
|
:style="{ backgroundColor: creator.colors.bannerBottom || '#A30E79' }">
|
||||||
<div class="relative z-20">
|
<div class="relative z-20">
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
borderBottom: `2px solid ${creator.colors.accent || '#000000'}`
|
borderBottom: `2px solid ${creator.colors.accent || '#000000'}`
|
||||||
}">
|
}">
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<!-- Logo-Name-Followers-->
|
<!-- Logo-Name-Followers-->
|
||||||
<div class="flex flex-row relative z-20">
|
<div class="flex flex-row relative z-20">
|
||||||
<div>
|
<div>
|
||||||
@@ -18,7 +17,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-column text-white cap px-2 mt-1">
|
<div class="flex flex-column text-white capitalize px-2 mt-1">
|
||||||
<p class="capitalize text-2xl font-bold">{{ creator.name }}</p>
|
<p class="capitalize text-2xl font-bold">{{ creator.name }}</p>
|
||||||
<div>{{ creator.subscriberCount }} Abonnés</div>
|
<div>{{ creator.subscriberCount }} Abonnés</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="relative w-full">
|
<div class="relative w-full mb-5">
|
||||||
<div class="rounded-b-2xl"
|
<div class="rounded-b-2xl"
|
||||||
:style="{ backgroundColor: creator.colors.bannerBottom || '#A30E79' }">
|
:style="{ backgroundColor: creator.colors.bannerBottom || '#A30E79' }">
|
||||||
<div class="relative z-20">
|
<div class="relative z-20">
|
||||||
Reference in New Issue
Block a user