Loader de scroll infini : styles réactivés, sans décalage de mise en page
Les règles `.scroll-spinner` et leurs keyframes étaient enfermées dans le bloc `/* … */` legacy de `_category.scss` : Sass recopie ces commentaires verbatim, les trois points n'avaient donc aucun style et restaient invisibles pendant le chargement AJAX. Bloc sorti du commentaire (le legacy reste en place), points allégés (5 px, gris) et marge haute élargie. Le modifieur `--reserve` réserve la place en permanence et n'anime que l'opacité, au lieu de basculer `display` : plus de saut de mise en page ni à l'apparition ni à la disparition. `infiniteScroll.js` bascule désormais la classe `is-loading`. Le `rootMargin` de l'observer passe à 700 px pour que la requête parte plus tôt, et le loader de l'agenda est supprimé (markup + JS). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WQLwtNFa1LNaN7QTAbYkZx
This commit is contained in:
@@ -1530,6 +1530,40 @@ footer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
.scroll-spinner {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.35rem;
|
||||||
|
padding: 3.5rem 0 1.5rem; }
|
||||||
|
.scroll-spinner__dot {
|
||||||
|
width: 5px;
|
||||||
|
height: 5px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #bbbbbb;
|
||||||
|
animation: scroll-spinner-bounce 1.2s infinite ease-in-out; }
|
||||||
|
.scroll-spinner__dot:nth-child(2) {
|
||||||
|
animation-delay: 0.2s; }
|
||||||
|
.scroll-spinner__dot:nth-child(3) {
|
||||||
|
animation-delay: 0.4s; }
|
||||||
|
.scroll-spinner--reserve {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: opacity 0.15s ease; }
|
||||||
|
.scroll-spinner--reserve .scroll-spinner__dot {
|
||||||
|
animation-play-state: paused; }
|
||||||
|
.scroll-spinner--reserve.is-loading {
|
||||||
|
opacity: 1; }
|
||||||
|
.scroll-spinner--reserve.is-loading .scroll-spinner__dot {
|
||||||
|
animation-play-state: running; }
|
||||||
|
|
||||||
|
@keyframes scroll-spinner-bounce {
|
||||||
|
0%, 80%, 100% {
|
||||||
|
transform: scale(0.6);
|
||||||
|
opacity: 0.4; }
|
||||||
|
40% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1; } }
|
||||||
.agenda-view-container {
|
.agenda-view-container {
|
||||||
display: none;
|
display: none;
|
||||||
margin-top: 3rem; }
|
margin-top: 3rem; }
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
var agendaDone = false;
|
var agendaDone = false;
|
||||||
var agendaLoading = false;
|
var agendaLoading = false;
|
||||||
var swiperWrapper = document.getElementById('agenda-swiper-wrapper');
|
var swiperWrapper = document.getElementById('agenda-swiper-wrapper');
|
||||||
var agendaSpinner = document.getElementById('agenda-spinner');
|
|
||||||
|
|
||||||
var categoryId = agendaEl.dataset.category || '';
|
var categoryId = agendaEl.dataset.category || '';
|
||||||
var includeChildren = agendaEl.dataset.includeChildren || '0';
|
var includeChildren = agendaEl.dataset.includeChildren || '0';
|
||||||
@@ -82,7 +81,6 @@
|
|||||||
if (agendaLoading || agendaDone) return;
|
if (agendaLoading || agendaDone) return;
|
||||||
agendaLoading = true;
|
agendaLoading = true;
|
||||||
agendaPage++;
|
agendaPage++;
|
||||||
agendaSpinner.style.display = 'flex';
|
|
||||||
|
|
||||||
var data = new FormData();
|
var data = new FormData();
|
||||||
data.append('action', 'load_more_agenda');
|
data.append('action', 'load_more_agenda');
|
||||||
@@ -98,7 +96,6 @@
|
|||||||
fetch(agendaViewData.ajaxUrl, { method: 'POST', body: data })
|
fetch(agendaViewData.ajaxUrl, { method: 'POST', body: data })
|
||||||
.then(function (r) { return r.json(); })
|
.then(function (r) { return r.json(); })
|
||||||
.then(function (result) {
|
.then(function (result) {
|
||||||
agendaSpinner.style.display = 'none';
|
|
||||||
agendaLoading = false;
|
agendaLoading = false;
|
||||||
if (result.success && result.data.html) {
|
if (result.success && result.data.html) {
|
||||||
var tmp = document.createElement('div');
|
var tmp = document.createElement('div');
|
||||||
@@ -118,7 +115,6 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(function () {
|
.catch(function () {
|
||||||
agendaSpinner.style.display = 'none';
|
|
||||||
agendaLoading = false;
|
agendaLoading = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
if (loading || done) return;
|
if (loading || done) return;
|
||||||
loading = true;
|
loading = true;
|
||||||
page++;
|
page++;
|
||||||
spinner.style.display = 'flex';
|
if (spinner) spinner.classList.add('is-loading');
|
||||||
|
|
||||||
var data = new FormData();
|
var data = new FormData();
|
||||||
data.append('action', 'load_more_posts');
|
data.append('action', 'load_more_posts');
|
||||||
@@ -46,7 +46,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
fetch(infiniteScrollData.ajaxUrl, { method: 'POST', body: data })
|
fetch(infiniteScrollData.ajaxUrl, { method: 'POST', body: data })
|
||||||
.then(function (response) { return response.json(); })
|
.then(function (response) { return response.json(); })
|
||||||
.then(function (result) {
|
.then(function (result) {
|
||||||
spinner.style.display = 'none';
|
if (spinner) spinner.classList.remove('is-loading');
|
||||||
if (result.success && result.data.html) {
|
if (result.success && result.data.html) {
|
||||||
grid.insertAdjacentHTML('beforeend', result.data.html);
|
grid.insertAdjacentHTML('beforeend', result.data.html);
|
||||||
loading = false;
|
loading = false;
|
||||||
@@ -56,16 +56,18 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(function () {
|
.catch(function () {
|
||||||
spinner.style.display = 'none';
|
if (spinner) spinner.classList.remove('is-loading');
|
||||||
loading = false;
|
loading = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Marge large : la requête part bien avant que la sentinelle soit à
|
||||||
|
// l'écran, les cards sont souvent déjà en place quand on arrive en bas
|
||||||
var observer = new IntersectionObserver(function (entries) {
|
var observer = new IntersectionObserver(function (entries) {
|
||||||
if (entries[0].isIntersecting) {
|
if (entries[0].isIntersecting) {
|
||||||
fetchPosts();
|
fetchPosts();
|
||||||
}
|
}
|
||||||
}, { rootMargin: '200px' });
|
}, { rootMargin: '700px' });
|
||||||
|
|
||||||
observer.observe(sentinel);
|
observer.observe(sentinel);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -405,6 +405,64 @@
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// ── Infinite scroll spinner ───────────────────────────────────────────────────
|
||||||
|
|
||||||
|
.scroll-spinner {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.35rem;
|
||||||
|
padding: 3.5rem 0 1.5rem;
|
||||||
|
|
||||||
|
&__dot {
|
||||||
|
width: 5px;
|
||||||
|
height: 5px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: $less-less-light-gray;
|
||||||
|
animation: scroll-spinner-bounce 1.2s infinite ease-in-out;
|
||||||
|
|
||||||
|
&:nth-child(2) {
|
||||||
|
animation-delay: 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-child(3) {
|
||||||
|
animation-delay: 0.4s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scroll infini : la place est réservée en permanence (on ne bascule pas
|
||||||
|
// display), sinon l'apparition des points décale la mise en page juste
|
||||||
|
// avant l'insertion des cards
|
||||||
|
&--reserve {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: opacity 0.15s ease;
|
||||||
|
|
||||||
|
.scroll-spinner__dot {
|
||||||
|
animation-play-state: paused;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-loading {
|
||||||
|
opacity: 1;
|
||||||
|
|
||||||
|
.scroll-spinner__dot {
|
||||||
|
animation-play-state: running;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes scroll-spinner-bounce {
|
||||||
|
0%, 80%, 100% {
|
||||||
|
transform: scale(0.6);
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
40% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ── Agenda slider view ────────────────────────────────────────────────────────
|
// ── Agenda slider view ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
.agenda-view-container {
|
.agenda-view-container {
|
||||||
|
|||||||
@@ -98,7 +98,7 @@
|
|||||||
data-axe="{{ active_axe }}"
|
data-axe="{{ active_axe }}"
|
||||||
data-date-from="{{ active_date_from }}"
|
data-date-from="{{ active_date_from }}"
|
||||||
data-date-to="{{ active_date_to }}"></div>
|
data-date-to="{{ active_date_to }}"></div>
|
||||||
<div id="scroll-spinner" class="scroll-spinner" style="display: none;">
|
<div id="scroll-spinner" class="scroll-spinner scroll-spinner--reserve">
|
||||||
<div class="scroll-spinner__dot"></div>
|
<div class="scroll-spinner__dot"></div>
|
||||||
<div class="scroll-spinner__dot"></div>
|
<div class="scroll-spinner__dot"></div>
|
||||||
<div class="scroll-spinner__dot"></div>
|
<div class="scroll-spinner__dot"></div>
|
||||||
@@ -123,11 +123,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<button class="agenda-swiper-next" aria-label="{{ current_language == 'en' ? 'Next' : 'Suivant' }}"><i class="iconoir-arrow-right"></i></button>
|
<button class="agenda-swiper-next" aria-label="{{ current_language == 'en' ? 'Next' : 'Suivant' }}"><i class="iconoir-arrow-right"></i></button>
|
||||||
</div>
|
</div>
|
||||||
<div id="agenda-spinner" class="scroll-spinner" style="display:none;">
|
|
||||||
<div class="scroll-spinner__dot"></div>
|
|
||||||
<div class="scroll-spinner__dot"></div>
|
|
||||||
<div class="scroll-spinner__dot"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
data-axe="{{ active_axe }}"
|
data-axe="{{ active_axe }}"
|
||||||
data-date-from="{{ active_date_from }}"
|
data-date-from="{{ active_date_from }}"
|
||||||
data-date-to="{{ active_date_to }}"></div>
|
data-date-to="{{ active_date_to }}"></div>
|
||||||
<div id="scroll-spinner" class="scroll-spinner" style="display: none;">
|
<div id="scroll-spinner" class="scroll-spinner scroll-spinner--reserve">
|
||||||
<div class="scroll-spinner__dot"></div>
|
<div class="scroll-spinner__dot"></div>
|
||||||
<div class="scroll-spinner__dot"></div>
|
<div class="scroll-spinner__dot"></div>
|
||||||
<div class="scroll-spinner__dot"></div>
|
<div class="scroll-spinner__dot"></div>
|
||||||
|
|||||||
@@ -75,7 +75,7 @@
|
|||||||
data-axe="{{ active_axe }}"
|
data-axe="{{ active_axe }}"
|
||||||
data-date-from="{{ active_date_from }}"
|
data-date-from="{{ active_date_from }}"
|
||||||
data-date-to="{{ active_date_to }}"></div>
|
data-date-to="{{ active_date_to }}"></div>
|
||||||
<div id="scroll-spinner" class="scroll-spinner" style="display: none;">
|
<div id="scroll-spinner" class="scroll-spinner scroll-spinner--reserve">
|
||||||
<div class="scroll-spinner__dot"></div>
|
<div class="scroll-spinner__dot"></div>
|
||||||
<div class="scroll-spinner__dot"></div>
|
<div class="scroll-spinner__dot"></div>
|
||||||
<div class="scroll-spinner__dot"></div>
|
<div class="scroll-spinner__dot"></div>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
data-axe="{{ active_axe }}"
|
data-axe="{{ active_axe }}"
|
||||||
data-date-from="{{ active_date_from }}"
|
data-date-from="{{ active_date_from }}"
|
||||||
data-date-to="{{ active_date_to }}"></div>
|
data-date-to="{{ active_date_to }}"></div>
|
||||||
<div id="scroll-spinner" class="scroll-spinner" style="display: none;">
|
<div id="scroll-spinner" class="scroll-spinner scroll-spinner--reserve">
|
||||||
<div class="scroll-spinner__dot"></div>
|
<div class="scroll-spinner__dot"></div>
|
||||||
<div class="scroll-spinner__dot"></div>
|
<div class="scroll-spinner__dot"></div>
|
||||||
<div class="scroll-spinner__dot"></div>
|
<div class="scroll-spinner__dot"></div>
|
||||||
|
|||||||
Reference in New Issue
Block a user