// this is slop. i know. i'm sorry. // atleast i'm not a reactfag. // we add some fancy text typing animation blah blah blah // it is quite overcomplicated. i have no hobbies 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; } } }, 180); label.setAttribute("data-animation-interval", animationInterval); } function eraselabel(label) { if (label.getAttribute("data-animating") === "true") { // clear the existing interval 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"; } }, 100); // store the interval so we can clear it if needed // this is a terrible way to do this like horrible label.setAttribute("data-animation-interval", eraseInterval); } 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; } updateTime(); // this is a terrible way to update the time setInterval(updateTime, 1); function calculateAverageUptime(services) { if (!services || services.length === 0) return 0; // did i ever mention that i hate math? const totalUptime = services.reduce( (sum, service) => sum + service.online_24_hours, 0, ); return (totalUptime / services.length).toFixed(2); } // projects const projectItems = document.querySelectorAll(".project-item"); projectItems.forEach((item) => { item.addEventListener("click", function () { const content = this.querySelector(".project-content"); const icon = this.querySelector(".expand-icon"); // close other expanded items projectItems.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") ? "−" : "+"; }); }); // status updater 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 > 500000) return "status-warning"; return "status-online"; } // not sure if this is the best way to do this function getGroupName(groupId) { const groupNames = { 4: "INFRASTRUCTURE", 5: "SERVICES", 6: "API", }; return groupNames[groupId] || `GROUP ${groupId}`; } // populate status page first 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(""); } // status page func 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"; }); } // initial update updateStatus(); // status details toggle document.querySelectorAll(".status-item .entry").forEach((item) => { const details = item.nextElementSibling; if (details && details.classList.contains("status-details")) { item.addEventListener("click", function () { details.classList.toggle("expanded"); }); } }); // navigation document.querySelectorAll('a[href^="#"]').forEach((anchor) => { anchor.addEventListener("click", function (e) { e.preventDefault(); document.querySelector(this.getAttribute("href")).scrollIntoView({ behavior: "smooth", }); }); }); // update active nav icon 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) { if (!wasActive) { icon.classList.add("active"); // complete instantly if (icon.isAnimating) { const text = label.getAttribute("data-text") || label.textContent; label.textContent = text; label.setAttribute("data-animating", "false"); clearInterval( parseInt(label.getAttribute("data-animation-interval")), ); } // only start if not currently animating if (!icon.hoverAnimationDone) { writeoutnavlabel(label); } icon.hoverAnimationDone = true; } } else { if (wasActive) { eraselabel(label); icon.classList.remove("active"); icon.hoverAnimationDone = false; icon.isAnimating = false; } } }); }); 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", (e) => { const label = icon.querySelector(".nav-label"); // continue if already active // prevent mouseleave from erasing label if (icon.isAnimating) { icon.hoverAnimationDone = true; } // if no animation, start one else if (!icon.hoverAnimationDone) { writeoutnavlabel(label); icon.isAnimating = true; icon.hoverAnimationDone = true; } label.style.opacity = "1"; }); }); // dom (196 reference) content event listener document.addEventListener("DOMContentLoaded", () => { // write out active nav icon label instantly const activeNavIcon = document.querySelector(".nav-icon.active"); if (activeNavIcon) { const label = activeNavIcon.querySelector(".nav-label"); if (label) writeoutnavlabel(label); } // fancy console log console.log( "%cELIA.NETWORK", "color: #2a5a5a; font-size: 24px; font-weight: bold; text-shadow: 2px 2px 4px rgba(42, 90, 90, 0.4), 4px 4px 8px rgba(42, 90, 90, 0.2), 6px 6px 12px rgba(42, 90, 90, 0.1), 0 0 20px rgba(42, 90, 90, 0.3); transform: perspective(1000px) rotateX(20deg) rotateY(-10deg) translateZ(50px); animation: console3d 8s infinite cubic-bezier(0.4, 0, 0.2, 1), glow 2s infinite alternate; @keyframes console3d { 0% { transform: perspective(1000px) rotateX(20deg) rotateY(-10deg) translateZ(50px); } 25% { transform: perspective(1000px) rotateX(-15deg) rotateY(15deg) translateZ(75px); } 50% { transform: perspective(1000px) rotateX(10deg) rotateY(20deg) translateZ(100px); } 75% { transform: perspective(1000px) rotateX(-20deg) rotateY(-15deg) translateZ(75px); } 100% { transform: perspective(1000px) rotateX(20deg) rotateY(-10deg) translateZ(50px); } } @keyframes glow { from { text-shadow: 0 0 20px rgba(42, 90, 90, 0.3), 0 0 40px rgba(42, 90, 90, 0.2); } to { text-shadow: 0 0 40px rgba(42, 90, 90, 0.5), 0 0 80px rgba(42, 90, 90, 0.3); } }", ); });