Corrections index projets et diaporama

- Vidéo en média d'en-tête de la fiche projet quand elle existe
  (comme la vignette d'index), sinon première image. La grille inclut
  la 1re image quand l'en-tête est une vidéo pour ne pas la perdre.
- Diaporama : images en HD (srcset @Nx via jquery.lazy) au lieu de la
  version SD 640px ; affichage plein écran sans rognage (object-fit
  contain, dimensions viewport).
- Diaporama : clic sur le fond ferme, navigation clavier (flèches +
  Échap). Indexation robuste par URL (data-src/src) corrigeant
  l'ouverture systématique sur l'image d'en-tête.
- Cartes projet mobile/tablette : titre ferré à gauche sous l'image
  au lieu d'être centré.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-09-11 17:02:22 +02:00
co-authored by Claude Opus 4.8
parent 4550a43fcd
commit b579febb87
6 changed files with 74 additions and 28 deletions
+15 -8
View File
@@ -362,7 +362,7 @@ body main .content .projet-card .loader {
body main .content .projet-card a {
width: 100%;
display: flex;
justify-content: center;
justify-content: flex-start;
}
body main .content .projet-card a figcaption {
color: #0e1229;
@@ -371,6 +371,7 @@ body main .content .projet-card a figcaption {
margin-top: 5px;
position: relative;
font-size: 0.95em;
text-align: left;
transition: opacity 0.4s ease-out;
}
body main .content .projet-card a figcaption .publique-title {
@@ -721,14 +722,20 @@ body main #reader figure#cover-image {
position: relative;
margin-top: 3vh;
}
body main #reader figure#cover-image-mobile img,
body main #reader figure#cover-image img {
body main #reader figure#cover-image-mobile img, body main #reader figure#cover-image-mobile video,
body main #reader figure#cover-image img,
body main #reader figure#cover-image video {
display: block;
width: 100%;
height: auto;
filter: grayscale(0);
transition: filter 0.4s ease-out;
mix-blend-mode: normal;
}
body main #reader figure#cover-image-mobile:hover img,
body main #reader figure#cover-image:hover img {
body main #reader figure#cover-image:hover img,
body main #reader figure#cover-image-mobile:hover video,
body main #reader figure#cover-image:hover video {
filter: grayscale(1);
mix-blend-mode: darken;
}
@@ -873,16 +880,16 @@ body main #reader .swiper .swiper-wrapper {
align-items: center;
}
body main #reader .swiper .swiper-wrapper .swiper-slide {
height: 100%;
height: 100vh;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
body main #reader .swiper .swiper-wrapper .swiper-slide img {
max-height: 90%;
max-width: 90%;
object-fit: cover;
width: 90vw;
height: 90vh;
object-fit: contain;
}
body main #reader .swiper .swiper-button-next, body main #reader .swiper .swiper-button-prev {
color: #0e1229;
File diff suppressed because one or more lines are too long
+29 -7
View File
@@ -718,26 +718,47 @@ function displayReader() {
},
});
// l'url réelle d'une image : data-src si pas encore chargée (lazy), sinon src (jquery.lazy retire data-src au chargement)
function imageSrc(img) {
return img.getAttribute('data-src') || img.getAttribute('src')
}
$('#cover-image img, .project-image').click( function(event) {
const totalImg = $('img')
// retrouver le slide correspondant à l'image cliquée par son url (robuste avec/sans vidéo d'en-tête, lazy chargé ou non)
const clickedSrc = imageSrc(event.target)
const slides = swiper.el.querySelectorAll('.swiper-slide img')
let indexImg = 0
for (let img of totalImg) {
if (event.target === img) { break }
indexImg++
}
swiper.slideToLoop(indexImg - 1)
slides.forEach((img, i) => {
if (imageSrc(img) === clickedSrc) { indexImg = i }
})
swiper.slideToLoop(indexImg)
$('body').css('overflow-y', 'hidden');
swiper.el.style.display = "block";
setTimeout(() => {
swiper.el.style.opacity = "1";
}, 10);
})
$('#close-carousel').click( () => {
function closeCarousel() {
$('body').css('overflow-y', 'auto');
swiper.el.style.opacity = "0";
setTimeout(() => {
swiper.el.style.display = "none";
}, 300);
}
$('#close-carousel').click(closeCarousel)
// un clic sur le fond (hors image, flèches et croix) ferme le diaporama
$('.swiper').click( function(event) {
if (event.target === this || $(event.target).hasClass('swiper-wrapper') || $(event.target).hasClass('swiper-slide')) {
closeCarousel()
}
})
// navigation clavier dans le diaporama (uniquement quand il est ouvert)
$(document).off('keydown.carousel').on('keydown.carousel', function(event) {
if (swiper.el.style.display !== 'block') { return }
switch (event.key) {
case 'Escape': closeCarousel(); break
case 'ArrowRight': swiper.slideNext(); break
case 'ArrowLeft': swiper.slidePrev(); break
}
})
@@ -763,6 +784,7 @@ function displayReader() {
function leaveReader() {
$(window).off('scroll')
$(document).off('keydown.carousel')
$('header').fadeIn()
if (!$('nav li a[href$=projets]').parent().hasClass('selected')) {
changeNavSelected('projets')
+14 -8
View File
@@ -205,14 +205,15 @@
a {
width: 100%;
display: flex;
justify-content: center;
figcaption {
justify-content: flex-start;
figcaption {
color: $mainColor;
background-color: transparent;
padding: 0;
margin-top: 5px;
position: relative;
font-size: $smallSize;
text-align: left;
@include transition-ease-out(opacity);
.publique-title {
@@ -546,14 +547,19 @@
figure#cover-image {
position: relative;
margin-top: 3vh;
img {
img, video {
display: block;
width: 100%;
height: auto;
filter: grayscale(0);
@include transition-ease-out(filter);
mix-blend-mode: normal;
}
}
figure#cover-image-mobile:hover img,
figure#cover-image:hover img {
figure#cover-image:hover img,
figure#cover-image-mobile:hover video,
figure#cover-image:hover video {
filter: grayscale(1);
mix-blend-mode: darken;
}
@@ -699,15 +705,15 @@
display: flex;
align-items: center;
.swiper-slide {
height: 100%;
height: 100vh;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
img {
max-height: 90%;
max-width: 90%;
object-fit: cover;
width: 90vw;
height: 90vh;
object-fit: contain;
}
}
}
@@ -1,8 +1,9 @@
<div class="swiper">
<div class="swiper-wrapper">
{% for image in page.media.images %}
{% set hd = image.srcset %}
<div class="swiper-slide">
<img class="lazy loader" src="{{ url('theme://images/loader/rolling.svg') }}" data-src="{{ image.url }}" alt="{{ page.title }}" />
<img class="lazy loader" src="{{ url('theme://images/loader/rolling.svg') }}" data-src="{{ image.url }}"{% if hd %} data-srcset="{{ hd }}" data-sizes="100vw"{% endif %} alt="{{ page.title }}" />
</div>
{% endfor %}
</div>
@@ -9,8 +9,13 @@
</h2>
</div>
<a href="{{ page.parent.parent.url }}"><div id="close-project" class="picto" data-src="{{ url('theme://images/pictos/cross.svg') }}" aria-hidden="true"></div></a>
{% set cover_video = page.media.videos|first.url %}
<figure id="cover-image-mobile" class="{{ class_suffix }}">
<img src="{{ url('theme://images/loader/rolling.svg') }}" data-src="{{ page.media.images|first.url }}" alt="{{ page.title }}" class="lazy loader">
{% if cover_video != null %}
<video autoplay muted loop playsinline src="{{ cover_video }}" type="video/mp4"></video>
{% else %}
<img src="{{ url('theme://images/loader/rolling.svg') }}" data-src="{{ page.media.images|first.url }}" alt="{{ page.title }}" class="lazy loader">
{% endif %}
</figure>
<div id="info-project" class="info-project-{{ class_suffix }}">
<h2 id="main-project-title">{{ page.title }}</h2>
@@ -22,7 +27,11 @@
</div>
</div>
<figure id="cover-image" class="{{ class_suffix }}">
<img src="{{ url('theme://images/loader/rolling.svg') }}" data-src="{{ page.media.images|first.url }}" alt="{{ page.title }}" class="lazy loader">
{% if cover_video != null %}
<video autoplay muted loop playsinline src="{{ cover_video }}" type="video/mp4"></video>
{% else %}
<img src="{{ url('theme://images/loader/rolling.svg') }}" data-src="{{ page.media.images|first.url }}" alt="{{ page.title }}" class="lazy loader">
{% endif %}
</figure>
<hr>
<div id="project-description">
@@ -31,7 +40,8 @@
<div id="project-images-grid">
{% for image in page.media.images %}
{% if image != page.media.images | first %}
{# quand l'en-tête est une vidéo, la 1re image n'est pas affichée ailleurs : on l'inclut dans la grille #}
{% if cover_video != null or image != page.media.images | first %}
<figure class="{{ class_suffix }}">
<img src="{{ url('theme://images/loader/rolling.svg') }}" data-src="{{ image.url }}" alt="{{ page.title }}" class="lazy loader project-image">
</figure>