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" }
]
}
};