Add rotating hero image gallery for desktop breakpoint
- Add 5 new hero images to assets/images/hero-gallery/ - Create hero-section.js with image rotation (6s interval) - Only preload/animate at >= 1450px to save mobile bandwidth - Fade transition with slight grow effect - Add overflow:hidden to prevent scrollbar during transition - Images use 30% right crop via transform system 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
After Width: | Height: | Size: 642 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 2.2 MiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 17 MiB |
|
After Width: | Height: | Size: 15 MiB |
|
After Width: | Height: | Size: 4.9 MiB |
|
After Width: | Height: | Size: 24 MiB |
|
After Width: | Height: | Size: 14 MiB |
@@ -64,6 +64,25 @@ $featured_commercial = new WP_Query(array(
|
||||
$fallback_image = get_template_directory_uri() . '/assets/images/hero.webp';
|
||||
$logo_cropped = get_template_directory_uri() . '/assets/images/logo-cropped.webp';
|
||||
|
||||
// Build gallery images array for desktop hero rotation
|
||||
// Include the original hero plus the 5 additional gallery images
|
||||
$gallery_source_images = array(
|
||||
'assets/images/hero-original.png',
|
||||
'assets/images/hero-gallery/hero-2.png',
|
||||
'assets/images/hero-gallery/hero-3.png',
|
||||
'assets/images/hero-gallery/hero-4.jpg',
|
||||
'assets/images/hero-gallery/hero-5.png',
|
||||
'assets/images/hero-gallery/hero-6.png',
|
||||
);
|
||||
|
||||
$gallery_images = array();
|
||||
foreach ($gallery_source_images as $source) {
|
||||
$transformed = homeproz_get_transformed_theme_image($source, 30, 2560, 90);
|
||||
if ($transformed) {
|
||||
$gallery_images[] = $transformed;
|
||||
}
|
||||
}
|
||||
|
||||
// Design 2: Two-column split (shown >= 1450px)
|
||||
?>
|
||||
<div class="hero-desktop-only">
|
||||
@@ -78,6 +97,7 @@ $featured_commercial = new WP_Query(array(
|
||||
'secondary_cta_text' => 'Contact Us',
|
||||
'secondary_cta_url' => home_url('/contact/'),
|
||||
'background_image' => $hero_image_split ?: $fallback_image,
|
||||
'gallery_images' => $gallery_images,
|
||||
'size' => 'large',
|
||||
));
|
||||
?>
|
||||
|
||||
@@ -8,6 +8,7 @@ import './main.scss';
|
||||
|
||||
// Import component JS
|
||||
import '../template-parts/header/navigation.js';
|
||||
import '../template-parts/components/hero-section.js';
|
||||
import '../template-parts/property/property-filters.js';
|
||||
import '../template-parts/property/property-gallery.js';
|
||||
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* Hero Section Gallery - Image Rotation
|
||||
*
|
||||
* Rotates hero background images with fade transition.
|
||||
* Only active at >= 1450px breakpoint. Pauses/resumes on resize.
|
||||
* Only preloads images when at desktop breakpoint to save mobile bandwidth.
|
||||
*
|
||||
* @package HomeProz
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
'use strict';
|
||||
|
||||
// Configuration
|
||||
var ROTATION_INTERVAL = 6000; // milliseconds between image swaps
|
||||
var BREAKPOINT = 1450; // minimum width for gallery to be active
|
||||
var FADE_DURATION = 1000; // milliseconds for fade transition
|
||||
|
||||
// State
|
||||
var galleryImages = [];
|
||||
var currentIndex = 0;
|
||||
var rotationTimer = null;
|
||||
var isActive = false;
|
||||
var imagesPreloaded = false;
|
||||
var $heroImageElement = null;
|
||||
|
||||
/**
|
||||
* Initialize the hero gallery
|
||||
*/
|
||||
function init() {
|
||||
// Only run on homepage with split hero
|
||||
if (!$('.Home_Page').length) return;
|
||||
|
||||
$heroImageElement = $('.hero-split-image');
|
||||
if (!$heroImageElement.length) return;
|
||||
|
||||
// Get gallery images from data attribute
|
||||
var imagesData = $heroImageElement.data('gallery-images');
|
||||
if (!imagesData || !imagesData.length) return;
|
||||
|
||||
galleryImages = imagesData;
|
||||
|
||||
// Check initial viewport width
|
||||
checkBreakpoint();
|
||||
|
||||
// Listen for resize events
|
||||
$(window).on('resize', debounce(checkBreakpoint, 150));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we're at the desktop breakpoint and start/stop accordingly
|
||||
*/
|
||||
function checkBreakpoint() {
|
||||
var windowWidth = $(window).width();
|
||||
|
||||
if (windowWidth >= BREAKPOINT) {
|
||||
if (!isActive) {
|
||||
startGallery();
|
||||
}
|
||||
} else {
|
||||
if (isActive) {
|
||||
stopGallery();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the gallery rotation
|
||||
*/
|
||||
function startGallery() {
|
||||
isActive = true;
|
||||
|
||||
// Preload images only when entering desktop mode (saves mobile bandwidth)
|
||||
if (!imagesPreloaded) {
|
||||
preloadImages();
|
||||
imagesPreloaded = true;
|
||||
}
|
||||
|
||||
// Start rotation timer
|
||||
rotationTimer = setInterval(rotateImage, ROTATION_INTERVAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the gallery rotation
|
||||
*/
|
||||
function stopGallery() {
|
||||
isActive = false;
|
||||
|
||||
if (rotationTimer) {
|
||||
clearInterval(rotationTimer);
|
||||
rotationTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Preload all gallery images using detached img elements
|
||||
*/
|
||||
function preloadImages() {
|
||||
$.each(galleryImages, function(index, imageUrl) {
|
||||
var img = new Image();
|
||||
img.src = imageUrl;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate to the next image with fade transition
|
||||
*/
|
||||
function rotateImage() {
|
||||
// Move to next image
|
||||
currentIndex = (currentIndex + 1) % galleryImages.length;
|
||||
var nextImage = galleryImages[currentIndex];
|
||||
|
||||
// Create overlay element for crossfade
|
||||
var $overlay = $('<div class="hero-split-image-overlay"></div>');
|
||||
$overlay.css({
|
||||
'position': 'absolute',
|
||||
'top': 0,
|
||||
'left': 0,
|
||||
'right': 0,
|
||||
'bottom': 0,
|
||||
'background-image': 'url(' + nextImage + ')',
|
||||
'background-size': 'cover',
|
||||
'background-position': 'center center',
|
||||
'background-repeat': 'no-repeat',
|
||||
'opacity': 0,
|
||||
'transform': 'scale(1.02)',
|
||||
'transition': 'opacity ' + FADE_DURATION + 'ms ease-in-out, transform ' + FADE_DURATION + 'ms ease-in-out',
|
||||
'z-index': 1
|
||||
});
|
||||
|
||||
// Ensure hero image container has relative positioning
|
||||
$heroImageElement.css('position', 'relative');
|
||||
|
||||
// Append overlay
|
||||
$heroImageElement.append($overlay);
|
||||
|
||||
// Trigger reflow then animate
|
||||
$overlay[0].offsetHeight; // Force reflow
|
||||
$overlay.css({
|
||||
'opacity': 1,
|
||||
'transform': 'scale(1)'
|
||||
});
|
||||
|
||||
// After transition, update background and remove overlay
|
||||
setTimeout(function() {
|
||||
$heroImageElement.css('background-image', 'url(' + nextImage + ')');
|
||||
$overlay.remove();
|
||||
}, FADE_DURATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple debounce function
|
||||
*/
|
||||
function debounce(func, wait) {
|
||||
var timeout;
|
||||
return function() {
|
||||
var context = this, args = arguments;
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(function() {
|
||||
func.apply(context, args);
|
||||
}, wait);
|
||||
};
|
||||
}
|
||||
|
||||
// Initialize when DOM is ready
|
||||
$(document).ready(init);
|
||||
|
||||
})(jQuery);
|
||||
@@ -13,6 +13,7 @@
|
||||
* - secondary_cta_text (string): Secondary button text
|
||||
* - secondary_cta_url (string): Secondary button URL
|
||||
* - background_image (string): Background image URL
|
||||
* - gallery_images (array): Array of image URLs for rotation gallery
|
||||
* - size (string): 'large' or 'small' (default: 'large')
|
||||
* - show_location_search (bool): Show location search dropdown (default: false)
|
||||
*/
|
||||
@@ -31,11 +32,15 @@ $primary_cta_url = isset($args['primary_cta_url']) ? $args['primary_cta_url'] :
|
||||
$secondary_cta_text = isset($args['secondary_cta_text']) ? $args['secondary_cta_text'] : '';
|
||||
$secondary_cta_url = isset($args['secondary_cta_url']) ? $args['secondary_cta_url'] : '';
|
||||
$background_image = isset($args['background_image']) ? $args['background_image'] : '';
|
||||
$gallery_images = isset($args['gallery_images']) ? $args['gallery_images'] : array();
|
||||
$size = isset($args['size']) ? $args['size'] : 'large';
|
||||
$show_location_search = isset($args['show_location_search']) ? $args['show_location_search'] : false;
|
||||
|
||||
$size_class = $size === 'small' ? 'hero-section--small' : 'hero-section--large';
|
||||
|
||||
// Prepare gallery data attribute for JS
|
||||
$gallery_data = !empty($gallery_images) ? esc_attr(wp_json_encode($gallery_images)) : '';
|
||||
|
||||
// Get locations for dropdown if needed
|
||||
$locations = array();
|
||||
if ($show_location_search) {
|
||||
@@ -103,5 +108,8 @@ if ($show_location_search) {
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero-split-image" <?php echo $background_image ? 'style="background-image: url(' . esc_url($background_image) . ');"' : ''; ?>></div>
|
||||
<div class="hero-split-image"
|
||||
<?php echo $background_image ? 'style="background-image: url(' . esc_url($background_image) . ');"' : ''; ?>
|
||||
<?php echo $gallery_data ? 'data-gallery-images="' . $gallery_data . '"' : ''; ?>
|
||||
></div>
|
||||
</section>
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
width: 100%;
|
||||
|
||||