This commit is contained in:
parent
3aa46c7456
commit
dd9e91c2d8
6 changed files with 251 additions and 5 deletions
39
assets/css/src/_lightbox.scss
Normal file
39
assets/css/src/_lightbox.scss
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/* Lightbox */
|
||||
.lightbox {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.9);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 1000;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: opacity 0.3s ease, visibility 0.3s ease;
|
||||
|
||||
&.open {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__image {
|
||||
width: 90vw;
|
||||
height: 90vh;
|
||||
object-fit: contain;
|
||||
cursor: zoom-out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cursor zoom-in sur toutes les images */
|
||||
img {
|
||||
cursor: zoom-in;
|
||||
}
|
||||
|
|
@ -652,6 +652,44 @@ section.poster-slider .controls button.poster-next {
|
|||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
/* Lightbox */
|
||||
.lightbox {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.9);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 1000;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: opacity 0.3s ease, visibility 0.3s ease;
|
||||
}
|
||||
.lightbox.open {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
.lightbox__content {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.lightbox__image {
|
||||
width: 90vw;
|
||||
height: 90vh;
|
||||
-o-object-fit: contain;
|
||||
object-fit: contain;
|
||||
cursor: zoom-out;
|
||||
}
|
||||
|
||||
/* Cursor zoom-in sur toutes les images */
|
||||
img {
|
||||
cursor: zoom-in;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 950px) {
|
||||
:root {
|
||||
--space-body: 1rem;
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -14,5 +14,6 @@
|
|||
@import 'src/sections/_video.scss';
|
||||
@import 'src/sections/_timeline.scss';
|
||||
@import 'src/sections/_poster-slider.scss';
|
||||
@import 'src/_lightbox.scss';
|
||||
|
||||
@import 'src/_responsive.scss';
|
||||
|
|
|
|||
139
assets/js/lightbox.js
Normal file
139
assets/js/lightbox.js
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const lightbox = document.getElementById('lightbox');
|
||||
const lightboxImg = document.querySelector('.lightbox__image');
|
||||
|
||||
let activeImg = null;
|
||||
let startX = 0;
|
||||
let startY = 0;
|
||||
let startTime = 0;
|
||||
const DRAG_THRESHOLD = 5;
|
||||
const TAP_DURATION = 300; // ms
|
||||
|
||||
function openLightbox(imgSrc, imgAlt) {
|
||||
lightboxImg.src = imgSrc;
|
||||
lightboxImg.alt = imgAlt || 'Image en grand format';
|
||||
lightbox.classList.add('open');
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
function closeLightbox() {
|
||||
lightbox.classList.remove('open');
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
function handleStart(e, img) {
|
||||
activeImg = img;
|
||||
startTime = Date.now();
|
||||
|
||||
if (e.type === 'mousedown') {
|
||||
startX = e.clientX;
|
||||
startY = e.clientY;
|
||||
} else if (e.type === 'touchstart') {
|
||||
startX = e.touches[0].clientX;
|
||||
startY = e.touches[0].clientY;
|
||||
}
|
||||
}
|
||||
|
||||
function handleMove(e) {
|
||||
if (!activeImg) return;
|
||||
|
||||
let currentX, currentY;
|
||||
if (e.type === 'mousemove') {
|
||||
currentX = e.clientX;
|
||||
currentY = e.clientY;
|
||||
} else if (e.type === 'touchmove') {
|
||||
currentX = e.touches[0].clientX;
|
||||
currentY = e.touches[0].clientY;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
const dx = Math.abs(currentX - startX);
|
||||
const dy = Math.abs(currentY - startY);
|
||||
|
||||
if (dx > DRAG_THRESHOLD || dy > DRAG_THRESHOLD) {
|
||||
activeImg = null;
|
||||
}
|
||||
}
|
||||
|
||||
function handleEnd(e, img) {
|
||||
if (!activeImg || activeImg !== img) return;
|
||||
|
||||
let currentX, currentY;
|
||||
if (e.type === 'mouseup') {
|
||||
currentX = e.clientX;
|
||||
currentY = e.clientY;
|
||||
} else if (e.type === 'touchend') {
|
||||
currentX = e.changedTouches[0].clientX;
|
||||
currentY = e.changedTouches[0].clientY;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
const dx = Math.abs(currentX - startX);
|
||||
const dy = Math.abs(currentY - startY);
|
||||
const duration = Date.now() - startTime;
|
||||
|
||||
// Ignorer si mouvement trop important ou durée trop longue
|
||||
if (dx > DRAG_THRESHOLD || dy > DRAG_THRESHOLD || duration > TAP_DURATION) {
|
||||
activeImg = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// Vérifier si l'image est dans un slider Swiper
|
||||
const swiperSlide = img.closest('.swiper-slide');
|
||||
if (swiperSlide) {
|
||||
const swiperContainer = swiperSlide.closest('.swiper');
|
||||
if (swiperContainer && swiperContainer.swiper) {
|
||||
const swiper = swiperContainer.swiper;
|
||||
if (swiper.isDragging || swiper.isTouched || swiper.animating) {
|
||||
activeImg = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Vérifier si le parent est un bouton ou lien
|
||||
if (img.closest('button, a')) {
|
||||
activeImg = null;
|
||||
return;
|
||||
}
|
||||
|
||||
openLightbox(img.src, img.alt);
|
||||
activeImg = null;
|
||||
|
||||
if (e.type === 'touchend') {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
document.querySelectorAll('img').forEach(img => {
|
||||
if (img.classList.contains('lightbox__image')) return;
|
||||
|
||||
// Mouse events
|
||||
img.addEventListener('mousedown', (e) => handleStart(e, img), { passive: true });
|
||||
img.addEventListener('mouseup', (e) => handleEnd(e, img));
|
||||
|
||||
// Touch events
|
||||
img.addEventListener('touchstart', (e) => handleStart(e, img), { passive: true });
|
||||
img.addEventListener('touchend', (e) => handleEnd(e, img), { passive: false });
|
||||
});
|
||||
|
||||
// Global move listeners
|
||||
document.addEventListener('mousemove', handleMove, { passive: true });
|
||||
document.addEventListener('touchmove', handleMove, { passive: true });
|
||||
|
||||
// Reset on global up
|
||||
document.addEventListener('mouseup', () => activeImg = null);
|
||||
document.addEventListener('touchend', () => activeImg = null);
|
||||
|
||||
// Fermer la lightbox au clic n'importe ou dessus
|
||||
lightbox.addEventListener('click', closeLightbox);
|
||||
|
||||
// Fermer avec Escape
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape' && lightbox.classList.contains('open')) {
|
||||
closeLightbox();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
defer
|
||||
></script>
|
||||
<script src="assets/js/poster-slider.js" defer></script>
|
||||
<script src="assets/js/lightbox.js" defer></script>
|
||||
<meta name="robots" content="none" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
@ -1341,5 +1342,13 @@
|
|||
</ul>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- Lightbox -->
|
||||
<div class="lightbox" id="lightbox">
|
||||
<div class="lightbox__content">
|
||||
<img src="" alt="Image en grand format" class="lightbox__image" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue