ImageGallery
AppResponsive image grid with a full-screen lightbox, right-click context menu (open, copy URL, move to first/last, remove), and drag-to-reorder. Supports 2–4 columns, square / video / portrait / auto aspect ratios, optional captions, zoom toggle, thumbnail strip, and full keyboard navigation (← → Escape).
Drag images to reorder • Right-click for context menu
<%- include('modules/app/ImageGallery', {
images: [
{ src: '/photo-1.jpg', alt: 'Mountain', caption: 'Sunrise over the Alps' },
{ src: '/photo-2.jpg', alt: 'Ocean', caption: 'Golden hour' },
{ src: '/photo-3.jpg', alt: 'Forest', caption: 'Morning mist' },
],
columns: 3,
aspect: 'square',
gap: 'md',
reorderable: true
}) %>
<%- include('modules/app/ImageGallery', {
images: images,
columns: 3,
aspect: 'square',
gap: 'md'
}) %>
<%- include('modules/app/ImageGallery', {
images: images,
columns: 2,
aspect: 'video',
gap: 'lg',
showCaptions: true
}) %>
<%- include('modules/app/ImageGallery', {
images: images,
columns: 4,
aspect: 'square',
gap: 'sm'
}) %>
<%
var _id = locals.id || 'gallery-' + Math.random().toString(36).substr(2, 9);
var _images = locals.images || [];
var _columns = locals.columns || 3;
var _aspect = locals.aspect || 'square';
var _gap = locals.gap || 'md';
var _lightbox = locals.lightbox !== false;
var _showCaptions = !!locals.showCaptions;
var _reorderable = !!locals.reorderable;
var _colClass = { 2: 'grid-cols-2', 3: 'grid-cols-2 sm:grid-cols-3', 4: 'grid-cols-2 sm:grid-cols-3 md:grid-cols-4' }[_columns] || 'grid-cols-2 sm:grid-cols-3';
var _gapClass = { sm: 'gap-1', md: 'gap-2', lg: 'gap-4' }[_gap] || 'gap-2';
var _aspClass = { square: 'aspect-square', video: 'aspect-video', portrait: 'aspect-[3/4]', auto: '' }[_aspect] || 'aspect-square';
%>
<%- include('./partials/_grid', { _id: _id, _colClass: _colClass, _gapClass: _gapClass }) %>
<%- include('./partials/_lightbox', { _id: _id }) %>