Home About Services Gallery Academy Contact Book Appointment
https://aestheticbeautysalon.in/gallery.js /* ===================================================== AESTHETIC SALON GALLERY JAVASCRIPT ===================================================== */ /* ===================================================== MOBILE MENU ===================================================== */ const galleryMenu = document.getElementById("galleryMenu"); const mobileGalleryNav = document.getElementById("mobileGalleryNav"); if (galleryMenu && mobileGalleryNav) { galleryMenu.addEventListener("click", () => { mobileGalleryNav.classList.toggle("open"); galleryMenu.classList.toggle("active"); }); /* Close menu when link is clicked */ const mobileLinks = mobileGalleryNav.querySelectorAll("a"); mobileLinks.forEach(link => { link.addEventListener("click", () => { mobileGalleryNav.classList.remove("open"); galleryMenu.classList.remove("active"); }); }); } /* ===================================================== GALLERY ELEMENTS ===================================================== */ const galleryItems = Array.from( document.querySelectorAll(".gallery-item") ); const filterButtons = document.querySelectorAll( ".gallery-filter-btn" ); /* ===================================================== CATEGORY FILTER ===================================================== */ filterButtons.forEach(button => { button.addEventListener("click", () => { /* Remove active from all buttons */ filterButtons.forEach(btn => { btn.classList.remove("active"); }); /* Add active to clicked button */ button.classList.add("active"); const category = button.dataset.category; galleryItems.forEach((item, index) => { const itemCategory = item.dataset.category; if ( category === "all" || itemCategory === category ) { /* Show */ item.style.display = "inline-block"; /* Animation */ item.animate( [ { opacity: 0, transform: "translateY(25px) scale(.96)" }, { opacity: 1, transform: "translateY(0) scale(1)" } ], { duration: 500, delay: index * 40, easing: "cubic-bezier(.2,.7,.2,1)", fill: "forwards" } ); } else { /* Hide */ item.style.display = "none"; } }); }); }); /* ===================================================== LIGHTBOX ELEMENTS ===================================================== */ const lightbox = document.getElementById( "galleryLightbox" ); const lightboxImage = document.getElementById( "lightboxImage" ); const lightboxTitle = document.getElementById( "lightboxTitle" ); const lightboxCategory = document.getElementById( "lightboxCategory" ); const lightboxClose = document.getElementById( "lightboxClose" ); const lightboxPrev = document.getElementById( "lightboxPrev" ); const lightboxNext = document.getElementById( "lightboxNext" ); /* ===================================================== VISIBLE GALLERY ITEMS ===================================================== */ let currentItems = galleryItems; let currentIndex = 0; /* ===================================================== UPDATE VISIBLE ITEMS ===================================================== */ function updateVisibleItems() { currentItems = galleryItems.filter(item => { return ( item.style.display !== "none" ); }); } /* ===================================================== OPEN LIGHTBOX ===================================================== */ function openLightbox(item) { updateVisibleItems(); currentIndex = currentItems.indexOf(item); if (currentIndex < 0) { currentIndex = 0; } showLightboxImage(); lightbox.classList.add("active"); document.body.style.overflow = "hidden"; /* Opening animation */ lightbox.animate( [ { opacity: 0 }, { opacity: 1 } ], { duration: 300, easing: "ease-out", fill: "forwards" } ); } /* ===================================================== SHOW CURRENT IMAGE ===================================================== */ function showLightboxImage() { if (!currentItems.length) return; const item = currentItems[currentIndex]; const image = item.querySelector("img"); const title = item.dataset.title || "Aesthetic Salon"; const category = item.dataset.category || "Beauty"; /* Image */ lightboxImage.src = image.src; lightboxImage.alt = image.alt; /* Category */ lightboxCategory.textContent = category.toUpperCase(); /* Title */ lightboxTitle.textContent = title; /* Image animation */ lightboxImage.animate( [ { opacity: 0, transform: "scale(.94)" }, { opacity: 1, transform: "scale(1)" } ], { duration: 350, easing: "cubic-bezier(.2,.7,.2,1)" } ); } /* ===================================================== GALLERY ITEM CLICK ===================================================== */ galleryItems.forEach(item => { item.addEventListener("click", event => { /* Prevent duplicate behaviour when clicking the expand button */ event.preventDefault(); openLightbox(item); }); }); /* ===================================================== CLOSE LIGHTBOX ===================================================== */ function closeLightbox() { lightbox.classList.remove("active"); document.body.style.overflow = ""; } if (lightboxClose) { lightboxClose.addEventListener( "click", closeLightbox ); } /* ===================================================== CLICK OUTSIDE IMAGE ===================================================== */ if (lightbox) { lightbox.addEventListener( "click", event => { if ( event.target === lightbox ) { closeLightbox(); } } ); } /* ===================================================== NEXT IMAGE ===================================================== */ function nextImage() { updateVisibleItems(); if (!currentItems.length) return; currentIndex++; if ( currentIndex >= currentItems.length ) { currentIndex = 0; } showLightboxImage(); } if (lightboxNext) { lightboxNext.addEventListener( "click", nextImage ); } /* ===================================================== PREVIOUS IMAGE ===================================================== */ function previousImage() { updateVisibleItems(); if (!currentItems.length) return; currentIndex--; if (currentIndex < 0) { currentIndex = currentItems.length - 1; } showLightboxImage(); } if (lightboxPrev) { lightboxPrev.addEventListener( "click", previousImage ); } /* ===================================================== KEYBOARD CONTROLS ===================================================== */ document.addEventListener( "keydown", event => { /* ESC */ if ( event.key === "Escape" && lightbox.classList.contains("active") ) { closeLightbox(); } /* RIGHT ARROW */ if ( event.key === "ArrowRight" && lightbox.classList.contains("active") ) { nextImage(); } /* LEFT ARROW */ if ( event.key === "ArrowLeft" && lightbox.classList.contains("active") ) { previousImage(); } } ); /* ===================================================== MOBILE SWIPE ===================================================== */ let touchStartX = 0; let touchEndX = 0; if (lightbox) { lightbox.addEventListener( "touchstart", event => { touchStartX = event.changedTouches[0].screenX; }, { passive: true } ); lightbox.addEventListener( "touchend", event => { touchEndX = event.changedTouches[0].screenX; handleSwipe(); }, { passive: true } ); } function handleSwipe() { const swipeDistance = touchEndX - touchStartX; /* Swipe left */ if (swipeDistance < -50) { nextImage(); } /* Swipe right */ if (swipeDistance > 50) { previousImage(); } } /* ===================================================== 3D IMAGE HOVER ===================================================== */ galleryItems.forEach(item => { item.addEventListener( "mousemove", event => { /* Disable effect on small screens */ if ( window.innerWidth < 700 ) return; const rect = item.getBoundingClientRect(); const x = event.clientX - rect.left; const y = event.clientY - rect.top; const centerX = rect.width / 2; const centerY = rect.height / 2; const rotateX = ((y - centerY) / centerY) * -3; const rotateY = ((x - centerX) / centerX) * 3; item.style.transform = ` perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale(1.015) `; } ); item.addEventListener( "mouseleave", () => { item.style.transform = "perspective(1000px) rotateX(0) rotateY(0) scale(1)"; } ); }); /* ===================================================== SCROLL REVEAL ===================================================== */ const revealItems = document.querySelectorAll( ".gallery-item" ); const revealObserver = new IntersectionObserver( entries => { entries.forEach(entry => { if ( entry.isIntersecting ) { entry.target.classList.add( "gallery-visible" ); revealObserver.unobserve( entry.target ); } }); }, { threshold: .08 } ); revealItems.forEach(item => { item.classList.add( "gallery-hidden" ); revealObserver.observe(item); }); /* ===================================================== SCROLL REVEAL CSS Added through JavaScript ===================================================== */ const revealStyle = document.createElement("style"); revealStyle.textContent = ` .gallery-hidden{ opacity:0; transform: translateY(35px) scale(.98); transition: opacity .8s ease, transform .8s cubic-bezier(.2,.7,.2,1); } .gallery-hidden.gallery-visible{ opacity:1; transform: translateY(0) scale(1); } `; document.head.appendChild( revealStyle ); /* ===================================================== SMOOTH ANCHOR SCROLL ===================================================== */ document .querySelectorAll( 'a[href^="#"]' ) .forEach(anchor => { anchor.addEventListener( "click", function(event) { const target = document.querySelector( this.getAttribute("href") ); if (target) { event.preventDefault(); target.scrollIntoView({ behavior:"smooth", block:"start" }); } } ); }); /* ===================================================== IMAGE ERROR HANDLER ===================================================== */ galleryItems.forEach(item => { const image = item.querySelector("img"); if (!image) return; image.addEventListener( "error", () => { console.warn( "Gallery image not found:", image.src ); /* * Keeps layout clean if * an image is missing. */ item.classList.add( "image-missing" ); } ); }); /* ===================================================== PAGE LOADED ===================================================== */ window.addEventListener( "load", () => { document.body.classList.add( "gallery-loaded" ); } ); /* ===================================================== AESTHETIC SALON COMMON HEADER / TOGGLE ===================================================== */ document.addEventListener("DOMContentLoaded", function () { const toggle = document.getElementById("mainToggle"); const mobileMenu = document.getElementById("mobileMenu"); /* ================================================= MOBILE TOGGLE ================================================= */ if (toggle && mobileMenu) { toggle.addEventListener("click", function () { toggle.classList.toggle("active"); mobileMenu.classList.toggle("open"); }); /* CLOSE MENU AFTER CLICK */ const menuLinks = mobileMenu.querySelectorAll("a"); menuLinks.forEach(function (link) { link.addEventListener( "click", function () { toggle.classList.remove( "active" ); mobileMenu.classList.remove( "open" ); } ); }); /* ESCAPE KEY */ document.addEventListener( "keydown", function (event) { if ( event.key === "Escape" ) { toggle.classList.remove( "active" ); mobileMenu.classList.remove( "open" ); } } ); } /* ================================================= ACTIVE PAGE ================================================= */ const currentPage = window.location.pathname .split("/") .pop() .toLowerCase(); const allLinks = document.querySelectorAll( ".main-nav a, .mobile-menu a" ); allLinks.forEach(function (link) { const href = link.getAttribute("href"); if (!href) return; const page = href .split("/") .pop() .split("#")[0] .toLowerCase(); if ( page === currentPage || ( currentPage === "" && page === "index.html" ) ) { link.classList.add("active"); } }); /* ================================================= HEADER SCROLL ================================================= */ const header = document.querySelector( ".main-header" ); window.addEventListener( "scroll", function () { if (!header) return; if (window.scrollY > 40) { header.style.background = "rgba(3,3,12,.97)"; header.style.boxShadow = "0 10px 40px rgba(0,0,0,.25)"; } else { header.style.background = "rgba(3,3,14,.92)"; header.style.boxShadow = "none"; } }, { passive: true } ); });