optimisations images

This commit is contained in:
Valentin Le Moign 2025-01-24 02:00:11 +01:00
parent 2e26680eaf
commit 298bafce49
3 changed files with 123 additions and 61 deletions

View File

@ -148,6 +148,30 @@ export const useContentStore = defineStore('content', {
case 'titre_texte': case 'titre_texte':
partieContent.titre = partie.attributes.field_titre; partieContent.titre = partie.attributes.field_titre;
partieContent.texte = partie.attributes.field_texte.value; partieContent.texte = partie.attributes.field_texte.value;
// get the resized images from the text
const imgRegex = /<img[^>]+>/g;
const uuidRegex = /data-entity-uuid="([^"]+)"/;
const imgTags = partieContent.texte.match(imgRegex);
if (imgTags) {
for (const imgTag of imgTags) {
const uuidMatch = imgTag.match(uuidRegex);
if (uuidMatch && uuidMatch[1]) {
const uuid = uuidMatch[1];
const response = await REST.get(`/jsonapi/file/file/${uuid}`);
const imagesFetch = response.data.data;
const newImgTag = imgTag
.replace(/src="[^"]+"/,`src="${imagesFetch.attributes.image_style_uri.content_medium}"`)
.replace('>',' data-large-src="' + imagesFetch.attributes.image_style_uri.content_large + '">');
partieContent.texte = partieContent.texte.replace(imgTag, newImgTag);
}
}
}
break; break;
case 'chiffres_cles': case 'chiffres_cles':
const chiffresClesFetch = await this.fetchFromRelationships('field_chiffres_clefs', partie.relationships); const chiffresClesFetch = await this.fetchFromRelationships('field_chiffres_clefs', partie.relationships);

View File

@ -2,51 +2,50 @@
<Transition name="fade"> <Transition name="fade">
<div v-if="isOpen" class="image-viewer-wrapper" @click="(e) => checkOutsideClick(e.target)"> <div v-if="isOpen" class="image-viewer-wrapper" @click="(e) => checkOutsideClick(e.target)">
<div v-if="!swiperContent" class="img-modale simple-viewer"> <div v-if="!swiperContent" class="img-modale simple-viewer">
<figure class="img-wrapper"> <figure class="img-wrapper">
<img :src="image.src" :alt="image.alt"> <img :src="image.src" :alt="image.alt">
<figcaption>{{ image.alt }}</figcaption> <figcaption>{{ image.alt }}</figcaption>
</figure> </figure>
</div>
<div v-else class="img-modale swiper-viewer">
<div class="swiper-wrapper">
<swiper-container
:slidesPerView="1"
:centeredSlides="true"
:loop="true"
:navigation="true"
:pagination="true"
:initialSlide="currentImgIndex"
:injectStyles="[`
.swiper-button-next, .swiper-button-prev {
color: white;
top: 50%;
}
.swiper-pagination-bullet:not(.swiper-pagination-bullet-active) {
background: white;
opacity: 0.8;
}
`]"
@swiperresize="(e) => setCaptions(e.target)"
>
<swiper-slide v-for="media in swiperContent">
<figure class="popup-figure">
<img :src="media.src" :alt="media.alt" class="popup-img">
<figcaption>{{ media.alt }}</figcaption>
</figure>
</swiper-slide>
</swiper-container>
</div>
</div>
<button @click="close" class="close-button">
<div></div>
<div></div>
</button>
</div> </div>
</Transition> <div v-else class="img-modale swiper-viewer">
<div class="swiper-wrapper">
<swiper-container
:slidesPerView="1"
:centeredSlides="true"
:loop="true"
:navigation="true"
:pagination="true"
:initialSlide="currentSlideIndex"
:injectStyles="[`
.swiper-button-next, .swiper-button-prev {
color: white;
top: 50%;
}
.swiper-pagination-bullet:not(.swiper-pagination-bullet-active) {
background: white;
opacity: 0.8;
}
`]"
>
<swiper-slide v-for="media in swiperContent">
<figure class="popup-figure">
<img :src="media.src" :alt="media.alt" class="popup-img">
<figcaption>{{ media.alt }}</figcaption>
</figure>
</swiper-slide>
</swiper-container>
</div>
</div>
<button @click="close" class="close-button">
<div></div>
<div></div>
</button>
</div>
</Transition>
</template> </template>
<script setup> <script setup>
import { ref, watch } from 'vue'; import { nextTick, ref, watch } from 'vue';
import { useWaitForImages } from '../composables/useWaitForImages'; import { useWaitForImages } from '../composables/useWaitForImages';
const props = defineProps({ const props = defineProps({
isOpen: Boolean, isOpen: Boolean,
@ -60,14 +59,20 @@ const props = defineProps({
} }
}); });
const currentImgIndex = ref(0); const currentSlideIndex = ref(0);
watch( watch(
() => props.isOpen, () => props.isOpen,
() => { () => {
toggleElementsOver(props.isOpen); toggleElementsOver(props.isOpen);
if (props.isOpen && props.swiperContent?.length) { if (props.isOpen) {
checkCurrentImage(); nextTick(() => {
const swiperContainer = document.querySelector('.image-viewer-wrapper');
setCaptions(swiperContainer);
})
if (props.swiperContent?.length) {
checkCurrentImage();
}
} }
} }
) )
@ -93,11 +98,9 @@ function toggleElementsOver(isOpen) {
} }
function checkCurrentImage() { function checkCurrentImage() {
// CHECK IF IMAGES ARE THE SAME WITH ALT
// IS NOT A GREAT SOLUTION
for (let i = 0; i < props.swiperContent.length; i++) { for (let i = 0; i < props.swiperContent.length; i++) {
if (props.swiperContent[i].alt === props.image.alt) { if (props.swiperContent[i].src.split('/').pop().split('?')[0] === props.image.src.split('/').pop().split('?')[0]) {
currentImgIndex.value = i; currentSlideIndex.value = i;
break; break;
} }
} }
@ -106,11 +109,17 @@ function checkCurrentImage() {
function setCaptions(container) { function setCaptions(container) {
useWaitForImages(container, () => { useWaitForImages(container, () => {
const slides = container.querySelectorAll('swiper-slide'); const slides = container.querySelectorAll('swiper-slide');
slides.forEach((slide) => { if (slides.length) {
const img = slide.querySelector('img'); slides.forEach((slide) => {
const caption = slide.querySelector('figcaption'); const img = slide.querySelector('img');
const caption = slide.querySelector('figcaption');
caption.style.width = `${img.offsetWidth}px`;
});
} else {
const img = container.querySelector('img');
const caption = container.querySelector('figcaption');
caption.style.width = `${img.offsetWidth}px`; caption.style.width = `${img.offsetWidth}px`;
}); }
}); });
} }
@ -155,18 +164,33 @@ function checkOutsideClick(target) {
align-items: center; align-items: center;
} }
> .simple-viewer { > .simple-viewer {
> .img-wrapper { display: flex;
max-width: 60%; justify-content: center;
align-items: center;
> figure.img-wrapper {
margin-top: 3%;
width: 100%;
height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center;
justify-content: center;
padding: 10vw;
box-sizing: border-box;
> img { > img {
width: 100%; max-height: 100%;
max-width: 100%;
width: auto !important;
height: auto !important;
margin-bottom: -5px;
object-fit: contain !important;
} }
> figcaption { > figcaption {
margin: 0; margin: 0;
background-color: white; background-color: white;
font-size: 0.8rem; /* cf main.scss */ font-size: 0.8rem; /* cf main.scss */
padding: 0.5rem 1.5rem; padding: 0.5rem 1.5rem;
box-sizing: border-box;
} }
} }
} }

View File

@ -12,6 +12,7 @@
ref="partieContent" ref="partieContent"
class="partie-content" class="partie-content"
v-alt v-alt
v-setVerticalImgs
:style="{ '--couleur': couleur }" :style="{ '--couleur': couleur }"
@click="handleImageClick"> @click="handleImageClick">
</div> </div>
@ -48,6 +49,18 @@ const vAlt = {
} }
}; };
const vSetVerticalImgs = {
mounted : (el) => {
const images = el.querySelectorAll('img');
images.forEach((img) => {
if (img.offsetHeight > img.offsetWidth) {
img.style.padding = '0 7vw';
img.nextElementSibling.style.padding = '0 7vw';
}
});
}
}
const partieContent = ref(null); const partieContent = ref(null);
onMounted(() => { onMounted(() => {
@ -96,7 +109,7 @@ const {
const handleImageClick = (event) => { const handleImageClick = (event) => {
const img = event.target; const img = event.target;
if (img.tagName === 'IMG') { if (img.tagName === 'IMG') {
openImageModale(img.src, img.alt); openImageModale(img.dataset.largeSrc, img.alt);
} }
}; };
</script> </script>
@ -131,6 +144,7 @@ const handleImageClick = (event) => {
.partie-content { .partie-content {
img { img {
box-sizing: border-box;
margin-top: 2rem; margin-top: 2rem;
cursor: pointer; cursor: pointer;
transition: transform 0.3s ease-out; transition: transform 0.3s ease-out;