AkurAI Build
Menu

Public repository / 439f0dcabf5cdf2b120c7724be895cf1df30507f

AkurAI-Framework / site/frontend/ai/components/media/image_gallery.js

Latest change 36f53e8d189d0609aaabc65e705cf9db9d497d14 - Port Media components as vanilla ES modules by Ólafur Búi Ólafsson

// Image Gallery component — renders a responsive grid with lightbox overlay.

export const def = {
  name: "image_gallery",
  category: "Media",
  title: "Image Gallery",

  match(payload) {
    return Array.isArray(payload?.images) && payload.images.length > 0 &&
           payload.images.every(img => typeof img?.src === "string");
  },

  render(payload, ctx) {
    const { images } = payload;

    // Container for the gallery grid
    const card = document.createElement("div");
    card.className = "card";
    card.style.padding = "0";

    // Grid wrapper
    const grid = document.createElement("div");
    grid.style.display = "grid";
    grid.style.gridTemplateColumns = "repeat(auto-fit, minmax(150px, 1fr))";
    grid.style.gap = "8px";
    grid.style.padding = "12px";

    // Lightbox overlay (initially hidden)
    const overlay = document.createElement("div");
    overlay.style.position = "fixed";
    overlay.style.top = "0";
    overlay.style.left = "0";
    overlay.style.right = "0";
    overlay.style.bottom = "0";
    overlay.style.backgroundColor = "rgba(0, 0, 0, 0.85)";
    overlay.style.display = "none";
    overlay.style.alignItems = "center";
    overlay.style.justifyContent = "center";
    overlay.style.zIndex = "9999";
    overlay.style.padding = "20px";

    const lightboxImg = document.createElement("img");
    lightboxImg.style.maxWidth = "90vw";
    lightboxImg.style.maxHeight = "90vh";
    lightboxImg.style.objectFit = "contain";

    const lightboxCaption = document.createElement("div");
    lightboxCaption.style.position = "absolute";
    lightboxCaption.style.bottom = "20px";
    lightboxCaption.style.left = "50%";
    lightboxCaption.style.transform = "translateX(-50%)";
    lightboxCaption.style.color = "#fff";
    lightboxCaption.style.fontSize = "14px";
    lightboxCaption.style.textAlign = "center";
    lightboxCaption.style.maxWidth = "90vw";

    overlay.appendChild(lightboxImg);
    overlay.appendChild(lightboxCaption);

    // Create gallery items
    images.forEach((img, idx) => {
      const thumb = document.createElement("img");
      thumb.src = img.src;
      thumb.alt = img.alt || `Gallery image ${idx + 1}`;
      thumb.loading = "lazy";
      thumb.style.width = "100%";
      thumb.style.height = "100%";
      thumb.style.objectFit = "cover";
      thumb.style.cursor = "pointer";
      thumb.style.borderRadius = "8px";
      thumb.style.aspectRatio = "1 / 1";
      thumb.style.transition = "transform 0.2s";

      thumb.addEventListener("mouseenter", () => {
        thumb.style.transform = "scale(1.05)";
      });

      thumb.addEventListener("mouseleave", () => {
        thumb.style.transform = "scale(1)";
      });

      thumb.addEventListener("click", () => {
        lightboxImg.src = img.src;
        lightboxCaption.textContent = img.alt || "";
        overlay.style.display = "flex";
      });

      const item = document.createElement("div");
      item.style.overflow = "hidden";
      item.style.borderRadius = "8px";
      item.style.backgroundColor = "var(--bg-2)";
      item.appendChild(thumb);

      grid.appendChild(item);
    });

    // Close lightbox on overlay click or Escape key
    overlay.addEventListener("click", (e) => {
      if (e.target === overlay) {
        overlay.style.display = "none";
      }
    });

    document.addEventListener("keydown", (e) => {
      if (e.key === "Escape" && overlay.style.display === "flex") {
        overlay.style.display = "none";
      }
    });

    card.appendChild(grid);
    document.body.appendChild(overlay);

    return card;
  },

  example: {
    images: [
      { src: "https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=200&h=200&fit=crop", alt: "Mountain" },
      { src: "https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=200&h=200&fit=crop", alt: "Valley" },
      { src: "https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=200&h=200&fit=crop", alt: "Lake" }
    ]
  }
};