From 08ed3dec23caf5ceb12258a06e57f867e8372e72 Mon Sep 17 00:00:00 2001 From: informaticker Date: Sun, 3 Nov 2024 23:17:56 +0100 Subject: [PATCH] Website --- assets/index.css | 576 +++++++++++++++++++++++++++++++++++++++++++++++ assets/index.js | 218 ++++++++++++++++++ index.html | 220 ++++++++++++++++++ 3 files changed, 1014 insertions(+) create mode 100644 assets/index.css create mode 100644 assets/index.js create mode 100644 index.html diff --git a/assets/index.css b/assets/index.css new file mode 100644 index 0000000..5e4720b --- /dev/null +++ b/assets/index.css @@ -0,0 +1,576 @@ +:root { + --bg-color: #0a0a0a; + --border-color: #2a5a5a; + --text-muted: #88aaaa; + --text-bright: #cef0f0; + --glow-color: rgba(42, 90, 90, 0.4); +} + +@keyframes pulse { + 0% { + box-shadow: 0 0 5px var(--glow-color); + opacity: 0.7; + } + 50% { + box-shadow: 0 0 10px var(--glow-color); + opacity: 1; + } + 100% { + box-shadow: 0 0 5px var(--glow-color); + opacity: 0.7; + } +} + +@keyframes slideInBorder { + 0% { + width: 0; + opacity: 0.2; + } + 100% { + width: 100%; + opacity: 1; + } +} + +html { + scroll-snap-type: y mandatory; + scroll-behavior: smooth; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +body { + background: var(--bg-color); + color: var(--text-bright); + font-family: "Courier New", monospace; + margin: 0; + padding: 0; + min-height: 100vh; + position: relative; + overflow-x: hidden; +} + +body::before { + content: ""; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: repeating-linear-gradient( + 0deg, + rgba(0, 0, 0, 0.1), + rgba(0, 0, 0, 0.1) 1px, + transparent 1px, + transparent 2px + ); + pointer-events: none; + z-index: 1000; +} + +.terminal { + margin-left: 80px; + padding: 20px; + max-width: 800px; + position: relative; +} + +.terminal::before { + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + border: 1px solid var(--border-color); + pointer-events: none; + opacity: 0.5; + clip-path: polygon(0 2%, 98% 0, 100% 98%, 2% 100%); +} + +.sidebar { + position: fixed; + left: 0; + top: 0; + bottom: 0; + width: 80px; + background: var(--bg-color); + border-right: 1px solid var(--border-color); + display: flex; + flex-direction: column; + align-items: center; + padding-top: 20px; + z-index: 1000; + 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; + margin: 20px 0; + text-decoration: none; + position: relative; + display: flex; + 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%; + left: 50%; + transform: translateX(-50%); + font-size: 10px; + opacity: 0; + transition: + opacity 0.3s ease, + transform 0.3s ease; + white-space: nowrap; + margin-top: 5px; + 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; + scroll-snap-align: start; + scroll-snap-stop: always; + position: relative; + overflow-y: auto; +} + +#contact { + height: auto; + min-height: 100vh; +} + +.section-title { + color: var(--text-muted); + margin-bottom: 20px; + font-size: 1.2em; + display: flex; + align-items: center; + position: relative; + padding-left: 20px; +} + +.section-title::before { + content: "◈"; + position: absolute; + left: 0; + bottom: 1px; + color: var(--text-bright); + 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; + bottom: -1px; + left: 0; + width: 100%; + height: 1px; + background: linear-gradient( + 90deg, + transparent, + var(--text-bright), + transparent + ); + animation: + 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; + border-left: 1px solid var(--border-color); + padding-left: 15px; + position: relative; +} + +.nested-entries::before { + content: ""; + position: absolute; + left: -1px; + top: 0; + bottom: 0; + width: 1px; + 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; + bottom: -2px; + left: 0; + width: 100%; + height: 2px; + background: linear-gradient( + 90deg, + transparent, + var(--text-bright), + var(--text-bright), + transparent + ); + transform: scaleX(0); + transform-origin: right; + transition: all 0.4s cubic-bezier(0.23, 1, 0.32, 1); + 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); + padding: 15px; + margin: 15px 0; + cursor: pointer; + transition: + border-color 0.3s ease, + 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, + 100% 15px, + 100% 100%, + 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); +} + +.project-item:hover, +.status-item: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; +} + +.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; + transition: + max-height 0.5s cubic-bezier(0.4, 0, 0.2, 1), + opacity 0.3s ease, + transform 0.3s ease; + margin-top: 10px; + 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); + text-decoration: none; + padding: 10px 15px; + border: 1px solid var(--border-color); + transition: + border-color 0.3s ease, + background-color 0.3s ease; + background: rgba(42, 90, 90, 0.05); + margin-top: 10px; + 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; + height: 8px; + 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; + transition: + max-height 0.5s cubic-bezier(0.4, 0, 0.2, 1), + opacity 0.3s ease, + transform 0.3s ease; + margin-top: 10px; + 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 { + display: flex; + align-items: center; + color: var(--text-bright); + text-decoration: none; + padding: 15px; + border: 1px solid var(--border-color); + transition: + border-color 0.3s ease, + background-color 0.3s ease; + background: rgba(42, 90, 90, 0.05); + clip-path: polygon( + 0 0, + 98% 0, + 100% 15px, + 100% 100%, + 2% 100%, + 0 calc(100% - 15px) + ); +} + +.contact-link:hover { + border-color: var(--text-bright); + background: rgba(42, 90, 90, 0.1); +} + +.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); + font-family: "Courier New", monospace; + margin-top: 4px; + color: var(--text-muted); +} + +.header-metrics { + display: flex; + align-items: baseline; + gap: 10px; + color: var(--text-muted); + font-size: 0.9em; + font-family: "Courier New", monospace; + line-height: 1; +} + +.separator { + color: var(--border-color); +} diff --git a/assets/index.js b/assets/index.js new file mode 100644 index 0000000..170e25f --- /dev/null +++ b/assets/index.js @@ -0,0 +1,218 @@ +// this is slop. i know. i'm sorry. +// 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; + label.textContent = ""; + label.style.opacity = "1"; + + let i = 0; + function type() { + if (i < text.length) { + label.textContent += text.charAt(i); + i++; + setTimeout(type, 100); + } + } + // why am i using a function inside a function? + // i don't know. i'm sorry. + type(); +} + +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"; +} + +function getGroupName(groupId) { + const groupNames = { + 4: "INFRASTRUCTURE", + 5: "SERVICES", + 6: "API", + }; + return groupNames[groupId] || `GROUP ${groupId}`; +} + +function createStatusHTML(services) { + // Group services by group_id + 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(""); +} + +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) => { + icon.classList.remove("active"); + if (icon.getAttribute("href") === `#${current}`) { + icon.classList.add("active"); + } + }); +}); + +// dom content event listener +document.addEventListener("DOMContentLoaded", () => { + writeoutnavlabel(); + 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 new file mode 100644 index 0000000..e863fc4 --- /dev/null +++ b/index.html @@ -0,0 +1,220 @@ + + + + elia.network + + + + + + +
+
+
+
+
+
|
+
Initializing...
+
+
ZÜRICH, SWITZERLAND
+
+
ELIA.NETWORK
+
+
+ WHAT WE DO + +
+
+ SERVICES +
+
+ MEDIA +
+
+ DOCS +
+
+ CHAT +
+
+
+ +
+ RESEARCH + +
+
+
+ +
+
PROJECTS
+ +
+
+
CAS
+ + +
+
+

+ Open-Source Language Model interface for use in web + browsers. +

+ +
+
+ +
+
+
cchat
+ + +
+
+

+ Language model interface designed for autonomous + agents that utilize the internet. +

+ +
+
+ +
+
+
discord-jellyfin-bot
+ + +
+
+

+ Discord music bot utilizing Jellyfin to play your + own music at crisp 96kbps Opus quality. +

+ +
+
+ +
+
+
netwatch
+ + +
+
+

+ Monitor internet connectivity in regions of war and + conflict. +

+ + +
+
+ +
+
SYSTEM STATUS
+
+
+
+
+ +
+
CONTACT
+ +
+
+ + + +