Loading…
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NovaAdmin | Responsive Admin Dashboard</title>
<meta name="description" content="Responsive Bootstrap 5 admin dashboard with sidebar navigation, KPI cards, Chart.js charts, activity feed, recent orders, and quick actions.">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.7.2/css/all.min.css">
</head>
<body>
<div class="admin-dashboard">
<a class="skip-link" href="#mainContent">Skip to content</a>
<div class="sidebar-backdrop" hidden></div>
<aside class="dashboard-sidebar" id="sidebarMenu" aria-label="Dashboard navigation">
<div class="sidebar-header">
<a href="#overview" class="brand" aria-label="NovaAdmin dashboard home">
<span class="brand-icon" aria-hidden="true"><i class="fa-solid fa-layer-group"></i></span>
<span>NovaAdmin</span>
</a>
<button class="sidebar-close d-lg-none" type="button" aria-label="Close navigation menu">
<i class="fa-solid fa-xmark" aria-hidden="true"></i>
</button>
</div>
<nav class="sidebar-nav" aria-label="Main dashboard links">
<a href="#overview" class="nav-link active" aria-current="page"><i class="fa-solid fa-chart-line" aria-hidden="true"></i><span>Overview</span></a>
<a href="#analytics" class="nav-link"><i class="fa-solid fa-chart-pie" aria-hidden="true"></i><span>Analytics</span></a>
<a href="#orders" class="nav-link"><i class="fa-solid fa-cart-shopping" aria-hidden="true"></i><span>Orders</span></a>
<a href="#activity" class="nav-link"><i class="fa-solid fa-bell" aria-hidden="true"></i><span>Activity</span></a>
<a href="#actions" class="nav-link"><i class="fa-solid fa-bolt" aria-hidden="true"></i><span>Actions</span></a>
</nav>
<div class="sidebar-card">
<p class="sidebar-card-label">Storage</p>
<strong>74% used</strong>
<div class="progress" role="progressbar" aria-label="Storage usage" aria-valuenow="74" aria-valuemin="0" aria-valuemax="100">
<div class="progress-bar" style="width: 74%"></div>
</div>
<small>148 GB of 200 GB</small>
</div>
</aside>
<div class="dashboard-shell">
<header class="topbar">
<div class="topbar-title">
<button class="menu-toggle d-lg-none" type="button" aria-controls="sidebarMenu" aria-expanded="false" aria-label="Open navigation menu">
<i class="fa-solid fa-bars" aria-hidden="true"></i>
</button>
<div>
<p class="eyebrow">Dashboard</p>
<h1>Business overview</h1>
</div>
</div>
<div class="topbar-actions">
<label class="search-box" for="orderSearch">
<span class="visually-hidden">Search orders</span>
<i class="fa-solid fa-magnifying-glass" aria-hidden="true"></i>
<input id="orderSearch" type="search" placeholder="Search orders">
</label>
<span class="date-pill"><i class="fa-regular fa-calendar me-1" aria-hidden="true"></i>2026 Report</span>
<button class="profile-button" type="button" aria-label="Open user profile menu">
<i class="fa-solid fa-user" aria-hidden="true"></i>
</button>
</div>
</header>
<main id="mainContent" class="dashboard-main">
<section class="kpi-grid" id="overview" aria-label="Dashboard statistics">
<article class="kpi-card">
<div class="kpi-icon revenue" aria-hidden="true"><i class="fa-solid fa-dollar-sign"></i></div>
<div>
<p>Revenue</p>
<strong>$128.4K</strong>
<span class="trend positive"><i class="fa-solid fa-arrow-trend-up" aria-hidden="true"></i> +18.2%</span>
</div>
</article>
<article class="kpi-card">
<div class="kpi-icon users" aria-hidden="true"><i class="fa-solid fa-users"></i></div>
<div>
<p>Active Users</p>
<strong>24,892</strong>
<span class="trend positive"><i class="fa-solid fa-arrow-trend-up" aria-hidden="true"></i> +9.7%</span>
</div>
</article>
<article class="kpi-card">
<div class="kpi-icon orders" aria-hidden="true"><i class="fa-solid fa-bag-shopping"></i></div>
<div>
<p>Orders</p>
<strong>3,482</strong>
<span class="trend positive"><i class="fa-solid fa-arrow-trend-up" aria-hidden="true"></i> +12.4%</span>
</div>
</article>
<article class="kpi-card">
<div class="kpi-icon issues" aria-hidden="true"><i class="fa-solid fa-triangle-exclamation"></i></div>
<div>
<p>Open Issues</p>
<strong>17</strong>
<span class="trend negative"><i class="fa-solid fa-arrow-trend-down" aria-hidden="true"></i> -4.1%</span>
</div>
</article>
</section>
<section class="chart-section" id="analytics" aria-label="Dashboard charts">
<div class="row g-4">
<div class="col-xl-8">
<article class="panel-card h-100">
<div class="panel-header">
<div>
<p class="eyebrow">Revenue</p>
<h2>Sales over time</h2>
</div>
<span class="panel-badge">Last 12 months</span>
</div>
<div class="chart-wrapper large-chart">
<canvas id="salesChart" role="img" aria-label="Line chart showing monthly sales revenue from January to December"></canvas>
<p class="chart-fallback" id="salesChartFallback" hidden>Sales chart is unavailable because Chart.js could not be loaded.</p>
</div>
</article>
</div>
<div class="col-xl-4">
<article class="panel-card h-100">
<div class="panel-header">
<div>
<p class="eyebrow">Acquisition</p>
<h2>Traffic sources</h2>
</div>
</div>
<div class="chart-wrapper small-chart">
<canvas id="trafficChart" role="img" aria-label="Doughnut chart showing traffic source distribution"></canvas>
<p class="chart-fallback" id="trafficChartFallback" hidden>Traffic chart is unavailable because Chart.js could not be loaded.</p>
</div>
</article>
</div>
</div>
</section>
<section class="details-grid">
<article class="panel-card" id="orders">
<div class="panel-header">
<div>
<p class="eyebrow">Orders</p>
<h2>Recent orders</h2>
</div>
<a class="text-link" href="#">View all</a>
</div>
<div class="table-responsive">
<table class="table align-middle orders-table">
<caption class="visually-hidden">Recent customer orders</caption>
<thead>
<tr>
<th scope="col">Order</th>
<th scope="col">Customer</th>
<th scope="col">Status</th>
<th scope="col">Amount</th>
</tr>
</thead>
<tbody>
<tr data-search="ord 1048 maya cruz completed 2480">
<td>#ORD-1048</td>
<td>Maya Cruz</td>
<td><span class="status-badge success">Completed</span></td>
<td>$2,480</td>
</tr>
<tr data-search="ord 1047 noah lee processing 1240">
<td>#ORD-1047</td>
<td>Noah Lee</td>
<td><span class="status-badge warning">Processing</span></td>
<td>$1,240</td>
</tr>
<tr data-search="ord 1046 ava santos pending 860">
<td>#ORD-1046</td>
<td>Ava Santos</td>
<td><span class="status-badge neutral">Pending</span></td>
<td>$860</td>
</tr>
<tr data-search="ord 1045 liam parker completed 3180">
<td>#ORD-1045</td>
<td>Liam Parker</td>
<td><span class="status-badge success">Completed</span></td>
<td>$3,180</td>
</tr>
</tbody>
</table>
</div>
<p class="table-status" aria-live="polite">Showing 4 orders.</p>
</article>
<aside class="side-panels">
<article class="panel-card" id="activity">
<div class="panel-header compact">
<div>
<p class="eyebrow">Activity</p>
<h2>Latest updates</h2>
</div>
</div>
<ul class="activity-list">
<li><span class="activity-dot blue"></span><div><strong>New report generated</strong><p>Revenue summary exported by Admin.</p></div></li>
<li><span class="activity-dot green"></span><div><strong>Payment received</strong><p>Invoice #INV-2219 was paid.</p></div></li>
<li><span class="activity-dot orange"></span><div><strong>Issue assigned</strong><p>Support ticket moved to Engineering.</p></div></li>
</ul>
</article>
<article class="panel-card" id="actions">
<div class="panel-header compact">
<div>
<p class="eyebrow">Actions</p>
<h2>Quick tools</h2>
</div>
</div>
<div class="quick-actions">
<button type="button"><i class="fa-solid fa-file-export" aria-hidden="true"></i><span>Export</span></button>
<button type="button"><i class="fa-solid fa-user-plus" aria-hidden="true"></i><span>Add User</span></button>
<button type="button"><i class="fa-solid fa-gear" aria-hidden="true"></i><span>Settings</span></button>
</div>
</article>
</aside>
</section>
</main>
<footer class="site-footer">
<p>© <span id="currentYear"></span> NovaAdmin. All rights reserved.</p>
<a href="#overview">Back to top</a>
</footer>
</div>
</div>
</body>
</html>:root {
--admin-bg: #f5f7fb;
--admin-sidebar: #0f172a;
--admin-sidebar-soft: #1e293b;
--admin-surface: #ffffff;
--admin-text: #111827;
--admin-muted: #64748b;
--admin-border: #e2e8f0;
--admin-primary: #2563eb;
--admin-primary-dark: #1d4ed8;
--admin-info: #06b6d4;
--admin-success: #16a34a;
--admin-warning: #f59e0b;
--admin-danger: #dc2626;
--admin-radius: 1.2rem;
--admin-shadow: 0 18px 45px rgba(15, 23, 42, 0.08);
}
html {
scroll-behavior: smooth;
}
body {
margin: 0;
background: var(--admin-bg);
}
.admin-dashboard {
min-height: 100vh;
display: flex;
background: var(--admin-bg);
color: var(--admin-text);
font-family: Inter, "Segoe UI", Roboto, Arial, sans-serif;
line-height: 1.6;
}
.admin-dashboard *,
.admin-dashboard *::before,
.admin-dashboard *::after {
box-sizing: border-box;
}
.admin-dashboard h1,
.admin-dashboard h2,
.admin-dashboard h3,
.admin-dashboard p {
margin-top: 0;
}
.admin-dashboard h1,
.admin-dashboard h2,
.admin-dashboard h3 {
color: var(--admin-text);
font-weight: 800;
letter-spacing: -0.04em;
line-height: 1.15;
}
.skip-link {
position: fixed;
top: -4rem;
left: 1rem;
z-index: 1300;
padding: 0.7rem 1rem;
border-radius: 0.65rem;
background: var(--admin-text);
color: #ffffff;
text-decoration: none;
}
.skip-link:focus {
top: 1rem;
color: #ffffff;
}
.dashboard-sidebar {
position: sticky;
top: 0;
z-index: 1000;
width: 280px;
min-width: 280px;
height: 100vh;
display: flex;
flex-direction: column;
gap: 1.5rem;
padding: 1.25rem;
background: linear-gradient(180deg, var(--admin-sidebar), #111827);
color: #cbd5e1;
}
.sidebar-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
}
.brand {
display: inline-flex;
align-items: center;
gap: 0.75rem;
color: #ffffff;
font-size: 1.1rem;
font-weight: 850;
text-decoration: none;
}
.brand:hover,
.brand:focus {
color: #ffffff;
}
.brand-icon {
display: inline-grid;
width: 2.5rem;
height: 2.5rem;
place-content: center;
border-radius: 0.85rem;
background: linear-gradient(135deg, var(--admin-primary), var(--admin-info));
color: #ffffff;
}
.sidebar-close,
.menu-toggle,
.profile-button {
display: inline-grid;
place-content: center;
border: 1px solid var(--admin-border);
border-radius: 0.85rem;
background: #ffffff;
color: var(--admin-text);
}
.sidebar-close {
width: 2.5rem;
height: 2.5rem;
border-color: rgba(255, 255, 255, 0.12);
background: var(--admin-sidebar-soft);
color: #ffffff;
}
.sidebar-nav {
display: grid;
gap: 0.45rem;
}
.sidebar-nav .nav-link {
display: flex;
align-items: center;
gap: 0.8rem;
padding: 0.82rem 0.9rem;
border-radius: 0.9rem;
color: #cbd5e1;
font-weight: 750;
text-decoration: none;
}
.sidebar-nav .nav-link i {
width: 1.1rem;
color: #93c5fd;
}
.sidebar-nav .nav-link:hover,
.sidebar-nav .nav-link:focus,
.sidebar-nav .nav-link.active {
background: rgba(255, 255, 255, 0.08);
color: #ffffff;
}
.sidebar-card {
margin-top: auto;
padding: 1rem;
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 1rem;
background: rgba(255, 255, 255, 0.06);
}
.sidebar-card-label {
margin-bottom: 0.25rem;
color: #93c5fd;
font-size: 0.78rem;
font-weight: 850;
letter-spacing: 0.12em;
text-transform: uppercase;
}
.sidebar-card strong {
display: block;
margin-bottom: 0.75rem;
color: #ffffff;
}
.sidebar-card .progress {
height: 0.5rem;
margin-bottom: 0.65rem;
background: rgba(255, 255, 255, 0.12);
}
.sidebar-card .progress-bar {
background: linear-gradient(90deg, var(--admin-primary), var(--admin-info));
}
.sidebar-card small {
color: #94a3b8;
}
.sidebar-backdrop {
position: fixed;
inset: 0;
z-index: 998;
background: rgba(15, 23, 42, 0.52);
}
.dashboard-shell {
min-width: 0;
flex: 1;
display: flex;
flex-direction: column;
}
.topbar {
position: sticky;
top: 0;
z-index: 900;
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
padding: 1rem clamp(1rem, 3vw, 2rem);
border-bottom: 1px solid var(--admin-border);
background: rgba(245, 247, 251, 0.9);
backdrop-filter: blur(14px);
}
.topbar-title {
display: flex;
align-items: center;
gap: 0.9rem;
}
.menu-toggle,
.profile-button {
width: 2.75rem;
height: 2.75rem;
}
.eyebrow {
margin-bottom: 0.2rem;
color: var(--admin-primary);
font-size: 0.76rem;
font-weight: 850;
letter-spacing: 0.14em;
text-transform: uppercase;
}
.topbar h1 {
margin-bottom: 0;
font-size: clamp(1.4rem, 3vw, 1.9rem);
}
.topbar-actions {
display: flex;
align-items: center;
gap: 0.75rem;
}
.search-box {
display: flex;
align-items: center;
gap: 0.55rem;
min-width: min(260px, 34vw);
padding: 0.65rem 0.8rem;
border: 1px solid var(--admin-border);
border-radius: 999px;
background: #ffffff;
color: var(--admin-muted);
}
.search-box input {
width: 100%;
border: 0;
outline: 0;
background: transparent;
color: var(--admin-text);
}
.date-pill {
display: inline-flex;
align-items: center;
white-space: nowrap;
padding: 0.65rem 0.85rem;
border: 1px solid var(--admin-border);
border-radius: 999px;
background: #ffffff;
color: var(--admin-muted);
font-size: 0.9rem;
font-weight: 750;
}
.dashboard-main {
display: grid;
gap: 1.5rem;
padding: clamp(1rem, 3vw, 2rem);
}
.kpi-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 1rem;
scroll-margin-top: 6rem;
}
.kpi-card,
.panel-card {
border: 1px solid var(--admin-border);
border-radius: var(--admin-radius);
background: var(--admin-surface);
box-shadow: var(--admin-shadow);
}
.kpi-card {
display: flex;
align-items: flex-start;
gap: 1rem;
padding: 1.2rem;
}
.kpi-icon {
display: grid;
width: 3rem;
height: 3rem;
place-content: center;
flex: 0 0 auto;
border-radius: 1rem;
color: #ffffff;
}
.kpi-icon.revenue {
background: linear-gradient(135deg, var(--admin-primary), var(--admin-info));
}
.kpi-icon.users {
background: linear-gradient(135deg, #7c3aed, #a78bfa);
}
.kpi-icon.orders {
background: linear-gradient(135deg, var(--admin-success), #86efac);
}
.kpi-icon.issues {
background: linear-gradient(135deg, var(--admin-warning), #facc15);
}
.kpi-card p {
margin-bottom: 0.2rem;
color: var(--admin-muted);
font-weight: 750;
}
.kpi-card strong {
display: block;
color: var(--admin-text);
font-size: 1.65rem;
font-weight: 850;
letter-spacing: -0.045em;
}
.trend {
display: inline-flex;
align-items: center;
gap: 0.35rem;
margin-top: 0.35rem;
font-size: 0.86rem;
font-weight: 800;
}
.trend.positive {
color: var(--admin-success);
}
.trend.negative {
color: var(--admin-danger);
}
.chart-section,
.details-grid,
.panel-card {
scroll-margin-top: 6rem;
}
.panel-card {
padding: clamp(1rem, 3vw, 1.35rem);
}
.panel-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 1rem;
margin-bottom: 1.25rem;
}
.panel-header.compact {
margin-bottom: 1rem;
}
.panel-header h2 {
margin-bottom: 0;
font-size: clamp(1.2rem, 2.4vw, 1.45rem);
}
.panel-badge {
padding: 0.45rem 0.75rem;
border-radius: 999px;
background: #eff6ff;
color: var(--admin-primary);
font-size: 0.85rem;
font-weight: 800;
white-space: nowrap;
}
.chart-wrapper {
position: relative;
width: 100%;
min-height: 310px;
}
.small-chart {
min-height: 300px;
}
#salesChart,
#trafficChart {
width: 100% !important;
height: 300px !important;
}
.chart-fallback {
margin: 0;
padding: 1rem;
border-radius: 1rem;
background: #eff6ff;
color: var(--admin-muted);
font-weight: 750;
}
.details-grid {
display: grid;
grid-template-columns: minmax(0, 1fr) 360px;
gap: 1.5rem;
}
.orders-table {
margin-bottom: 0;
}
.orders-table th {
color: var(--admin-muted);
font-size: 0.78rem;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.orders-table td,
.orders-table th {
padding: 0.9rem 0.75rem;
border-color: var(--admin-border);
}
.status-badge {
display: inline-flex;
padding: 0.3rem 0.6rem;
border-radius: 999px;
font-size: 0.78rem;
font-weight: 850;
}
.status-badge.success {
background: #dcfce7;
color: #166534;
}
.status-badge.warning {
background: #fef3c7;
color: #92400e;
}
.status-badge.neutral {
background: #e0f2fe;
color: #075985;
}
.table-status {
margin: 1rem 0 0;
color: var(--admin-muted);
font-size: 0.9rem;
font-weight: 750;
}
.text-link {
color: var(--admin-primary);
font-weight: 800;
text-decoration: none;
}
.text-link:hover,
.text-link:focus {
color: var(--admin-primary-dark);
text-decoration: underline;
}
.side-panels {
display: grid;
gap: 1rem;
}
.activity-list {
display: grid;
gap: 1rem;
margin: 0;
padding: 0;
list-style: none;
}
.activity-list li {
display: flex;
gap: 0.75rem;
}
.activity-list p {
margin-bottom: 0;
color: var(--admin-muted);
font-size: 0.92rem;
}
.activity-dot {
width: 0.75rem;
height: 0.75rem;
margin-top: 0.45rem;
border-radius: 50%;
flex: 0 0 auto;
}
.activity-dot.blue {
background: var(--admin-primary);
}
.activity-dot.green {
background: var(--admin-success);
}
.activity-dot.orange {
background: var(--admin-warning);
}
.quick-actions {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0.7rem;
}
.quick-actions button {
display: grid;
place-items: center;
gap: 0.4rem;
min-height: 5.2rem;
border: 1px solid var(--admin-border);
border-radius: 1rem;
background: #f8fafc;
color: var(--admin-text);
font-weight: 800;
}
.quick-actions button:hover,
.quick-actions button:focus {
border-color: var(--admin-primary);
color: var(--admin-primary);
}
.site-footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
margin-top: auto;
padding: 1.2rem clamp(1rem, 3vw, 2rem);
border-top: 1px solid var(--admin-border);
color: var(--admin-muted);
font-size: 0.92rem;
}
.site-footer p {
margin-bottom: 0;
}
.site-footer a {
color: var(--admin-primary);
font-weight: 800;
text-decoration: none;
}
.site-footer a:hover,
.site-footer a:focus {
text-decoration: underline;
}
.admin-dashboard a:focus-visible,
.admin-dashboard button:focus-visible,
.admin-dashboard input:focus-visible {
outline: 3px solid rgba(37, 99, 235, 0.35);
outline-offset: 3px;
}
@media (max-width: 1199.98px) {
.kpi-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.details-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 991.98px) {
.admin-dashboard {
display: block;
}
.dashboard-sidebar {
position: fixed;
left: 0;
top: 0;
transform: translateX(-105%);
transition: transform 0.25s ease;
}
.dashboard-sidebar.is-open {
transform: translateX(0);
}
.topbar {
align-items: flex-start;
flex-direction: column;
}
.topbar-actions {
width: 100%;
flex-wrap: wrap;
}
.search-box {
min-width: 100%;
}
}
@media (max-width: 575.98px) {
.kpi-grid,
.quick-actions {
grid-template-columns: 1fr;
}
.panel-header,
.site-footer {
flex-direction: column;
align-items: flex-start;
}
.dashboard-sidebar {
width: min(86vw, 300px);
min-width: min(86vw, 300px);
}
}
@media (prefers-reduced-motion: reduce) {
html {
scroll-behavior: auto;
}
.admin-dashboard *,
.admin-dashboard *::before,
.admin-dashboard *::after {
animation-duration: 0.001ms !important;
transition-duration: 0.001ms !important;
}
}document.addEventListener("DOMContentLoaded", function () {
"use strict";
const dashboard = document.querySelector(".admin-dashboard");
if (!dashboard) return;
const sidebar = dashboard.querySelector("#sidebarMenu");
const sidebarBackdrop = dashboard.querySelector(".sidebar-backdrop");
const menuToggle = dashboard.querySelector(".menu-toggle");
const sidebarClose = dashboard.querySelector(".sidebar-close");
const navLinks = Array.from(dashboard.querySelectorAll(".sidebar-nav .nav-link"));
const year = dashboard.querySelector("#currentYear");
const orderSearch = dashboard.querySelector("#orderSearch");
const orderRows = Array.from(dashboard.querySelectorAll(".orders-table tbody tr"));
const tableStatus = dashboard.querySelector(".table-status");
const salesCanvas = dashboard.querySelector("#salesChart");
const trafficCanvas = dashboard.querySelector("#trafficChart");
const salesFallback = dashboard.querySelector("#salesChartFallback");
const trafficFallback = dashboard.querySelector("#trafficChartFallback");
const placeholderLinks = Array.from(dashboard.querySelectorAll("a[href='#']"));
if (year) {
year.textContent = String(new Date().getFullYear());
}
placeholderLinks.forEach(function (link) {
link.addEventListener("click", function (event) {
event.preventDefault();
});
});
function openSidebar() {
if (!sidebar || !menuToggle) return;
sidebar.classList.add("is-open");
menuToggle.setAttribute("aria-expanded", "true");
menuToggle.setAttribute("aria-label", "Close navigation menu");
if (sidebarBackdrop) sidebarBackdrop.hidden = false;
}
function closeSidebar() {
if (!sidebar || !menuToggle) return;
sidebar.classList.remove("is-open");
menuToggle.setAttribute("aria-expanded", "false");
menuToggle.setAttribute("aria-label", "Open navigation menu");
if (sidebarBackdrop) sidebarBackdrop.hidden = true;
}
if (menuToggle) {
menuToggle.addEventListener("click", function () {
if (sidebar && sidebar.classList.contains("is-open")) {
closeSidebar();
} else {
openSidebar();
}
});
}
if (sidebarClose) {
sidebarClose.addEventListener("click", closeSidebar);
}
if (sidebarBackdrop) {
sidebarBackdrop.addEventListener("click", closeSidebar);
}
document.addEventListener("keydown", function (event) {
if (event.key === "Escape") closeSidebar();
});
navLinks.forEach(function (link) {
link.addEventListener("click", function () {
navLinks.forEach(function (currentLink) {
currentLink.classList.remove("active");
currentLink.removeAttribute("aria-current");
});
link.classList.add("active");
link.setAttribute("aria-current", "page");
closeSidebar();
});
});
function normalize(value) {
return String(value || "").toLowerCase().trim();
}
function updateOrderRows() {
const query = normalize(orderSearch ? orderSearch.value : "");
let visibleCount = 0;
orderRows.forEach(function (row) {
const searchable = normalize(row.getAttribute("data-search")) + " " + normalize(row.textContent);
const shouldShow = !query || searchable.indexOf(query) !== -1;
row.hidden = !shouldShow;
if (shouldShow) visibleCount += 1;
});
if (tableStatus) {
tableStatus.textContent = visibleCount === 1 ? "Showing 1 order." : "Showing " + visibleCount + " orders.";
}
}
if (orderSearch) {
orderSearch.addEventListener("input", updateOrderRows);
}
function showChartFallback(canvas, fallback) {
if (canvas) canvas.hidden = true;
if (fallback) fallback.hidden = false;
}
function createCharts() {
if (typeof Chart === "undefined") {
showChartFallback(salesCanvas, salesFallback);
showChartFallback(trafficCanvas, trafficFallback);
return;
}
Chart.defaults.font.family = "Inter, Segoe UI, Roboto, Arial, sans-serif";
Chart.defaults.color = "#64748b";
if (salesCanvas) {
const salesContext = salesCanvas.getContext("2d");
const gradient = salesContext.createLinearGradient(0, 0, 0, 300);
gradient.addColorStop(0, "rgba(37, 99, 235, 0.24)");
gradient.addColorStop(1, "rgba(37, 99, 235, 0.02)");
new Chart(salesContext, {
type: "line",
data: {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
datasets: [
{
label: "Revenue",
data: [42, 48, 46, 57, 63, 71, 76, 82, 91, 98, 112, 128],
borderColor: "#2563eb",
backgroundColor: gradient,
pointBackgroundColor: "#2563eb",
pointBorderColor: "#ffffff",
pointBorderWidth: 2,
pointRadius: 4,
pointHoverRadius: 6,
borderWidth: 3,
tension: 0.36,
fill: true
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
interaction: {
mode: "index",
intersect: false
},
plugins: {
legend: {
display: false
},
tooltip: {
callbacks: {
label: function (context) {
return "Revenue: $" + context.parsed.y + "K";
}
}
}
},
scales: {
x: {
grid: {
display: false
}
},
y: {
beginAtZero: true,
ticks: {
callback: function (value) {
return "$" + value + "K";
}
},
grid: {
color: "rgba(100, 116, 139, 0.16)"
}
}
}
}
});
}
if (trafficCanvas) {
new Chart(trafficCanvas, {
type: "doughnut",
data: {
labels: ["Organic", "Referral", "Social", "Email"],
datasets: [
{
data: [52, 18, 21, 9],
backgroundColor: ["#2563eb", "#06b6d4", "#16a34a", "#f59e0b"],
borderColor: "#ffffff",
borderWidth: 4,
hoverOffset: 8
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
cutout: "68%",
plugins: {
legend: {
position: "bottom",
labels: {
boxWidth: 12,
padding: 16,
usePointStyle: true
}
},
tooltip: {
callbacks: {
label: function (context) {
return context.label + ": " + context.parsed + "%";
}
}
}
}
}
});
}
}
if ("IntersectionObserver" in window && navLinks.length) {
const sections = navLinks
.map(function (link) {
const href = link.getAttribute("href");
return href && href.startsWith("#") ? dashboard.querySelector(href) : null;
})
.filter(Boolean);
const observer = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
navLinks.forEach(function (link) {
const isActive = link.getAttribute("href") === "#" + entry.target.id;
link.classList.toggle("active", isActive);
if (isActive) {
link.setAttribute("aria-current", "page");
} else {
link.removeAttribute("aria-current");
}
});
}
});
}, { rootMargin: "-30% 0px -55% 0px", threshold: 0.05 });
sections.forEach(function (section) {
observer.observe(section);
});
}
createCharts();
updateOrderRows();
});