Gallery Layout Controls

Below you will find my implementation to customize the art galleries, specifically the masonry gallery. Provided is a slider which enables changing the number of columns. Effectively this makes images larger, or smaller. If you click on the start and end pictures to the left and right of the slider, the position is changed by one respectively. The slider position (number of columns) is displayed on the slider knob. There is an image counter which displays the number of images in the gallery with support for dynamically changing galleries. There is a button to make the gallery full screen width, or have a maximum of 2200px, which is the standard maximum page width. This is added to make viewing on ultra wide monitors more pleasurable. There is also a bit of code that detects the aspect ratio and sets the maximum width automatically if the viewer is using an ultra wide monitor. Additionally there is a button that takes you to the product page to purchase any of the images as a physical print, this can be removed upon preference, of course, as it relies on having a custom made product in your shop.

HTML:

<div class="custom-slider-main-container">
<div class="custom-slider-container">
<P class="custom-image-number-text"></P>
<div class="custom-resize-button"></div>
<div class="custom-slider-track-container">
<div class="custom-slider-start"></div>
<div class="custom-slider-track">
<div class="custom-slider-thumb">
<P class="custom-thumb-position-text">3</P>
</div>
</div>
<div class="custom-slider-end"></div>
</div>
<button id="customBuyButton" class="custom-buy-button sqs-block-button-element--medium sqs-button-element--primary sqs-block-button-element">Acquire One</button>
</div>
</div>
JAVASCRIPT:

<script>
document.addEventListener('DOMContentLoaded', function() {
const gallery = document.querySelector('.gallery-masonry-wrapper');
const sliderMainContainer = document.querySelector('.custom-slider-main-container');
const headerActions = document.querySelector('.header-actions');
let isTouch = false;
function checkHeader() {
const styles = window.getComputedStyle(headerActions);
isTouch = styles.getPropertyValue('display') !== 'flex';
}
checkHeader();
if (gallery && !isTouch) {
const mainGallerySection = document.querySelector('.gallery-section');
const mainGalleryContent = mainGallerySection.querySelector('.content-wrapper');  
const gallerySection = document.querySelector('.gallery-masonry');
gallerySection.prepend(sliderMainContainer);
const thumb = document.querySelector('.custom-slider-thumb');
const track = document.querySelector('.custom-slider-track');
const trackStart = document.querySelector('.custom-slider-start');
const trackEnd = document.querySelector('.custom-slider-end');
const thumbText = document.querySelector('.custom-thumb-position-text');
const imageNumberText = document.querySelector('.custom-image-number-text');
const resizeButton = document.querySelector('.custom-resize-button');  
var sizedToFit = false;
//columns changer slider
const thumbSize = 26;
let isDragging = false;
const positions = 16;
let stepSize = (track.offsetWidth - thumbSize) / (positions - 1);
thumb.addEventListener('mousedown', (e) => {
isDragging = true;
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
});
function updateColumnCount() {
setTimeout(() => {
const trackRect = track.getBoundingClientRect();
const thumbRect = thumb.getBoundingClientRect();
let finalLeft = thumbRect.left - trackRect.left;
const closestPositionIndex = Math.round(finalLeft / stepSize);
const sliderValue = Math.min(Math.max(closestPositionIndex + 1, 1), positions);
thumbText.textContent = sliderValue;
gallery.style.columns = sliderValue;
}, 50);
}
function onMouseMove(e) {
if (!isDragging) return;
const trackRect = track.getBoundingClientRect();
let newLeft = e.clientX - trackRect.left;
if (newLeft < 0) newLeft = 0;
if (newLeft > trackRect.width - thumbSize) newLeft = trackRect.width - thumbSize;
const closestPosition = Math.round(newLeft / stepSize) * stepSize;
thumb.style.left = `${closestPosition}px`;
updateColumnCount();
}
function onMouseUp() {
isDragging = false;
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
}
function setSliderToColumnCount() {
const currentColumns = parseInt(getComputedStyle(gallery).columns);
const columnIndex = Math.min(Math.max(currentColumns - 1, 0), positions - 1);
const initialPosition = columnIndex * stepSize;
thumb.style.left = `${initialPosition}px`;
}
setSliderToColumnCount();
track.addEventListener('click', (e) => {
const trackRect = track.getBoundingClientRect();
let clickPosition = e.clientX - trackRect.left;
if (clickPosition < 0) clickPosition = 0;
if (clickPosition > trackRect.width - thumbSize) clickPosition = trackRect.width - thumbSize;
const closestPosition = Math.round(clickPosition / stepSize) * stepSize;
thumb.style.left = `${closestPosition}px`;
updateColumnCount();
});
trackStart.addEventListener('click', (e) => {
const currentLeft = parseFloat(thumb.style.left) || 0;
let newPosition = currentLeft - stepSize;
if (newPosition < 0) newPosition = 0; 
thumb.style.left = `${newPosition}px`;
updateColumnCount();
});
trackEnd.addEventListener('click', (e) => {
const currentLeft = parseFloat(thumb.style.left) || 0;
let newPosition = currentLeft + stepSize;
const maxPosition = (positions - 1) * stepSize;
if (newPosition > maxPosition) newPosition = maxPosition;
thumb.style.left = `${newPosition}px`;
updateColumnCount();
});
//resize to fit button
function resizeGallery() {
if (sizedToFit == false) {
mainGalleryContent.style.maxWidth = '2200px';
sizedToFit = true;
} else {
mainGalleryContent.style.maxWidth = '100%';
sizedToFit = false;
}
}
resizeButton.addEventListener('click', function() {
resizeGallery();
resizeButton.classList.toggle('resized');
});
//check if the user is on an ultra-wide monitor
function isUltraWide() {
const screenWidth = window.screen.width;
const screenHeight = window.screen.height;
const aspectRatio = screenWidth / screenHeight;
return aspectRatio > 16 / 9; //aspect ratio
}
if (isUltraWide()) {
resizeButton.click();
}
//buy any artwork button
const buyButton = document.querySelector('.custom-buy-button');
buyButton.addEventListener('click', function(event) {
event.preventDefault();
const targetUrl = '/shop/p/original-poster'; 
window.location.href = targetUrl;
});
//display number of images in gallery
function updateImageCount() {
const imageCount = gallery.querySelectorAll('.gallery-masonry-item').length;
imageNumberText.textContent = imageCount + ' sigils';
if (imageCount == 0){
buyButton.style.display = 'none';   
} else {
buyButton.style.display = '';  
}
}
updateImageCount();
const observer = new MutationObserver((mutationsList) => {
for (let mutation of mutationsList) {
if (mutation.type === 'childList') {
updateImageCount();
}
}
});
observer.observe(gallery, { childList: true, subtree: true });
//exit
} else {
sliderMainContainer.remove();
}
});
</script>
CSS:

.custom-resize-button {
  width: 60px;
  height: 30px;
  margin-top: -5px;
  margin-bottom: -5px;
  margin-left: -30px;
  margin-right: 30px;
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
  background-image: url(https://images.squarespace-cdn.com/content/v1/6654b2fee26f292de13f1a9d/fb291717-6793-4d60-8b6b-1f22b49d6348/resizeSmallerIcon1.png);
  pointer-events: auto;
  cursor: pointer;
}
.custom-resize-button.resized {
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
  background-image: url(https://images.squarespace-cdn.com/content/v1/6654b2fee26f292de13f1a9d/3b8ee440-05a8-4c83-9d6e-d720f4be48f0/resizeBiggerIcon1.png);
}
//slider
.custom-slider-main-container::after {
  content: '';
  position: absolute;
  top: 0%;
  width: 100%;
  max-width: 2200px;
  height: 2px;
  background: linear-gradient(90deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 15%, rgba(0,0,0,1) 85%, rgba(0,0,0,0) 100%) !important;
}
.custom-slider-main-container {
  width: 100%;
  margin-top: 5px;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 50px;
  border-bottom: solid 3px black;
}
.custom-slider-container {
  width: 100%;
  display: flex;
  justify-content: center;
  max-width: 2200px;
  position: relative;
  height: auto;
}
.custom-slider-track-container {
  display: flex;
  align-items: center;
  width: 500px;
  height: auto;
  position: relative;
}
.custom-slider-start {
  width: 20px;
  height: 20px;
  margin-right: -2px;
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
  background-image: url(https://images.squarespace-cdn.com/content/v1/6654b2fee26f292de13f1a9d/9a9087db-9c75-4422-83ea-6571840d16a7/grid1Icon1.png);
  cursor: pointer;
}
.custom-slider-track {
  width: 80%;
  height: 2px;
  background: #000000;
  position: relative;
}
.custom-slider-end {
  width: 20px;
  height: 20px;
  margin-left: -2px;
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
  background-image: url(https://images.squarespace-cdn.com/content/v1/6654b2fee26f292de13f1a9d/789e9ac6-2404-4632-99d7-cc3338cb6ddf/grid16Icon.png);
  cursor: pointer;
}
.custom-slider-thumb {
  display: flex;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 20px;
  height: 20px;
  background: #ffc700;
  border-radius: 50%;
  border: solid 3px black;
  cursor: pointer;
  align-items: center;
  justify-content: center;
}
.custom-thumb-position-text {
  font-size: 13px;
  font-weight: bold;
  position: absolute;
  align-items: center;
  text-align: center;
  pointer-events: none;
  width: auto;
  padding-top: 4px;
  padding-right: 1px;
  letter-spacing: -1px;
}
.custom-thumb-position-text::selection {
  background: rgba(0, 0, 0, 0) !important;
  color: #000000;
}
//buy art button
#customBuyButton {
 position: absolute;
  width: 300px;
  right: 20px;
  line-height: 8px !important;
  height: 35px !important;
  padding-top: 10px !important;
  padding-bottom: 7px !important;
  text-align: right;
  letter-spacing: 2.5px !important;
  margin-top: -8px;
}
//image counter
.custom-image-number-text {
  position: absolute;
  left: 20px;
  max-width: 300px;
  letter-spacing: 2px;
  margin-top: -7px;
}

Note that in the (Javascript) code above I disable the controls on mobile, as my gallery is always one column wide on mobile.

Previous
Previous

Shop breadcrumbs navigation

Next
Next

Adding LIVE IMAGE SEARCH