From 6dad6cc7bc52d2f749ae010530f48985733c8eee Mon Sep 17 00:00:00 2001 From: Valentin Date: Mon, 7 Oct 2024 03:19:22 +0200 Subject: [PATCH] =?UTF-8?q?refactor=20du=20store=20et=20des=20templates=20?= =?UTF-8?q?suite=20=C3=A0=20la=20refont=20du=20backend?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/themes/custom/caravane/assets/js/main.js | 2 +- .../caravane/assets/js/stores/content.js | 567 ++++++++++-------- .../caravane/assets/js/vuejs/ImageModale.vue | 93 --- .../caravane/assets/js/vuejs/Modale.vue | 383 ++++-------- .../js/vuejs/components/ImageModale.vue | 200 ++++++ .../js/vuejs/components/ModaleFooter.vue | 54 ++ .../js/vuejs/components/ModaleHeader.vue | 27 + .../parties/ModaleCarteSensible.vue | 21 + .../components/parties/ModaleChiffresCles.vue | 21 + .../components/parties/ModaleDiaporama.vue | 86 +++ .../components/parties/ModaleEntretien.vue | 84 +++ .../components/parties/ModaleExergue.vue | 35 ++ .../components/parties/ModaleTitreTexte.vue | 140 +++++ .../vuejs/components/parties/ModaleVideos.vue | 11 + .../js/vuejs/composables/useImageModale.js | 46 ++ .../assets/js/vuejs/composables/useUtils.js | 21 + .../custom/caravane/assets/scss/main.scss | 293 +++------ 17 files changed, 1259 insertions(+), 825 deletions(-) delete mode 100644 web/themes/custom/caravane/assets/js/vuejs/ImageModale.vue create mode 100644 web/themes/custom/caravane/assets/js/vuejs/components/ImageModale.vue create mode 100644 web/themes/custom/caravane/assets/js/vuejs/components/ModaleFooter.vue create mode 100644 web/themes/custom/caravane/assets/js/vuejs/components/ModaleHeader.vue create mode 100644 web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleCarteSensible.vue create mode 100644 web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleChiffresCles.vue create mode 100644 web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleDiaporama.vue create mode 100644 web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleEntretien.vue create mode 100644 web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleExergue.vue create mode 100644 web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleTitreTexte.vue create mode 100644 web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleVideos.vue create mode 100644 web/themes/custom/caravane/assets/js/vuejs/composables/useImageModale.js create mode 100644 web/themes/custom/caravane/assets/js/vuejs/composables/useUtils.js diff --git a/web/themes/custom/caravane/assets/js/main.js b/web/themes/custom/caravane/assets/js/main.js index 33f54a9..cd38854 100644 --- a/web/themes/custom/caravane/assets/js/main.js +++ b/web/themes/custom/caravane/assets/js/main.js @@ -164,7 +164,7 @@ import router from './router/router'; const nid = icon.querySelector('.nid'); const nidValue = nid.querySelector('.separated-content').innerText; - icon.addEventListener('click', function(event) { + icon.addEventListener('click', function(event) { store.fetchEtapeData(nidValue); }); diff --git a/web/themes/custom/caravane/assets/js/stores/content.js b/web/themes/custom/caravane/assets/js/stores/content.js index 536c60f..dcc38a5 100644 --- a/web/themes/custom/caravane/assets/js/stores/content.js +++ b/web/themes/custom/caravane/assets/js/stores/content.js @@ -4,265 +4,340 @@ import { defineStore } from 'pinia'; import REST from '../api/rest-axios'; export const useContentStore = defineStore('content', { - state: () => ({ - href: '', - etape: { - title: '', - adresse: {}, - etape_number: '', - dates: { - start: { - d: '', - m: '', - y: '', - }, - end: { - d: '', - m: '', - y: '', - }, + state: () => ({ + href: '', + etape: { + title: '', + adresse: {}, + etape_number: '', + vignette: {}, + couleur: '', + previous: {}, + next: {}, + dates: { + start: { + d: '', + m: '', + y: '', + }, + end: { + d: '', + m: '', + y: '', + }, + }, + parties: [], }, - geofield: {}, - // galeries: [], - parties: [], - saison: {}, - thematiques: [], - vignette: {}, - couleur: '', - sensibleMap: {}, - previous: {}, - next: {}, - }, - page: { - title: '', - text: '', - }, - loading: false, - error: null, + page: { + title: '', + vignette: {}, + parties: [], + }, + loading: false, + error: null, }), actions: { - async fetchEtapeData(nid) { - this.loading = true; - this.error = null; - this.etape = {}; - this.page = {}; - try { - const response = await REST.get(`/jsonapi/node/etape/`); - for (let [index, etape] of response.data.data.entries()) { - if (etape.attributes.drupal_internal__nid == nid) { - for (let metatag of etape.attributes.metatag) { - if (metatag.tag === "link") { - this.href = metatag.attributes.href; - } - } - this.etape.title = etape.attributes.title; - this.etape.adresse = etape.attributes.field_adresse; - this.etape.etape_number = etape.attributes.field_arret_numero; - this.etape.dates = { - start: this.getCleanDate(etape.attributes.field_dates.value), - end: this.getCleanDate(etape.attributes.field_dates.end_value), - } - this.etape.geofield = etape.attributes.field_geofield; - // this.etape.galeries = await this.fetchEtapeContent('field_galleries', etape.relationships); - const partiesFetch = await this.fetchEtapeContent('field_parties', etape.relationships); - let partiesArray = [] + async fetchEtapeData(nid) { + this.resetStore(); + try { + const response = await REST.get(`/jsonapi/node/etape/`); + for (let etape of response.data.data) { + if (etape.attributes.drupal_internal__nid == nid) { + for (let metatag of etape.attributes.metatag) { + if (metatag.tag === "link") { + this.href = metatag.attributes.href; + } + } + this.etape.title = etape.attributes.title; + this.etape.adresse = etape.attributes.field_adresse; + this.etape.etape_number = etape.attributes.field_arret_numero; + const vignetteFetch = await this.fetchContent('field_vignette', etape.relationships); + this.etape.vignette = { + url: vignetteFetch.attributes.uri.url, + alt: etape.relationships.field_vignette.data.meta.alt + }; + this.etape.couleur = etape.attributes.field_couleur; - if (partiesFetch) { - for (let partie of partiesFetch) { - let partieContent = { - title: partie.attributes.field_titre || '', - text: partie.attributes.field_texte.value || '', - diaporama: [], - chiffresCles: [], - videos: [], - } - - if (partie.relationships.field_diaporama) { - const diaporama = await REST.get(partie.relationships.field_diaporama.links.related.href); - - partie.relationships.field_diaporama.data.forEach((element, i) => { - partieContent.diaporama[i] = {}; - partieContent.diaporama[i].alt = element.meta.alt; - }); - - diaporama.data.data.forEach((element, i) => { - partieContent.diaporama[i].url = element.attributes.uri.url; - }); - } - - if (partie.attributes.field_chiffres_cles) { - for (let chiffre of partie.attributes.field_chiffres_cles) { - partieContent.chiffresCles.push(chiffre.processed); - } - } - - if (partie.attributes.field_videos) { - for (let video of partie.attributes.field_videos) { - const videoId = video.split('?v=')[1]; - const videoUrl = `https://www.youtube.com/embed/${videoId}`; - partieContent.videos.push(videoUrl); - } - } - - partiesArray.push(partieContent); - } - } - - this.etape.parties = partiesArray; - this.etape.saison = await this.fetchEtapeContent('field_saison', etape.relationships); - this.etape.thematiques = await this.fetchEtapeContent('field_thematiques', etape.relationships); - const vignetteFetch = await this.fetchEtapeContent('field_vignette', etape.relationships); - this.etape.vignette = { url: vignetteFetch.attributes.uri.url, alt: etape.attributes.field_vignette_alt }; - const sensibleMapFetch = await this.fetchEtapeContent('field_carte_sensible', etape.relationships); - if (sensibleMapFetch) { - this.etape.sensibleMap = { url: sensibleMapFetch.attributes.uri.url, alt: etape.relationships.field_carte_sensible.data.meta.alt }; - } - this.etape.couleur = etape.attributes.field_couleur; - - // get previous and next étape infos - // the list from the json api /node is not ordered - // and i need authentification to get the json view ordered list - // so i get it from the displayed list in the page - const orderedEtapesList = document.querySelectorAll('#etapes-liste li'); - - if (orderedEtapesList) { - const processEtape = async (etapeItemNid, etapesList, key) => { - for (let etape of etapesList) { - if (etape.attributes.drupal_internal__nid == etapeItemNid) { - const vignetteFetch = await REST.get(etape.relationships.field_vignette.links.related.href); - this.etape[key] = { - nid: etape.attributes.drupal_internal__nid, - couleur: etape.attributes.field_couleur, - title: etape.attributes.title, - postalCode: etape.attributes.field_adresse.postal_code, - dates: { + this.etape.dates = { start: this.getCleanDate(etape.attributes.field_dates.value), end: this.getCleanDate(etape.attributes.field_dates.end_value), - }, - vignette: { - url: vignetteFetch.data.data.attributes.uri.url, - alt: etape.relationships.field_vignette.data.meta.alt, - }, - }; - break; - } - } - }; - - for (let li of orderedEtapesList) { - if (li.querySelector('a').dataset.nodeNid === nid) { - const previousEtapeItemNid = li.previousElementSibling?.querySelector('a').dataset.nodeNid; - const nextEtapeItemNid = li.nextElementSibling?.querySelector('a').dataset.nodeNid; - - if (previousEtapeItemNid) { - await processEtape(previousEtapeItemNid, response.data.data, 'previous'); - } - - if (nextEtapeItemNid) { - await processEtape(nextEtapeItemNid, response.data.data, 'next'); - } - } - } - } + } - this.setActiveItemInMenu(); - break; + const partiesFetch = await this.fetchContent('field_parties', etape.relationships); + if (partiesFetch) { + this.etape.parties = []; + for (let partie of partiesFetch) { + const partieType = partie.type.replace(/^paragraph--/, ""); + let partieContent = { + type: partieType, + }; + + switch (partieType) { + case 'carte_sensible': + const carteSensibleFetch = await this.fetchContent('field_image_carte', partie.relationships); + if (carteSensibleFetch) { + partieContent.carteSensible = { + url: carteSensibleFetch.attributes.uri.url, + alt: partie.relationships.field_image_carte.data.meta.alt, + }; + } + break; + case 'titre_texte': + partieContent.titre = partie.attributes.field_titre; + partieContent.texte = partie.attributes.field_texte.value; + break; + case 'chiffres_cles': + const chiffresClesFetch = await this.fetchContent('field_chiffres_clefs', partie.relationships); + if (chiffresClesFetch) { + partieContent.chiffresCles = []; + for (let chiffre of chiffresClesFetch) { + partieContent.chiffresCles.push({ + chiffre: chiffre.attributes.field_chiffre, + description: chiffre.attributes.field_description, + }); + } + } + break; + case 'diaporama': + const diaporamaFetch = await this.fetchContent('field_diaporama', partie.relationships); + if (diaporamaFetch) { + partieContent.diaporama = []; + for (let [index, image] of diaporamaFetch.entries()) { + partieContent.diaporama.push({ + url: image.attributes.uri.url, + alt: partie.relationships.field_diaporama.data[index].meta.alt, + }); + } + } + break; + case 'entretien': + partieContent.entretien = {}; + const personnesFetch = await this.fetchContent('field_personne_s', partie.relationships); + const questionsReponsesFetch = await this.fetchContent('field_questions_reponses', partie.relationships); + if (personnesFetch && questionsReponsesFetch) { + partieContent.entretien.personnes = []; + for (let personne of personnesFetch) { + const portraitFetch = await this.fetchContent('field_portrait', personne.relationships); + if (portraitFetch) { + partieContent.entretien.personnes.push({ + portrait: portraitFetch.attributes.uri.url, + alt: personne.relationships.field_portrait.data.meta.alt, + description: personne.attributes.field_description, + }); + } + } + partieContent.entretien.questionsReponses = []; + for (let qr of questionsReponsesFetch) { + partieContent.entretien.questionsReponses.push({ + question: qr.attributes.field_question, + reponse: qr.attributes.field_reponse.value, + }); + } + } + break; + case 'exergue': + partieContent.exergue = partie.attributes.field_texte_exergue.value; + break; + case 'video': + partieContent.videos = []; + for (let video of partie.attributes.field_videos) { + const videoId = video.split('?v=')[1]; + const videoUrl = `https://www.youtube.com/embed/${videoId}`; + partieContent.videos.push(videoUrl); + } + break; + } + this.etape.parties.push(partieContent); + } + } + + // get previous and next étape infos + // the list from the json api /node is not ordered + // and i need authentification to get the json view ordered list + // so i get it from the displayed list in the page + const orderedEtapesList = document.querySelectorAll('#etapes-liste li'); + + if (orderedEtapesList) { + const processEtape = async (etapeItemNid, etapesList, key) => { + for (let etape of etapesList) { + if (etape.attributes.drupal_internal__nid == etapeItemNid) { + const vignetteFetch = await REST.get(etape.relationships.field_vignette.links.related.href); + this.etape[key] = { + nid: etape.attributes.drupal_internal__nid, + couleur: etape.attributes.field_couleur, + title: etape.attributes.title, + postalCode: etape.attributes.field_adresse.postal_code, + dates: { + start: this.getCleanDate(etape.attributes.field_dates.value), + end: this.getCleanDate(etape.attributes.field_dates.end_value), + }, + vignette: { + url: vignetteFetch.data.data.attributes.uri.url, + alt: etape.relationships.field_vignette.data.meta.alt, + }, + }; + break; + } + } + }; + + for (let li of orderedEtapesList) { + if (li.querySelector('a').dataset.nodeNid == nid) { + const previousEtapeItemNid = li.previousElementSibling?.querySelector('a').dataset.nodeNid; + const nextEtapeItemNid = li.nextElementSibling?.querySelector('a').dataset.nodeNid; + if (previousEtapeItemNid) { + await processEtape(previousEtapeItemNid, response.data.data, 'previous'); + } + if (nextEtapeItemNid) { + await processEtape(nextEtapeItemNid, response.data.data, 'next'); + } + } + } + } + break; + } + } + this.setActiveItemInMenu(nid); + } catch (error) { + this.error = 'Failed to fetch data'; + console.error('Issue with getNodeData', error); + } finally { + this.loading = false; + } + }, + async fetchStaticData(nid) { + this.resetStore(); + try { + const response = await REST.get(`/jsonapi/node/static/`); + for (let page of response.data.data) { + if (page.attributes.drupal_internal__nid == nid) { + for (let metatag of page.attributes.metatag) { + if (metatag.tag === "link") { + this.href = metatag.attributes.href; + } + } + this.page.title = page.attributes.title; + const vignetteFetch = await this.fetchContent('field_vignette', page.relationships); + this.page.vignette = { + url: vignetteFetch.attributes.uri.url, + alt: page.relationships.field_vignette.data.meta.alt + }; + + const partiesFetch = await this.fetchContent('field_parties_static', page.relationships); + if (partiesFetch) { + this.page.parties = []; + + + for (let partie of partiesFetch) { + const partieType = partie.type.replace(/^paragraph--/, ""); + let partieContent = { + type: partieType, + }; + + switch (partieType) { + case 'titre_texte': + partieContent.titre = partie.attributes.field_titre; + partieContent.texte = partie.attributes.field_texte.value; + break; + case 'diaporama': + const diaporamaFetch = await this.fetchContent('field_diaporama', partie.relationships); + if (diaporamaFetch) { + partieContent.diaporama = []; + for (let [index, image] of diaporamaFetch.entries()) { + partieContent.diaporama.push({ + url: image.attributes.uri.url, + alt: partie.relationships.field_diaporama.data[index].meta.alt, + }); + } + } + break; + case 'video': + partieContent.videos = []; + for (let video of partie.attributes.field_videos) { + const videoId = video.split('?v=')[1]; + const videoUrl = `https://www.youtube.com/embed/${videoId}`; + partieContent.videos.push(videoUrl); + } + break; + } + this.page.parties.push(partieContent); + } + } + } + } + this.setActiveItemInMenu(nid); + } catch (error) { + this.error = 'Failed to fetch data'; + console.error('Issue with getNodeData', error); + } finally { + this.loading = false; + } + }, + async fetchContent(field, relationships) { + if (relationships[field].data) { + try { + const contentLink = relationships[field].links.related.href; + const contentFetch = await REST.get(contentLink); + return contentFetch.data.data; + } catch (error) { + this.error = 'Failed to fetch data'; + console.error('Issue with getNodeData', error); } } - } catch (error) { - this.error = 'Failed to fetch data'; - console.error('Issue with getNodeData', error); - } finally { - this.loading = false; - } - }, - async fetchStaticData(nid) { - this.loading = true; - this.error = null; - this.etape = {}; - this.page = {}; - try { - const response = await REST.get(`/jsonapi/node/static/`); - for (let staticContent of response.data.data) { - if (staticContent.attributes.drupal_internal__nid == nid) { - staticContent.attributes.metatag.forEach(item => { - if (item.tag === 'meta') { - this.page.title = item.attributes.content.split(' |')[0]; - } - if (item.tag === 'link') { - this.href = item.attributes.href; - } - }) - this.page.text = staticContent.attributes.field_texte.value; - } - } - this.setActiveItemInMenu(); - } catch (error) { - this.error = 'Failed to fetch data'; - console.error('Issue with getNodeData', error); - } finally { - this.loading = false; - } - }, - emptyAll() { - this.etape = {}; - this.page = {}; - this.setActiveItemInMenu(); - }, - setActiveItemInMenu() { - const title = this.etape.title || this.page.title; - - const generalLinks = document.querySelectorAll('#menu > ul > li > a'); - if (Object.entries(this.etape).length === 0 && Object.entries(this.page).length === 0) { - for (let link of generalLinks) { - link.classList.remove('is-active'); - } - generalLinks[0].classList.add('is-active'); - } else { - for (let link of generalLinks) { - if (link.innerText === title) { - link.classList.add('is-active'); - } else { + }, + emptyAll(nid) { + this.etape = {}; + this.page = {}; + this.setActiveItemInMenu(nid); + }, + setActiveItemInMenu(nid) { + const title = this.etape.title || this.page.title; + + const generalLinks = document.querySelectorAll('#menu > ul > li > a'); + if (Object.entries(this.etape).length === 0 && Object.entries(this.page).length === 0) { + for (let link of generalLinks) { link.classList.remove('is-active'); } - } - } - - const etapeLinks = document.querySelectorAll('#etapes-liste li'); - for (let link of etapeLinks) { - const a = link.querySelector('a'); - if (a.innerText === title) { - link.classList.remove('inactive'); + generalLinks[0].classList.add('is-active'); } else { - link.classList.add('inactive'); + for (let link of generalLinks) { + if (link.dataset.nodeNid == nid) { + link.classList.add('is-active'); + } else { + link.classList.remove('is-active'); + } + } } - } - const inactiveLinks = document.querySelectorAll('#etapes-liste li.inactive'); - if (inactiveLinks.length === etapeLinks.length) { - for (let link of inactiveLinks) { - link.classList.remove('inactive'); + + const etapeLinks = document.querySelectorAll('#etapes-liste li'); + for (let link of etapeLinks) { + const a = link.querySelector('a'); + if (a.innerText === title) { + link.classList.remove('inactive'); + } else { + link.classList.add('inactive'); + } } - } - }, - async fetchEtapeContent(field, relationships) { - if (relationships[field].data) { - try { - const contentLink = relationships[field].links.related.href; - const contentFetch = await REST.get(contentLink); - return contentFetch.data.data; - } catch (error) { - this.error = 'Failed to fetch data'; - console.error('Issue with getNodeData', error); + const inactiveLinks = document.querySelectorAll('#etapes-liste li.inactive'); + if (inactiveLinks.length === etapeLinks.length) { + for (let link of inactiveLinks) { + link.classList.remove('inactive'); + } } - } - }, - getCleanDate(date) { - return { - d: date.split('-')[2], - m: new Intl.DateTimeFormat('fr-FR', { month: 'long' }).format(new Date(date)), - y: date.split('-')[0], - } - } + }, + resetStore() { + this.loading = true; + this.error = null; + this.href = ''; + this.etape = {}; + this.page = {}; + }, + getCleanDate(date) { + return { + d: date.split('-')[2], + m: new Intl.DateTimeFormat('fr-FR', { month: 'long' }).format(new Date(date)), + y: date.split('-')[0], + } + }, }, - }); - +}); \ No newline at end of file diff --git a/web/themes/custom/caravane/assets/js/vuejs/ImageModale.vue b/web/themes/custom/caravane/assets/js/vuejs/ImageModale.vue deleted file mode 100644 index 90a138d..0000000 --- a/web/themes/custom/caravane/assets/js/vuejs/ImageModale.vue +++ /dev/null @@ -1,93 +0,0 @@ - - - - - \ No newline at end of file diff --git a/web/themes/custom/caravane/assets/js/vuejs/Modale.vue b/web/themes/custom/caravane/assets/js/vuejs/Modale.vue index 31fce36..4d8305d 100644 --- a/web/themes/custom/caravane/assets/js/vuejs/Modale.vue +++ b/web/themes/custom/caravane/assets/js/vuejs/Modale.vue @@ -1,169 +1,66 @@ - +onMounted(() => { + handleRouteChange(); + handleColorChange(); + handleHrefChange(); +}); + \ No newline at end of file diff --git a/web/themes/custom/caravane/assets/js/vuejs/components/ImageModale.vue b/web/themes/custom/caravane/assets/js/vuejs/components/ImageModale.vue new file mode 100644 index 0000000..85dddfb --- /dev/null +++ b/web/themes/custom/caravane/assets/js/vuejs/components/ImageModale.vue @@ -0,0 +1,200 @@ + + + + + \ No newline at end of file diff --git a/web/themes/custom/caravane/assets/js/vuejs/components/ModaleFooter.vue b/web/themes/custom/caravane/assets/js/vuejs/components/ModaleFooter.vue new file mode 100644 index 0000000..ec8e280 --- /dev/null +++ b/web/themes/custom/caravane/assets/js/vuejs/components/ModaleFooter.vue @@ -0,0 +1,54 @@ + + + \ No newline at end of file diff --git a/web/themes/custom/caravane/assets/js/vuejs/components/ModaleHeader.vue b/web/themes/custom/caravane/assets/js/vuejs/components/ModaleHeader.vue new file mode 100644 index 0000000..ca3fcde --- /dev/null +++ b/web/themes/custom/caravane/assets/js/vuejs/components/ModaleHeader.vue @@ -0,0 +1,27 @@ + + + \ No newline at end of file diff --git a/web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleCarteSensible.vue b/web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleCarteSensible.vue new file mode 100644 index 0000000..4b11943 --- /dev/null +++ b/web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleCarteSensible.vue @@ -0,0 +1,21 @@ + + + \ No newline at end of file diff --git a/web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleChiffresCles.vue b/web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleChiffresCles.vue new file mode 100644 index 0000000..315d3c5 --- /dev/null +++ b/web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleChiffresCles.vue @@ -0,0 +1,21 @@ + + + \ No newline at end of file diff --git a/web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleDiaporama.vue b/web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleDiaporama.vue new file mode 100644 index 0000000..014396c --- /dev/null +++ b/web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleDiaporama.vue @@ -0,0 +1,86 @@ + + + + + \ No newline at end of file diff --git a/web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleEntretien.vue b/web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleEntretien.vue new file mode 100644 index 0000000..ad859b2 --- /dev/null +++ b/web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleEntretien.vue @@ -0,0 +1,84 @@ + + + + + \ No newline at end of file diff --git a/web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleExergue.vue b/web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleExergue.vue new file mode 100644 index 0000000..76ae371 --- /dev/null +++ b/web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleExergue.vue @@ -0,0 +1,35 @@ + + + + + \ No newline at end of file diff --git a/web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleTitreTexte.vue b/web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleTitreTexte.vue new file mode 100644 index 0000000..a43ea17 --- /dev/null +++ b/web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleTitreTexte.vue @@ -0,0 +1,140 @@ + + + + + \ No newline at end of file diff --git a/web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleVideos.vue b/web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleVideos.vue new file mode 100644 index 0000000..fa45647 --- /dev/null +++ b/web/themes/custom/caravane/assets/js/vuejs/components/parties/ModaleVideos.vue @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/web/themes/custom/caravane/assets/js/vuejs/composables/useImageModale.js b/web/themes/custom/caravane/assets/js/vuejs/composables/useImageModale.js new file mode 100644 index 0000000..36041b1 --- /dev/null +++ b/web/themes/custom/caravane/assets/js/vuejs/composables/useImageModale.js @@ -0,0 +1,46 @@ +import { ref } from 'vue'; + +export function useImageModal() { + const isModaleOpen = ref(false); + const currentImage = ref({ src: '', alt: '' }); + const swiperPopupContent = ref([]); + + const body = document.querySelector('body'); + const hamburger = document.querySelector('#hamburger'); + const menu = document.querySelector('#menu'); + + const openImageModale = (src, alt, swiperMedia) => { + currentImage.value = { src, alt }; + swiperPopupContent.value = swiperMedia || []; + isModaleOpen.value = true; + toggleBodyScroll(true); + }; + + const closeImageModale = () => { + isModaleOpen.value = false; + swiperPopupContent.value = []; + toggleBodyScroll(false); + }; + + const toggleBodyScroll = (disableScroll) => { + if (disableScroll) { + body.classList.add('no-scroll'); + hamburger.style.opacity = 0; + menu.style.display = 'none'; + } else { + body.classList.remove('no-scroll'); + menu.style.display = 'flex'; + setTimeout(() => { + hamburger.style.opacity = 1; + }, 300); + } + }; + + return { + isModaleOpen, + currentImage, + swiperPopupContent, + openImageModale, + closeImageModale, + }; +} \ No newline at end of file diff --git a/web/themes/custom/caravane/assets/js/vuejs/composables/useUtils.js b/web/themes/custom/caravane/assets/js/vuejs/composables/useUtils.js new file mode 100644 index 0000000..e42c713 --- /dev/null +++ b/web/themes/custom/caravane/assets/js/vuejs/composables/useUtils.js @@ -0,0 +1,21 @@ +export function useUtils() { + const isObjectEmpty = (obj) => { + if (!obj || typeof obj !== 'object') return true; + + return !Object.keys(obj).some((key) => { + const value = obj[key]; + if (Array.isArray(value)) return value.length > 0; + if (typeof value === 'object') return !isObjectEmpty(value); + return value !== null && value !== undefined && value !== ''; + }); + }; + + const scrollTop = () => { + window.scrollTo({ top: 0, behavior: 'smooth' }); + }; + + return { + isObjectEmpty, + scrollTop, + }; +} \ No newline at end of file diff --git a/web/themes/custom/caravane/assets/scss/main.scss b/web/themes/custom/caravane/assets/scss/main.scss index 551b693..65602d2 100644 --- a/web/themes/custom/caravane/assets/scss/main.scss +++ b/web/themes/custom/caravane/assets/scss/main.scss @@ -5,6 +5,7 @@ $body-margin-y: 5px; $body-margin-bottom: 4vh; $modale-x-padding: 5vw; +$modale-bottom-padding: 180px; $sm-font-size: 0.8rem; $m-font-size: 1.4rem; @@ -233,6 +234,7 @@ body{ align-items: center; height: 100%; > .layout__region--first { + display: none; padding-left: $body-margin-x; grid-column: 1 / span 4; position: relative; @@ -588,7 +590,6 @@ body{ > #content-modale { > div:not(.image-viewer-wrapper, .image-modale) { padding-bottom: 40vh; - background-color: red; > .content-wrapper { left: 25vw; width: 50vw; @@ -596,6 +597,7 @@ body{ z-index: 2; position: relative; background-color: white; + padding-bottom: $modale-bottom-padding; img { width: 100%; height: auto; @@ -606,7 +608,7 @@ body{ overflow: hidden; } > header { - // margin-bottom: 3rem; + margin-bottom: 2rem; > .cover { max-height: 60vh; display: flex; @@ -670,12 +672,14 @@ body{ width: 100%; padding: 0 $modale-x-padding; box-sizing: border-box; - > #sensible-map { - width: calc(100% + $modale-x-padding); - margin-left: calc(($modale-x-padding / 2) * -1); - margin-top: calc($modale-x-padding / 2); - > figure { + > .partie { + width: 100%; + display: inline-block; + > .sensible-map { margin: 0; + width: calc(100% + $modale-x-padding); + margin-left: calc(($modale-x-padding / 2) * -1); + margin-top: calc($modale-x-padding / 2); .vh--message { font-size: $sm-font-size; top: 1rem; @@ -688,12 +692,9 @@ body{ margin-left: calc($modale-x-padding / 2); } } - } - > .partie { - width: 100%; - display: inline-block; > .partie-title, - > .chiffres-cles { + > .chiffres-cles, + > .entretien { > h3 { position: relative; display: inline-block; @@ -747,16 +748,6 @@ body{ } } } - > .partie-content { - img { - margin-top: 2rem; - cursor: pointer; - transition: transform 0.3s ease-out; - &:hover { - transform: scale(1.01); - } - } - } > .diaporama { width: calc(100% + 2 * #{$modale-x-padding}); margin-top: 5rem; @@ -796,87 +787,89 @@ body{ background-size: repeat; } } - .pattern-bottom { - width: calc(100% + $modale-x-padding * 2); - margin-left: -$modale-x-padding; - height: 180px; - margin-top: -90px; - } - .related-etape-links { - position: absolute; - margin-top: -3rem; - width: calc(100% - $modale-x-padding); - margin-left: -$modale-x-padding; - padding: 0 calc($modale-x-padding / 2); - display: grid; - grid-template-columns: 1fr 1fr; - > .card { - width: 80%; - display: flex; - align-items: center; - cursor: pointer; - transition: transform 0.3s ease-out; - &:hover { - transform: scale(1.05); - } - &.next { - grid-column: 2 / span 1; - justify-self: flex-end; - } - > .icon { - z-index: 2; - width: 10px; - height: 30px; + > footer { + .pattern-bottom { + mask-image: linear-gradient(to top, rgba(0,0,0,1), rgba(0,0,0,0)); + height: $modale-bottom-padding; + position: absolute; + bottom: 0; + } + .related-etape-links { + position: absolute; + bottom: calc(($modale-bottom-padding / 2) * -1); + width: 100%; + box-sizing: border-box; + padding: 0 calc($modale-x-padding / 2); + display: grid; + grid-template-columns: 1fr 1fr; + > .card { + width: 80%; display: flex; - flex-direction: column; - justify-content: center; align-items: center; - > div { - display: block; - width: 20px; - height: 10px; - &:first-of-type, &:last-of-type { - height: 8px; - clip-path: polygon(0 0, 100% 0, 50% 100%); - } - &:first-of-type { - transform: rotate(180deg); - } + cursor: pointer; + transition: transform 0.3s ease-out; + &:hover { + transform: scale(1.05); } - } - > .card-content { - z-index: 1; - background-color: white; - display: flex; - width: 100%; - > .infos { - width: 60%; - text-align: center; - > .titre { - padding: 1rem 0.5rem; - font-weight: bold; - font-family: 'Joost', sans-serif; - font-size: $m-font-size; - > span { - font-weight: lighter; + &.next { + grid-column: 2 / span 1; + justify-self: flex-end; + } + > .icon { + z-index: 2; + width: 10px; + height: 30px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + > div { + display: block; + width: 20px; + height: 10px; + &:first-of-type, &:last-of-type { + height: 8px; + clip-path: polygon(0 0, 100% 0, 50% 100%); + } + &:first-of-type { + transform: rotate(180deg); } } - > .date { - font-size: $sm-font-size; - font-family: 'Marianne', sans-serif; - font-weight: lighter; - padding-bottom: 1rem; - } } - > .vignette { - width: 40%; - position: relative; - > img { - top: 0; - position: absolute; - width: 100%; - height: 100%; - object-fit: cover; + > .card-content { + z-index: 1; + background-color: white; + display: flex; + width: 100%; + > .infos { + width: 60%; + text-align: center; + > .titre { + padding: 1rem 0.5rem; + font-weight: bold; + font-family: 'Joost', sans-serif; + font-size: $m-font-size; + > span { + font-weight: lighter; + } + } + > .date { + font-size: $sm-font-size; + font-family: 'Marianne', sans-serif; + font-weight: lighter; + padding-bottom: 1rem; + } + } + > .vignette { + width: 40%; + position: relative; + > img { + top: 0; + position: absolute; + width: 100%; + height: 100%; + object-fit: cover; + } } } } @@ -884,112 +877,6 @@ body{ } } } - > .image-viewer-wrapper { - backdrop-filter: blur(3px); - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 100; - > .img-modale { - background-color: rgba(0, 0, 0, 0.8); - width: 100%; - height: 100%; - display: flex; - justify-content: center; - align-items: center; - } - > .simple-viewer { - > .img-wrapper { - max-width: 60%; - display: flex; - flex-direction: column; - > img { - width: 100%; - } - > figcaption { - margin: 0; - background-color: white; - font-size: $sm-font-size; - padding: 0.5rem 1.5rem; - } - } - } - > .swiper-viewer { - z-index: 1; - > .swiper-wrapper { - height: 100%; - width: 100%; - swiper-container { - height: 95%; - swiper-slide { - display: flex; - justify-content: center; - align-items: flex-start; - figure { - margin-top: 3%; - max-width: 60%; - height: 80%; - img { - height: -webkit-fill-available; - max-width: 100%; - margin-bottom: -5px; - object-fit: cover; - } - figcaption { - margin: 0; - background-color: white; - font-size: $sm-font-size; - padding: 0.5rem 1.5rem; - } - } - } - } - } - } - > .close-button { - position: fixed; - top: 2rem; - right: $body-margin-x; - background-color: unset; - border: none; - display: block; - height: 3rem; - width: 3rem; - border-radius: 1.5rem; - cursor: pointer; - background-color: white; - padding: 0; - display: flex; - justify-content: center; - align-items: center; - z-index: 2; - > div { - display: block; - height: 2px; - border-radius: 4px; - width: 60%; - background-color: $main-color; - position: absolute; - transition: transform 0.3s ease; - &:nth-of-type(1) { - transform: rotate(45deg) scale(1); - } - &:nth-of-type(2) { - transform: rotate(-45deg) scale(1); - } - } - &:hover { - > div:nth-of-type(1) { - transform: rotate(45deg) scale(1.1); - } - > div:nth-of-type(2) { - transform: rotate(-45deg) scale(1.1); - } - } - } - } } } }