mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-06-04 04:22:57 +00:00
small fix, don't worry about it
This commit is contained in:
@@ -0,0 +1,612 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0"/>
|
||||
<title>[NuFest] – App Project · Clounest (1:1 Match)</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.min.js"></script>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet"/>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: { sans: ['Inter','system-ui','sans-serif'] },
|
||||
colors: {
|
||||
base:'#16171c', sidebar:'#111217', card:'#1c1d24',
|
||||
pink:'#e8316a', green:'#3dd68c', orange:'#ff7043',
|
||||
purple:'#9c7ef0', muted:'#6b6e7d', dim:'#9295a4', primary:'#e8e9f0',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
*,*::before,*::after{box-sizing:border-box}
|
||||
html,body{height:100%;margin:0;background:#16171c;color:#e8e9f0;font-family:'Inter',sans-serif;overflow:hidden}
|
||||
::-webkit-scrollbar{width:4px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:rgba(255,255,255,.1);border-radius:99px}
|
||||
|
||||
/* Animations */
|
||||
@keyframes fadeUp{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}
|
||||
@keyframes pulse-dot{0%{box-shadow:0 0 0 0 rgba(61, 214, 140, 0.7)}70%{box-shadow:0 0 0 6px rgba(61, 214, 140, 0)}100%{box-shadow:0 0 0 0 rgba(61, 214, 140, 0)}}
|
||||
@keyframes slideInRight{from{opacity:0;transform:translateX(20px)}to{opacity:1;transform:translateX(0)}}
|
||||
@keyframes slideOutRight{from{opacity:1;transform:translateX(0)}to{opacity:0;transform:translateX(20px)}}
|
||||
|
||||
/* Components */
|
||||
.nav-item{width:40px;height:40px;border-radius:10px;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#6b6e7d;transition:background .15s,color .15s}
|
||||
.nav-item:hover{background:rgba(255,255,255,.06);color:#9295a4}
|
||||
.nav-item.active{background:rgba(255,255,255,.09);color:#e8e9f0}
|
||||
.nav-item svg{width:18px;height:18px;stroke:currentColor;fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
|
||||
|
||||
.tab{display:flex;align-items:center;gap:6px;padding:10px 14px;font-size:13.5px;font-weight:500;color:#6b6e7d;cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1px;transition:all .15s;white-space:nowrap;user-select:none}
|
||||
.tab:hover{color:#9295a4}
|
||||
.tab.active{color:#e8e9f0;border-bottom-color:#e8316a}
|
||||
.tab svg{width:14px;height:14px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round}
|
||||
|
||||
.card{background:#1c1d24;border:1px solid rgba(255,255,255,.08);border-radius:20px;padding:20px;display:flex;flex-direction:column;transition:border-color .2s;animation:fadeUp .4s ease both}
|
||||
.card:hover{border-color:rgba(255,255,255,.14)}
|
||||
.card:nth-child(1){animation-delay:.04s}.card:nth-child(2){animation-delay:.09s}.card:nth-child(3){animation-delay:.14s}.card:nth-child(4){animation-delay:.19s}.card:nth-child(5){animation-delay:.24s}
|
||||
|
||||
.card-icon{width:34px;height:34px;border-radius:10px;background:rgba(255,255,255,.07);display:flex;align-items:center;justify-content:center;flex-shrink:0}
|
||||
.card-icon svg{width:16px;height:16px;stroke:#9295a4;fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
|
||||
|
||||
.arrow-btn{width:30px;height:30px;border-radius:9px;background:#e8316a;display:flex;align-items:center;justify-content:center;cursor:pointer;flex-shrink:0;transition:box-shadow .15s,transform .15s}
|
||||
.arrow-btn:hover{transform:scale(1.07)}
|
||||
.arrow-btn svg{width:13px;height:13px;stroke:white;fill:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round}
|
||||
|
||||
.search-box{display:flex;align-items:center;gap:8px;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.08);border-radius:10px;padding:0 12px;height:34px;width:220px}
|
||||
.search-box svg{width:14px;height:14px;stroke:#6b6e7d;fill:none;stroke-width:2;stroke-linecap:round;flex-shrink:0}
|
||||
.search-box input{background:none;border:none;outline:none;color:#9295a4;font-size:13px;width:100%;font-family:inherit}
|
||||
.search-box input::placeholder{color:#6b6e7d}
|
||||
|
||||
.pill-group{display:flex;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.08);border-radius:10px;overflow:hidden}
|
||||
.pill{padding:5px 14px;font-size:12.5px;font-weight:500;color:#6b6e7d;cursor:pointer;transition:all .15s;user-select:none}
|
||||
.pill.active{background:rgba(255,255,255,.1);color:#e8e9f0}
|
||||
.pill:hover:not(.active){color:#9295a4}
|
||||
|
||||
.btn-stop{height:38px;padding:0 20px;border-radius:11px;border:1px solid rgba(255,255,255,.15);background:rgba(255,255,255,.06);color:#e8e9f0;font-size:13.5px;font-weight:700;font-family:inherit;cursor:pointer;display:flex;align-items:center;gap:8px;transition:background .15s}
|
||||
.btn-stop:hover{background:rgba(255,255,255,.1)}
|
||||
.btn-stop.disabled{opacity:0.5;cursor:not-allowed;}
|
||||
|
||||
.btn-restart{height:38px;padding:0 20px;border-radius:11px;border:none;background:#e8316a;color:white;font-size:13.5px;font-weight:700;font-family:inherit;cursor:pointer;display:flex;align-items:center;gap:8px;transition:all .15s}
|
||||
.btn-restart:hover{background:#d12960}
|
||||
.btn-restart.disabled{background:#444;cursor:not-allowed;}
|
||||
|
||||
.btn-restart svg,.btn-stop svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:2.2;stroke-linecap:round}
|
||||
|
||||
.chart-wrap{position:relative;width:100%}
|
||||
.chart-wrap canvas{width:100%!important;height:100%!important}
|
||||
|
||||
.flag{width:26px;height:26px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:15px;background:rgba(255,255,255,.05)}
|
||||
.stat-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}
|
||||
.badge-active{padding:2px 8px;border-radius:6px;background:rgba(61, 214, 140, 0.15);font-size:10px;font-weight:700;letter-spacing:.7px;color:#3dd68c;text-transform:uppercase;transition: all 0.3s;}
|
||||
.badge-stopped{padding:2px 8px;border-radius:6px;background:rgba(255, 255, 255, 0.08);font-size:10px;font-weight:700;letter-spacing:.7px;color:#6b6e7d;text-transform:uppercase;}
|
||||
|
||||
.cache-seg{height:32px;transition:opacity .2s,filter .2s;cursor:pointer}
|
||||
.cache-seg:hover{filter:brightness(1.15)}
|
||||
.speed-row{display:flex;align-items:center;gap:5px;font-size:12.5px;font-weight:600}
|
||||
.speed-row svg{width:12px;height:12px;stroke:currentColor;fill:none;stroke-width:2.5;stroke-linecap:round}
|
||||
|
||||
/* Live Indicator */
|
||||
.live-dot{width:8px;height:8px;background:#3dd68c;border-radius:50%;display:inline-block;margin-right:6px;animation:pulse-dot 2s infinite}
|
||||
.live-dot.stopped{background:#6b6e7d;animation:none}
|
||||
|
||||
/* Toast Notifications */
|
||||
.toast-container{position:fixed;bottom:24px;right:24px;z-index:9999;display:flex;flex-direction:column;gap:10px;pointer-events:none}
|
||||
.toast{pointer-events:auto;background:#1c1d24;border:1px solid rgba(255,255,255,.1);color:#e8e9f0;padding:12px 16px;border-radius:12px;box-shadow:0 8px 30px rgba(0,0,0,.4);font-size:13px;font-weight:500;display:flex;align-items:center;gap:10px;animation:slideInRight .3s ease forwards}
|
||||
.toast.hiding{animation:slideOutRight .3s ease forwards}
|
||||
.toast svg{width:18px;height:18px;flex-shrink:0}
|
||||
.toast.success svg{stroke:#3dd68c}
|
||||
.toast.info svg{stroke:#6c8ef0}
|
||||
.toast.warning svg{stroke:#ff7043}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div style="display:flex;height:100vh;overflow:hidden">
|
||||
|
||||
<!-- ════ SIDEBAR ════ -->
|
||||
<aside style="width:64px;background:#111217;border-right:1px solid rgba(255,255,255,.07);display:flex;flex-direction:column;align-items:center;padding:16px 0;gap:5px;flex-shrink:0">
|
||||
<div style="width:38px;height:38px;border-radius:50%;background:#e8316a;display:flex;align-items:center;justify-content:center;margin-bottom:14px">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="white"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 14H9V8h2v8zm4 0h-2V8h2v8z"/></svg>
|
||||
</div>
|
||||
<div class="nav-item active"><svg viewBox="0 0 24 24"><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/></svg></div>
|
||||
<div class="nav-item"><svg viewBox="0 0 24 24"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/></svg></div>
|
||||
<div class="nav-item"><svg viewBox="0 0 24 24"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5v6c0 1.66 4.03 3 9 3s9-1.34 9-3V5"/><path d="M3 11v6c0 1.66 4.03 3 9 3s9-1.34 9-3v-6"/></svg></div>
|
||||
<div class="nav-item"><svg viewBox="0 0 24 24"><circle cx="18" cy="8" r="3"/><circle cx="6" cy="15" r="3"/><path d="M18 11a9 9 0 0 1-9 9M6 12a9 9 0 0 1 9-9"/></svg></div>
|
||||
<div class="nav-item"><svg viewBox="0 0 24 24"><path d="M22 12h-4l-3 9L9 3l-3 9H2"/></svg></div>
|
||||
<div style="flex:1"></div>
|
||||
<div class="nav-item"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M19.07 4.93a10 10 0 0 1 0 14.14M4.93 4.93a10 10 0 0 0 0 14.14"/></svg></div>
|
||||
<div class="nav-item"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg></div>
|
||||
<div style="width:34px;height:34px;border-radius:50%;background:#22233a;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;color:#9295a4;cursor:pointer;margin-top:4px;letter-spacing:-.3px">w.</div>
|
||||
</aside>
|
||||
|
||||
<!-- ════ MAIN ════ -->
|
||||
<div style="flex:1;display:flex;flex-direction:column;overflow:hidden;min-width:0">
|
||||
|
||||
<!-- ── TOPBAR ── -->
|
||||
<header style="height:52px;background:#111217;border-bottom:1px solid rgba(255,255,255,.07);display:flex;align-items:center;padding:0 22px;gap:14px;flex-shrink:0">
|
||||
<div class="search-box">
|
||||
<svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||
<input type="text" placeholder="Search logs..."/>
|
||||
</div>
|
||||
<div style="margin-left:auto;display:flex;align-items:center;gap:8px">
|
||||
<button style="height:32px;padding:0 14px;border-radius:9px;border:1px solid rgba(255,255,255,.1);background:transparent;color:#9295a4;font-size:13px;font-weight:500;cursor:pointer;font-family:inherit">Support</button>
|
||||
<button style="height:32px;padding:0 14px;border-radius:9px;border:none;background:rgba(255,255,255,.08);color:#e8e9f0;font-size:13px;font-weight:500;cursor:pointer;font-family:inherit;display:flex;align-items:center;gap:6px">
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><polyline points="17 11 12 6 7 11"/><polyline points="17 18 12 13 7 18"/></svg>
|
||||
Upgrade
|
||||
</button>
|
||||
<button style="width:32px;height:32px;border-radius:9px;border:1px solid rgba(255,255,255,.1);background:transparent;display:flex;align-items:center;justify-content:center;cursor:pointer">
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="#9295a4" stroke-width="2" stroke-linecap="round"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- ── SCROLL CONTENT ── -->
|
||||
<div style="flex:1;overflow-y:auto;padding:0 24px 28px">
|
||||
|
||||
<!-- breadcrumb -->
|
||||
<div style="display:flex;align-items:center;gap:6px;padding:14px 0 10px;color:#6b6e7d;font-size:13px">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#6b6e7d" stroke-width="2" stroke-linecap:round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
|
||||
<a href="#" style="color:#6b6e7d;text-decoration:none">Servers</a>
|
||||
<span style="opacity:.4">/</span>
|
||||
<span style="color:#9295a4">[NuFest] - App Project</span>
|
||||
</div>
|
||||
|
||||
<!-- project header -->
|
||||
<div style="display:flex;align-items:center;padding-bottom:18px">
|
||||
<div style="width:46px;height:46px;border-radius:13px;background:#e8316a;display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-right:14px">
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="white"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 14H9V8h2v8zm4 0h-2V8h2v8z"/></svg>
|
||||
</div>
|
||||
<div>
|
||||
<div style="display:flex;align-items:center;gap:10px">
|
||||
<span style="font-size:20px;font-weight:800;letter-spacing:-.5px">[NuFest] - App Project</span>
|
||||
<span class="badge-active" id="statusBadge"><span class="live-dot" id="liveDot"></span>Active</span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:16px;margin-top:4px">
|
||||
<a href="#" style="display:flex;align-items:center;gap:4px;color:#6b6e7d;font-size:12.5px;text-decoration:none">https://nufest-dth.app <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg></a>
|
||||
<a href="#" style="display:flex;align-items:center;gap:4px;color:#6b6e7d;font-size:12.5px;text-decoration:none">Project Information <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><polyline points="9 18 15 12 9 6"/></svg></a>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-left:auto;display:flex;gap:10px">
|
||||
<button class="btn-stop" id="btnStop">
|
||||
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="3" fill="currentColor" stroke="none"/></svg>
|
||||
STOP
|
||||
</button>
|
||||
<button class="btn-restart disabled" id="btnRestart" disabled>
|
||||
<svg viewBox="0 0 24 24"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-4.5"/></svg>
|
||||
RESTART
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- tabs -->
|
||||
<div style="display:flex;border-bottom:1px solid rgba(255,255,255,.07);margin-bottom:18px">
|
||||
<div class="tab active" onclick="setTab(this)"><svg viewBox="0 0 24 24"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>Metrics</div>
|
||||
<div class="tab" onclick="setTab(this)"><svg viewBox="0 0 24 24"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>Requests</div>
|
||||
<div class="tab" onclick="setTab(this)"><svg viewBox="0 0 24 24"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>APIs</div>
|
||||
<div class="tab" onclick="setTab(this)"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M19.07 4.93a10 10 0 0 1 0 14.14M4.93 4.93a10 10 0 0 0 0 14.14"/></svg>Config</div>
|
||||
</div>
|
||||
|
||||
<!-- metrics header -->
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px">
|
||||
<span style="font-size:15px;font-weight:700">Metrics</span>
|
||||
<div style="display:flex;align-items:center;gap:8px">
|
||||
<button style="height:32px;padding:0 12px;border-radius:9px;border:1px solid rgba(255,255,255,.09);background:rgba(255,255,255,.04);color:#9295a4;font-size:12.5px;font-weight:500;font-family:inherit;cursor:pointer;display:flex;align-items:center;gap:6px">
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/></svg>
|
||||
Filter
|
||||
</button>
|
||||
<div class="pill-group" id="timePills">
|
||||
<div class="pill active" onclick="setPill(this)">Day</div>
|
||||
<div class="pill" onclick="setPill(this)">Month</div>
|
||||
<div class="pill" onclick="setPill(this)">Year</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ████ ROW 1 ████ -->
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr 1.95fr;gap:13px;margin-bottom:13px">
|
||||
|
||||
<!-- CPU -->
|
||||
<div class="card">
|
||||
<div style="display:flex;align-items:center;gap:10px;margin-bottom:12px">
|
||||
<div class="card-icon"><svg viewBox="0 0 24 24"><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="9" y="9" width="6" height="6"/><line x1="9" y1="1" x2="9" y2="4"/><line x1="15" y1="1" x2="15" y2="4"/><line x1="9" y1="20" x2="9" y2="23"/><line x1="15" y1="20" x2="15" y2="23"/><line x1="20" y1="9" x2="23" y2="9"/><line x1="20" y1="14" x2="23" y2="14"/><line x1="1" y1="9" x2="4" y2="9"/><line x1="1" y1="14" x2="4" y2="14"/></svg></div>
|
||||
<span style="font-size:14px;font-weight:600">CPU Usage</span>
|
||||
</div>
|
||||
<div style="font-size:38px;font-weight:900;letter-spacing:-1.5px;line-height:1" id="cpuText">12%</div>
|
||||
<div style="font-size:12px;color:#6b6e7d;margin-top:4px"><span style="color:#3dd68c;font-weight:700" id="cpuStatus">Good</span> Daily usage</div>
|
||||
<div class="chart-wrap" style="height:76px;margin:12px 0 6px"><canvas id="cpuChart"></canvas></div>
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding-top:4px">
|
||||
<span style="font-size:13px;color:#6b6e7d;font-weight:500;cursor:pointer">Details</span>
|
||||
<div class="arrow-btn"><svg viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- RAM -->
|
||||
<div class="card">
|
||||
<div style="display:flex;align-items:center;gap:10px;margin-bottom:12px">
|
||||
<div class="card-icon"><svg viewBox="0 0 24 24"><rect x="2" y="8" width="20" height="8" rx="2"/><path d="M6 8V6M10 8V6M14 8V6M18 8V6M6 16v2M18 16v2"/></svg></div>
|
||||
<span style="font-size:14px;font-weight:600">RAM Usage</span>
|
||||
</div>
|
||||
<div style="font-size:38px;font-weight:900;letter-spacing:-1.5px;line-height:1" id="ramText">65%</div>
|
||||
<div style="font-size:12px;color:#6b6e7d;margin-top:4px"><span style="color:#f0a040;font-weight:700">Average</span> Daily usage</div>
|
||||
<div style="display:flex;justify-content:center;align-items:center;margin:10px 0 4px;position:relative">
|
||||
<canvas id="ramCanvas" width="160" height="94"></canvas>
|
||||
<div style="position:absolute;bottom:14px;text-align:center">
|
||||
<div style="font-size:10.5px;color:#6b6e7d;margin-bottom:1px">Used</div>
|
||||
<div style="font-size:12.5px;font-weight:700" id="ramDetail">5.4 GB / 8GB</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding-top:4px">
|
||||
<span style="font-size:13px;color:#6b6e7d;font-weight:500;cursor:pointer">Details</span>
|
||||
<div class="arrow-btn"><svg viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CACHE -->
|
||||
<div class="card">
|
||||
<div style="display:flex;align-items:center;gap:10px;margin-bottom:12px">
|
||||
<div class="card-icon"><svg viewBox="0 0 24 24"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg></div>
|
||||
<span style="font-size:14px;font-weight:600">Cache</span>
|
||||
</div>
|
||||
<div style="font-size:38px;font-weight:900;letter-spacing:-1.5px;line-height:1">352 MB</div>
|
||||
<div style="font-size:12px;color:#6b6e7d;margin-top:4px"><span style="color:#f0a040;font-weight:700">220MB Average</span> cached images and files</div>
|
||||
|
||||
<!-- SEGMENTED BAR -->
|
||||
<div style="display:flex;align-items:center;gap:5px;margin:16px 0 15px;height:32px">
|
||||
<div class="cache-seg" style="width:43%;background:#ff6b5b;border-radius:10px 4px 4px 10px"></div>
|
||||
<div class="cache-seg" style="width:13%;background:#8c6ef0;border-radius:5px"></div>
|
||||
<div class="cache-seg" style="flex:1;background:rgba(255,255,255,.07);border-radius:4px 10px 10px 4px"></div>
|
||||
</div>
|
||||
|
||||
<!-- stats row -->
|
||||
<div style="display:grid;grid-template-columns:1fr auto 1fr auto 1fr;gap:0;align-items:stretch">
|
||||
<div>
|
||||
<div style="display:flex;align-items:center;gap:5px;font-size:11px;color:#6b6e7d;margin-bottom:5px">
|
||||
<div class="stat-dot" style="background:#ff6b5b"></div> Cache
|
||||
</div>
|
||||
<div style="display:flex;align-items:baseline;gap:4px">
|
||||
<span style="font-size:15px;font-weight:800">212 MB</span>
|
||||
<span style="font-size:11px;color:#6b6e7d">12%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="width:1px;background:rgba(255,255,255,.08);margin:0 16px"></div>
|
||||
<div>
|
||||
<div style="display:flex;align-items:center;gap:5px;font-size:11px;color:#6b6e7d;margin-bottom:5px">
|
||||
<div class="stat-dot" style="background:#8c6ef0"></div> Non-Cache
|
||||
</div>
|
||||
<div style="display:flex;align-items:baseline;gap:4px">
|
||||
<span style="font-size:15px;font-weight:800">85.5 MB</span>
|
||||
<span style="font-size:11px;color:#6b6e7d">4%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="width:1px;background:rgba(255,255,255,.08);margin:0 16px"></div>
|
||||
<div>
|
||||
<div style="font-size:11px;color:#6b6e7d;margin-bottom:5px">Total</div>
|
||||
<div style="font-size:15px;font-weight:800">1.75 GB</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding-top:16px">
|
||||
<span style="font-size:13px;color:#6b6e7d;font-weight:500;cursor:pointer">Details</span>
|
||||
<div class="arrow-btn"><svg viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div><!-- /row 1 -->
|
||||
|
||||
<!-- ████ ROW 2 ████ -->
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:13px">
|
||||
|
||||
<!-- ACTIVE USER (Changed to Line Area Chart) -->
|
||||
<div class="card" style="flex-direction:row;padding:0;overflow:hidden">
|
||||
<div style="flex:1;padding:20px 18px 18px 20px;display:flex;flex-direction:column">
|
||||
<div style="display:flex;align-items:center;gap:10px;margin-bottom:12px">
|
||||
<div class="card-icon"><svg viewBox="0 0 24 24"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75"/></svg></div>
|
||||
<span style="font-size:14px;font-weight:600">Active User</span>
|
||||
</div>
|
||||
<div style="font-size:36px;font-weight:900;letter-spacing:-1.5px;line-height:1" id="userText">475 K</div>
|
||||
<div style="font-size:12px;color:#6b6e7d;margin-top:4px">User active right now</div>
|
||||
<div style="display:flex;align-items:center;gap:5px;margin-top:12px;flex-wrap:wrap">
|
||||
<span class="flag">🇨🇳</span><span class="flag">🇮🇩</span><span class="flag">🇲🇲</span><span class="flag">🇲🇾</span><span class="flag">🇯🇵</span><span class="flag">🇮🇳</span><span class="flag">🇰🇷</span><span class="flag">🇵🇭</span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-top:auto;padding-top:14px">
|
||||
<span style="font-size:13px;color:#6b6e7d;font-weight:500;cursor:pointer">Details</span>
|
||||
<div class="arrow-btn"><svg viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Line Area Chart -->
|
||||
<div style="width:50%;padding:16px 14px 46px 0;display:flex;align-items:flex-end">
|
||||
<div class="chart-wrap" style="height:130px"><canvas id="userChart"></canvas></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PERFORMANCE -->
|
||||
<div class="card">
|
||||
<div style="display:flex;align-items:center;gap:10px;margin-bottom:12px">
|
||||
<div class="card-icon"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></div>
|
||||
<span style="font-size:14px;font-weight:600">Performance</span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:flex-start;gap:16px;flex:1">
|
||||
<div style="flex:1">
|
||||
<div style="font-size:36px;font-weight:900;letter-spacing:-1.5px;line-height:1" id="perfText">89%</div>
|
||||
<div style="font-size:12px;color:#6b6e7d;margin-top:4px"><span style="color:#3dd68c;font-weight:700">Good</span> Last scan on Jun 12, 2024</div>
|
||||
</div>
|
||||
<div style="display:flex;flex-direction:column;align-items:flex-end;gap:8px">
|
||||
<div class="chart-wrap" style="width:134px;height:58px"><canvas id="perfChart"></canvas></div>
|
||||
<div style="display:flex;flex-direction:column;gap:4px;align-items:flex-end">
|
||||
<div class="speed-row" style="color:#6c8ef0">
|
||||
<svg viewBox="0 0 24 24"><line x1="12" y1="19" x2="12" y2="5"/><polyline points="5 12 12 19 19 12"/></svg>
|
||||
<span id="upSpeed">10.4</span> Mbps
|
||||
</div>
|
||||
<div class="speed-row" style="color:#e8316a">
|
||||
<svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 5 5 12"/></svg>
|
||||
<span id="downSpeed">5.2</span> Mbps
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding-top:14px">
|
||||
<span style="font-size:13px;color:#6b6e7d;font-weight:500;cursor:pointer">Check Speed</span>
|
||||
<div class="arrow-btn"><svg viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div><!-- /row 2 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast Container -->
|
||||
<div class="toast-container" id="toastContainer"></div>
|
||||
|
||||
<!-- ══════════════════════ SCRIPTS ══════════════════════ -->
|
||||
<script>
|
||||
Chart.defaults.font.family = "'Inter',sans-serif";
|
||||
Chart.defaults.color = '#6b6e7d';
|
||||
Chart.defaults.animation.duration = 800;
|
||||
Chart.defaults.animation.easing = 'easeInOutQuart';
|
||||
|
||||
// System State
|
||||
let isSystemRunning = true;
|
||||
let simulationInterval;
|
||||
const MAX_DATA_POINTS = 24;
|
||||
|
||||
/* ── TOAST SYSTEM ── */
|
||||
function showToast(message, type = 'info') {
|
||||
const container = document.getElementById('toastContainer');
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast ${type}`;
|
||||
|
||||
let icon = '';
|
||||
if(type === 'success') icon = '<svg viewBox="0 0 24 24" fill="none" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>';
|
||||
else if(type === 'warning') icon = '<svg viewBox="0 0 24 24" fill="none" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>';
|
||||
else icon = '<svg viewBox="0 0 24 24" fill="none" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>';
|
||||
|
||||
toast.innerHTML = `${icon}<span>${message}</span>`;
|
||||
container.appendChild(toast);
|
||||
|
||||
setTimeout(() => {
|
||||
toast.classList.add('hiding');
|
||||
toast.addEventListener('animationend', () => toast.remove());
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
/* ── DATA & CHART SETUP ── */
|
||||
const initialData = {
|
||||
cpu: Array.from({length: MAX_DATA_POINTS}, () => Math.floor(Math.random() * 30) + 10),
|
||||
user: Array.from({length: 15}, () => Math.floor(Math.random() * 50) + 40),
|
||||
perf: Array.from({length: 12}, () => Math.floor(Math.random() * 20) + 70),
|
||||
perf2: Array.from({length: 12}, () => Math.floor(Math.random() * 20) + 60),
|
||||
};
|
||||
|
||||
/* ── CPU CHART (Line with Dots) ── */
|
||||
const cpuCtx = document.getElementById('cpuChart').getContext('2d');
|
||||
const cpuChart = new Chart(cpuCtx,{
|
||||
type:'line',
|
||||
data:{
|
||||
labels:Array.from({length: MAX_DATA_POINTS}, (_,i) => i),
|
||||
datasets:[{
|
||||
data: initialData.cpu,
|
||||
borderColor:'#ff7043',
|
||||
borderWidth: 2,
|
||||
backgroundColor: 'transparent', // No fill
|
||||
tension: 0.3, // Slight curve, not too wavy
|
||||
pointRadius: 2, // Visible small dots
|
||||
pointBackgroundColor: '#ff7043',
|
||||
pointHoverRadius: 5,
|
||||
fill: false
|
||||
}]
|
||||
},
|
||||
options:{
|
||||
responsive:true,maintainAspectRatio:false,
|
||||
plugins:{legend:{display:false},tooltip:{enabled:false}},
|
||||
scales:{
|
||||
x:{display:false},
|
||||
y:{display:false, min:0, max:100}
|
||||
},
|
||||
interaction:{mode:'index',intersect:false},
|
||||
}
|
||||
});
|
||||
|
||||
/* ── RAM DONUT (Flat Solid Color) ── */
|
||||
let currentRamPercent = 65;
|
||||
function drawRam(percent){
|
||||
const c=document.getElementById('ramCanvas'), ctx=c.getContext('2d');
|
||||
const W=c.width, H=c.height, cx=W/2, cy=H-8, R=68, r=52;
|
||||
ctx.clearRect(0,0,W,H);
|
||||
const segs=28, gap=.048, filled=Math.round(segs * (percent/100));
|
||||
for(let i=0;i<segs;i++){
|
||||
const a0=Math.PI+(Math.PI/segs)*i+gap/2;
|
||||
const a1=Math.PI+(Math.PI/segs)*(i+1)-gap/2;
|
||||
const f=i<filled;
|
||||
ctx.beginPath();
|
||||
ctx.arc(cx,cy,R,a0,a1);
|
||||
ctx.arc(cx,cy,r,a1,a0,true);
|
||||
ctx.closePath();
|
||||
if(f){
|
||||
ctx.fillStyle = '#9c7ef0';
|
||||
} else {
|
||||
ctx.fillStyle='rgba(255,255,255,.07)';
|
||||
}
|
||||
ctx.fill();
|
||||
}
|
||||
}
|
||||
drawRam(currentRamPercent);
|
||||
|
||||
/* ── USER CHART (Line Area Chart - 1:1 Match) ── */
|
||||
const userCtx=document.getElementById('userChart').getContext('2d');
|
||||
const userChart=new Chart(userCtx,{
|
||||
type:'line',
|
||||
data:{
|
||||
labels:Array.from({length:15},(_,i)=>i),
|
||||
datasets:[{
|
||||
data:initialData.user,
|
||||
borderColor:'#e8316a', // Pink Line
|
||||
borderWidth: 2,
|
||||
backgroundColor: 'rgba(232, 49, 106, 0.15)', // Subtle Pink Fill
|
||||
tension: 0.4, // Smooth curve
|
||||
pointRadius: 0, // No dots, just the wave
|
||||
fill: true, // This creates the area chart
|
||||
borderCapStyle: 'round'
|
||||
}]
|
||||
},
|
||||
options:{
|
||||
responsive:true,maintainAspectRatio:false,
|
||||
plugins:{legend:{display:false},tooltip:{enabled:false}},
|
||||
scales:{
|
||||
x:{display:false},
|
||||
y:{display:false, min:0, max:120}
|
||||
},
|
||||
interaction:{mode:'index',intersect:false},
|
||||
}
|
||||
});
|
||||
|
||||
/* ── PERF CHART (Solid Area Fill) ── */
|
||||
const perfCtx=document.getElementById('perfChart').getContext('2d');
|
||||
const perfChart=new Chart(perfCtx,{
|
||||
type:'line',
|
||||
data:{
|
||||
labels:Array.from({length:12},(_,i)=>i),
|
||||
datasets:[
|
||||
{
|
||||
data:initialData.perf,
|
||||
borderColor:'#6c8ef0',
|
||||
borderWidth: 2,
|
||||
backgroundColor: 'rgba(108, 142, 240, 0.15)',
|
||||
tension:.4,
|
||||
pointRadius: 0,
|
||||
fill: true
|
||||
},
|
||||
{
|
||||
data:initialData.perf2,
|
||||
borderColor:'#9c7ef0',
|
||||
borderWidth: 2,
|
||||
backgroundColor: 'rgba(156, 126, 240, 0.15)',
|
||||
tension:.4,
|
||||
pointRadius: 0,
|
||||
fill: true
|
||||
}
|
||||
]
|
||||
},
|
||||
options:{
|
||||
responsive:true,maintainAspectRatio:false,
|
||||
plugins:{legend:{display:false},tooltip:{enabled:false}},
|
||||
scales:{x:{display:false},y:{display:false}},
|
||||
}
|
||||
});
|
||||
|
||||
/* ── SIMULATION LOGIC ── */
|
||||
function getRandom(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
function updateDashboard() {
|
||||
if(!isSystemRunning) return;
|
||||
|
||||
// 1. Update CPU
|
||||
const newCpu = getRandom(10, 45);
|
||||
document.getElementById('cpuText').innerText = `${newCpu}%`;
|
||||
|
||||
cpuChart.data.datasets[0].data.shift();
|
||||
cpuChart.data.datasets[0].data.push(newCpu);
|
||||
cpuChart.update('none');
|
||||
|
||||
// 2. Update RAM
|
||||
currentRamPercent = getRandom(50, 85);
|
||||
document.getElementById('ramText').innerText = `${currentRamPercent}%`;
|
||||
const gbUsed = (8 * (currentRamPercent/100)).toFixed(1);
|
||||
document.getElementById('ramDetail').innerText = `${gbUsed} GB / 8GB`;
|
||||
drawRam(currentRamPercent);
|
||||
|
||||
// 3. Update Users
|
||||
const newUserVal = getRandom(60, 110);
|
||||
document.getElementById('userText').innerText = `${newUserVal} K`;
|
||||
userChart.data.datasets[0].data.shift();
|
||||
userChart.data.datasets[0].data.push(newUserVal);
|
||||
userChart.update('none');
|
||||
|
||||
// 4. Update Perf & Speed
|
||||
const perfVal = getRandom(82, 99);
|
||||
document.getElementById('perfText').innerText = `${perfVal}%`;
|
||||
|
||||
const up = (Math.random() * 5 + 8).toFixed(1);
|
||||
const down = (Math.random() * 3 + 4).toFixed(1);
|
||||
document.getElementById('upSpeed').innerText = up;
|
||||
document.getElementById('downSpeed').innerText = down;
|
||||
|
||||
perfChart.data.datasets[0].data.shift();
|
||||
perfChart.data.datasets[0].data.push(perfVal);
|
||||
perfChart.data.datasets[1].data.shift();
|
||||
perfChart.data.datasets[1].data.push(perfVal - 5);
|
||||
perfChart.update('none');
|
||||
}
|
||||
|
||||
simulationInterval = setInterval(updateDashboard, 2000);
|
||||
|
||||
/* ── CONTROLS ── */
|
||||
const btnStop = document.getElementById('btnStop');
|
||||
const btnRestart = document.getElementById('btnRestart');
|
||||
const statusBadge = document.getElementById('statusBadge');
|
||||
const liveDot = document.getElementById('liveDot');
|
||||
|
||||
btnStop.addEventListener('click', () => {
|
||||
if(!isSystemRunning) return;
|
||||
isSystemRunning = false;
|
||||
statusBadge.className = 'badge-stopped';
|
||||
statusBadge.innerHTML = 'Stopped';
|
||||
liveDot.classList.add('stopped');
|
||||
btnStop.classList.add('disabled');
|
||||
btnStop.disabled = true;
|
||||
btnRestart.classList.remove('disabled');
|
||||
btnRestart.disabled = false;
|
||||
showToast('System monitoring paused', 'warning');
|
||||
});
|
||||
|
||||
btnRestart.addEventListener('click', () => {
|
||||
if(isSystemRunning) return;
|
||||
isSystemRunning = true;
|
||||
statusBadge.className = 'badge-active';
|
||||
statusBadge.innerHTML = '<span class="live-dot" id="liveDot"></span>Active';
|
||||
btnRestart.classList.add('disabled');
|
||||
btnRestart.disabled = true;
|
||||
btnStop.classList.remove('disabled');
|
||||
btnStop.disabled = false;
|
||||
showToast('System restarted successfully', 'success');
|
||||
});
|
||||
|
||||
/* ── TAB/PILL SWITCH ── */
|
||||
function setPill(el){
|
||||
document.querySelectorAll('#timePills .pill').forEach(p=>p.classList.remove('active'));
|
||||
el.classList.add('active');
|
||||
}
|
||||
|
||||
function setTab(el){
|
||||
document.querySelectorAll('.tab').forEach(t=>t.classList.remove('active'));
|
||||
el.classList.add('active');
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user