Files
Containr/docs/references/self.html
T
2026-04-10 12:02:36 +02:00

613 lines
34 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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>