feat: add HUD dashboard panels - UK map, server metrics, network graph, power/containers, scan bar
This commit is contained in:
parent
ae1c7e0b71
commit
e12d33fce3
3 changed files with 891 additions and 69 deletions
547
css/style.css
547
css/style.css
|
|
@ -287,6 +287,9 @@ a:hover { color: #fff; text-shadow: 0 0 10px var(--accent-glow); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* === HERO SECTION === */
|
/* === HERO SECTION === */
|
||||||
|
/* ============================
|
||||||
|
HERO HUD GRID LAYOUT
|
||||||
|
============================ */
|
||||||
.hero {
|
.hero {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -296,48 +299,194 @@ a:hover { color: #fff; text-shadow: 0 0 10px var(--accent-glow); }
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-hud {
|
.hero-hud-grid {
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 800px;
|
max-width: 1200px;
|
||||||
padding: 4rem;
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
grid-template-rows: auto auto;
|
||||||
|
gap: 1.5rem;
|
||||||
|
animation: fadeIn 1s ease both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hud-col-left,
|
||||||
|
.hud-col-right {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================
|
||||||
|
PANELS (shared)
|
||||||
|
============================ */
|
||||||
|
.panel {
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
background: rgba(10, 14, 20, 0.5);
|
background: rgba(10, 14, 20, 0.6);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* HUD Corners */
|
.panel::before {
|
||||||
.hud-corner {
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 20px;
|
top: 0; left: 0;
|
||||||
height: 20px;
|
width: 20px; height: 20px;
|
||||||
|
border-top: 2px solid var(--accent);
|
||||||
|
border-left: 2px solid var(--accent);
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hud-tl { top: -1px; left: -1px; border-top: 2px solid var(--accent); border-left: 2px solid var(--accent); }
|
.panel::after {
|
||||||
.hud-tr { top: -1px; right: -1px; border-top: 2px solid var(--accent); border-right: 2px solid var(--accent); }
|
content: '';
|
||||||
.hud-bl { bottom: -1px; left: -1px; border-bottom: 2px solid var(--accent); border-left: 2px solid var(--accent); }
|
position: absolute;
|
||||||
.hud-br { bottom: -1px; right: -1px; border-bottom: 2px solid var(--accent); border-right: 2px solid var(--accent); }
|
bottom: 0; right: 0;
|
||||||
|
width: 20px; height: 20px;
|
||||||
|
border-bottom: 2px solid var(--accent);
|
||||||
|
border-right: 2px solid var(--accent);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
.hero-content {
|
.panel-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
background: rgba(0, 255, 200, 0.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-title {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.6rem;
|
||||||
|
letter-spacing: 3px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-icon {
|
||||||
|
color: var(--accent);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-pct {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.7rem;
|
||||||
|
color: var(--accent);
|
||||||
|
text-shadow: 0 0 10px var(--accent-glow);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-status-dot {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.55rem;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-green { color: var(--accent); }
|
||||||
|
|
||||||
|
.panel-content {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================
|
||||||
|
MAP PANEL
|
||||||
|
============================ */
|
||||||
|
.map-panel {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 320px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-content {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uk-map-svg {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 220px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pulse rings */
|
||||||
|
.pulse-ring {
|
||||||
|
animation: pulseRing 3s ease-out infinite;
|
||||||
|
transform-origin: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pulse-ring-1 { animation-delay: 0s; }
|
||||||
|
.pulse-ring-2 { animation-delay: 1s; }
|
||||||
|
.pulse-ring-3 { animation-delay: 2s; }
|
||||||
|
|
||||||
|
@keyframes pulseRing {
|
||||||
|
0% { opacity: 0.8; r: 8; }
|
||||||
|
100% { opacity: 0; r: 35; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map scan line */
|
||||||
|
.map-scan-line {
|
||||||
|
animation: mapScan 4s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes mapScan {
|
||||||
|
0% { transform: translateY(0); opacity: 0.4; }
|
||||||
|
50% { opacity: 0.8; }
|
||||||
|
100% { transform: translateY(400px); opacity: 0.2; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-data-overlay {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0.5rem;
|
||||||
|
left: 1rem;
|
||||||
|
right: 1rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-coord-block {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.coord-label {
|
||||||
|
display: block;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.5rem;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.coord-value {
|
||||||
|
display: block;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: var(--accent);
|
||||||
|
text-shadow: 0 0 8px var(--accent-glow);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================
|
||||||
|
IDENTITY BLOCK
|
||||||
|
============================ */
|
||||||
|
.hud-identity {
|
||||||
|
text-align: center;
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.hero-label {
|
.hero-label {
|
||||||
font-family: var(--font-mono);
|
font-family: var(--font-mono);
|
||||||
font-size: 0.65rem;
|
font-size: 0.65rem;
|
||||||
letter-spacing: 4px;
|
letter-spacing: 4px;
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1rem;
|
||||||
animation: fadeInDown 1s ease 0.2s both;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Glitch Effect */
|
|
||||||
.hero-title {
|
.hero-title {
|
||||||
font-family: var(--font-display);
|
font-family: var(--font-display);
|
||||||
font-size: clamp(2.5rem, 8vw, 5rem);
|
font-size: clamp(2rem, 5vw, 3.5rem);
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
letter-spacing: 8px;
|
letter-spacing: 8px;
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1rem;
|
||||||
animation: fadeInUp 1s ease 0.4s both;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.glitch {
|
.glitch {
|
||||||
|
|
@ -379,13 +528,10 @@ a:hover { color: #fff; text-shadow: 0 0 10px var(--accent-glow); }
|
||||||
97% { opacity: 0; }
|
97% { opacity: 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Typing Effect */
|
|
||||||
.hero-subtitle {
|
.hero-subtitle {
|
||||||
font-family: var(--font-mono);
|
font-family: var(--font-mono);
|
||||||
font-size: 1rem;
|
font-size: 0.9rem;
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
margin-bottom: 3rem;
|
|
||||||
animation: fadeIn 1s ease 0.8s both;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.typing-prefix { color: var(--text-secondary); }
|
.typing-prefix { color: var(--text-secondary); }
|
||||||
|
|
@ -399,33 +545,326 @@ a:hover { color: #fff; text-shadow: 0 0 10px var(--accent-glow); }
|
||||||
50% { opacity: 0; }
|
50% { opacity: 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hero Stats */
|
/* ============================
|
||||||
.hero-stats {
|
SERVER METRICS PANEL
|
||||||
|
============================ */
|
||||||
|
.hud-metrics {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
flex-direction: column;
|
||||||
gap: 3rem;
|
gap: 0.75rem;
|
||||||
animation: fadeInUp 1s ease 1s both;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-item {
|
.metric-row {
|
||||||
text-align: center;
|
display: grid;
|
||||||
|
grid-template-columns: 80px 1fr 45px;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-label {
|
.metric-label {
|
||||||
display: block;
|
font-family: var(--font-mono);
|
||||||
font-size: 0.55rem;
|
font-size: 0.55rem;
|
||||||
letter-spacing: 3px;
|
letter-spacing: 2px;
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-bar {
|
||||||
|
height: 6px;
|
||||||
|
background: rgba(0, 255, 200, 0.08);
|
||||||
|
border: 1px solid rgba(0, 255, 200, 0.15);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-fill {
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, var(--accent), rgba(0, 255, 200, 0.4));
|
||||||
|
box-shadow: 0 0 8px var(--accent-glow);
|
||||||
|
transition: width 1.5s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-fill::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
right: 0; top: 0;
|
||||||
|
width: 2px; height: 100%;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 0 6px var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-val {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.65rem;
|
||||||
|
color: var(--accent);
|
||||||
|
text-align: right;
|
||||||
|
text-shadow: 0 0 6px var(--accent-glow);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================
|
||||||
|
POWER + CONTAINERS ROW
|
||||||
|
============================ */
|
||||||
|
.hud-row-panels {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hud-row-panels::before,
|
||||||
|
.hud-row-panels::after { display: none; }
|
||||||
|
|
||||||
|
.hud-mini-panel {
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
background: rgba(10, 14, 20, 0.6);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hud-mini-panel:first-child { margin-right: -0.5px; }
|
||||||
|
.hud-mini-panel:last-child { margin-left: -0.5px; }
|
||||||
|
|
||||||
|
.hud-mini-panel::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0; left: 0;
|
||||||
|
width: 12px; height: 12px;
|
||||||
|
border-top: 2px solid var(--accent);
|
||||||
|
border-left: 2px solid var(--accent);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hud-mini-panel::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0; right: 0;
|
||||||
|
width: 12px; height: 12px;
|
||||||
|
border-bottom: 2px solid var(--accent);
|
||||||
|
border-right: 2px solid var(--accent);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.power-display {
|
||||||
|
text-align: center;
|
||||||
|
padding: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.power-big {
|
||||||
|
font-family: var(--font-display);
|
||||||
|
font-size: 2.5rem;
|
||||||
|
font-weight: 900;
|
||||||
|
color: var(--accent);
|
||||||
|
text-shadow: 0 0 20px var(--accent-glow);
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.power-unit {
|
||||||
|
font-size: 1rem;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.containers-display {
|
||||||
|
text-align: center;
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-count {
|
||||||
|
font-family: var(--font-display);
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text-primary);
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-count span {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-total {
|
||||||
|
color: var(--text-secondary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-bar {
|
||||||
|
height: 4px;
|
||||||
|
background: rgba(0, 255, 200, 0.08);
|
||||||
|
border: 1px solid rgba(0, 255, 200, 0.1);
|
||||||
margin-bottom: 0.4rem;
|
margin-bottom: 0.4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-value {
|
.container-fill {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background: var(--accent);
|
||||||
|
box-shadow: 0 0 6px var(--accent-glow);
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-label {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.5rem;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
color: var(--accent);
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================
|
||||||
|
NETWORK GRAPH PANEL
|
||||||
|
============================ */
|
||||||
|
.graph-container {
|
||||||
|
padding: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#networkGraph {
|
||||||
|
width: 100%;
|
||||||
|
height: 100px;
|
||||||
|
display: block;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graph-stats {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graph-stat {
|
||||||
|
text-align: center;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graph-stat-label {
|
||||||
|
display: block;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.5rem;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graph-stat-value {
|
||||||
|
display: block;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.7rem;
|
||||||
|
color: var(--accent);
|
||||||
|
text-shadow: 0 0 6px var(--accent-glow);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================
|
||||||
|
BOTTOM STATUS BAR
|
||||||
|
============================ */
|
||||||
|
.hud-bottom-bar {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
background: rgba(10, 14, 20, 0.6);
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hud-bottom-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hud-id {
|
||||||
|
font-family: var(--font-display);
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
letter-spacing: 1px;
|
font-weight: 700;
|
||||||
|
letter-spacing: 2px;
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-online { color: var(--accent); }
|
.hud-dot-online {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.55rem;
|
||||||
|
color: var(--accent);
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hud-bottom-stats {
|
||||||
|
display: flex;
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hud-bstat {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hud-bstat-label {
|
||||||
|
display: block;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.45rem;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-bottom: 0.15rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hud-bstat-value {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.6rem;
|
||||||
|
color: var(--text-primary);
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hud-online { color: var(--accent); }
|
||||||
|
|
||||||
|
.hud-bottom-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hud-scan-label {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.5rem;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
animation: scanPulse 2s ease infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes scanPulse {
|
||||||
|
0%, 100% { opacity: 0.5; }
|
||||||
|
50% { opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.hud-scan-bar {
|
||||||
|
width: 60px;
|
||||||
|
height: 4px;
|
||||||
|
background: rgba(0, 255, 200, 0.08);
|
||||||
|
border: 1px solid rgba(0, 255, 200, 0.15);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hud-scan-fill {
|
||||||
|
height: 100%;
|
||||||
|
width: 0%;
|
||||||
|
background: var(--accent);
|
||||||
|
box-shadow: 0 0 6px var(--accent-glow);
|
||||||
|
transition: width 0.3s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hud-scan-pct {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.55rem;
|
||||||
|
color: var(--accent);
|
||||||
|
min-width: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scan Line Animation */
|
||||||
|
.scan-line {
|
||||||
|
position: absolute;
|
||||||
|
top: 0; left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
background: linear-gradient(90deg, transparent, var(--accent), transparent);
|
||||||
|
opacity: 0.6;
|
||||||
|
animation: scan 4s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Scan Line Animation */
|
/* Scan Line Animation */
|
||||||
.scan-line {
|
.scan-line {
|
||||||
|
|
@ -1063,6 +1502,7 @@ a:hover { color: #fff; text-shadow: 0 0 10px var(--accent-glow); }
|
||||||
|
|
||||||
/* === RESPONSIVE === */
|
/* === RESPONSIVE === */
|
||||||
@media (max-width: 1024px) {
|
@media (max-width: 1024px) {
|
||||||
|
.hero-hud-grid { grid-template-columns: 1fr 1fr; gap: 1rem; max-width: 900px; }
|
||||||
.blog-grid, .dev-grid { grid-template-columns: repeat(2, 1fr); }
|
.blog-grid, .dev-grid { grid-template-columns: repeat(2, 1fr); }
|
||||||
.panels-grid { grid-template-columns: 1fr; }
|
.panels-grid { grid-template-columns: 1fr; }
|
||||||
.contact-grid { grid-template-columns: 1fr; }
|
.contact-grid { grid-template-columns: 1fr; }
|
||||||
|
|
@ -1117,8 +1557,31 @@ a:hover { color: #fff; text-shadow: 0 0 10px var(--accent-glow); }
|
||||||
|
|
||||||
.nav-item.active .dropdown { max-height: 300px; }
|
.nav-item.active .dropdown { max-height: 300px; }
|
||||||
|
|
||||||
.hero-hud { padding: 2rem; }
|
/* HUD grid stacks on mobile */
|
||||||
.hero-stats { flex-direction: column; gap: 1rem; }
|
.hero-hud-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 1rem;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hud-row-panels { grid-template-columns: 1fr 1fr; }
|
||||||
|
|
||||||
|
.hero-title { font-size: clamp(1.8rem, 6vw, 2.5rem); }
|
||||||
|
|
||||||
|
.hud-bottom-bar {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.75rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hud-bottom-stats {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hud-bottom-right { justify-content: center; }
|
||||||
|
|
||||||
.blog-grid, .dev-grid { grid-template-columns: 1fr; }
|
.blog-grid, .dev-grid { grid-template-columns: 1fr; }
|
||||||
.links-grid { grid-template-columns: 1fr; }
|
.links-grid { grid-template-columns: 1fr; }
|
||||||
.skill-bar { grid-template-columns: 1fr; gap: 0.3rem; }
|
.skill-bar { grid-template-columns: 1fr; gap: 0.3rem; }
|
||||||
|
|
@ -1129,7 +1592,11 @@ a:hover { color: #fff; text-shadow: 0 0 10px var(--accent-glow); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 480px) {
|
@media (max-width: 480px) {
|
||||||
.hero-title { letter-spacing: 4px; }
|
.hero-title { letter-spacing: 4px; font-size: 1.5rem; }
|
||||||
.section-header { flex-direction: column; align-items: flex-start; gap: 0.75rem; }
|
.section-header { flex-direction: column; align-items: flex-start; gap: 0.75rem; }
|
||||||
.section-line { display: none; }
|
.section-line { display: none; }
|
||||||
|
.hud-row-panels { grid-template-columns: 1fr; }
|
||||||
|
.hud-bottom-stats { gap: 0.5rem; }
|
||||||
|
.metric-row { grid-template-columns: 60px 1fr 35px; gap: 0.5rem; }
|
||||||
|
.graph-stats { flex-direction: column; gap: 0.5rem; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
186
index.html
186
index.html
|
|
@ -84,13 +84,68 @@
|
||||||
|
|
||||||
<!-- Hero Section -->
|
<!-- Hero Section -->
|
||||||
<section class="hero" id="home">
|
<section class="hero" id="home">
|
||||||
<div class="hero-hud">
|
<div class="hero-hud-grid">
|
||||||
<div class="hud-corner hud-tl"></div>
|
|
||||||
<div class="hud-corner hud-tr"></div>
|
|
||||||
<div class="hud-corner hud-bl"></div>
|
|
||||||
<div class="hud-corner hud-br"></div>
|
|
||||||
|
|
||||||
<div class="hero-content">
|
<!-- Left Column: Map + Identity -->
|
||||||
|
<div class="hud-col-left">
|
||||||
|
<div class="panel map-panel">
|
||||||
|
<div class="panel-header">
|
||||||
|
<span class="panel-title">OPERATOR LOCATION</span>
|
||||||
|
<span class="panel-icon">↗</span>
|
||||||
|
</div>
|
||||||
|
<div class="map-content">
|
||||||
|
<svg viewBox="0 0 250 400" class="uk-map-svg">
|
||||||
|
<defs>
|
||||||
|
<pattern id="mapGrid" width="20" height="20" patternUnits="userSpaceOnUse">
|
||||||
|
<path d="M 20 0 L 0 0 0 20" fill="none" stroke="rgba(0,255,200,0.06)" stroke-width="0.5"/>
|
||||||
|
</pattern>
|
||||||
|
<filter id="glow"><feGaussianBlur stdDeviation="3" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge></filter>
|
||||||
|
<radialGradient id="dotGlow" cx="50%" cy="50%" r="50%">
|
||||||
|
<stop offset="0%" stop-color="#00ffc8" stop-opacity="0.5"/>
|
||||||
|
<stop offset="100%" stop-color="#00ffc8" stop-opacity="0"/>
|
||||||
|
</radialGradient>
|
||||||
|
</defs>
|
||||||
|
<rect width="250" height="400" fill="url(#mapGrid)"/>
|
||||||
|
<!-- UK mainland outline -->
|
||||||
|
<polygon points="80,12 95,8 120,5 140,8 155,18 152,35 148,55 142,72 138,88 135,100 142,108 150,118 155,135 158,155 162,175 168,195 172,215 170,235 168,255 172,272 168,280 155,288 142,292 130,296 115,302 100,308 85,315 72,318 65,310 75,295 82,280 88,268 85,255 72,248 62,238 55,222 52,205 55,192 60,182 68,175 78,168 82,155 80,140 75,125 70,112 62,100 55,82 52,65 58,45 68,30" fill="rgba(0,255,200,0.03)" stroke="#00ffc8" stroke-width="1.2" stroke-opacity="0.4" stroke-linejoin="round"/>
|
||||||
|
<!-- Northern Ireland (simplified) -->
|
||||||
|
<polygon points="42,105 55,98 62,102 58,115 48,118 38,112" fill="rgba(0,255,200,0.02)" stroke="#00ffc8" stroke-width="0.8" stroke-opacity="0.3" stroke-linejoin="round"/>
|
||||||
|
<!-- Crosshair lines at Manchester -->
|
||||||
|
<line x1="0" y1="172" x2="250" y2="172" stroke="#00ffc8" stroke-width="0.3" stroke-opacity="0.25" stroke-dasharray="4,4"/>
|
||||||
|
<line x1="90" y1="0" x2="90" y2="400" stroke="#00ffc8" stroke-width="0.3" stroke-opacity="0.25" stroke-dasharray="4,4"/>
|
||||||
|
<!-- Manchester glow -->
|
||||||
|
<circle cx="90" cy="172" r="25" fill="url(#dotGlow)"/>
|
||||||
|
<!-- Manchester dot -->
|
||||||
|
<circle cx="90" cy="172" r="3" fill="#00ffc8" filter="url(#glow)"/>
|
||||||
|
<!-- Pulse rings -->
|
||||||
|
<circle cx="90" cy="172" r="8" fill="none" stroke="#00ffc8" stroke-width="0.8" class="pulse-ring pulse-ring-1"/>
|
||||||
|
<circle cx="90" cy="172" r="16" fill="none" stroke="#00ffc8" stroke-width="0.5" class="pulse-ring pulse-ring-2"/>
|
||||||
|
<circle cx="90" cy="172" r="24" fill="none" stroke="#00ffc8" stroke-width="0.3" class="pulse-ring pulse-ring-3"/>
|
||||||
|
<!-- Manchester label -->
|
||||||
|
<text x="108" y="168" fill="#00ffc8" font-size="8" font-family="'JetBrains Mono',monospace" letter-spacing="1">MANCHESTER</text>
|
||||||
|
<text x="108" y="180" fill="rgba(0,255,200,0.5)" font-size="6" font-family="'JetBrains Mono',monospace">53.48°N 2.24°W</text>
|
||||||
|
<!-- Scan sweep -->
|
||||||
|
<line x1="0" y1="0" x2="250" y2="0" stroke="#00ffc8" stroke-width="1" stroke-opacity="0.4" class="map-scan-line"/>
|
||||||
|
</svg>
|
||||||
|
<div class="map-data-overlay">
|
||||||
|
<div class="map-coord-block">
|
||||||
|
<span class="coord-label">LAT</span>
|
||||||
|
<span class="coord-value">+53.48°</span>
|
||||||
|
</div>
|
||||||
|
<div class="map-coord-block">
|
||||||
|
<span class="coord-label">LONG</span>
|
||||||
|
<span class="coord-value">-2.24°</span>
|
||||||
|
</div>
|
||||||
|
<div class="map-coord-block">
|
||||||
|
<span class="coord-label">ALT</span>
|
||||||
|
<span class="coord-value">78m (ASL)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Identity Block -->
|
||||||
|
<div class="hud-identity">
|
||||||
<div class="hero-label">SYSTEM IDENTIFICATION</div>
|
<div class="hero-label">SYSTEM IDENTIFICATION</div>
|
||||||
<h1 class="hero-title">
|
<h1 class="hero-title">
|
||||||
<span class="glitch" data-text="JAESWIFT">JAESWIFT</span>
|
<span class="glitch" data-text="JAESWIFT">JAESWIFT</span>
|
||||||
|
|
@ -100,25 +155,120 @@
|
||||||
<span class="typing-text" id="typingText"></span>
|
<span class="typing-text" id="typingText"></span>
|
||||||
<span class="typing-cursor">█</span>
|
<span class="typing-cursor">█</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="hero-stats">
|
|
||||||
<div class="stat-item">
|
|
||||||
<span class="stat-label">STATUS</span>
|
|
||||||
<span class="stat-value stat-online">● OPERATIONAL</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-item">
|
|
||||||
<span class="stat-label">UPTIME</span>
|
|
||||||
<span class="stat-value" id="uptime">0d 00h 00m</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-item">
|
|
||||||
<span class="stat-label">LOCATION</span>
|
<!-- Right Column: Data Panels -->
|
||||||
<span class="stat-value">EARTH // LEO</span>
|
<div class="hud-col-right">
|
||||||
|
<!-- Server Metrics -->
|
||||||
|
<div class="panel hud-data-panel">
|
||||||
|
<div class="panel-header">
|
||||||
|
<span class="panel-title">SERVER METRICS</span>
|
||||||
|
<span class="panel-pct" id="serverHealth">98%</span>
|
||||||
|
</div>
|
||||||
|
<div class="panel-content hud-metrics">
|
||||||
|
<div class="metric-row">
|
||||||
|
<span class="metric-label">CPU LOAD</span>
|
||||||
|
<div class="metric-bar"><div class="metric-fill" id="cpuBar"></div></div>
|
||||||
|
<span class="metric-val" id="cpuVal">23%</span>
|
||||||
|
</div>
|
||||||
|
<div class="metric-row">
|
||||||
|
<span class="metric-label">MEMORY</span>
|
||||||
|
<div class="metric-bar"><div class="metric-fill" id="memBar"></div></div>
|
||||||
|
<span class="metric-val" id="memVal">67%</span>
|
||||||
|
</div>
|
||||||
|
<div class="metric-row">
|
||||||
|
<span class="metric-label">DISK I/O</span>
|
||||||
|
<div class="metric-bar"><div class="metric-fill" id="diskBar"></div></div>
|
||||||
|
<span class="metric-val" id="diskVal">45%</span>
|
||||||
|
</div>
|
||||||
|
<div class="metric-row">
|
||||||
|
<span class="metric-label">BANDWIDTH</span>
|
||||||
|
<div class="metric-bar"><div class="metric-fill" id="bwBar"></div></div>
|
||||||
|
<span class="metric-val" id="bwVal">78%</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Scanning animation -->
|
<!-- Battery / Power -->
|
||||||
<div class="scan-line"></div>
|
<div class="panel hud-data-panel hud-row-panels">
|
||||||
|
<div class="hud-mini-panel">
|
||||||
|
<div class="panel-header">
|
||||||
|
<span class="panel-title">POWER</span>
|
||||||
|
<span class="panel-status-dot status-green">● ON MAINS</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="panel-content power-display">
|
||||||
|
<div class="power-big" id="powerPct">98<span class="power-unit">%</span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hud-mini-panel">
|
||||||
|
<div class="panel-header">
|
||||||
|
<span class="panel-title">CONTAINERS</span>
|
||||||
|
<span class="panel-icon">↗</span>
|
||||||
|
</div>
|
||||||
|
<div class="panel-content containers-display">
|
||||||
|
<div class="container-count"><span id="containerUp">8</span> / <span class="container-total">8</span></div>
|
||||||
|
<div class="container-bar"><div class="container-fill" id="containerBar"></div></div>
|
||||||
|
<span class="container-label">ALL RUNNING</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Network Graph -->
|
||||||
|
<div class="panel hud-data-panel">
|
||||||
|
<div class="panel-header">
|
||||||
|
<span class="panel-title">NETWORK TRAFFIC</span>
|
||||||
|
<span class="panel-icon">↗</span>
|
||||||
|
</div>
|
||||||
|
<div class="panel-content graph-container">
|
||||||
|
<canvas id="networkGraph"></canvas>
|
||||||
|
<div class="graph-stats">
|
||||||
|
<div class="graph-stat">
|
||||||
|
<span class="graph-stat-label">DOWNLOAD</span>
|
||||||
|
<span class="graph-stat-value" id="dlSpeed">1.6 Gbps</span>
|
||||||
|
</div>
|
||||||
|
<div class="graph-stat">
|
||||||
|
<span class="graph-stat-label">UPLOAD</span>
|
||||||
|
<span class="graph-stat-value" id="ulSpeed">1.2 Gbps</span>
|
||||||
|
</div>
|
||||||
|
<div class="graph-stat">
|
||||||
|
<span class="graph-stat-label">PACKETS</span>
|
||||||
|
<span class="graph-stat-value" id="packetCount">12 / 1.012</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Bottom Status Bar -->
|
||||||
|
<div class="hud-bottom-bar">
|
||||||
|
<div class="hud-bottom-left">
|
||||||
|
<span class="hud-id">JAE-001X</span>
|
||||||
|
<span class="hud-dot-online">● ONLINE</span>
|
||||||
|
</div>
|
||||||
|
<div class="hud-bottom-stats">
|
||||||
|
<div class="hud-bstat">
|
||||||
|
<span class="hud-bstat-label">STATUS</span>
|
||||||
|
<span class="hud-bstat-value hud-online">● OPERATIONAL</span>
|
||||||
|
</div>
|
||||||
|
<div class="hud-bstat">
|
||||||
|
<span class="hud-bstat-label">UPTIME</span>
|
||||||
|
<span class="hud-bstat-value" id="uptime">0d 00h 00m</span>
|
||||||
|
</div>
|
||||||
|
<div class="hud-bstat">
|
||||||
|
<span class="hud-bstat-label">COORDS</span>
|
||||||
|
<span class="hud-bstat-value">53.48°N // 2.24°W</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hud-bottom-right">
|
||||||
|
<span class="hud-scan-label">SCANNING...</span>
|
||||||
|
<div class="hud-scan-bar"><div class="hud-scan-fill" id="scanFill"></div></div>
|
||||||
|
<span class="hud-scan-pct" id="scanPct">0%</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="scan-line"></div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- About Section -->
|
<!-- About Section -->
|
||||||
|
|
|
||||||
205
js/main.js
205
js/main.js
|
|
@ -542,6 +542,205 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── INIT ───
|
// ─── INIT ───
|
||||||
|
|
||||||
|
// ─── NETWORK GRAPH ───
|
||||||
|
function initNetworkGraph() {
|
||||||
|
const canvas = document.getElementById('networkGraph');
|
||||||
|
if (!canvas) return;
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
function resize() {
|
||||||
|
const rect = canvas.parentElement.getBoundingClientRect();
|
||||||
|
canvas.width = rect.width;
|
||||||
|
canvas.height = 100;
|
||||||
|
}
|
||||||
|
resize();
|
||||||
|
window.addEventListener('resize', resize);
|
||||||
|
|
||||||
|
const dlData = [];
|
||||||
|
const ulData = [];
|
||||||
|
const maxPoints = 80;
|
||||||
|
|
||||||
|
// Seed initial data
|
||||||
|
for (let i = 0; i < maxPoints; i++) {
|
||||||
|
dlData.push(30 + Math.random() * 40);
|
||||||
|
ulData.push(20 + Math.random() * 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawLine(data, color, alpha) {
|
||||||
|
const w = canvas.width;
|
||||||
|
const h = canvas.height;
|
||||||
|
const step = w / (maxPoints - 1);
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.strokeStyle = color;
|
||||||
|
ctx.lineWidth = 1.5;
|
||||||
|
ctx.globalAlpha = alpha;
|
||||||
|
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
const x = i * step;
|
||||||
|
const y = h - (data[i] / 100) * h;
|
||||||
|
if (i === 0) ctx.moveTo(x, y);
|
||||||
|
else ctx.lineTo(x, y);
|
||||||
|
}
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
// Fill under the line
|
||||||
|
ctx.lineTo(canvas.width, canvas.height);
|
||||||
|
ctx.lineTo(0, canvas.height);
|
||||||
|
ctx.closePath();
|
||||||
|
ctx.fillStyle = color;
|
||||||
|
ctx.globalAlpha = alpha * 0.08;
|
||||||
|
ctx.fill();
|
||||||
|
ctx.globalAlpha = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawGrid() {
|
||||||
|
const w = canvas.width;
|
||||||
|
const h = canvas.height;
|
||||||
|
ctx.strokeStyle = 'rgba(0,255,200,0.06)';
|
||||||
|
ctx.lineWidth = 0.5;
|
||||||
|
|
||||||
|
// Horizontal
|
||||||
|
for (let y = 0; y < h; y += 20) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(0, y);
|
||||||
|
ctx.lineTo(w, y);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
// Vertical
|
||||||
|
for (let x = 0; x < w; x += 30) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(x, 0);
|
||||||
|
ctx.lineTo(x, h);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateStats() {
|
||||||
|
const dl = dlData[dlData.length - 1];
|
||||||
|
const ul = ulData[ulData.length - 1];
|
||||||
|
const dlEl = document.getElementById('dlSpeed');
|
||||||
|
const ulEl = document.getElementById('ulSpeed');
|
||||||
|
const pkEl = document.getElementById('packetCount');
|
||||||
|
if (dlEl) dlEl.textContent = (dl * 0.032).toFixed(1) + ' Gbps';
|
||||||
|
if (ulEl) ulEl.textContent = (ul * 0.028).toFixed(1) + ' Gbps';
|
||||||
|
if (pkEl) pkEl.textContent = Math.floor(dl * 180).toLocaleString() + ' pkt/s';
|
||||||
|
}
|
||||||
|
|
||||||
|
function animate() {
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
drawGrid();
|
||||||
|
|
||||||
|
// Push new data
|
||||||
|
const lastDl = dlData[dlData.length - 1];
|
||||||
|
const lastUl = ulData[ulData.length - 1];
|
||||||
|
dlData.push(Math.max(10, Math.min(95, lastDl + (Math.random() - 0.48) * 12)));
|
||||||
|
ulData.push(Math.max(5, Math.min(85, lastUl + (Math.random() - 0.48) * 10)));
|
||||||
|
if (dlData.length > maxPoints) dlData.shift();
|
||||||
|
if (ulData.length > maxPoints) ulData.shift();
|
||||||
|
|
||||||
|
drawLine(dlData, '#00ffc8', 0.9);
|
||||||
|
drawLine(ulData, '#00a8ff', 0.6);
|
||||||
|
updateStats();
|
||||||
|
|
||||||
|
requestAnimationFrame(animate);
|
||||||
|
}
|
||||||
|
animate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── METRIC BARS (fluctuating) ───
|
||||||
|
function initMetricBars() {
|
||||||
|
const metrics = [
|
||||||
|
{ bar: 'cpuBar', val: 'cpuVal', base: 23, range: 18 },
|
||||||
|
{ bar: 'memBar', val: 'memVal', base: 67, range: 8 },
|
||||||
|
{ bar: 'diskBar', val: 'diskVal', base: 45, range: 25 },
|
||||||
|
{ bar: 'bwBar', val: 'bwVal', base: 78, range: 15 },
|
||||||
|
];
|
||||||
|
|
||||||
|
function updateMetrics() {
|
||||||
|
metrics.forEach(m => {
|
||||||
|
const barEl = document.getElementById(m.bar);
|
||||||
|
const valEl = document.getElementById(m.val);
|
||||||
|
if (!barEl || !valEl) return;
|
||||||
|
|
||||||
|
const val = Math.max(5, Math.min(98, m.base + (Math.random() - 0.5) * m.range));
|
||||||
|
barEl.style.width = val + '%';
|
||||||
|
valEl.textContent = Math.round(val) + '%';
|
||||||
|
|
||||||
|
// Colour shift for high values
|
||||||
|
if (val > 85) {
|
||||||
|
barEl.style.background = 'linear-gradient(90deg, #ff4757, rgba(255,71,87,0.4))';
|
||||||
|
barEl.style.boxShadow = '0 0 8px rgba(255,71,87,0.4)';
|
||||||
|
valEl.style.color = '#ff4757';
|
||||||
|
} else if (val > 70) {
|
||||||
|
barEl.style.background = 'linear-gradient(90deg, #ffa502, rgba(255,165,2,0.4))';
|
||||||
|
barEl.style.boxShadow = '0 0 8px rgba(255,165,2,0.3)';
|
||||||
|
valEl.style.color = '#ffa502';
|
||||||
|
} else {
|
||||||
|
barEl.style.background = '';
|
||||||
|
barEl.style.boxShadow = '';
|
||||||
|
valEl.style.color = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateMetrics();
|
||||||
|
setInterval(updateMetrics, 2000 + Math.random() * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── SCAN BAR ───
|
||||||
|
function initScanBar() {
|
||||||
|
const fill = document.getElementById('scanFill');
|
||||||
|
const pct = document.getElementById('scanPct');
|
||||||
|
if (!fill || !pct) return;
|
||||||
|
|
||||||
|
let progress = 0;
|
||||||
|
function tick() {
|
||||||
|
progress += 0.5 + Math.random() * 1.5;
|
||||||
|
if (progress >= 100) {
|
||||||
|
progress = 0;
|
||||||
|
fill.style.transition = 'none';
|
||||||
|
fill.style.width = '0%';
|
||||||
|
pct.textContent = '0%';
|
||||||
|
setTimeout(() => {
|
||||||
|
fill.style.transition = 'width 0.3s linear';
|
||||||
|
requestAnimationFrame(tick);
|
||||||
|
}, 800);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fill.style.width = progress + '%';
|
||||||
|
pct.textContent = Math.round(progress) + '%';
|
||||||
|
setTimeout(tick, 80 + Math.random() * 120);
|
||||||
|
}
|
||||||
|
|
||||||
|
fill.style.transition = 'width 0.3s linear';
|
||||||
|
tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── POWER FLICKER ───
|
||||||
|
function initPowerFlicker() {
|
||||||
|
const el = document.getElementById('powerPct');
|
||||||
|
if (!el) return;
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
const vals = [97, 98, 99, 98, 100, 98, 97, 99];
|
||||||
|
const v = vals[Math.floor(Math.random() * vals.length)];
|
||||||
|
el.innerHTML = v + '<span class="power-unit">%</span>';
|
||||||
|
}, 4000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── SERVER HEALTH ───
|
||||||
|
function initServerHealth() {
|
||||||
|
const el = document.getElementById('serverHealth');
|
||||||
|
if (!el) return;
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
const v = 95 + Math.floor(Math.random() * 5);
|
||||||
|
el.textContent = v + '%';
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
initNavbar();
|
initNavbar();
|
||||||
initClock();
|
initClock();
|
||||||
|
|
@ -556,6 +755,12 @@
|
||||||
initFooterSignal();
|
initFooterSignal();
|
||||||
initHUDFlickers();
|
initHUDFlickers();
|
||||||
initPanelGlow();
|
initPanelGlow();
|
||||||
|
initNetworkGraph();
|
||||||
|
initMetricBars();
|
||||||
|
initScanBar();
|
||||||
|
initPowerFlicker();
|
||||||
|
initServerHealth();
|
||||||
|
|
||||||
|
|
||||||
// Page load animation
|
// Page load animation
|
||||||
document.body.style.opacity = '0';
|
document.body.style.opacity = '0';
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue