Index > JS > add arrow key navigation + go to prev/next project after/before first/last picture
All checks were successful
Deploy / Deploy to Production (push) Successful in 5s

This commit is contained in:
Camilledenoray 2026-06-11 18:40:52 +02:00
parent 2563b27d26
commit 412c2a5547
2 changed files with 131 additions and 24 deletions

View file

@ -1,34 +1,137 @@
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", () => {
// Éléments statiques : calculés une seule fois au chargement
const prevButtons = document.querySelectorAll("button.prev"); const prevButtons = document.querySelectorAll("button.prev");
const nextButtons = document.querySelectorAll("button.next"); const nextButtons = document.querySelectorAll("button.next");
nextButtons.forEach((nextButton) => { const projects = document.querySelectorAll(".projects-index .project");
nextButton.addEventListener("click", () => { const firstProject = projects[0];
const activePicture = nextButton const lastProject = projects[projects.length - 1];
.closest(".project-slideshow")
.querySelector("picture.active"); const firstPictureFirstProject = firstProject.querySelector(
const targetPicture = ".project-slideshow picture:first-of-type",
activePicture.nextElementSibling && );
activePicture.nextElementSibling.tagName === "PICTURE" const firstPictureLastProject = lastProject.querySelector(
? activePicture.nextElementSibling ".project-slideshow picture:first-of-type",
: nextButton.closest(".project-slideshow").querySelector("picture"); );
const lastPictureLastProject = lastProject.querySelector(
".project-slideshow picture:last-of-type",
);
// Fonctions de navigation : les éléments « courants » sont re-requêtés
// à chaque appel pour refléter l'état actuel du DOM.
function goToNextPicture() {
const activePicture = document.querySelector(
".project.selected .project-slideshow > picture.active",
);
const lastPicture = document.querySelector(
".project.selected .project-slideshow > picture:last-of-type",
);
const selectedProject = document.querySelector(".project.selected");
const nextProject = selectedProject.nextElementSibling;
const firstPictureNextProject = nextProject?.querySelector(
".project-slideshow picture:first-of-type",
);
if (activePicture !== lastPicture) {
activePicture.classList.remove("active"); activePicture.classList.remove("active");
targetPicture.classList.add("active"); activePicture.nextElementSibling.classList.add("active");
}); } else {
selectedProject.classList.remove("selected");
activePicture.classList.remove("active");
if (selectedProject !== lastProject) {
nextProject.classList.add("selected");
firstPictureNextProject.classList.add("active");
} else {
firstProject.classList.add("selected");
firstPictureFirstProject.classList.add("active");
}
}
}
function goToPrevPicture() {
const activePicture = document.querySelector(
".project.selected .project-slideshow > picture.active",
);
const firstPicture = document.querySelector(
".project.selected .project-slideshow > picture:first-of-type",
);
const selectedProject = document.querySelector(".project.selected");
const prevProject = selectedProject.previousElementSibling;
const lastPicturePrevProject = prevProject?.querySelector(
".project-slideshow picture:last-of-type",
);
if (activePicture !== firstPicture) {
activePicture.classList.remove("active");
activePicture.previousElementSibling.classList.add("active");
} else {
selectedProject.classList.remove("selected");
activePicture.classList.remove("active");
if (selectedProject !== firstProject) {
prevProject.classList.add("selected");
lastPicturePrevProject.classList.add("active");
} else {
lastProject.classList.add("selected");
lastPictureLastProject.classList.add("active");
}
}
}
function goToPrevProject() {
const activePicture = document.querySelector(
".project.selected .project-slideshow > picture.active",
);
const selectedProject = document.querySelector(".project.selected");
const prevProject = selectedProject.previousElementSibling;
const firstPicturePrevProject = prevProject?.querySelector(
".project-slideshow picture:first-of-type",
);
activePicture.classList.remove("active");
selectedProject.classList.remove("selected");
if (selectedProject !== firstProject) {
prevProject.classList.add("selected");
firstPicturePrevProject.classList.add("active");
} else {
lastProject.classList.add("selected");
firstPictureLastProject.classList.add("active");
}
}
function goToNextProject() {
const activePicture = document.querySelector(
".project.selected .project-slideshow > picture.active",
);
const selectedProject = document.querySelector(".project.selected");
const nextProject = selectedProject.nextElementSibling;
const firstPictureNextProject = nextProject?.querySelector(
".project-slideshow picture:first-of-type",
);
activePicture.classList.remove("active");
selectedProject.classList.remove("selected");
if (selectedProject !== lastProject) {
nextProject.classList.add("selected");
firstPictureNextProject.classList.add("active");
} else {
firstProject.classList.add("selected");
firstPictureFirstProject.classList.add("active");
}
}
nextButtons.forEach((nextButton) => {
nextButton.addEventListener("click", goToNextPicture);
}); });
prevButtons.forEach((prevButton) => { prevButtons.forEach((prevButton) => {
prevButton.addEventListener("click", () => { prevButton.addEventListener("click", goToPrevPicture);
const slideshow = prevButton.closest(".project-slideshow"); });
const activePicture = slideshow.querySelector("picture.active");
const pictures = [...slideshow.querySelectorAll("picture")]; document.addEventListener("keyup", (event) => {
const targetPicture = if (event.key === "ArrowRight") goToNextPicture();
activePicture.previousElementSibling && if (event.key === "ArrowLeft") goToPrevPicture();
activePicture.previousElementSibling.tagName === "PICTURE" if (event.key === "ArrowUp") goToPrevProject();
? activePicture.previousElementSibling if (event.key === "ArrowDown") goToNextProject();
: pictures[pictures.length - 1];
activePicture.classList.remove("active");
targetPicture.classList.add("active");
});
}); });
}); });

View file

@ -21,6 +21,10 @@ allProjects.forEach((currentProject) => {
} }
}); });
currentProject
.querySelectorAll("picture")
.forEach((picture) => picture.classList.remove("active"));
currentProject.querySelector("picture:first-child").classList.add("active");
currentProject.classList.toggle("selected"); currentProject.classList.toggle("selected");
Router.setParam("project", currentProject.dataset.slug); Router.setParam("project", currentProject.dataset.slug);