// Disable GSAP's use of requestAnimationFrame gsap.ticker.fps(60); gsap.ticker.lagSmoothing(0); // Add an event listener to call showLoadingSpinner when the DOM is fully loaded // document.addEventListener('DOMContentLoaded', function() { showLoadingSpinner(); }); function select(selector) { return document.querySelector(selector); } function showLoadingSpinner() { const spinner = select("#loading-spinner"); spinner.style.display = "block"; } function hideLoadingSpinner() { const spinner = select("#loading-spinner"); spinner.style.display = "none"; } document.addEventListener("click", debounce((e) => { if (e.target.closest(`[data-action="openModal"]`)) { const device = e.target.dataset.device; const action = e.target.dataset.actionType; let url = `/${action}/${device}`; if (action === "wol") { fetchKey().then((key) => { url += `?key=${key}`; showLoadingSpinner(); openModal(url); }).catch(error => { console.error('Error fetching key:', error); }); } else { showLoadingSpinner(); openModal(url); } } if ( e.target.closest(`[data-action="closeModal"]`) || e.target.classList.contains("modal-wrapper") ) { closeModal(); } }, 300)); let countdown; async function fetchKey() { try { const response = await fetch('/get_key'); const data = await response.json(); return data.key; } catch (error) { console.error('Error fetching key:', error); throw error; } } function openModal(url) { closeExistingModal().then(() => { fetch(url) .then(response => response.text()) .then(html => { hideLoadingSpinner(); const modal = ` `; select("body").insertAdjacentHTML("beforeend", modal); const wrapper = select(".modal-wrapper"); wrapper.style.display = "flex"; select("body").style.overflow = "hidden"; setTimeout(() => { wrapper.style.opacity = 1; wrapper.classList.add("show"); startCountdown(); }, 100); }).catch(error => { hideLoadingSpinner(); console.error('Error fetching content:', error) }); }); } function closeModal() { const wrapper = document.querySelector(".modal-wrapper"); return new Promise((resolve) => { if (wrapper) { const container = document.querySelector(".modal-container"); if (container) { container.style.transform = 'scale(0)'; } wrapper.style.opacity = 0; setTimeout(() => { if (wrapper.parentNode) { wrapper.remove(); } select("body").style.overflow = ""; clearTimeout(countdown); resolve(); }, 500); } else { resolve(); } }); } function closeExistingModal() { const existingWrapper = document.querySelector(".modal-wrapper"); return new Promise((resolve) => { if (existingWrapper) { existingWrapper.style.opacity = 0; setTimeout(() => { if (existingWrapper.parentNode) { existingWrapper.remove(); } select("body").style.overflow = ""; // Reset body overflow clearTimeout(countdown); // Clear any existing countdown resolve(); }, 500); } else { resolve(); } }); } function startCountdown() { const timer = document.getElementById('modal-timer'); if (timer) { timer.classList.add('timer-animation'); countdown = setTimeout(() => { closeModal(); }, 5000); } } /* Debounce Function */ function debounce(func, wait) { let timeout; return function(...args) { clearTimeout(timeout); timeout = setTimeout(() => func.apply(this, args), wait); }; } window.onload = function() { document.querySelector(".preloader").style.display = 'flex'; const loadingText = new SplitType(".loading-text.initial", { types: "chars" }); const completeText = new SplitType(".loading-text.complete", { types: "chars" }); const titleText = new SplitType(".content h1", { types: "chars" }); const paragraphText = new SplitType(".content p", { types: "chars" }); gsap.set(".loading-text.complete", { y: "100%" }); gsap.set(loadingText.chars, { opacity: 0, y: 100 }); gsap.set(completeText.chars, { opacity: 0, y: 100 }); gsap.to(loadingText.chars, { opacity: 1, y: 0, duration: 0.5, stagger: 0.05, ease: "power2.out" }); const colorStages = [ { bg: "rgb(60, 66, 55)", text: "rgb(230, 225, 215)" }, { bg: "rgb(200, 180, 160)", text: "rgb(60, 66, 55)" }, { bg: "rgb(230, 225, 215)", text: "rgb(60, 66, 55)" }, { bg: "rgb(100, 110, 90)", text: "rgb(230, 225, 215)" } ]; function updateColors(progress) { const stage = Math.floor(progress / 25); if (stage < colorStages.length) { document.querySelector(".preloader").style.backgroundColor = colorStages[stage].bg; document.querySelector(".progress-bar").style.backgroundColor = colorStages[stage].text; document.querySelectorAll(".loading-text .char, .percentage").forEach((el) => { el.style.color = colorStages[stage].text; }); } } const tl = gsap.timeline({ paused: true }); tl.to(".progress-bar", { width: "100%", duration: 5, ease: "power1.inOut", onUpdate: function () { const progress = Math.round(this.progress() * 100); document.querySelector(".percentage").textContent = progress; updateColors(progress); } }).to(".loading-text.initial", { y: "-100%", duration: 0.5, ease: "power2.inOut" }).to(".loading-text.complete", { y: "0%", duration: 0.5, ease: "power2.inOut" }, "<" ).to(completeText.chars, { opacity: 1, y: 0, duration: 0.3, stagger: 0.03, ease: "power2.out" }, "<0.2" ).to(".preloader", { y: "-100vh", duration: 1, ease: "power2.inOut", delay: 0.8 }).set(".content", { visibility: "visible" }, "-=1").to([titleText.chars, paragraphText.chars], { opacity: 1, y: 0, duration: 1, stagger: 0.02, ease: "power4.out" }, "-=0.5").set(".preloader", { display: "none" }); let isFirstLoad = !localStorage.getItem('firstLoadDone'); if (!isFirstLoad) { const tl = gsap.timeline(); tl.set(".preloader", { display: "none" }).set(".content", { visibility: "visible" }, "-=1").to([titleText.chars, paragraphText.chars], { opacity: 1, y: 0, duration: 2, stagger: 0.04, ease: "power2.out" }, "=0.5") } else { document.querySelector('.preloader').style.display = 'flex'; tl.play(); // Start the GSAP timeline localStorage.setItem('firstLoadDone', 'true'); } };