/* =================================== VELORA - Main Application JS =================================== */ (function($) { 'use strict'; const Velora = { init: function() { this.preloader(); this.backToTop(); this.search(); this.tooltips(); this.quantity(); this.tabs(); this.zoom(); this.gallery(); this.countdown(); this.lazyLoad(); this.newsletter(); this.imagePreviews(); }, // Image previews for file inputs imagePreviews: function() { $(document).on('change', 'input[type="file"][data-preview]', function() { const input = this; const previewId = $(this).data('preview'); const preview = document.getElementById(previewId); if (!preview) return; if (input.files && input.files[0]) { const reader = new FileReader(); reader.onload = function(e) { preview.src = e.target.result; preview.style.display = 'block'; }; reader.readAsDataURL(input.files[0]); } else { preview.src = ''; preview.style.display = 'none'; } }); // Multi-image preview $(document).on('change', '#images-input', function() { const container = document.getElementById('images-preview'); if (!container) return; container.innerHTML = ''; const files = this.files; for (let i = 0; i < Math.min(files.length, 8); i++) { const reader = new FileReader(); const wrap = document.createElement('div'); wrap.style.cssText = 'width:80px;height:80px;border-radius:8px;overflow:hidden;border:1px solid #eee;'; const img = document.createElement('img'); img.style.cssText = 'width:100%;height:100%;object-fit:cover;'; reader.onload = (function(w, im) { return function(e) { im.src = e.target.result; w.appendChild(im); }; })(wrap, img); reader.readAsDataURL(files[i]); } }); }, // Preloader preloader: function() { $(window).on('load', function() { setTimeout(function() { $('#preloader').addClass('hidden'); $('body').css('overflow', 'auto'); }, 800); }); }, // Back to Top backToTop: function() { $(window).on('scroll', function() { if ($(this).scrollTop() > 300) { $('#back-to-top').addClass('show'); } else { $('#back-to-top').removeClass('show'); } }); $('#back-to-top').on('click', function(e) { e.preventDefault(); $('html, body').animate({ scrollTop: 0 }, 600); }); }, // Live Search search: function() { let searchTimer; const runSearch = function(input, resultsContainer) { const query = input.val(); clearTimeout(searchTimer); if (query.length < 2) { resultsContainer.removeClass('active').empty(); return; } searchTimer = setTimeout(function() { $.ajax({ url: SITE_URL + 'ajax/search.php', type: 'GET', data: { q: query }, dataType: 'json', success: function(response) { if (response.success && response.data.length > 0) { let html = ''; response.data.forEach(function(item) { html += ''; html += '' + item.name + ''; html += '
'; html += '
' + item.name + '
'; html += '
' + item.price + '
'; html += '
'; }); resultsContainer.html(html).addClass('active'); } else { resultsContainer.html('
No products found
').addClass('active'); } } }); }, 300); }; // Desktop search $('#search-input').on('input', function() { runSearch($(this), $('#search-results')); }); // Mobile search $('#mobile-search-input').on('input', function() { runSearch($(this), $('#mobile-search-results')); }); $(document).on('click', function(e) { if (!$(e.target).closest('.search-wrapper').length) { $('#search-results, #mobile-search-results').removeClass('active'); } }); // Mobile search toggle $('#mobile-search-toggle').on('click', function(e) { e.preventDefault(); const bar = $('#mobile-search-bar'); bar.toggleClass('active'); if (bar.hasClass('active')) { setTimeout(function() { $('#mobile-search-input').focus(); }, 200); } }); $('#mobile-search-close').on('click', function(e) { e.preventDefault(); $('#mobile-search-bar').removeClass('active'); $('#mobile-search-input').val(''); $('#mobile-search-results').removeClass('active').empty(); }); }, // Bootstrap Tooltips tooltips: function() { var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')); tooltipTriggerList.map(function (el) { return new bootstrap.Tooltip(el); }); }, // Quantity Controls quantity: function() { $(document).on('click', '.qty-btn', function() { const $input = $(this).siblings('.qty-input'); const currentVal = parseInt($input.val()); const min = parseInt($input.attr('min')) || 1; const max = parseInt($input.attr('max')) || 999; if ($(this).hasClass('qty-plus')) { if (currentVal < max) { $input.val(currentVal + 1).trigger('change'); } } else if ($(this).hasClass('qty-minus')) { if (currentVal > min) { $input.val(currentVal - 1).trigger('change'); } } }); }, // Product Tabs tabs: function() { $('.tab-btn').on('click', function() { const target = $(this).data('target'); $('.tab-btn').removeClass('active'); $(this).addClass('active'); $('.tab-content').removeClass('active'); $(target).addClass('active'); }); }, // Product Image Zoom zoom: function() { if ($('.product-zoom').length) { $('.product-zoom').on('mousemove', function(e) { const offset = $(this).offset(); const x = (e.pageX - offset.left) / $(this).width() * 100; const y = (e.pageY - offset.top) / $(this).height() * 100; $(this).find('img').css('transform-origin', x + '% ' + y + '%'); }); $('.product-zoom').on('mouseenter', function() { $(this).find('img').css('transform', 'scale(1.5)'); }).on('mouseleave', function() { $(this).find('img').css('transform', 'scale(1)'); }); } }, // Product Gallery gallery: function() { $(document).on('click', '.gallery-thumb img', function() { const mainImg = $(this).closest('.product-gallery').find('.main-image img'); const newSrc = $(this).data('large') || $(this).attr('src'); mainImg.attr('src', newSrc); $('.gallery-thumb').removeClass('active'); $(this).closest('.gallery-thumb').addClass('active'); }); }, // Countdown Timer countdown: function() { $('.countdown-timer').each(function() { const $this = $(this); const endTime = new Date($this.data('end-time')).getTime(); const timer = setInterval(function() { const now = new Date().getTime(); const distance = endTime - now; if (distance < 0) { clearInterval(timer); $this.html('
Deal Expired
'); return; } const days = Math.floor(distance / (1000 * 60 * 60 * 24)); const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)); const seconds = Math.floor((distance % (1000 * 60)) / 1000); $this.find('.days').text(String(days).padStart(2, '0')); $this.find('.hours').text(String(hours).padStart(2, '0')); $this.find('.minutes').text(String(minutes).padStart(2, '0')); $this.find('.seconds').text(String(seconds).padStart(2, '0')); }, 1000); }); }, // Lazy Load Images lazyLoad: function() { if ('IntersectionObserver' in window) { const imageObserver = new IntersectionObserver(function(entries) { entries.forEach(function(entry) { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; img.classList.add('loaded'); imageObserver.unobserve(img); } }); }); document.querySelectorAll('img[data-src]').forEach(function(img) { imageObserver.observe(img); }); } }, // Newsletter Subscription newsletter: function() { $('#newsletter-form').on('submit', function(e) { e.preventDefault(); const email = $(this).find('input[name="email"]').val(); const $btn = $(this).find('button[type="submit"]'); const originalText = $btn.html(); $btn.prop('disabled', true).html(' Subscribing...'); $.ajax({ url: SITE_URL + 'ajax/newsletter.php', type: 'POST', data: { email: email, csrf_token: CSRF_TOKEN }, dataType: 'json', success: function(response) { if (response.success) { toastr.success(response.message); $('#newsletter-form')[0].reset(); } else { toastr.error(response.message); } $btn.prop('disabled', false).html(originalText); }, error: function() { toastr.error('Something went wrong. Please try again.'); $btn.prop('disabled', false).html(originalText); } }); }); } }; // Initialize on document ready $(document).ready(function() { Velora.init(); // Smooth scroll for anchor links $('a[href^="#"]').on('click', function(e) { const target = $(this).attr('href'); if (target !== '#' && $(target).length) { e.preventDefault(); $('html, body').animate({ scrollTop: $(target).offset().top - 100 }, 600); } }); }); // Global AJAX setup $.ajaxSetup({ headers: { 'X-CSRF-Token': CSRF_TOKEN } }); })(jQuery); // =================================== // Navigation Progress + Page Loader // =================================== (function() { 'use strict'; // Hide preloader once page is fully ready (including images) function hidePreloader() { document.body.classList.add('loaded'); } if (document.readyState === 'complete') { hidePreloader(); } else { window.addEventListener('load', hidePreloader); // Failsafe: hide after 2s even if some images hang setTimeout(hidePreloader, 2000); } // Show progress bar on internal link clicks document.addEventListener('click', function(e) { var link = e.target.closest('a'); if (!link) return; var href = link.getAttribute('href'); // Skip: empty, anchors, external, mailto, tel, target=_blank, modifier keys if (!href || href.charAt(0) === '#') return; if (link.target === '_blank') return; if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return; if (href.indexOf('javascript:') === 0 || href.indexOf('mailto:') === 0 || href.indexOf('tel:') === 0) return; // External link check try { var url = new URL(href, window.location.origin); if (url.origin !== window.location.origin) return; } catch (err) { return; } // Skip AJAX / form-submit links if (link.hasAttribute('data-no-progress')) return; var bar = document.getElementById('nav-progress'); if (bar) { bar.classList.remove('done'); bar.classList.add('active'); } }); // Mark progress as done on page show (back/forward cache) window.addEventListener('pageshow', function() { var bar = document.getElementById('nav-progress'); if (bar) { bar.classList.remove('active'); bar.classList.add('done'); setTimeout(function() { bar.classList.remove('done'); }, 500); } }); // Also mark done when page becomes hidden (user navigates away) document.addEventListener('visibilitychange', function() { if (document.visibilityState === 'hidden') { var bar = document.getElementById('nav-progress'); if (bar) bar.classList.add('done'); } }); })();