From 2746f73cff77c71208c8b533abd49ac1b243b32d Mon Sep 17 00:00:00 2001 From: elijah <146715005+schizoposter@users.noreply.github.com> Date: Mon, 4 Nov 2024 15:42:18 +0100 Subject: [PATCH] JS refactor and new contact page --- assets/index.css | 194 ++++++++++++++++++++++++++++++---------------- assets/index.js | 196 +++++++++++++++++++++++------------------------ index.html | 71 +++++++++-------- 3 files changed, 263 insertions(+), 198 deletions(-) diff --git a/assets/index.css b/assets/index.css index b14c744..cf70003 100644 --- a/assets/index.css +++ b/assets/index.css @@ -5,7 +5,6 @@ --text-bright: #cef0f0; --glow-color: rgba(42, 90, 90, 0.6); } - @keyframes pulse { 0% { box-shadow: 0 0 5px var(--glow-color); @@ -20,7 +19,6 @@ opacity: 0.5; } } - @keyframes slideInBorder { 0% { width: 0; @@ -31,7 +29,6 @@ opacity: 1; } } - html { scroll-snap-type: y mandatory; scroll-behavior: smooth; @@ -40,7 +37,6 @@ html { -ms-user-select: none; user-select: none; } - body { background: var(--bg-color); color: var(--text-bright); @@ -51,7 +47,6 @@ body { position: relative; overflow-x: hidden; } - body::before { content: ""; position: fixed; @@ -69,14 +64,12 @@ body::before { pointer-events: none; z-index: 1000; } - .terminal { margin-left: 80px; padding: 20px; max-width: 800px; position: relative; } - .terminal::before { content: ""; position: absolute; @@ -89,7 +82,6 @@ body::before { opacity: 0.5; clip-path: polygon(0 2%, 98% 0, 100% 98%, 2% 100%); } - .sidebar { position: fixed; left: 0; @@ -106,7 +98,6 @@ body::before { box-shadow: 1px 0 15px var(--glow-color); clip-path: polygon(0 0, 90% 0, 100% 2%, 100% 98%, 90% 100%, 0 100%); } - .nav-icon { color: var(--text-muted); cursor: pointer; @@ -117,12 +108,10 @@ body::before { flex-direction: column; align-items: center; } - .nav-icon .icon { font-size: 24px; transition: color 0.3s ease; } - .nav-icon .nav-label { position: absolute; top: 100%; @@ -138,35 +127,28 @@ body::before { pointer-events: none; color: var(--text-muted); } - .nav-icon.active .nav-label { opacity: 1; transform: translateX(-50%) translateY(0); color: var(--text-muted); } - .nav-icon:hover .nav-label { opacity: 1; transform: translateX(-50%) translateY(0); } - .nav-icon:hover .icon { color: var(--text-bright); } - .nav-icon.active .icon { color: var(--text-bright); } - .nav-icon.active { color: var(--text-bright); position: relative; } - .nav-icon:hover { color: var(--text-bright); } - .section { height: 100vh; padding: 20px 0; @@ -175,12 +157,10 @@ body::before { position: relative; overflow-y: auto; } - #contact { height: auto; min-height: 100vh; } - .section-title { color: var(--text-muted); margin-bottom: 20px; @@ -190,7 +170,6 @@ body::before { position: relative; padding-left: 20px; } - .section-title::before { content: "◈"; position: absolute; @@ -200,14 +179,12 @@ body::before { text-shadow: 0 0 10px var(--glow-color); background: none; } - .header { border-bottom: none; padding-bottom: 10px; margin-bottom: 20px; position: relative; } - .header::after { content: ""; position: absolute; @@ -225,24 +202,20 @@ body::before { pulse 2s infinite, slideInBorder 1s ease-out; } - .timestamp { font-size: 0.9em; color: var(--text-muted); font-family: "Courier New", monospace; line-height: 1; } - .location { margin-top: 4px; color: var(--text-muted); padding-bottom: 5px; } - .entry-list { margin-top: 10px; } - .nested-entries { margin-left: 20px; margin-top: 5px; @@ -250,7 +223,6 @@ body::before { padding-left: 15px; position: relative; } - .nested-entries::before { content: ""; position: absolute; @@ -261,31 +233,26 @@ body::before { background: var(--border-color); box-shadow: 0 0 8px var(--glow-color); } - .entry { margin: 10px 0; padding-left: 20px; position: relative; } - .entry::before { content: "▹"; position: absolute; left: 0; margin-right: 10px; } - .entry-link { color: inherit; text-decoration: none; transition: all 0.3s ease; position: relative; } - .entry-link:hover { color: var(--text-bright); } - .entry-link::after { content: ""; position: absolute; @@ -306,12 +273,10 @@ body::before { box-shadow: 0 0 8px var(--glow-color); opacity: 0.8; } - .entry-link:hover::after { transform: scaleX(1); transform-origin: left; } - .project-item, .status-item { border: 1px solid var(--border-color); @@ -349,7 +314,6 @@ body::before { border-left: 3px solid rgba(42, 90, 90, 0.6); border-top: 2px solid rgba(255, 255, 255, 0.15); } - .project-item:hover, .status-item:hover { border-color: var(--text-bright); @@ -361,35 +325,29 @@ body::before { transform: translateY(-2px) translateZ(10px); animation: pulse 2s infinite; } - .project-header { display: flex; justify-content: space-between; align-items: center; } - .project-header .entry::before { content: "◈"; color: var(--text-muted); text-shadow: 0 0 5px var(--glow-color); transition: all 0.3s ease; } - .project-item:hover .project-header .entry::before { color: var(--text-bright); text-shadow: 0 0 10px var(--glow-color); transform: rotate(45deg); } - .expand-icon { color: var(--text-muted); transition: transform 0.3s ease; } - .project-item.expanded .expand-icon { transform: rotate(45deg); } - .project-content { max-height: 0; overflow: hidden; @@ -401,13 +359,11 @@ body::before { opacity: 0; transform: translateY(-10px); } - .project-content.expanded { max-height: 500px; opacity: 1; transform: translateY(0); } - .project-link { display: inline-block; color: var(--text-bright); @@ -422,17 +378,14 @@ body::before { position: relative; overflow: hidden; } - .project-link:hover { border-color: var(--text-bright); background: rgba(42, 90, 90, 0.1); } - .status-grid { display: grid; gap: 15px; } - .status-indicator { display: inline-block; width: 8px; @@ -440,22 +393,18 @@ body::before { border-radius: 50%; margin-right: 10px; } - .status-online { background-color: #4caf50; box-shadow: 0 0 10px rgba(76, 175, 80, 0.3); } - .status-offline { background-color: #f44336; box-shadow: 0 0 10px rgba(244, 67, 54, 0.3); } - .status-warning { background-color: #ff9800; box-shadow: 0 0 10px rgba(255, 152, 0, 0.3); } - .status-details { max-height: 0; overflow: hidden; @@ -467,20 +416,17 @@ body::before { opacity: 0; transform: translateY(-10px); } - .status-details.expanded { max-height: 500px; opacity: 1; transform: translateY(0); } - .contact-links { display: flex; flex-direction: column; gap: 20px; margin-top: 20px; } - .contact-link { border: 1px solid var(--border-color); padding: 15px; @@ -517,7 +463,6 @@ body::before { 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); @@ -528,53 +473,43 @@ body::before { transform: translateY(-2px) translateZ(10px); animation: pulse 2s infinite; } - .contact-icon { margin-right: 15px; font-size: 24px; } - @media (max-width: 768px) { .terminal { margin-left: 60px; padding: 15px; } - .sidebar { width: 60px; } - .nav-icon { font-size: 20px; } - .project-item, .contact-link, .status-item { padding: 10px; } } - @media (max-width: 480px) { .terminal { margin-left: 50px; padding: 10px; } - .sidebar { width: 50px; } - .nav-icon { font-size: 18px; margin: 15px 0; } - .section-title { font-size: 1em; } } - .status-average { font-size: 0.9em; color: var(--text-muted); @@ -582,7 +517,6 @@ body::before { margin-top: 4px; color: var(--text-muted); } - .header-metrics { display: flex; align-items: baseline; @@ -592,7 +526,133 @@ body::before { font-family: "Courier New", monospace; line-height: 1; } - .separator { color: var(--border-color); } +.contact-grid { + display: grid; + gap: 20px; + margin-top: 20px; +} +.contact-card { + background: linear-gradient( + 135deg, + rgba(42, 90, 90, 0.05) 0%, + rgba(42, 90, 90, 0.1) 100% + ); + border: 1px solid var(--border-color); + clip-path: polygon( + 0 0, + 95% 0, + 100% 20px, + 100% 100%, + 5% 100%, + 0 calc(100% - 20px) + ); +} +.contact-header { + padding: 15px; + border-bottom: 1px solid var(--border-color); + display: flex; + justify-content: space-between; + align-items: center; +} +.contact-type { + color: var(--text-bright); + font-size: 0.9em; +} +.connection-status { + display: flex; + align-items: center; + font-size: 0.8em; + color: var(--text-muted); +} +.status-dot { + width: 6px; + height: 6px; + background: var(--text-bright); + border-radius: 50%; + margin-right: 8px; + box-shadow: 0 0 8px var(--glow-color); + animation: pulse 2s infinite; +} +.contact-content { + padding: 15px; +} +.contact-method { + display: flex; + align-items: center; + padding: 12px; + margin: 8px 0; + text-decoration: none; + color: var(--text-muted); + border: 1px solid transparent; + background: rgba(42, 90, 90, 0.1); + transition: all 0.3s ease; + position: relative; + overflow: hidden; +} +.contact-method:hover { + color: var(--text-bright); + border-color: var(--border-color); + background: rgba(42, 90, 90, 0.2); + transform: translateX(5px); +} +.contact-method::before { + content: ""; + position: absolute; + left: 0; + top: 0; + width: 2px; + height: 100%; + background: var(--text-bright); + box-shadow: 0 0 10px var(--glow-color); + opacity: 0; + transition: opacity 0.3s ease; +} +.contact-method:hover::before { + opacity: 1; +} +.method-icon { + font-size: 1.2em; + margin-right: 15px; + color: var(--text-bright); +} +.method-details { + flex: 1; + display: flex; + flex-direction: column; +} +.method-name { + font-size: 0.9em; + margin-bottom: 4px; +} +.method-address { + font-size: 0.8em; + color: var(--text-muted); +} +.connection-indicator { + margin-left: 10px; + transition: transform 0.3s ease; +} +.contact-method:hover .connection-indicator { + transform: translateX(5px); +} +@media (max-width: 768px) { + .contact-grid { + gap: 15px; + } + .contact-method { + padding: 10px; + } +} +@media (max-width: 480px) { + .contact-header { + flex-direction: column; + align-items: flex-start; + gap: 8px; + } + .method-details { + font-size: 0.9em; + } +} diff --git a/assets/index.js b/assets/index.js index 86bece0..288ba58 100644 --- a/assets/index.js +++ b/assets/index.js @@ -1,8 +1,21 @@ -// this is slop. i know. i'm sorry. -// atleast i'm not a reactfag. +// animation speeds (ms) +const TYPING_SPEED = 180; +const ERASE_SPEED = 100; +const STATUS_UPDATE_INTERVAL = 60000; // 1min +const TIME_UPDATE_INTERVAL = 1; // 1ms (still terrible) -// we add some fancy text typing animation blah blah blah -// it is quite overcomplicated. i have no hobbies +// status thresholds +const LATENCY_WARNING_THRESHOLD = 500000; + +// mapping for group names because i'm lazy +const GROUP_NAMES = { + 4: "INFRASTRUCTURE", + 5: "SERVICES", + 6: "API", +}; + +// fancy text typing animation for nav labels +// overcomplicated as fuck but whatever function writeoutnavlabel(label) { if (label.getAttribute("data-animating") === "true") return; @@ -26,18 +39,17 @@ function writeoutnavlabel(label) { icon.hoverAnimationDone = true; } } - }, 180); + }, TYPING_SPEED); label.setAttribute("data-animation-interval", animationInterval); } +// erase animation for nav labels +// also terrible but consistent with the above function eraselabel(label) { if (label.getAttribute("data-animating") === "true") { - // clear the existing interval const existingInterval = label.getAttribute("data-animation-interval"); - if (existingInterval) { - clearInterval(existingInterval); - } + if (existingInterval) clearInterval(existingInterval); } label.setAttribute("data-animating", "true"); @@ -51,13 +63,13 @@ function eraselabel(label) { label.setAttribute("data-animating", "false"); label.style.opacity = "0"; } - }, 100); + }, ERASE_SPEED); - // 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); } +// time display updater +// still updates way too frequently but whatever function updateTime() { const now = new Date(); const timeString = now @@ -75,13 +87,9 @@ function updateTime() { document.getElementById("current-time").textContent = timeString; } -updateTime(); -// this is a terrible way to update the time -setInterval(updateTime, 1); - +// status helper functions 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, @@ -89,28 +97,6 @@ function calculateAverageUptime(services) { 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); } @@ -121,20 +107,16 @@ function formatUptime(uptime) { function getStatusClass(service) { if (!service.online) return "status-offline"; - if (service.latency > 500000) return "status-warning"; + if (service.latency > LATENCY_WARNING_THRESHOLD) 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}`; + return GROUP_NAMES[groupId] || `GROUP ${groupId}`; } -// populate status page first +// creates the HTML for the status page +// groups services by their group_id function createStatusHTML(services) { const groups = services.reduce((acc, service) => { const groupId = service.group_id; @@ -146,33 +128,33 @@ function createStatusHTML(services) { return Object.entries(groups) .map( ([groupId, groupServices]) => ` -