From d6960d09809e2da816cf68bcc9bfb2d24f24bfad Mon Sep 17 00:00:00 2001 From: elijah <146715005+schizoposter@users.noreply.github.com> Date: Mon, 4 Nov 2024 12:11:42 +0100 Subject: [PATCH] Added animations --- assets/index.css | 42 ++++++++++---- assets/index.js | 141 +++++++++++++++++++++++++++++++++++++++++------ index.html | 44 ++++++++++++--- 3 files changed, 193 insertions(+), 34 deletions(-) diff --git a/assets/index.css b/assets/index.css index 5e4720b..b14c744 100644 --- a/assets/index.css +++ b/assets/index.css @@ -3,13 +3,13 @@ --border-color: #2a5a5a; --text-muted: #88aaaa; --text-bright: #cef0f0; - --glow-color: rgba(42, 90, 90, 0.4); + --glow-color: rgba(42, 90, 90, 0.6); } @keyframes pulse { 0% { box-shadow: 0 0 5px var(--glow-color); - opacity: 0.7; + opacity: 0.5; } 50% { box-shadow: 0 0 10px var(--glow-color); @@ -17,7 +17,7 @@ } 100% { box-shadow: 0 0 5px var(--glow-color); - opacity: 0.7; + opacity: 0.5; } } @@ -482,16 +482,21 @@ body::before { } .contact-link { - display: flex; - align-items: center; - color: var(--text-bright); - text-decoration: none; - padding: 15px; border: 1px solid var(--border-color); + padding: 15px; + margin: 15px 0; + cursor: pointer; transition: border-color 0.3s ease, - background-color 0.3s ease; - background: rgba(42, 90, 90, 0.05); + background-color 0.3s ease, + box-shadow 0.3s ease, + transform 0.3s ease; + position: relative; + background: linear-gradient( + 135deg, + rgba(42, 90, 90, 0.1), + rgba(42, 90, 90, 0.2) + ); clip-path: polygon( 0 0, 98% 0, @@ -500,11 +505,28 @@ body::before { 2% 100%, 0 calc(100% - 15px) ); + transform: translateZ(20px); + box-shadow: + 0 5px 15px rgba(0, 0, 0, 0.4), + 0 10px 20px rgba(42, 90, 90, 0.3), + inset 0 1px rgba(255, 255, 255, 0.2), + inset -2px -2px 4px rgba(0, 0, 0, 0.5); + transform-style: preserve-3d; + perspective: 1000px; + backdrop-filter: blur(5px); + border-left: 3px solid rgba(42, 90, 90, 0.6); + border-top: 2px solid rgba(255, 255, 255, 0.15); } .contact-link:hover { border-color: var(--text-bright); background: rgba(42, 90, 90, 0.1); + box-shadow: + 0 5px 15px rgba(0, 0, 0, 0.3), + 0 10px 20px rgba(42, 90, 90, 0.2), + inset 0 1px rgba(255, 255, 255, 0.2); + transform: translateY(-2px) translateZ(10px); + animation: pulse 2s infinite; } .contact-icon { diff --git a/assets/index.js b/assets/index.js index 03a987e..86bece0 100644 --- a/assets/index.js +++ b/assets/index.js @@ -2,24 +2,60 @@ // atleast i'm not a reactfag. // we add some fancy text typing animation blah blah blah -function writeoutnavlabel() { - const firstNavIcon = document.querySelector('.nav-icon[href="#about"]'); - const label = firstNavIcon.querySelector(".nav-label"); - const text = label.textContent; +// 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; - function type() { + let animationInterval = setInterval(() => { if (i < text.length) { label.textContent += text.charAt(i); i++; - setTimeout(type, 180); + } 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); } } - // why am i using a function inside a function? - // i don't know. i'm sorry. - type(); + + 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() { @@ -88,7 +124,7 @@ function getStatusClass(service) { 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", @@ -98,8 +134,8 @@ function getGroupName(groupId) { return groupNames[groupId] || `GROUP ${groupId}`; } +// populate status page first function createStatusHTML(services) { - // Group services by group_id const groups = services.reduce((acc, service) => { const groupId = service.group_id; if (!acc[groupId]) acc[groupId] = []; @@ -136,6 +172,7 @@ function createStatusHTML(services) { .join(""); } +// status page func function updateStatus() { const statusContainer = document.getElementById("status-container"); const averageUptimeElement = document.getElementById("average-uptime"); @@ -201,16 +238,88 @@ window.addEventListener("scroll", () => { }); document.querySelectorAll(".nav-icon").forEach((icon) => { - icon.classList.remove("active"); - if (icon.getAttribute("href") === `#${current}`) { - icon.classList.add("active"); + 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; + } } }); }); -// dom content event listener +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", () => { - writeoutnavlabel(); + // 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); } }", diff --git a/index.html b/index.html index 83c34a1..da530d7 100644 --- a/index.html +++ b/index.html @@ -203,14 +203,42 @@
CONTACT