364 lines
12 KiB
JavaScript
364 lines
12 KiB
JavaScript
document.addEventListener("DOMContentLoaded", () => {
|
|
// Fix double H1: demote hidden Magento page-title h1 to <p>
|
|
const magH1 = document.querySelector(".page-title-wrapper h1");
|
|
if (magH1) {
|
|
const p = document.createElement("p");
|
|
p.className = magH1.className;
|
|
p.innerHTML = magH1.innerHTML;
|
|
magH1.parentNode.replaceChild(p, magH1);
|
|
}
|
|
|
|
// Hamburger menu toggle
|
|
const hamburgerBtn = document.querySelector(".hamburger-btn");
|
|
const navMenu = document.querySelector(".nav-links");
|
|
const navBackdrop = document.getElementById("nav-backdrop");
|
|
|
|
function closeNavMenu() {
|
|
navMenu.classList.remove("open");
|
|
hamburgerBtn.classList.remove("open");
|
|
hamburgerBtn.setAttribute("aria-expanded", "false");
|
|
if (navBackdrop) navBackdrop.classList.remove("open");
|
|
}
|
|
|
|
if (hamburgerBtn && navMenu) {
|
|
hamburgerBtn.addEventListener("click", () => {
|
|
const isOpen = navMenu.classList.toggle("open");
|
|
hamburgerBtn.classList.toggle("open", isOpen);
|
|
hamburgerBtn.setAttribute("aria-expanded", String(isOpen));
|
|
if (navBackdrop) navBackdrop.classList.toggle("open", isOpen);
|
|
});
|
|
navMenu.querySelectorAll("a").forEach((a) => {
|
|
a.addEventListener("click", closeNavMenu);
|
|
});
|
|
if (navBackdrop) navBackdrop.addEventListener("click", closeNavMenu);
|
|
}
|
|
|
|
const sections = document.querySelectorAll(".section");
|
|
const navLinks = document.querySelectorAll(".nav-links a");
|
|
const scrollIndicator = document.querySelector(".scroll-indicator");
|
|
const heroInput = document.getElementById("hero-input");
|
|
const typewriterEl = document.getElementById("typewriter-title");
|
|
|
|
// Hero search: open store picker, then redirect to {STORE_URL}/catalogsearch/result/?q=...
|
|
const buySearchForm = document.querySelector("#buy-section .hero-search-form");
|
|
if (buySearchForm) {
|
|
buySearchForm.addEventListener("submit", (e) => {
|
|
e.preventDefault();
|
|
const q = (heroInput?.value || "").trim();
|
|
if (!q) return;
|
|
const slug = `catalogsearch/result/?q=${encodeURIComponent(q)}`;
|
|
if (typeof window.openStoreModal === "function") {
|
|
window.openStoreModal(slug);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Multi-stage Typewriter Sequence
|
|
const typeStrings = [
|
|
"Network hardware sourcing made simple",
|
|
"for every site",
|
|
"for every need",
|
|
"for every environment",
|
|
];
|
|
|
|
async function runTypewriter() {
|
|
if (!typewriterEl) return;
|
|
|
|
async function typeInto(element, text, speed) {
|
|
element.classList.add("typing-cursor");
|
|
for (const char of text) {
|
|
element.textContent += char;
|
|
await new Promise((r) => setTimeout(r, speed));
|
|
}
|
|
element.classList.remove("typing-cursor");
|
|
}
|
|
|
|
async function fadeStep() {
|
|
typewriterEl.style.opacity = "0";
|
|
await new Promise((r) => setTimeout(r, 600));
|
|
typewriterEl.innerHTML = "";
|
|
typewriterEl.style.opacity = "1";
|
|
await new Promise((r) => setTimeout(r, 200));
|
|
}
|
|
|
|
// Delay for server animation
|
|
await new Promise((r) => setTimeout(r, 3500));
|
|
|
|
// -- Text Phases --
|
|
for (let i = 0; i < typeStrings.length; i++) {
|
|
const span = document.createElement("span");
|
|
typewriterEl.appendChild(span);
|
|
await typeInto(span, typeStrings[i], 45);
|
|
|
|
await new Promise((r) => setTimeout(r, 1200));
|
|
await fadeStep();
|
|
}
|
|
|
|
// -- FINAL PHASE: BRAND LOGO --
|
|
const brandBox = document.createElement("div");
|
|
brandBox.style.display = "flex";
|
|
brandBox.style.flexDirection = "column";
|
|
brandBox.style.alignItems = "center";
|
|
brandBox.style.gap = "15px";
|
|
brandBox.style.opacity = "0"; // Start invisible
|
|
brandBox.style.transition = "opacity 0.6s ease-out";
|
|
|
|
const brandImg = document.createElement("img");
|
|
brandImg.src = window.PROLOGY_CONFIG.LOGO_SRC;
|
|
brandImg.alt = "Prology";
|
|
brandImg.style.height = "80px";
|
|
brandImg.style.width = "auto";
|
|
brandImg.style.filter = "none"; // Logo full màu
|
|
|
|
const finalTag = document.createElement("div");
|
|
finalTag.style.fontSize = "1.6rem";
|
|
finalTag.style.fontWeight = "600";
|
|
finalTag.style.color = "var(--primary)";
|
|
finalTag.style.letterSpacing = "0.15em";
|
|
finalTag.style.textTransform = "uppercase";
|
|
|
|
brandBox.appendChild(brandImg);
|
|
brandBox.appendChild(finalTag);
|
|
typewriterEl.appendChild(brandBox);
|
|
|
|
// 1. Kick off Logo Fade-in
|
|
setTimeout(() => {
|
|
brandBox.style.opacity = "1";
|
|
}, 200);
|
|
await new Promise((r) => setTimeout(r, 1000));
|
|
|
|
// 2. Type the final tagline
|
|
await typeInto(finalTag, "Your Network Hardware Partner", 50);
|
|
|
|
// 3. Wait a moment so user can read it, then fade out the tagline/logo
|
|
await new Promise((r) => setTimeout(r, 1500));
|
|
brandBox.style.opacity = "0";
|
|
|
|
// 4. Wait for fade out, hide it, and show the eBay Banner
|
|
await new Promise((r) => setTimeout(r, 600));
|
|
brandBox.style.display = "none";
|
|
|
|
const ebayBanner = document.getElementById("hero-ebay-integrated");
|
|
if (ebayBanner) {
|
|
// Typewriter xong hẳn — giờ mới hide wrapper và show banner
|
|
const wrapper = document.querySelector(".hero-animation-wrapper");
|
|
if (wrapper) wrapper.style.display = "none";
|
|
ebayBanner.classList.add("visible");
|
|
}
|
|
}
|
|
|
|
runTypewriter();
|
|
|
|
// Auto-focus timer removed here.
|
|
// Auto-focusing after 19s caused the browser to scroll back to the top while the user was reading below.
|
|
|
|
// Switch between Source (Buy) and Sell Modes
|
|
window.switchTab = function (mode) {
|
|
const buySection = document.getElementById("buy-section");
|
|
const sellSection = document.getElementById("sell-section");
|
|
const tabs = document.querySelectorAll(".search-tab");
|
|
|
|
// Toggle tabs
|
|
tabs.forEach((tab) => {
|
|
tab.classList.toggle(
|
|
"active",
|
|
tab.textContent.toLowerCase().includes(mode),
|
|
);
|
|
});
|
|
|
|
// Toggle sections with a small fade
|
|
if (mode === "buy") {
|
|
sellSection.style.display = "none";
|
|
buySection.style.display = "block";
|
|
document.getElementById("hero-input").focus();
|
|
} else {
|
|
buySection.style.display = "none";
|
|
sellSection.style.display = "block";
|
|
document.getElementById("sell-email-init").focus();
|
|
}
|
|
};
|
|
|
|
let isScrolling = false;
|
|
let currentSectionIndex = 0;
|
|
|
|
function updateUI(index) {
|
|
currentSectionIndex = index;
|
|
const currentSection = sections[index];
|
|
const id = currentSection.getAttribute("id");
|
|
|
|
// Update Top Nav based on href matches, not raw index parity
|
|
navLinks.forEach((link) => {
|
|
link.classList.remove("active", "past");
|
|
const targetId = link.getAttribute("href");
|
|
|
|
if (targetId === `#${id}`) {
|
|
link.classList.add("active");
|
|
} else if (id === "warehouse" && targetId === "#quality") {
|
|
link.classList.add("active");
|
|
}
|
|
});
|
|
|
|
// Toggle light color for scroll indicator on dark sections (1, 3, 5)
|
|
if (scrollIndicator) {
|
|
if (index % 2 !== 0) {
|
|
scrollIndicator.classList.add("light");
|
|
} else {
|
|
scrollIndicator.classList.remove("light");
|
|
}
|
|
}
|
|
|
|
// Hide Scroll Indicator on last page
|
|
if (scrollIndicator) {
|
|
if (index === sections.length - 1) {
|
|
scrollIndicator.style.opacity = "0";
|
|
} else {
|
|
scrollIndicator.style.opacity = "1";
|
|
}
|
|
}
|
|
}
|
|
|
|
// Logic cuộn tự động đã được chuyển qua CSS scroll-snap để tối ưu hiệu năng và tương thích màn hình
|
|
|
|
function scrollToSection(index) {
|
|
isScrolling = true;
|
|
updateUI(index);
|
|
sections[index].scrollIntoView({ behavior: "smooth" });
|
|
|
|
setTimeout(() => {
|
|
isScrolling = false;
|
|
}, 800); // Wait for animation to finish
|
|
}
|
|
|
|
// ============ SECTION OBSERVER ============
|
|
const observerOptions = {
|
|
threshold: 0.5,
|
|
};
|
|
|
|
const observer = new IntersectionObserver((entries) => {
|
|
entries.forEach((entry) => {
|
|
if (entry.isIntersecting) {
|
|
const id = entry.target.getAttribute("id");
|
|
const index = Array.from(sections).indexOf(entry.target);
|
|
|
|
// Update internal index for wheel/space navigation
|
|
if (!isScrolling) currentSectionIndex = index;
|
|
|
|
// Update Top Nav
|
|
navLinks.forEach((link) => {
|
|
link.classList.remove("active");
|
|
const targetId = link.getAttribute("href");
|
|
|
|
if (targetId === `#${id}`) {
|
|
link.classList.add("active");
|
|
}
|
|
// Special case: Keep 'Why Us' highlighted when inside Global Logistics
|
|
if (id === "warehouse" && targetId === "#quality") {
|
|
link.classList.add("active");
|
|
}
|
|
});
|
|
|
|
entry.target.classList.add("visible");
|
|
}
|
|
});
|
|
}, observerOptions);
|
|
|
|
sections.forEach((section) => observer.observe(section));
|
|
|
|
// Hide scroll indicator when footer is visible
|
|
const footerEl = document.querySelector("footer.page-footer");
|
|
if (footerEl && scrollIndicator) {
|
|
const footerObserver = new IntersectionObserver((entries) => {
|
|
entries.forEach((entry) => {
|
|
scrollIndicator.style.opacity = entry.isIntersecting ? "0" : "";
|
|
});
|
|
}, { threshold: 0.05 });
|
|
footerObserver.observe(footerEl);
|
|
}
|
|
|
|
// ============ SMOOTH SCROLL (Navbar) ============
|
|
document.querySelectorAll('a[href^="#"]').forEach((anchor) => {
|
|
anchor.addEventListener("click", function (e) {
|
|
e.preventDefault();
|
|
const targetId = this.getAttribute("href");
|
|
const target = document.querySelector(targetId);
|
|
if (target) {
|
|
const index = Array.from(sections).indexOf(target);
|
|
if (index !== -1) scrollToSection(index);
|
|
}
|
|
});
|
|
});
|
|
|
|
// ============ ANIMATE PORT SEQUENCE ============
|
|
const switchPanel = document.getElementById("animated-switch-panel");
|
|
if (switchPanel) {
|
|
const totalColumns = 24;
|
|
const totalRows = 2;
|
|
|
|
for (let r = 0; r < totalRows; r++) {
|
|
const rowDiv = document.createElement("div");
|
|
rowDiv.className = "port-row";
|
|
|
|
for (let c = 0; c < totalColumns; c++) {
|
|
const portDiv = document.createElement("div");
|
|
|
|
// Randomly decide if this port gets a cable ( ~40% chance )
|
|
// EXCLUDE Port 22 of Bottom Row (r=1, c=21) for the master cable
|
|
if (Math.random() < 0.4 && !(r === 1 && c === 21)) {
|
|
portDiv.className = "port-front active-port";
|
|
// Random drop-in delay between 0 and 2.5 seconds
|
|
const plugDelay = Math.random() * 2.5;
|
|
portDiv.style.setProperty("--delay", `${plugDelay}s`);
|
|
|
|
portDiv.innerHTML = `
|
|
<div class="port-led"></div>
|
|
<div class="cable-front">
|
|
<div class="cable-head-front"></div>
|
|
<div class="cable-wire-front"></div>
|
|
</div>
|
|
`;
|
|
} else {
|
|
// Inactive port just has the base shell and an unlit LED
|
|
portDiv.className = "port-front";
|
|
portDiv.innerHTML = `<div class="port-led"></div>`;
|
|
}
|
|
|
|
rowDiv.appendChild(portDiv);
|
|
}
|
|
switchPanel.appendChild(rowDiv);
|
|
}
|
|
}
|
|
|
|
// ============ QUALITY SLIDER LOGIC ============
|
|
let currentQSlide = 0;
|
|
const qSlides = document.querySelectorAll(".q-slide");
|
|
const qDots = document.querySelectorAll(".dot");
|
|
let qInterval;
|
|
|
|
window.setQSlide = function (index) {
|
|
if (index === currentQSlide) return;
|
|
|
|
qSlides[currentQSlide].classList.remove("active");
|
|
qDots[currentQSlide].classList.remove("active");
|
|
|
|
currentQSlide = index;
|
|
|
|
qSlides[currentQSlide].classList.add("active");
|
|
qDots[currentQSlide].classList.add("active");
|
|
|
|
// Reset interval on manual click
|
|
clearInterval(qInterval);
|
|
startQAutoPlay();
|
|
};
|
|
|
|
function startQAutoPlay() {
|
|
qInterval = setInterval(() => {
|
|
let next = (currentQSlide + 1) % qSlides.length;
|
|
setQSlide(next);
|
|
}, 5000);
|
|
}
|
|
|
|
if (qSlides.length > 0) {
|
|
startQAutoPlay();
|
|
}
|
|
});
|