// animation speeds cause why not const TYPING_SPEED = 60; const ERASE_SPEED = 80; const STATUS_UPDATE_INTERVAL = 60000; // 1min updates const TIME_UPDATE_INTERVAL = 1; // 1ms updates (yeah its bad) // status warning stuff const LATENCY_WARNING_THRESHOLD = 500000; // lazy group name mapping const GROUP_NAMES = { 4: "INFRASTRUCTURE", 5: "SERVICES", 6: "API", }; // does the fancy typing animation for nav labels // its way overcomplicated but whatever function writeoutnavlabel(label) { if (label.getAttribute("data-animating") === "true") return; const text = label.getAttribute("data-text") || label.textContent; label.setAttribute("data-text", text); label.textContent = ""; label.style.opacity = "1"; label.setAttribute("data-animating", "true"); let i = 0; let animationInterval = setInterval(() => { if (i < text.length) { label.textContent += text.charAt(i); i++; } else { clearInterval(animationInterval); label.setAttribute("data-animating", "false"); const icon = label.closest(".nav-icon"); if (icon) { icon.isAnimating = false; icon.hoverAnimationDone = true; } } }, TYPING_SPEED); label.setAttribute("data-animation-interval", animationInterval); } // erases the nav labels // just as terrible as the typing but matches function eraselabel(label) { if (label.getAttribute("data-animating") === "true") { const existingInterval = label.getAttribute("data-animation-interval"); if (existingInterval) clearInterval(existingInterval); } label.setAttribute("data-animating", "true"); let eraseInterval = setInterval(() => { const currentText = label.textContent; if (currentText.length > 0) { label.textContent = currentText.slice(0, -1); } else { clearInterval(eraseInterval); label.setAttribute("data-animating", "false"); label.style.opacity = "0"; } }, ERASE_SPEED); label.setAttribute("data-animation-interval", eraseInterval); } // we get the client info from the headers // unclean but it works function updateClientInfo() { fetch(window.location.href) .then((response) => { const clientInfo = response.headers.get("X-Client-Info"); if (clientInfo) { document.querySelector(".location").textContent = clientInfo; } }) .catch((error) => { console.error("Error fetching X-Client-Info:", error); }); } // updates the time display // probably updates too much but eh function updateTime() { const now = new Date(); const timeString = now .toLocaleString("en-US", { month: "2-digit", day: "2-digit", year: "numeric", hour: "2-digit", minute: "2-digit", second: "2-digit", fractionalSecondDigits: 3, hour12: true, }) .toUpperCase(); document.getElementById("current-time").textContent = timeString; } // bunch of status helper functions for formatting and stuff function calculateAverageUptime(services) { if (!services || services.length === 0) return 0; const totalUptime = services.reduce( (sum, service) => sum + service.online_24_hours, 0, ); return (totalUptime / services.length).toFixed(2); } function formatLatency(latency) { return (Math.round((latency / 1000) * 10) / 10).toFixed(1); } function formatUptime(uptime) { return uptime.toFixed(2); } function getStatusClass(service) { if (!service.online) return "status-offline"; if (service.latency > LATENCY_WARNING_THRESHOLD) return "status-warning"; return "status-online"; } function getGroupName(groupId) { return GROUP_NAMES[groupId] || `GROUP ${groupId}`; } // builds all the html for status page // groups everything by group_id cause organization function createStatusHTML(services) { const groups = services.reduce((acc, service) => { const groupId = service.group_id; if (!acc[groupId]) acc[groupId] = []; acc[groupId].push(service); return acc; }, {}); return Object.entries(groups) .map( ([groupId, groupServices]) => `
${getGroupName(parseInt(groupId))}
${groupServices .map( (service) => `
${service.name.toUpperCase()} ${service.online ? "OPERATIONAL" : "OFFLINE"}
Latency: ${formatLatency(service.latency)}ms
Uptime 24h: ${formatUptime(service.online_24_hours)}%
7-day Uptime: ${formatUptime(service.online_7_days)}%
`, ) .join("")}
`, ) .join(""); } // main status updater // fetches and displays all service statuses function updateStatus() { const statusContainer = document.getElementById("status-container"); const averageUptimeElement = document.getElementById("average-uptime"); fetch("https://status.elia.network/api/services") .then((response) => response.json()) .then((data) => { statusContainer.innerHTML = createStatusHTML(data); const averageUptime = calculateAverageUptime(data); averageUptimeElement.textContent = `UPTIME ${averageUptime}%`; document.querySelectorAll(".status-item").forEach((item) => { item.addEventListener("click", function () { const details = this.querySelector(".status-details"); details.classList.toggle("expanded"); }); }); }) .catch((error) => { statusContainer.innerHTML = `
UNABLE TO FETCH STATUS DATA
${error.message}
`; averageUptimeElement.textContent = "UPTIME ERROR"; }); } // handles expanding/collapsing project items // closes others when opening new one document.querySelectorAll(".project-item").forEach((item) => { item.addEventListener("click", function () { const content = this.querySelector(".project-content"); const icon = this.querySelector(".expand-icon"); document.querySelectorAll(".project-item").forEach((otherItem) => { if (otherItem !== item) { otherItem .querySelector(".project-content") .classList.remove("expanded"); otherItem.querySelector(".expand-icon").textContent = "+"; } }); content.classList.toggle("expanded"); icon.textContent = content.classList.contains("expanded") ? "−" : "+"; }); }); // smooth scrolls to sections when clicking nav // better than jumping around document.querySelectorAll('a[href^="#"]').forEach((anchor) => { anchor.addEventListener("click", function (e) { e.preventDefault(); document.querySelector(this.getAttribute("href")).scrollIntoView({ behavior: "smooth", }); }); }); // handles active nav icon updates on scroll // shows which section youre looking at window.addEventListener("scroll", () => { let current = ""; document.querySelectorAll("section").forEach((section) => { const sectionTop = section.offsetTop; if (scrollY >= sectionTop - 60) { current = section.getAttribute("id"); } }); document.querySelectorAll(".nav-icon").forEach((icon) => { const label = icon.querySelector(".nav-label"); const isCurrentSection = icon.getAttribute("href") === `#${current}`; const wasActive = icon.classList.contains("active"); if (isCurrentSection && !wasActive) { icon.classList.add("active"); label.style.opacity = "1"; if (!icon.isAnimating && !icon.hoverAnimationDone) { writeoutnavlabel(label); icon.hoverAnimationDone = true; } } else if (!isCurrentSection && wasActive) { icon.classList.remove("active"); if (!icon.isAnimating) { eraselabel(label); icon.isAnimating = false; icon.hoverAnimationDone = false; } } }); }); // nav icon hover stuff // does the typing animation when hovering document.querySelectorAll(".nav-icon").forEach((icon) => { icon.hoverAnimationDone = false; icon.isAnimating = false; icon.addEventListener("mouseenter", () => { if (!icon.classList.contains("active") && !icon.isAnimating) { const label = icon.querySelector(".nav-label"); writeoutnavlabel(label); icon.isAnimating = true; } }); icon.addEventListener("mouseleave", () => { if (!icon.classList.contains("active")) { const label = icon.querySelector(".nav-label"); eraselabel(label); icon.isAnimating = false; icon.hoverAnimationDone = false; } }); icon.addEventListener("click", () => { const label = icon.querySelector(".nav-label"); label.style.opacity = "1"; }); }); // sets everything up when page loads // starts all the intervals and stuff document.addEventListener("DOMContentLoaded", () => { updateTime(); setInterval(updateTime, TIME_UPDATE_INTERVAL); updateStatus(); setInterval(updateStatus, STATUS_UPDATE_INTERVAL); updateClientInfo(); const activeNavIcon = document.querySelector(".nav-icon.active"); if (activeNavIcon) { const label = activeNavIcon.querySelector(".nav-label"); if (label) writeoutnavlabel(label); } // fancy console log for style points console.log( "%cELIA.NETWORK", "color: #2a5a5a; font-size: 24px; font-weight: bold; text-shadow: 2px 2px 4px rgba(42, 90, 90, 0.3);", ); });