/** * Mobile Touch Optimization * Eliminates double-tap behavior and ensures immediate response on mobile devices */ (function () { "use strict"; // Only apply on touch devices if (!("ontouchstart" in window)) return; // Disable 300ms click delay on mobile let touchStartX, touchStartY; // Add fastclick functionality for immediate response document.addEventListener( "touchstart", function (e) { touchStartX = e.touches[0].clientX; touchStartY = e.touches[0].clientY; }, { passive: true }, ); document.addEventListener( "touchend", function (e) { if (!touchStartX || !touchStartY) return; const touchEndX = e.changedTouches[0].clientX; const touchEndY = e.changedTouches[0].clientY; // Check if it's a tap (not a swipe) const diffX = Math.abs(touchEndX - touchStartX); const diffY = Math.abs(touchEndY - touchStartY); if (diffX < 10 && diffY < 10) { // This is a tap, ensure immediate response const target = e.target.closest( "a, button, [data-bs-toggle], .product-card, .portfolio-card, .blog-card, .nav-link, .btn", ); if (target && !target.disabled) { // Add visual feedback target.style.opacity = "0.7"; setTimeout(() => { target.style.opacity = ""; }, 100); } } touchStartX = null; touchStartY = null; }, { passive: false }, ); // Remove hover states that cause double-tap on mobile if (window.matchMedia("(hover: none)").matches) { const style = document.createElement("style"); style.textContent = ` /* Override hover states for immediate touch response */ .product-card, .portfolio-card, .blog-card, .btn, .nav-link { transition: transform 0.1s ease, opacity 0.1s ease !important; } `; document.head.appendChild(style); } // Optimize click handlers for mobile function optimizeClickHandler(selector) { const elements = document.querySelectorAll(selector); elements.forEach((el) => { if (el.dataset.mobileOptimized) return; el.dataset.mobileOptimized = "true"; // Remove any existing event listeners that might cause delays el.style.pointerEvents = "auto"; el.style.touchAction = "manipulation"; // Ensure proper z-index for touch const computedStyle = window.getComputedStyle(el); if (computedStyle.position === "static") { el.style.position = "relative"; } }); } // Apply optimizations when DOM is ready document.addEventListener("DOMContentLoaded", function () { optimizeClickHandler( "a, button, .product-card, .portfolio-card, .blog-card, .btn, .nav-link, .filter-btn, .add-to-cart-btn", ); }); // Apply optimizations to dynamically added content const observer = new MutationObserver(function (mutations) { mutations.forEach(function (mutation) { if (mutation.type === "childList") { mutation.addedNodes.forEach(function (node) { if (node.nodeType === Node.ELEMENT_NODE) { optimizeClickHandler( "a, button, .product-card, .portfolio-card, .blog-card, .btn, .nav-link, .filter-btn, .add-to-cart-btn", ); } }); } }); }); observer.observe(document.body, { childList: true, subtree: true, }); })();