190 lines
6.5 KiB
JavaScript
190 lines
6.5 KiB
JavaScript
/* =========================================================
|
|
Apex Turf — Landing Page Interactions
|
|
========================================================= */
|
|
(function () {
|
|
"use strict";
|
|
|
|
var prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
|
|
/* ---------- Sticky header ---------- */
|
|
var header = document.getElementById("siteHeader");
|
|
function onScroll() {
|
|
if (window.scrollY > 40) {
|
|
header.classList.add("is-scrolled");
|
|
} else {
|
|
header.classList.remove("is-scrolled");
|
|
}
|
|
toggleBackToTop();
|
|
}
|
|
window.addEventListener("scroll", onScroll, { passive: true });
|
|
onScroll();
|
|
|
|
/* ---------- Mobile nav toggle ---------- */
|
|
var navToggle = document.getElementById("navToggle");
|
|
var mainNav = document.getElementById("mainNav");
|
|
navToggle.addEventListener("click", function () {
|
|
var isOpen = document.body.classList.toggle("nav-open");
|
|
navToggle.setAttribute("aria-expanded", isOpen ? "true" : "false");
|
|
});
|
|
mainNav.querySelectorAll("a").forEach(function (link) {
|
|
link.addEventListener("click", function () {
|
|
document.body.classList.remove("nav-open");
|
|
navToggle.setAttribute("aria-expanded", "false");
|
|
});
|
|
});
|
|
|
|
/* ---------- Active nav link on scroll ---------- */
|
|
var navLinks = Array.prototype.slice.call(mainNav.querySelectorAll("a"));
|
|
var sections = navLinks
|
|
.map(function (link) {
|
|
var id = link.getAttribute("href");
|
|
return id && id.charAt(0) === "#" ? document.querySelector(id) : null;
|
|
})
|
|
.filter(Boolean);
|
|
|
|
if ("IntersectionObserver" in window && sections.length) {
|
|
var navObserver = new IntersectionObserver(
|
|
function (entries) {
|
|
entries.forEach(function (entry) {
|
|
if (entry.isIntersecting) {
|
|
var id = "#" + entry.target.id;
|
|
navLinks.forEach(function (link) {
|
|
link.classList.toggle("is-active", link.getAttribute("href") === id);
|
|
});
|
|
}
|
|
});
|
|
},
|
|
{ rootMargin: "-45% 0px -50% 0px", threshold: 0 }
|
|
);
|
|
sections.forEach(function (section) { navObserver.observe(section); });
|
|
}
|
|
|
|
/* ---------- Scroll reveal (with fallbacks so content never stays stuck hidden) ---------- */
|
|
var revealEls = document.querySelectorAll(".reveal");
|
|
function revealAll() {
|
|
revealEls.forEach(function (el) { el.classList.add("is-visible"); });
|
|
}
|
|
try {
|
|
if ("IntersectionObserver" in window && !prefersReducedMotion) {
|
|
var revealObserver = new IntersectionObserver(
|
|
function (entries, obs) {
|
|
entries.forEach(function (entry) {
|
|
if (entry.isIntersecting) {
|
|
entry.target.classList.add("is-visible");
|
|
obs.unobserve(entry.target);
|
|
}
|
|
});
|
|
},
|
|
{ threshold: 0.15 }
|
|
);
|
|
revealEls.forEach(function (el) { revealObserver.observe(el); });
|
|
// Safety net: if the observer never fires (paint quirks, fragment-jump
|
|
// navigation, etc.) don't leave content permanently invisible.
|
|
setTimeout(revealAll, 2500);
|
|
} else {
|
|
revealAll();
|
|
}
|
|
} catch (err) {
|
|
revealAll();
|
|
}
|
|
|
|
/* ---------- Hero right-pane tabs (Pádel / Football / Golf) ---------- */
|
|
var tabButtons = document.querySelectorAll("#heroTabs button");
|
|
var scenes = document.querySelectorAll(".right-scene");
|
|
var sceneOrder = ["padel", "football", "golf"];
|
|
var currentIndex = 0;
|
|
var rotateTimer = null;
|
|
var rightPane = document.querySelector(".pane-right");
|
|
|
|
function showScene(name) {
|
|
tabButtons.forEach(function (btn) {
|
|
var active = btn.getAttribute("data-scene") === name;
|
|
btn.classList.toggle("is-active", active);
|
|
btn.setAttribute("aria-selected", active ? "true" : "false");
|
|
});
|
|
scenes.forEach(function (scene) {
|
|
scene.classList.toggle("is-active", scene.getAttribute("data-scene") === name);
|
|
});
|
|
currentIndex = sceneOrder.indexOf(name);
|
|
}
|
|
|
|
function nextScene() {
|
|
currentIndex = (currentIndex + 1) % sceneOrder.length;
|
|
showScene(sceneOrder[currentIndex]);
|
|
}
|
|
|
|
function startRotation() {
|
|
stopRotation();
|
|
if (!prefersReducedMotion) {
|
|
rotateTimer = setInterval(nextScene, 6000);
|
|
}
|
|
}
|
|
function stopRotation() {
|
|
if (rotateTimer) { clearInterval(rotateTimer); rotateTimer = null; }
|
|
}
|
|
|
|
tabButtons.forEach(function (btn) {
|
|
btn.addEventListener("click", function () {
|
|
showScene(btn.getAttribute("data-scene"));
|
|
startRotation();
|
|
});
|
|
});
|
|
|
|
if (rightPane) {
|
|
rightPane.addEventListener("mouseenter", stopRotation);
|
|
rightPane.addEventListener("mouseleave", startRotation);
|
|
rightPane.addEventListener("focusin", stopRotation);
|
|
rightPane.addEventListener("focusout", startRotation);
|
|
}
|
|
|
|
startRotation();
|
|
|
|
/* ---------- Smooth scroll with header offset ---------- */
|
|
var headerOffset = function () {
|
|
return header.offsetHeight + 12;
|
|
};
|
|
document.querySelectorAll('a[href^="#"]').forEach(function (link) {
|
|
link.addEventListener("click", function (e) {
|
|
var targetId = link.getAttribute("href");
|
|
if (targetId.length < 2) return;
|
|
var target = document.querySelector(targetId);
|
|
if (!target) return;
|
|
e.preventDefault();
|
|
var top = target.getBoundingClientRect().top + window.pageYOffset - headerOffset();
|
|
window.scrollTo({ top: top, behavior: prefersReducedMotion ? "auto" : "smooth" });
|
|
history.pushState(null, "", targetId);
|
|
});
|
|
});
|
|
|
|
/* ---------- Quote form (front-end only) ---------- */
|
|
var form = document.getElementById("quoteForm");
|
|
var successBox = document.getElementById("formSuccess");
|
|
if (form) {
|
|
form.addEventListener("submit", function (e) {
|
|
e.preventDefault();
|
|
if (!form.checkValidity()) {
|
|
form.reportValidity();
|
|
return;
|
|
}
|
|
successBox.classList.add("show");
|
|
form.reset();
|
|
successBox.scrollIntoView({ behavior: prefersReducedMotion ? "auto" : "smooth", block: "center" });
|
|
setTimeout(function () { successBox.classList.remove("show"); }, 8000);
|
|
});
|
|
}
|
|
|
|
/* ---------- Back to top ---------- */
|
|
var backToTop = document.getElementById("backToTop");
|
|
function toggleBackToTop() {
|
|
if (!backToTop) return;
|
|
backToTop.classList.toggle("show", window.scrollY > 700);
|
|
}
|
|
backToTop.addEventListener("click", function () {
|
|
window.scrollTo({ top: 0, behavior: prefersReducedMotion ? "auto" : "smooth" });
|
|
});
|
|
|
|
/* ---------- Footer year ---------- */
|
|
var yearEl = document.getElementById("year");
|
|
if (yearEl) { yearEl.textContent = new Date().getFullYear(); }
|
|
})();
|