Skip to main content

HTML Image gallery with shine hover feature (easy for customer to update, pulls alt text) 

1. Create a standard page with all the images you want to feature. Currently works best if divisible by 4. 
2. Add the HTML code below to a page and replace the example URL with the URL of the page you just created.
NOTE: the URL that feeds the photos has to be consistent with the main domain... so youll need to update the URL when launching or updating the main domain. 

Scoped Image Gallery
Collage of fire trucks, police vehicles, working dogs, and team activities.
NEW EDITION WITH IMAGES OPEN ON CLICK AND YOU CAN PARSE THROUGH 

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Scoped Image Gallery with Modal Navigation</title>
  <style>
    /* Visually hidden class for screen readers */
    .visually-hidden {
      position: absolute;
      width: 1px;
      height: 1px;
      margin: -1px;
      padding: 0;
      border: 0;
      overflow: hidden;
      clip: rect(0, 0, 0, 0);
      white-space: nowrap;
    }

    /* Gallery styles */
    .gallery-container * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    .gallery-container {
      background: #fff;
      padding: 20px;
      font-family: Arial, sans-serif;
    }
    .gallery-container .gallery {
      display: flex;
      flex-wrap: wrap;
      gap: 10px;
      justify-content: center;
    }
    .gallery-container .gallery-item {
      position: relative;
      width: calc(25% - 10px);  /* Adjust columns as desired */
      height: 250px;           /* Fixed height; images will crop */
      overflow: hidden;
      cursor: pointer;
    }
    .gallery-container .gallery-item img {
      width: 100%;
      height: 100%;
      object-fit: cover;
      transition: transform 0.5s ease;
    }
    .gallery-container .gallery-item::after {
      content: "";
      position: absolute;
      top: 0;
      left: -100%;
      width: 50%;
      height: 100%;
      background: rgba(255, 255, 255, 0.3);
      transform: skewX(-25deg);
      transition: left 0.5s ease;
    }
    .gallery-container .gallery-item:hover img {
      transform: scale(1.1);
    }
    .gallery-container .gallery-item:hover::after {
      left: 100%;
    }

    /* Modal overlay styles */
    .modal {
      display: none; /* hidden by default */
      position: fixed;
      z-index: 1000;
      left: 0;
      top: 0;
      width: 100%;
      height: 100%;
      overflow: auto;
      background-color: rgba(0, 0, 0, 0.8);
    }
    .modal-content {
      margin: 5% auto;
      display: block;
      max-width: 90%;
      max-height: 80%;
    }
    .modal-content:focus {
      outline: none;
    }
    .close-button {
      position: absolute;
      top: 20px;
      right: 30px;
      color: #fff;
      font-size: 30px;
      font-weight: bold;
      background: transparent;
      border: none;
      cursor: pointer;
    }
    .close-button:focus {
      outline: 2px solid #fff;
    }
    /* Navigation arrow buttons */
    .nav-button {
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
      color: #fff;
      font-size: 40px;
      background: transparent;
      border: none;
      cursor: pointer;
      padding: 10px;
    }
    .nav-button:focus {
      outline: 2px solid #fff;
    }
    .nav-left {
      left: 20px;
    }
    .nav-right {
      right: 20px;
    }
  </style>
</head>
<body>
  <div class="gallery-container">
    <div class="gallery" id="gallery"></div>
  </div>

  <!-- Modal for full screen view -->
  <div id="modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="modalTitle">
    <h2 id="modalTitle" class="visually-hidden">Image preview</h2>
    <button class="close-button" id="closeModal" aria-label="Close modal">&times;</button>
    <button class="nav-button nav-left" id="prevBtn" aria-label="Previous image">&#10094;</button>
    <button class="nav-button nav-right" id="nextBtn" aria-label="Next image">&#10095;</button>
    <img class="modal-content" id="modalImg" tabindex="0" alt="">
  </div>

  <script>
    let lastFocusedElement; // to restore focus after closing modal
    let galleryImages = []; // global array to store images
    let currentIndex = 0;   // track the current image index

    // Opens modal with the image at the given index
    function openModal(index) {
      const modal = document.getElementById("modal");
      const modalImg = document.getElementById("modalImg");
      // Store the element that triggered the modal
      lastFocusedElement = document.activeElement;
      currentIndex = index;
      modalImg.src = galleryImages[currentIndex].src;
      modalImg.alt = galleryImages[currentIndex].alt;
      modal.style.display = "block";
      modalImg.focus();
    }

    // Update modal content with currentIndex
    function updateModal() {
      const modalImg = document.getElementById("modalImg");
      modalImg.src = galleryImages[currentIndex].src;
      modalImg.alt = galleryImages[currentIndex].alt;
    }

    // Closes the modal and restores focus
    function closeModal() {
      const modal = document.getElementById("modal");
      modal.style.display = "none";
      if (lastFocusedElement) {
        lastFocusedElement.focus();
      }
    }

    // Navigate to the previous image
    function showPrevious() {
      currentIndex = (currentIndex - 1 + galleryImages.length) % galleryImages.length;
      updateModal();
    }

    // Navigate to the next image
    function showNext() {
      currentIndex = (currentIndex + 1) % galleryImages.length;
      updateModal();
    }

    // Close modal when clicking the close button
    document.getElementById("closeModal").addEventListener("click", closeModal);

    // Close modal when clicking outside the modal content (but not on navigation buttons)
    document.getElementById("modal").addEventListener("click", function(e) {
      if (e.target === this) {
        closeModal();
      }
    });

    // Event listeners for navigation buttons
    document.getElementById("prevBtn").addEventListener("click", function(e) {
      e.stopPropagation();
      showPrevious();
    });
    document.getElementById("nextBtn").addEventListener("click", function(e) {
      e.stopPropagation();
      showNext();
    });

    // Keyboard accessibility for modal
    document.addEventListener("keydown", function(e) {
      const modal = document.getElementById("modal");
      if (modal.style.display === "block") {
        if (e.key === "Escape") {
          closeModal();
        } else if (e.key === "ArrowLeft") {
          showPrevious();
        } else if (e.key === "ArrowRight") {
          showNext();
        }
      }
    });

    // Load gallery images and set up click/keyboard events
    function loadGallery() {
      fetch("https://izzysworld.specialdistrict.org/bucketlist-gallery-attempt")
        .then(response => response.text())
        .then(html => {
          const parser = new DOMParser();
          const doc = parser.parseFromString(html, "text/html");
          // Find the container that holds <figure> or <img> elements
          const container = 
            doc.querySelector("#poc > div") ||
            doc.querySelector("#poc") ||
            doc.querySelector(".body") ||
            doc;
          // Look for <figure> elements
          const figures = container.querySelectorAll("figure");
          console.log("Found", figures.length, "figures.");
          // Build an array of objects: { src, alt }
          galleryImages = Array.from(figures).map(figure => {
            const img = figure.querySelector("img");
            if (!img) return null;
            const src = img.src;
            const alt = img.getAttribute("alt") || "Gallery image";
            return { src, alt };
          }).filter(Boolean);
          return galleryImages;
        })
        .then(images => {
          console.log("Extracted images:", images);
          const gallery = document.getElementById("gallery");
          images.forEach((image, index) => {
            const item = document.createElement("div");
            item.className = "gallery-item";
            // Make each item keyboard-focusable
            item.setAttribute("tabindex", "0");

            const img = document.createElement("img");
            img.src = image.src;
            img.alt = image.alt;

            // Open modal on click or Enter key press
            item.addEventListener("click", function() {
              openModal(index);
            });
            item.addEventListener("keydown", function(e) {
              if (e.key === "Enter") {
                openModal(index);
              }
            });

            item.appendChild(img);
            gallery.appendChild(item);
          });
        })
        .catch(error => {
          console.error("Error loading gallery:", error);
        });
    }
    
    loadGallery();
  </script>
</body>
</html>

https://izzysworld.specialdistrict.org/amplify-homepage-preview