<div class="dashboard-wrapper">
<!-- Sidebar -->
<div class="sidebar-nav">
<div class="brand">
<svg viewBox="0 0 24 24" width="32" height="32" fill="none" stroke="#3b82f6" stroke-width="2"><polygon points="12 2 2 7 12 12 22 7 12 2"></polygon><polyline points="2 17 12 22 22 17"></polyline><polyline points="2 12 12 17 22 12"></polyline></svg>
</div>
<div class="nav-links">
<div class="nav-item active">
<svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7"></rect><rect x="14" y="3" width="7" height="7"></rect><rect x="14" y="14" width="7" height="7"></rect><rect x="3" y="14" width="7" height="7"></rect></svg>
</div>
<div class="nav-item">
<svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"></polyline></svg>
</div>
<div class="nav-item">
<svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M23 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg>
</div>
<div class="nav-item">
<svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>
</div>
</div>
</div>
<!-- Main Content -->
<div class="main-content">
<!-- Header -->
<header class="top-header">
<div class="search-bar">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="#64748b" stroke-width="2"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>
<input type="text" class="search-input" placeholder="Search analytics...">
</div>
<div class="header-profile">
<button class="icon-btn">
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path><path d="M13.73 21a2 2 0 0 1-3.46 0"></path></svg>
<span class="notification-dot"></span>
</button>
<img src="https://placehold.co/40x40/3b82f6/ffffff?text=AD" alt="User" class="avatar">
</div>
</header>
<!-- KPI Row -->
<div class="kpi-grid">
<div class="kpi-card">
<div class="kpi-top">
<span class="kpi-title">Total Revenue</span>
<div class="kpi-icon blue"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="1" x2="12" y2="23"></line><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"></path></svg></div>
</div>
<h2 class="kpi-value">$124,563.00</h2>
<div class="kpi-bottom"><span class="trend positive">↑ 14.5%</span><span class="vs-text">vs last month</span></div>
</div>
<div class="kpi-card">
<div class="kpi-top">
<span class="kpi-title">Active Users</span>
<div class="kpi-icon green"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M23 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg></div>
</div>
<h2 class="kpi-value">45,231</h2>
<div class="kpi-bottom"><span class="trend positive">↑ 8.2%</span><span class="vs-text">vs last month</span></div>
</div>
<div class="kpi-card">
<div class="kpi-top">
<span class="kpi-title">Conversion Rate</span>
<div class="kpi-icon purple"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg></div>
</div>
<h2 class="kpi-value">3.24%</h2>
<div class="kpi-bottom"><span class="trend negative">↓ 1.1%</span><span class="vs-text">vs last month</span></div>
</div>
<!-- Circular Gauge KPI -->
<div class="kpi-card">
<div class="kpi-top">
<span class="kpi-title">Server Load</span>
<div class="kpi-icon red"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"></polyline></svg></div>
</div>
<div class="gauge-container">
<svg viewBox="0 0 100 50" class="kpi-gauge">
<path d="M 10 50 A 40 40 0 0 1 90 50" fill="none" stroke="#1e293b" stroke-width="8" stroke-linecap="round"></path>
<path id="load-gauge" d="M 10 50 A 40 40 0 0 1 90 50" fill="none" stroke="#ef4444" stroke-width="8" stroke-linecap="round" stroke-dasharray="126" stroke-dashoffset="126"></path>
</svg>
<div class="gauge-text" id="load-text">0%</div>
</div>
</div>
</div>
<!-- Main Chart Area -->
<div class="chart-section">
<div class="section-header">
<h3>Revenue Trajectory</h3>
<button class="export-btn">Download Report</button>
</div>
<div class="svg-chart-box">
<svg id="dynamic-curve" viewBox="0 0 1000 300" width="100%" height="100%" preserveAspectRatio="none">
<!-- Grid Lines -->
<line x1="0" y1="50" x2="1000" y2="50" stroke="#1e293b" stroke-width="1"></line>
<line x1="0" y1="150" x2="1000" y2="150" stroke="#1e293b" stroke-width="1"></line>
<line x1="0" y1="250" x2="1000" y2="250" stroke="#1e293b" stroke-width="1"></line>
<defs>
<linearGradient id="curve-grad" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#3b82f6"></stop>
<stop offset="50%" stop-color="#8b5cf6"></stop>
<stop offset="100%" stop-color="#ec4899"></stop>
</linearGradient>
<linearGradient id="fill-grad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="rgba(139, 92, 246, 0.4)"></stop>
<stop offset="100%" stop-color="rgba(139, 92, 246, 0)"></stop>
</linearGradient>
</defs>
<!-- Filled Area & Line injected by JS -->
<path id="curve-fill" fill="url(#fill-grad)" opacity="0"></path>
<path id="curve-line" fill="none" stroke="url(#curve-grad)" stroke-width="4" stroke-linecap="round"></path>
</svg>
</div>
</div>
<!-- Bottom Row Layout -->
<div class="bottom-grid">
<!-- Bar Chart -->
<div class="bar-card">
<div class="section-header">
<h3>Traffic Sources</h3>
</div>
<div class="bar-chart-wrapper" id="bar-chart">
<!-- Bars injected by JS -->
</div>
<div class="bar-labels">
<span>Org</span><span>Dir</span><span>Soc</span><span>Ref</span><span>Eml</span><span>Oth</span>
</div>
</div>
<!-- Activity Feed -->
<div class="activity-card">
<div class="section-header">
<h3>Recent Activity</h3>
</div>
<div class="activity-list">
<div class="activity-item">
<img src="https://placehold.co/32x32/10b981/ffffff?text=OK" alt="User" class="activity-avatar">
<div class="activity-info">
<span class="act-title">New subscription purchased</span>
<span class="act-time">2 minutes ago</span>
</div>
<span class="status-pill status-success">Success</span>
</div>
<div class="activity-item">
<img src="https://placehold.co/32x32/f59e0b/ffffff?text=WARN" alt="User" class="activity-avatar">
<div class="activity-info">
<span class="act-title">Database sync delayed</span>
<span class="act-time">15 minutes ago</span>
</div>
<span class="status-pill status-warning">Warning</span>
</div>
<div class="activity-item">
<img src="https://placehold.co/32x32/ef4444/ffffff?text=ERR" alt="User" class="activity-avatar">
<div class="activity-info">
<span class="act-title">Payment gateway failed</span>
<span class="act-time">1 hour ago</span>
</div>
<span class="status-pill status-danger">Failed</span>
</div>
<div class="activity-item">
<img src="https://placehold.co/32x32/3b82f6/ffffff?text=INFO" alt="User" class="activity-avatar">
<div class="activity-info">
<span class="act-title">Weekly report generated</span>
<span class="act-time">3 hours ago</span>
</div>
<span class="status-pill status-info">Info</span>
</div>
</div>
</div>
</div>
</div>
</div>
*, *::before, *::after {
box-sizing: border-box;
}
body {
font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
margin: 0;
background: #020617;
color: #f8fafc;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
padding: 20px;
}
.dashboard-wrapper {
display: flex;
width: 100%;
max-width: 1400px;
height: 90vh;
min-height: 800px;
background: #0f172a;
border-radius: 24px;
border: 1px solid #1e293b;
overflow: hidden;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
}
.sidebar-nav {
width: 80px;
background: #020617;
border-right: 1px solid #1e293b;
display: flex;
flex-direction: column;
align-items: center;
padding: 24px 0;
}
.brand {
margin-bottom: 40px;
}
.nav-links {
display: flex;
flex-direction: column;
gap: 32px;
}
.nav-item {
color: #475569;
cursor: pointer;
transition: color 0.2s, transform 0.2s;
display: flex;
justify-content: center;
align-items: center;
width: 48px;
height: 48px;
border-radius: 12px;
}
.nav-item:hover {
color: #94a3b8;
background: rgba(255, 255, 255, 0.05);
}
.nav-item.active {
color: #ffffff;
background: #3b82f6;
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
}
.main-content {
flex-grow: 1;
padding: 32px;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 32px;
}
.top-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.search-bar {
display: flex;
align-items: center;
background: #020617;
border: 1px solid #1e293b;
padding: 10px 16px;
border-radius: 12px;
width: 300px;
}
.search-input {
background: transparent;
border: none;
color: #f8fafc;
outline: none;
margin-left: 12px;
width: 100%;
font-size: 0.95rem;
font-family: inherit;
}
.header-profile {
display: flex;
align-items: center;
gap: 20px;
}
.icon-btn {
background: transparent;
border: none;
color: #94a3b8;
cursor: pointer;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.notification-dot {
position: absolute;
top: -2px;
right: -2px;
width: 8px;
height: 8px;
background: #ef4444;
border-radius: 50%;
border: 2px solid #0f172a;
}
.avatar {
width: 44px;
height: 44px;
border-radius: 50%;
border: 2px solid #1e293b;
cursor: pointer;
}
.kpi-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 24px;
}
.kpi-card {
background: #020617;
border: 1px solid #1e293b;
padding: 24px;
border-radius: 20px;
display: flex;
flex-direction: column;
position: relative;
}
.kpi-top {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.kpi-title {
color: #94a3b8;
font-size: 0.95rem;
font-weight: 500;
}
.kpi-icon {
width: 36px;
height: 36px;
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
}
.kpi-icon.blue { background: rgba(59, 130, 246, 0.1); color: #3b82f6; }
.kpi-icon.green { background: rgba(16, 185, 129, 0.1); color: #10b981; }
.kpi-icon.purple { background: rgba(139, 92, 246, 0.1); color: #8b5cf6; }
.kpi-icon.red { background: rgba(239, 68, 68, 0.1); color: #ef4444; }
.kpi-value {
margin: 0 0 12px 0;
font-size: 2rem;
font-weight: 700;
letter-spacing: -0.5px;
}
.kpi-bottom {
display: flex;
align-items: center;
gap: 8px;
}
.trend {
font-size: 0.85rem;
font-weight: 600;
}
.trend.positive { color: #10b981; }
.trend.negative { color: #ef4444; }
.vs-text {
color: #64748b;
font-size: 0.85rem;
}
/* Custom Circular Gauge for Load */
.gauge-container {
display: flex;
align-items: center;
gap: 16px;
margin-top: 8px;
}
.kpi-gauge {
width: 60px;
height: 30px;
overflow: visible;
}
.gauge-text {
font-size: 1.5rem;
font-weight: 700;
color: #f8fafc;
}
.chart-section {
background: #020617;
border: 1px solid #1e293b;
border-radius: 20px;
padding: 24px;
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
}
.section-header h3 {
margin: 0;
font-size: 1.25rem;
font-weight: 600;
}
.export-btn {
background: #1e293b;
color: #f8fafc;
border: none;
padding: 8px 16px;
border-radius: 8px;
font-size: 0.85rem;
font-weight: 600;
cursor: pointer;
transition: background 0.2s;
}
.export-btn:hover { background: #334155; }
.svg-chart-box {
width: 100%;
height: 280px;
}
.bottom-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
}
.bar-card, .activity-card {
background: #020617;
border: 1px solid #1e293b;
border-radius: 20px;
padding: 24px;
height: 320px;
display: flex;
flex-direction: column;
}
/* Bar Chart Styles */
.bar-chart-wrapper {
flex-grow: 1;
display: flex;
align-items: flex-end;
justify-content: space-between;
padding-bottom: 10px;
border-bottom: 1px solid #1e293b;
gap: 8px;
}
.chart-bar {
flex: 1;
background: linear-gradient(to top, #3b82f6, #8b5cf6);
border-radius: 4px 4px 0 0;
height: 0%;
transition: height 1.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.bar-labels {
display: flex;
justify-content: space-between;
padding-top: 12px;
}
.bar-labels span {
flex: 1;
text-align: center;
color: #64748b;
font-size: 0.8rem;
font-weight: 500;
}
/* Activity Feed Styles */
.activity-list {
display: flex;
flex-direction: column;
gap: 20px;
overflow-y: auto;
}
.activity-item {
display: flex;
align-items: center;
gap: 16px;
}
.activity-avatar {
width: 36px;
height: 36px;
border-radius: 10px;
}
.activity-info {
display: flex;
flex-direction: column;
flex-grow: 1;
}
.act-title {
font-weight: 500;
font-size: 0.95rem;
}
.act-time {
color: #64748b;
font-size: 0.8rem;
margin-top: 4px;
}
.status-pill {
padding: 4px 10px;
border-radius: 12px;
font-size: 0.75rem;
font-weight: 600;
}
.status-success { background: rgba(16, 185, 129, 0.1); color: #10b981; }
.status-warning { background: rgba(245, 158, 11, 0.1); color: #f59e0b; }
.status-danger { background: rgba(239, 68, 68, 0.1); color: #ef4444; }
.status-info { background: rgba(59, 130, 246, 0.1); color: #3b82f6; }
/* Responsive adjustments */
@media (max-width: 1200px) {
.kpi-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 900px) {
.bottom-grid { grid-template-columns: 1fr; }
.bar-card, .activity-card { height: auto; min-height: 300px; }
}
/* We use native JS to animate everything without external libraries */
/* 1. Animate Main SVG Curve Chart */
const curveLine = document.getElementById("curve-line");
const curveFill = document.getElementById("curve-fill");
let pathString = "M 0 250";
let fillString = "M 0 250";
const points = 20;
const xStep = 1000 / points;
let currentY = 250;
for (let i = 1; i <= points; i++) {
const currentX = i * xStep;
/* Random trend upward */
const change = (Math.random() * 80) - 50;
currentY += change;
if (currentY < 20) currentY = 20;
if (currentY > 260) currentY = 260;
const prevX = (i - 1) * xStep;
const cp1X = prevX + (xStep / 2);
const cp1Y = currentY - change;
const cp2X = currentX - (xStep / 2);
const cp2Y = currentY;
const curveSegment = " C " + cp1X + " " + cp1Y + ", " + cp2X + " " + cp2Y + ", " + currentX + " " + currentY;
pathString += curveSegment;
fillString += curveSegment;
}
fillString += " L 1000 300 L 0 300 Z";
curveLine.setAttribute("d", pathString);
curveFill.setAttribute("d", fillString);
const pathLength = curveLine.getTotalLength();
curveLine.style.strokeDasharray = pathLength;
curveLine.style.strokeDashoffset = pathLength;
curveLine.style.transition = "stroke-dashoffset 2s cubic-bezier(0.34, 1.56, 0.64, 1)";
/* 2. Setup Bar Chart */
const barContainer = document.getElementById("bar-chart");
const numBars = 6;
const barsElements = new Array();
for (let i = 0; i < numBars; i++) {
const bar = document.createElement("div");
bar.className = "chart-bar";
barContainer.appendChild(bar);
barsElements.push(bar);
}
/* 3. Server Load Gauge Update */
const loadGauge = document.getElementById("load-gauge");
const loadText = document.getElementById("load-text");
const totalGaugeLength = 126;
function updateServerLoad() {
const loadVal = Math.floor(Math.random() * 40) + 40; // 40 to 80%
const offset = totalGaugeLength - (loadVal / 100) * totalGaugeLength;
loadGauge.style.transition = "stroke-dashoffset 1s ease-out";
loadGauge.style.strokeDashoffset = offset;
loadText.innerText = loadVal + "%";
}
/* 4. Trigger Animations on Load */
setTimeout(function() {
/* Animate line */
curveLine.style.strokeDashoffset = 0;
/* Fade in fill slightly after line starts */
setTimeout(function() {
curveFill.style.transition = "opacity 1.5s ease";
curveFill.style.opacity = "1";
}, 500);
/* Animate bars */
barsElements.forEach(function(bar) {
const randomHeight = Math.floor(Math.random() * 70) + 20;
bar.style.height = randomHeight + "%";
});
/* Start Gauge */
updateServerLoad();
setInterval(updateServerLoad, 3000);
}, 200);