Files
homeproz/wp-content/themes/homeproz/template-parts/agent/agent-gallery.js
T
Hanson.xyz Dev acc8ac87a0 wip
2026-01-04 17:50:08 -06:00

263 lines
9.1 KiB
JavaScript
Executable File

/**
* Agent Gallery JavaScript
*
* Thumbnail slider with lightbox functionality
*
* @package HomeProz
*/
(function($) {
'use strict';
// Early return if not on agent page
if (!$('.Single_Agent').length) {
return;
}
var AgentGallery = {
$gallery: null,
$thumbsSlider: null,
$thumbs: null,
$lightbox: null,
$lightboxImage: null,
$lightboxCounter: null,
images: [],
currentIndex: 0,
isTransitioning: false,
slideDuration: 300,
init: function() {
this.$gallery = $('.agent-gallery');
if (!this.$gallery.length) {
return;
}
this.$thumbsSlider = this.$gallery.find('.agent-gallery-thumbs-slider');
this.$thumbs = this.$gallery.find('.agent-gallery-thumb');
this.$lightbox = this.$gallery.find('.agent-gallery-lightbox');
this.$lightboxImage = this.$lightbox.find('.lightbox-image');
this.$lightboxCounter = this.$lightbox.find('.lightbox-current');
// Load images data
var $dataScript = this.$gallery.find('.agent-gallery-data');
if ($dataScript.length) {
try {
this.images = JSON.parse($dataScript.text());
} catch (e) {
console.error('Failed to parse gallery data');
return;
}
}
if (this.images.length === 0) {
return;
}
this.initSlick();
this.bindEvents();
},
initSlick: function() {
// Only init slick if more images than can fit
this.$thumbsSlider.slick({
slidesToShow: 6,
slidesToScroll: 3,
arrows: true,
dots: false,
infinite: false,
speed: 300,
autoplay: false,
variableWidth: false,
prevArrow: '<button type="button" class="slick-prev" aria-label="Previous"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg></button>',
nextArrow: '<button type="button" class="slick-next" aria-label="Next"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg></button>',
responsive: [
{
breakpoint: 768,
settings: {
slidesToShow: 4,
slidesToScroll: 2
}
},
{
breakpoint: 480,
settings: {
slidesToShow: 3,
slidesToScroll: 2
}
}
]
});
},
bindEvents: function() {
var self = this;
// Thumbnail clicks open lightbox
this.$thumbs.on('click', function() {
var index = parseInt($(this).data('index'));
self.openLightbox(index);
});
// Close lightbox - clicking overlay, container, or close button
this.$lightbox.find('.lightbox-close, .lightbox-overlay, .lightbox-container').on('click', function(e) {
// Only close if clicking directly on these elements, not their children (except close btn)
if (e.target === this || $(this).hasClass('lightbox-close')) {
self.closeLightbox();
}
});
// Lightbox navigation
this.$lightbox.find('.lightbox-prev').on('click', function() {
self.slideLightboxImage('prev');
});
this.$lightbox.find('.lightbox-next').on('click', function() {
self.slideLightboxImage('next');
});
// Keyboard navigation
$(document).on('keydown', function(e) {
if (!self.$lightbox.is('[aria-hidden="false"]')) {
return;
}
switch (e.key) {
case 'Escape':
self.closeLightbox();
break;
case 'ArrowLeft':
self.slideLightboxImage('prev');
break;
case 'ArrowRight':
self.slideLightboxImage('next');
break;
}
});
// Swipe support for lightbox
this.bindSwipeEvents();
},
bindSwipeEvents: function() {
var self = this;
var startX = 0;
var threshold = 50;
var $container = this.$lightbox.find('.lightbox-image-container');
$container[0].addEventListener('touchstart', function(e) {
if (e.touches.length === 1) {
startX = e.touches[0].clientX;
}
}, { passive: true });
$container[0].addEventListener('touchend', function(e) {
if (e.changedTouches.length !== 1) return;
var deltaX = e.changedTouches[0].clientX - startX;
if (Math.abs(deltaX) > threshold) {
if (deltaX > 0) {
self.slideLightboxImage('prev');
} else {
self.slideLightboxImage('next');
}
}
}, { passive: true });
},
openLightbox: function(index) {
this.currentIndex = index;
this.updateLightboxImage();
this.$lightbox.attr('aria-hidden', 'false');
$('body').addClass('lightbox-open');
},
closeLightbox: function() {
this.$lightbox.attr('aria-hidden', 'true');
$('body').removeClass('lightbox-open');
},
slideLightboxImage: function(direction) {
var self = this;
if (this.isTransitioning || this.images.length <= 1) {
return;
}
var newIndex;
if (direction === 'prev') {
newIndex = this.currentIndex - 1;
if (newIndex < 0) newIndex = this.images.length - 1;
} else {
newIndex = this.currentIndex + 1;
if (newIndex >= this.images.length) newIndex = 0;
}
this.isTransitioning = true;
var image = this.images[newIndex];
var slideFrom = direction === 'next' ? '100%' : '-100%';
var slideTo = direction === 'next' ? '-100%' : '100%';
var $container = this.$lightbox.find('.lightbox-image-container');
// Create new image
var $newImage = $('<img class="lightbox-slide-image" />');
$newImage.attr('src', image.url);
$newImage.attr('alt', image.alt || 'Gallery photo');
$newImage.css({
'position': 'absolute',
'max-width': '100%',
'max-height': 'calc(100vh - 8rem)',
'object-fit': 'contain',
'transform': 'translateX(' + slideFrom + ')',
'left': '50%',
'top': '50%',
'margin-left': '-45vw',
'margin-top': 'calc(-50vh + 4rem)'
});
$container.css({
'position': 'relative',
'overflow': 'hidden'
});
$container.append($newImage);
this.$lightboxImage.css('transition', 'transform ' + this.slideDuration + 'ms ease-out');
$newImage.css('transition', 'transform ' + this.slideDuration + 'ms ease-out');
// Trigger reflow
$newImage[0].offsetHeight;
this.$lightboxImage.css('transform', 'translateX(' + slideTo + ')');
$newImage.css('transform', 'translateX(0)');
setTimeout(function() {
self.$lightboxImage.attr('src', image.url);
self.$lightboxImage.attr('alt', image.alt || 'Gallery photo');
self.$lightboxImage.css({ 'transition': '', 'transform': '' });
$newImage.remove();
self.isTransitioning = false;
self.$lightboxCounter.text(newIndex + 1);
}, this.slideDuration);
this.currentIndex = newIndex;
},
updateLightboxImage: function() {
var image = this.images[this.currentIndex];
this.$lightboxImage.attr('src', image.url);
this.$lightboxImage.attr('alt', image.alt || 'Gallery photo');
this.$lightboxCounter.text(this.currentIndex + 1);
}
};
$(function() {
AgentGallery.init();
});
})(jQuery);