Website
This commit is contained in:
parent
30e512c242
commit
08ed3dec23
576
assets/index.css
Normal file
576
assets/index.css
Normal file
@ -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);
|
||||||
|
}
|
218
assets/index.js
Normal file
218
assets/index.js
Normal file
@ -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]) => `
|
||||||
|
<div class="status-group">
|
||||||
|
<div class="subsection-title">${getGroupName(parseInt(groupId))}</div>
|
||||||
|
${groupServices
|
||||||
|
.map(
|
||||||
|
(service) => `
|
||||||
|
<div class="status-item">
|
||||||
|
<div class="entry" data-service="${service.permalink}">
|
||||||
|
<span class="status-indicator ${getStatusClass(service)}"></span>
|
||||||
|
<span class="service-name">${service.name.toUpperCase()}</span>
|
||||||
|
<span class="service-status">${service.online ? "OPERATIONAL" : "OFFLINE"}</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-details">
|
||||||
|
<div class="status-metric">Latency: ${formatLatency(service.latency)}ms</div>
|
||||||
|
<div class="status-metric">Uptime 24h: ${formatUptime(service.online_24_hours)}%</div>
|
||||||
|
<div class="status-metric">7-day Uptime: ${formatUptime(service.online_7_days)}%</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
)
|
||||||
|
.join("")}
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
)
|
||||||
|
.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 = `
|
||||||
|
<div class="error-message">
|
||||||
|
UNABLE TO FETCH STATUS DATA
|
||||||
|
<div style="font-size: 0.8em; margin-top: 5px;">
|
||||||
|
${error.message}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
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); } }",
|
||||||
|
);
|
||||||
|
});
|
220
index.html
Normal file
220
index.html
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>elia.network</title>
|
||||||
|
<link rel="stylesheet" href="assets/index.css" />
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav class="sidebar">
|
||||||
|
<a href="#about" class="nav-icon">
|
||||||
|
<span class="icon">⎮</span>
|
||||||
|
<span class="nav-label">ABOUT</span>
|
||||||
|
</a>
|
||||||
|
<a href="#projects" class="nav-icon">
|
||||||
|
<span class="icon">⎔</span>
|
||||||
|
<span class="nav-label">PROJECTS</span>
|
||||||
|
</a>
|
||||||
|
<a href="#status" class="nav-icon">
|
||||||
|
<span class="icon">◈</span>
|
||||||
|
<span class="nav-label">STATUS</span>
|
||||||
|
</a>
|
||||||
|
<a href="#contact" class="nav-icon">
|
||||||
|
<span class="icon">⊡</span>
|
||||||
|
<span class="nav-label">CONTACT</span>
|
||||||
|
</a>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="terminal">
|
||||||
|
<section id="about" class="section">
|
||||||
|
<div class="header">
|
||||||
|
<div class="header-metrics">
|
||||||
|
<div class="timestamp" id="current-time"></div>
|
||||||
|
<div class="separator">|</div>
|
||||||
|
<div class="status-average" id="average-uptime">Initializing...</div>
|
||||||
|
</div>
|
||||||
|
<div class="location">ZÜRICH, SWITZERLAND</div>
|
||||||
|
</div>
|
||||||
|
<div class="section-title">ELIA.NETWORK</div>
|
||||||
|
<div class="entry-list">
|
||||||
|
<div class="entry">
|
||||||
|
WHAT WE DO
|
||||||
|
<div class="nested-entries">
|
||||||
|
<div class="entry">
|
||||||
|
<a
|
||||||
|
href="https://status.elia.network"
|
||||||
|
class="entry-link"
|
||||||
|
>NETWORK INFRASTRUCTURE</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="entry">
|
||||||
|
<a href="#" class="entry-link"
|
||||||
|
>RESEARCH (SEE BELOW)</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="entry">
|
||||||
|
SERVICES
|
||||||
|
<div class="nested-entries">
|
||||||
|
<div class="entry">
|
||||||
|
<a
|
||||||
|
href="https://media.elia.services"
|
||||||
|
class="entry-link"
|
||||||
|
>MEDIA</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="entry">
|
||||||
|
<a
|
||||||
|
href="https://docs.elia.network"
|
||||||
|
class="entry-link"
|
||||||
|
>DOCS</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="entry">
|
||||||
|
<a
|
||||||
|
href="https://chat.elia.services"
|
||||||
|
class="entry-link"
|
||||||
|
>CHAT</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="entry">
|
||||||
|
RESEARCH
|
||||||
|
<div class="nested-entries">
|
||||||
|
<div class="entry">
|
||||||
|
<a
|
||||||
|
href="https://huggingface.co/informatiker"
|
||||||
|
class="entry-link"
|
||||||
|
>NLP</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="entry">
|
||||||
|
<a
|
||||||
|
href="https://netwatch.elia.network"
|
||||||
|
class="entry-link"
|
||||||
|
>INTERNET IN TIMES OF WAR</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="projects" class="section">
|
||||||
|
<div class="section-title">PROJECTS</div>
|
||||||
|
|
||||||
|
<div class="project-item">
|
||||||
|
<div class="project-header">
|
||||||
|
<div class="entry">CAS</div>
|
||||||
|
<span class="expand-icon">+</span>
|
||||||
|
</div>
|
||||||
|
<div class="project-content">
|
||||||
|
<p>
|
||||||
|
Open-Source Language Model interface for use in web
|
||||||
|
browsers.
|
||||||
|
</p>
|
||||||
|
<div class="project-links">
|
||||||
|
<a
|
||||||
|
href="https://git.elia.network/elia/cas/"
|
||||||
|
class="project-link"
|
||||||
|
>⎔ GIT →</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="project-item">
|
||||||
|
<div class="project-header">
|
||||||
|
<div class="entry">cchat</div>
|
||||||
|
<span class="expand-icon">+</span>
|
||||||
|
</div>
|
||||||
|
<div class="project-content">
|
||||||
|
<p>
|
||||||
|
Language model interface designed for autonomous
|
||||||
|
agents that utilize the internet.
|
||||||
|
</p>
|
||||||
|
<div class="project-links">
|
||||||
|
<a
|
||||||
|
href="https://git.elia.network/informaticker/cchat"
|
||||||
|
class="project-link"
|
||||||
|
>⎔ GIT →</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="project-item">
|
||||||
|
<div class="project-header">
|
||||||
|
<div class="entry">discord-jellyfin-bot</div>
|
||||||
|
<span class="expand-icon">+</span>
|
||||||
|
</div>
|
||||||
|
<div class="project-content">
|
||||||
|
<p>
|
||||||
|
Discord music bot utilizing Jellyfin to play your
|
||||||
|
own music at crisp 96kbps Opus quality.
|
||||||
|
</p>
|
||||||
|
<div class="project-links">
|
||||||
|
<a
|
||||||
|
href="https://git.elia.network/informaticker/discord-jellyfin-bot"
|
||||||
|
class="project-link"
|
||||||
|
>⎔ GIT →</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="project-item">
|
||||||
|
<div class="project-header">
|
||||||
|
<div class="entry">netwatch</div>
|
||||||
|
<span class="expand-icon">+</span>
|
||||||
|
</div>
|
||||||
|
<div class="project-content">
|
||||||
|
<p>
|
||||||
|
Monitor internet connectivity in regions of war and
|
||||||
|
conflict.
|
||||||
|
</p>
|
||||||
|
<div class="project-links">
|
||||||
|
<a
|
||||||
|
href="https://git.elia.network/elia/netwatch"
|
||||||
|
class="project-link"
|
||||||
|
>⎔ GIT →</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="project-links">
|
||||||
|
<a
|
||||||
|
href="https://netwatch.elia.network"
|
||||||
|
class="project-link"
|
||||||
|
>⎔ NETWATCH →</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="status" class="section">
|
||||||
|
<div class="section-title">SYSTEM STATUS</div>
|
||||||
|
<div id="status-container" class="status-grid">
|
||||||
|
<div class="status-group"></div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="contact" class="section">
|
||||||
|
<div class="section-title">CONTACT</div>
|
||||||
|
<div class="contact-links">
|
||||||
|
<a href="mailto:noc@elia.network" class="contact-link">
|
||||||
|
<span class="contact-icon">✉</span>
|
||||||
|
NOC EMAIL
|
||||||
|
</a>
|
||||||
|
<a href="https://t.me/beslikmeister" class="contact-link">
|
||||||
|
<span class="contact-icon">⎆</span>
|
||||||
|
TELEGRAM
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="assets/index.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user