Skip to main content
The lightbox functions provide a full-screen image viewing experience with thumbnail navigation, keyboard shortcuts, and gesture controls.

State Variables

The lightbox system maintains the following state:
let lightboxImages = [];               // Array of image URLs
let lightboxCurrentIndex = 0;          // Currently displayed image index
let lightboxThumbPage = 0;             // Current thumbnail page
const LIGHTBOX_THUMBS_PER_PAGE = 8;   // Fixed: 8 thumbnails per page

openLightbox

Opens the lightbox modal at a specific image index.
const openLightbox = (index) => {
  const lightbox = $("#lightbox");
  lightboxCurrentIndex = index;
  // Calculate which page this image is on
  lightboxThumbPage = Math.floor(index / LIGHTBOX_THUMBS_PER_PAGE);
  updateLightboxImage();
  renderLightboxThumbnails();
  lightbox.classList.remove("hidden");
  lightbox.classList.add("flex");
  document.body.style.overflow = "hidden";
};
index
number
required
Zero-based index of the image to display initially

Behavior

  • Sets lightboxCurrentIndex to provided index
  • Calculates appropriate lightboxThumbPage for the image
  • Calls updateLightboxImage() to load the image
  • Calls renderLightboxThumbnails() to show thumbnails
  • Shows lightbox by toggling classes: removes hidden, adds flex
  • Disables body scroll with overflow: hidden
Location: ~/workspace/source/app.js:56-66

Example Usage

// Open lightbox at third image
openLightbox(2);

// Typically called from gallery thumbnail double-click
thumb.addEventListener("dblclick", () => openLightbox(i));

closeLightbox

Closes the lightbox modal and restores page scrolling.
const closeLightbox = () => {
  const lightbox = $("#lightbox");
  lightbox.classList.add("hidden");
  lightbox.classList.remove("flex");
  document.body.style.overflow = "";
};

Behavior

  • Hides lightbox by toggling classes: adds hidden, removes flex
  • Restores body scroll by resetting overflow style
Location: ~/workspace/source/app.js:68-73

Triggered By

  • Close button click
  • Escape key press
  • Backdrop click (clicking outside the image)

updateLightboxImage

Updates the displayed image and counter in the lightbox.
const updateLightboxImage = () => {
  const lightboxImage = $("#lightbox-image");
  const lightboxCounter = $("#lightbox-counter");
  
  if (lightboxImages.length > 0) {
    lightboxImage.src = lightboxImages[lightboxCurrentIndex];
    lightboxImage.alt = `Imagen ${lightboxCurrentIndex + 1}`;
    lightboxCounter.textContent = `${lightboxCurrentIndex + 1} / ${lightboxImages.length}`;
  }
  
  // Update thumbnail highlights
  updateLightboxThumbHighlights();
};

Behavior

  • Updates #lightbox-image src and alt attributes
  • Updates #lightbox-counter text with “current / total” format
  • Calls updateLightboxThumbHighlights() to update thumbnail styling
Location: ~/workspace/source/app.js:75-87

Return Value

None (void). Modifies DOM directly.

updateLightboxThumbHighlights

Updates thumbnail styling to indicate the active image.
const updateLightboxThumbHighlights = () => {
  const thumbs = document.querySelectorAll("#lightbox-thumbnails .lightbox-thumb");
  const startIndex = lightboxThumbPage * LIGHTBOX_THUMBS_PER_PAGE;
  
  thumbs.forEach((thumb, i) => {
    const actualIndex = startIndex + i;
    const isActive = actualIndex === lightboxCurrentIndex;
    thumb.classList.toggle("ring-2", isActive);
    thumb.classList.toggle("ring-white", isActive);
    thumb.classList.toggle("opacity-50", !isActive);
  });
};

Behavior

  • Queries all .lightbox-thumb elements
  • Calculates actual image index based on current page
  • Toggles CSS classes:
    • Active: ring-2 ring-white, removes opacity-50
    • Inactive: opacity-50, removes ring classes
Location: ~/workspace/source/app.js:89-100

renderLightboxThumbnails

Renders the current page of lightbox thumbnails with navigation controls.
const renderLightboxThumbnails = () => {
  const container = $("#lightbox-thumbnails");
  const paginationContainer = $("#lightbox-pagination");
  const prevBtn = $("#lightbox-thumb-prev");
  const nextBtn = $("#lightbox-thumb-next");
  
  container.innerHTML = "";
  
  const totalPages = getTotalPages(lightboxImages.length, LIGHTBOX_THUMBS_PER_PAGE);
  const startIndex = lightboxThumbPage * LIGHTBOX_THUMBS_PER_PAGE;
  const endIndex = Math.min(startIndex + LIGHTBOX_THUMBS_PER_PAGE, lightboxImages.length);
  
  // Creates thumbnail elements...
  // Updates navigation buttons...
  // Renders pagination dots...
}

Behavior

  • Clears thumbnail container
  • Calculates visible image range for current page
  • Creates thumbnail DOM elements (8 per page)
  • Binds click handlers to thumbnails:
    thumb.addEventListener("click", () => {
      lightboxCurrentIndex = i;
      updateLightboxImage();
    });
    
  • Updates prev/next button disabled states
  • Renders pagination dots with light styling (isLight = true)
Location: ~/workspace/source/app.js:102-142

DOM Structure

Each thumbnail:
  • Classes: lightbox-thumb w-12 h-12 md:w-14 md:h-14 rounded-lg overflow-hidden cursor-pointer transition-all flex-shrink-0
  • Active: ring-2 ring-white
  • Inactive: opacity-50 hover:opacity-80

lightboxNext

Navigates to the next image in the lightbox, with wraparound and auto-pagination.
const lightboxNext = () => {
  lightboxCurrentIndex = (lightboxCurrentIndex + 1) % lightboxImages.length;
  // Auto-advance page if needed
  const newPage = Math.floor(lightboxCurrentIndex / LIGHTBOX_THUMBS_PER_PAGE);
  if (newPage !== lightboxThumbPage) {
    lightboxThumbPage = newPage;
    renderLightboxThumbnails();
  } else {
    updateLightboxImage();
  }
};

Behavior

  • Increments index with modulo wraparound (last → first)
  • Calculates if new image is on a different thumbnail page
  • If page changed: updates lightboxThumbPage and calls renderLightboxThumbnails()
  • If same page: calls updateLightboxImage() only
Location: ~/workspace/source/app.js:144-154

Triggered By

  • Next button click (#lightbox-next)
  • Right arrow key press

lightboxPrev

Navigates to the previous image in the lightbox, with wraparound and auto-pagination.
const lightboxPrev = () => {
  lightboxCurrentIndex = (lightboxCurrentIndex - 1 + lightboxImages.length) % lightboxImages.length;
  // Auto-advance page if needed
  const newPage = Math.floor(lightboxCurrentIndex / LIGHTBOX_THUMBS_PER_PAGE);
  if (newPage !== lightboxThumbPage) {
    lightboxThumbPage = newPage;
    renderLightboxThumbnails();
  } else {
    updateLightboxImage();
  }
};

Behavior

  • Decrements index with modulo wraparound (first → last)
  • Calculates if new image is on a different thumbnail page
  • If page changed: updates lightboxThumbPage and calls renderLightboxThumbnails()
  • If same page: calls updateLightboxImage() only
Location: ~/workspace/source/app.js:156-166

Triggered By

  • Previous button click (#lightbox-prev)
  • Left arrow key press

lightboxThumbNextPage

Advances to the next page of lightbox thumbnails.
const lightboxThumbNextPage = () => {
  const totalPages = getTotalPages(lightboxImages.length, LIGHTBOX_THUMBS_PER_PAGE);
  if (lightboxThumbPage < totalPages - 1) {
    lightboxThumbPage++;
    renderLightboxThumbnails();
  }
};

Behavior

  • Calculates total pages
  • Checks if next page exists
  • Increments lightboxThumbPage and re-renders
Location: ~/workspace/source/app.js:168-174

lightboxThumbPrevPage

Goes back to the previous page of lightbox thumbnails.
const lightboxThumbPrevPage = () => {
  if (lightboxThumbPage > 0) {
    lightboxThumbPage--;
    renderLightboxThumbnails();
  }
};

Behavior

  • Checks if previous page exists
  • Decrements lightboxThumbPage and re-renders
Location: ~/workspace/source/app.js:176-181

initLightbox

Initializes all lightbox event listeners and keyboard shortcuts.
const initLightbox = () => {
  const lightbox = $("#lightbox");
  const closeBtn = $("#lightbox-close");
  const prevBtn = $("#lightbox-prev");
  const nextBtn = $("#lightbox-next");
  const thumbPrevBtn = $("#lightbox-thumb-prev");
  const thumbNextBtn = $("#lightbox-thumb-next");
  
  if (!lightbox) return;
  
  closeBtn?.addEventListener("click", closeLightbox);
  prevBtn?.addEventListener("click", lightboxPrev);
  nextBtn?.addEventListener("click", lightboxNext);
  thumbPrevBtn?.addEventListener("click", lightboxThumbPrevPage);
  thumbNextBtn?.addEventListener("click", lightboxThumbNextPage);
  
  // Close on backdrop click
  lightbox.addEventListener("click", (e) => {
    if (e.target === lightbox) closeLightbox();
  });
  
  // Keyboard navigation
  document.addEventListener("keydown", (e) => {
    if (lightbox.classList.contains("hidden")) return;
    
    if (e.key === "Escape") closeLightbox();
    if (e.key === "ArrowRight") lightboxNext();
    if (e.key === "ArrowLeft") lightboxPrev();
  });
};

Behavior

  • Binds click handlers to all lightbox control buttons
  • Registers backdrop click handler (clicking the dark overlay closes lightbox)
  • Registers keyboard shortcuts:
    • Escape: Close lightbox
    • Arrow Right: Next image
    • Arrow Left: Previous image
  • Only processes keyboard events when lightbox is visible
Location: ~/workspace/source/app.js:183-212

When to Call

Call once during page initialization, before any lightbox interactions:
const loadData = async () => {
  initLightbox();  // Initialize event listeners first
  // ... then load and display property data
};

Integration Flow

  1. Initialization: initLightbox() sets up event listeners
  2. Opening: openLightbox(index) displays lightbox at specific image
  3. Navigation: User clicks next/prev or uses arrow keys → lightboxNext()/lightboxPrev()
  4. Thumbnail selection: User clicks thumbnail → updates lightboxCurrentIndexupdateLightboxImage()
  5. Page navigation: lightboxThumbNextPage()/lightboxThumbPrevPage() for thumbnail pagination
  6. Closing: User presses Escape, clicks close button, or clicks backdrop → closeLightbox()

Key Features

  • Keyboard navigation: Arrow keys and Escape
  • Auto-pagination: Thumbnails automatically advance when navigating to images on different pages
  • Wraparound: Last image → first image, first image → last image
  • Backdrop dismiss: Click outside image to close
  • Image counter: “3 / 12” format display

Build docs developers (and LLMs) love