Add ExclusiveContentcontainer with route.
This commit is contained in:
@@ -22,6 +22,8 @@ import Explorer from "@/views/explorer/explorer.vue";
|
||||
import {useAuthStore} from "@/stores/authStore.js";
|
||||
import ForYouPage from "@/views/profile/ForYouPage.vue";
|
||||
import CreatorPresentation from "@/views/creators/CreatorPresentation.vue";
|
||||
import CreatorExclusiveContent from "@/views/creators/CreatorExclusiveContent.vue";
|
||||
|
||||
|
||||
const routes = [
|
||||
{
|
||||
@@ -50,6 +52,10 @@ const routes = [
|
||||
path: '/content/post',
|
||||
component: PostContent,
|
||||
},
|
||||
{
|
||||
path: '/@:creator/exclusivecontent',
|
||||
component: CreatorExclusiveContent
|
||||
},
|
||||
|
||||
{
|
||||
path: '/helpandcontact',
|
||||
|
||||
80
src/views/creators/CreatorExclusiveContent.vue
Normal file
80
src/views/creators/CreatorExclusiveContent.vue
Normal file
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<div :style="{ backgroundColor: '#2D2728' }">
|
||||
<div class="mt-10" v-if="creator && creator.id">
|
||||
<div class="max-w-[1500px] mx-auto">
|
||||
<creator-banner :creator="creator"
|
||||
@content-posted="contentPosted"
|
||||
></creator-banner>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<div v-if="loading">
|
||||
<v-progress-linear indeterminate></v-progress-linear>
|
||||
</div>
|
||||
<div v-else>
|
||||
<v-card>
|
||||
<v-card-text style="text-align: center;">
|
||||
Aucun créateur au nom de {{ route.params.creator }}
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row max-w-[1500px] mx-auto justify-center mt-8">
|
||||
<div>
|
||||
<div class="flex flex-column px-2 max-w-[1200px]">
|
||||
<exclusive-content-container :creator="creator"></exclusive-content-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="max-w-80 hidden xl:block">
|
||||
<!-- Rewards component will be visible only on xl screens -->
|
||||
<rewards :creator="creator"></rewards>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
|
||||
<script async setup>
|
||||
import {watch, ref, onBeforeMount} from 'vue';
|
||||
import {useRoute} from 'vue-router';
|
||||
import {useClient} from "@/plugins/api.js";
|
||||
import CreatorBanner from "@/views/creators/CreatorBanner.vue";
|
||||
import Creatornewssummary from "@/views/creators/CreatorNewsSummary.vue";
|
||||
import Rewards from "@/views/creators/Rewards.vue";
|
||||
import ExclusiveContentContainer from "@/views/creators/ExclusiveContentContainer.vue";
|
||||
|
||||
|
||||
const creator = ref(null)
|
||||
const loading = ref(true)
|
||||
const contents = ref([])
|
||||
|
||||
const client = useClient()
|
||||
const route = useRoute()
|
||||
|
||||
function contentPosted(content) {
|
||||
contents.value.unshift(content)
|
||||
}
|
||||
|
||||
onBeforeMount(async () => await fetchCreatorData(route.params.creator))
|
||||
|
||||
watch(
|
||||
() => route.params.creator,
|
||||
async () => await fetchCreatorData(route.params.creator)
|
||||
)
|
||||
|
||||
const fetchCreatorData = async (creatorAlias) => {
|
||||
try {
|
||||
loading.value = true
|
||||
const response = await client.get(`/api/creators/@${creatorAlias}`)
|
||||
creator.value = response.data
|
||||
} catch (error) {
|
||||
console.error(`Error fetching content: ${error}`)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -42,8 +42,8 @@ import {watch, ref, onBeforeMount} from 'vue';
|
||||
import {useRoute} from 'vue-router';
|
||||
import {useClient} from "@/plugins/api.js";
|
||||
import CreatorBanner from "@/views/creators/CreatorBanner.vue";
|
||||
import Creatornewssummary from "@/views/creators/banner/Creatornewssummary.vue";
|
||||
import Rewards from "@/views/creators/banner/Rewards.vue";
|
||||
import Creatornewssummary from "@/views/creators/CreatorNewsSummary.vue";
|
||||
import Rewards from "@/views/creators/Rewards.vue";
|
||||
|
||||
|
||||
const creator = ref(null)
|
||||
|
||||
180
src/views/creators/ExclusiveContentContainer.vue
Normal file
180
src/views/creators/ExclusiveContentContainer.vue
Normal file
@@ -0,0 +1,180 @@
|
||||
<template>
|
||||
<div class="overflow-hidden relative" @wheel="handleScroll">
|
||||
<!-- Container that holds all the posts and permet le défilement -->
|
||||
<div class="relative h-[1000px] max-h-[1000px] overflow-hidden p-4">
|
||||
<div class="transition-transform duration-500" :style="{ transform: `translateY(-${scrollPosition}px)` }">
|
||||
<!-- Grille avec colonnes dynamiques basées sur la largeur -->
|
||||
<div class="grid gap-3 grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 min-w-[250px]">
|
||||
<div v-for="(item, index) in contenuexclusif" :key="index"
|
||||
class="my-1 text-white rounded-lg w-full border-2 shadow h-[380px] hover-card relative overflow-hidden"
|
||||
:style="{
|
||||
background: creator.colors.bannerTop,
|
||||
borderColor: `rgba(${getRGB(creator.colors.bannerBottom)}, 0.38)`
|
||||
}">
|
||||
<div class="flex justify-center items-center">
|
||||
</div>
|
||||
<div>
|
||||
<img :src="item.photo" class="w-full h-auto max-h-[170px] object-cover" />
|
||||
|
||||
<!-- Section du nombre de clics et du bouton d'édition -->
|
||||
<div class="flex flex-row justify-between items-center p-2">
|
||||
<div class="flex items-center">
|
||||
<p class="text-xs">{{ item.date }}</p>
|
||||
<p class="text-xs px-2">|</p>
|
||||
<p class="text-xs">200 clicks</p>
|
||||
</div>
|
||||
<!-- Bouton pour éditer le contenu à droite -->
|
||||
<v-btn class="" icon variant="plain" @click="editCard(item)">
|
||||
<v-icon>mdi-dots-vertical</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
<p class="text-md p-4">{{ item.title }}</p>
|
||||
<!-- Section des étoiles, fixée dans le coin inférieur droit -->
|
||||
<div v-if="item.rating" class="stars flex justify-end p-2 absolute bottom-0 right-0">
|
||||
<!-- Génération dynamique des étoiles -->
|
||||
<span v-for="star in 5" :key="star" class="text-yellow-500">
|
||||
<v-icon v-if="star <= item.rating">mdi-star</v-icon>
|
||||
<v-icon v-else>mdi-star-outline</v-icon>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, defineProps } from 'vue';
|
||||
|
||||
function hexToRgb(hex) {
|
||||
let shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
||||
hex = hex.replace(shorthandRegex, function(m, r, g, b) {
|
||||
return r + r + g + g + b + b;
|
||||
});
|
||||
|
||||
let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
return result ? {
|
||||
r: parseInt(result[1], 16),
|
||||
g: parseInt(result[2], 16),
|
||||
b: parseInt(result[3], 16)
|
||||
} : null;
|
||||
}
|
||||
|
||||
function getRGB(hexColor) {
|
||||
const rgb = hexToRgb(hexColor);
|
||||
return `${rgb.r}, ${rgb.g}, ${rgb.b}`;
|
||||
}
|
||||
|
||||
const contenuexclusif = ref([
|
||||
{ title: 'Créer un site web moderne', description: 'Un guide pour concevoir un site qui attire l\'attention et se démarque.', photo: '/images/usersmedia/HutopyProfile/profilepictures/profileHutopyProfile01.png', rating: 2, date: '2024-09-19' },
|
||||
{ title: ' Les secrets d’un logo réussiLes secrets d’un logo réussiLes secrets d’un logo réussi', description: 'Découvrez les astuces pour un logo mémorable et distinctif.Découvrez les astuces pour un logo mémorable et distinctif.', photo: '/images/usersmedia/HutopyProfile/profilepictures/profileHutopyProfile01.png', rating: 4, date: '2024-09-19' },
|
||||
{ title: 'Les secrets d’un logo réussi', description: 'Découvrez les astuces pour un logo mémorable et distinctif.', photo: '/images/usersmedia/HutopyProfile/profilepictures/profileHutopyProfile01.png', rating: 4, date: '2024-09-19' },
|
||||
{ title: 'Les secrets d’un logo réussi', description: 'Découvrez les astuces pour un logo mémorable et distinctif.', photo: '/images/usersmedia/HutopyProfile/profilepictures/profileHutopyProfile01.png', rating: 4, date: '2024-09-19' },
|
||||
{ title: 'Les secrets d’un logo réussi', description: 'Découvrez les astuces pour un logo mémorable et distinctif.', photo: '/images/usersmedia/HutopyProfile/profilepictures/profileHutopyProfile01.png', rating: 4, date: '2024-09-19' },
|
||||
{ title: 'Les secrets d’un logo réussi', description: 'Découvrez les astuces pour un logo mémorable et distinctif.', photo: '/images/usersmedia/HutopyProfile/profilepictures/profileHutopyProfile01.png', rating: 4, date: '2024-09-19' },
|
||||
{ title: 'Les secrets d’un logo réussi', description: 'Découvrez les astuces pour un logo mémorable et distinctif.', photo: '/images/usersmedia/HutopyProfile/profilepictures/profileHutopyProfile01.png', rating: 4, date: '2024-09-19' },
|
||||
{ title: 'Les secrets d’un logo réussi', description: 'Découvrez les astuces pour un logo mémorable et distinctif.', photo: '/images/usersmedia/HutopyProfile/profilepictures/profileHutopyProfile01.png', rating: 4, date: '2024-09-19' },
|
||||
{ title: 'Les secrets d’un logo réussi', description: 'Découvrez les astuces pour un logo mémorable et distinctif.', photo: '/images/usersmedia/HutopyProfile/profilepictures/profileHutopyProfile01.png', rating: 4, date: '2024-09-19' },
|
||||
{ title: 'Les secrets d’un logo réussi', description: 'Découvrez les astuces pour un logo mémorable et distinctif.', photo: '/images/usersmedia/HutopyProfile/profilepictures/profileHutopyProfile01.png', rating: 4, date: '2024-09-19' },
|
||||
{ title: 'Les secrets d’un logo réussi', description: 'Découvrez les astuces pour un logo mémorable et distinctif.', photo: '/images/usersmedia/HutopyProfile/profilepictures/profileHutopyProfile01.png', rating: 4, date: '2024-09-19' },
|
||||
{ title: 'Les secrets d’un logo réussi', description: 'Découvrez les astuces pour un logo mémorable et distinctif.', photo: '/images/usersmedia/HutopyProfile/profilepictures/profileHutopyProfile01.png', rating: 4, date: '2024-09-19' },
|
||||
{ title: 'Les secrets d’un logo réussi', description: 'Découvrez les astuces pour un logo mémorable et distinctif.', photo: '/images/usersmedia/HutopyProfile/profilepictures/profileHutopyProfile01.png', rating: 4, date: '2024-09-19' },
|
||||
{ title: 'Les secrets d’un logo réussi', description: 'Découvrez les astuces pour un logo mémorable et distinctif.', photo: '/images/usersmedia/HutopyProfile/profilepictures/profileHutopyProfile01.png', rating: 4, date: '2024-09-19' },
|
||||
{ title: 'Les secrets d’un logo réussi', description: 'Découvrez les astuces pour un logo mémorable et distinctif.', photo: '/images/usersmedia/HutopyProfile/profilepictures/profileHutopyProfile01.png', rating: 4, date: '2024-09-19' },
|
||||
{ title: 'Les secrets d’un logo réussi', description: 'Découvrez les astuces pour un logo mémorable et distinctif.', photo: '/images/usersmedia/HutopyProfile/profilepictures/profileHutopyProfile01.png', rating: 4, date: '2024-09-19' },
|
||||
// autres objets...
|
||||
]);
|
||||
|
||||
const scrollPosition = ref(0);
|
||||
const cardHeight = 320;
|
||||
|
||||
const props = defineProps({
|
||||
creator: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
function handleScroll(event) {
|
||||
event.preventDefault();
|
||||
const scrollSpeed = 100;
|
||||
scrollPosition.value += event.deltaY > 0 ? scrollSpeed : -scrollSpeed;
|
||||
|
||||
const totalRows = Math.ceil(contenuexclusif.value.length / getCurrentCols());
|
||||
const visibleRows = 1000 / cardHeight;
|
||||
const maxScrollPosition = totalRows * cardHeight - visibleRows * cardHeight + 360;
|
||||
|
||||
if (scrollPosition.value < 0) {
|
||||
scrollPosition.value = 0;
|
||||
} else if (scrollPosition.value > maxScrollPosition) {
|
||||
scrollPosition.value = maxScrollPosition;
|
||||
}
|
||||
}
|
||||
|
||||
const gridColsClass = computed(() => {
|
||||
const width = window.innerWidth;
|
||||
if (width >= 1200) {
|
||||
return 'grid-cols-4';
|
||||
} else if (width >= 900) {
|
||||
return 'grid-cols-3';
|
||||
} else if (width >= 600) {
|
||||
return 'grid-cols-2';
|
||||
} else {
|
||||
return 'grid-cols-1';
|
||||
}
|
||||
});
|
||||
|
||||
function getCurrentCols() {
|
||||
const width = window.innerWidth;
|
||||
if (width >= 1200) {
|
||||
return 4;
|
||||
} else if (width >= 900) {
|
||||
return 3;
|
||||
} else if (width >= 600) {
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
function editCard(item) {
|
||||
console.log(`Editing card: ${item.title}`);
|
||||
}
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
gridColsClass.value = getCurrentCols();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.hover-card {
|
||||
transition: transform 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.hover-card:hover {
|
||||
transform: scale(1.03); /* Effet de hover restauré */
|
||||
}
|
||||
|
||||
.stars .v-icon {
|
||||
font-size: 18px; /* Ajustez la taille des icônes */
|
||||
}
|
||||
|
||||
.limited-text {
|
||||
height: 60px; /* Limite la hauteur du texte */
|
||||
overflow: hidden; /* Empêche le texte de dépasser */
|
||||
text-overflow: ellipsis; /* Ajoute des points de suspension si le texte dépasse */
|
||||
white-space: nowrap; /* Le texte reste sur une seule ligne */
|
||||
}
|
||||
|
||||
.stars {
|
||||
position: absolute; /* Fixe les étoiles au bas à droite */
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
</style>
|
||||
Reference in New Issue
Block a user