Pages Hard
Analytics Page
A data-driven analytics dashboard with date range picker, area/funnel charts, heatmap, metric comparisons, and exportable data table. No libraries.
Open in Lab
MCP
vanilla-js css
Targets: JS HTML
Code
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background: #f3f4f6;
color: #1f2937;
line-height: 1.5;
min-height: 100vh;
}
/* โโ Top Nav โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.top-nav {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
padding: 0.75rem 1.5rem;
background: #fff;
border-bottom: 1px solid #e5e7eb;
position: sticky;
top: 0;
z-index: 50;
}
.nav-left {
display: flex;
align-items: center;
gap: 0.5rem;
}
.nav-logo {
color: #6366f1;
}
.nav-title {
font-size: 1.125rem;
font-weight: 600;
}
.date-range-selector {
display: flex;
gap: 0.25rem;
background: #f3f4f6;
border-radius: 0.5rem;
padding: 0.25rem;
}
.date-pill {
padding: 0.375rem 0.75rem;
border: none;
border-radius: 0.375rem;
background: transparent;
color: #6b7280;
font-size: 0.8125rem;
font-weight: 500;
cursor: pointer;
transition: all 0.15s ease;
white-space: nowrap;
}
.date-pill:hover {
color: #374151;
background: #e5e7eb;
}
.date-pill.active {
background: #6366f1;
color: #fff;
box-shadow: 0 1px 3px rgba(99, 102, 241, 0.35);
}
/* โโ Dashboard โโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.dashboard {
max-width: 1200px;
margin: 0 auto;
padding: 1.5rem;
display: flex;
flex-direction: column;
gap: 1.5rem;
}
/* โโ Metric Cards โโโโโโโโโโโโโโโโโโโโโโโโโ */
.metrics-row {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1rem;
}
.metric-card {
background: #fff;
border-radius: 0.75rem;
padding: 1.25rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.04);
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.metric-label {
font-size: 0.8125rem;
color: #6b7280;
font-weight: 500;
}
.metric-value {
font-size: 1.75rem;
font-weight: 700;
letter-spacing: -0.025em;
color: #111827;
}
.metric-trend {
font-size: 0.75rem;
display: flex;
align-items: center;
gap: 0.25rem;
color: #6b7280;
}
.metric-trend span {
font-weight: 600;
}
.trend-up span,
.trend-up svg {
color: #059669;
}
.trend-down span,
.trend-down svg {
color: #dc2626;
}
/* โโ Chart Cards โโโโโโโโโโโโโโโโโโโโโโโโโโ */
.chart-card {
background: #fff;
border-radius: 0.75rem;
padding: 1.5rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.04);
}
.chart-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 1rem;
}
.chart-title {
font-size: 1rem;
font-weight: 600;
color: #111827;
}
.chart-subtitle {
font-size: 0.8125rem;
color: #9ca3af;
margin-top: 0.125rem;
}
.chart-container {
width: 100%;
overflow-x: auto;
}
#areaChart {
width: 100%;
height: auto;
display: block;
}
/* โโ Two Column โโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.two-col {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5rem;
}
/* โโ Funnel โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.funnel-container {
display: flex;
flex-direction: column;
gap: 1rem;
}
.funnel-step {
display: flex;
flex-direction: column;
gap: 0.375rem;
}
.funnel-info {
display: flex;
justify-content: space-between;
font-size: 0.8125rem;
}
.funnel-label {
font-weight: 600;
color: #374151;
}
.funnel-count {
color: #6b7280;
}
.funnel-bar-track {
background: #f3f4f6;
border-radius: 0.375rem;
height: 2rem;
overflow: hidden;
}
.funnel-bar {
height: 100%;
border-radius: 0.375rem;
display: flex;
align-items: center;
padding-left: 0.75rem;
font-size: 0.75rem;
font-weight: 600;
color: #fff;
width: 0;
transition: width 0.8s cubic-bezier(0.22, 1, 0.36, 1);
}
.funnel-step:nth-child(1) .funnel-bar {
background: linear-gradient(90deg, #6366f1, #818cf8);
}
.funnel-step:nth-child(2) .funnel-bar {
background: linear-gradient(90deg, #7c3aed, #a78bfa);
}
.funnel-step:nth-child(3) .funnel-bar {
background: linear-gradient(90deg, #8b5cf6, #c4b5fd);
}
.funnel-step:nth-child(4) .funnel-bar {
background: linear-gradient(90deg, #a855f7, #d8b4fe);
}
/* โโ Heatmap โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.heatmap-wrapper {
display: flex;
flex-direction: column;
gap: 0.5rem;
overflow-x: auto;
}
.heatmap-days {
display: flex;
flex-direction: column;
gap: 0.125rem;
font-size: 0.625rem;
color: #9ca3af;
position: absolute;
margin-top: 0.125rem;
}
.heatmap-days span {
height: 13px;
line-height: 13px;
}
.heatmap-grid {
display: grid;
grid-template-rows: repeat(7, 13px);
grid-auto-flow: column;
grid-auto-columns: 13px;
gap: 2px;
padding-left: 2rem;
}
.heatmap-cell {
width: 11px;
height: 11px;
border-radius: 2px;
position: relative;
}
.heatmap-cell.level-0 {
background: #ebedf0;
}
.heatmap-cell.level-1 {
background: #9be9a8;
}
.heatmap-cell.level-2 {
background: #40c463;
}
.heatmap-cell.level-3 {
background: #216e39;
}
.heatmap-cell .tooltip {
display: none;
position: absolute;
bottom: calc(100% + 6px);
left: 50%;
transform: translateX(-50%);
background: #1f2937;
color: #fff;
font-size: 0.6875rem;
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
white-space: nowrap;
pointer-events: none;
z-index: 10;
}
.heatmap-cell:hover .tooltip {
display: block;
}
.heatmap-legend {
display: flex;
align-items: center;
gap: 0.25rem;
justify-content: flex-end;
font-size: 0.6875rem;
color: #9ca3af;
padding-right: 0.25rem;
}
.heatmap-legend .heatmap-cell {
cursor: default;
}
/* โโ Data Table โโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.table-wrap {
overflow-x: auto;
}
.data-table {
width: 100%;
border-collapse: collapse;
font-size: 0.875rem;
}
.data-table th {
text-align: left;
padding: 0.75rem 1rem;
font-weight: 600;
color: #6b7280;
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.05em;
border-bottom: 2px solid #e5e7eb;
white-space: nowrap;
}
.data-table td {
padding: 0.75rem 1rem;
border-bottom: 1px solid #f3f4f6;
color: #374151;
}
.data-table tbody tr:nth-child(even) {
background: #f9fafb;
}
.data-table tbody tr:hover {
background: #f3f4f6;
}
.data-table td:first-child {
font-weight: 500;
color: #6366f1;
}
/* โโ Export Button โโโโโโโโโโโโโโโโโโโโโโโโโโ */
.export-btn {
display: inline-flex;
align-items: center;
gap: 0.375rem;
padding: 0.5rem 0.875rem;
font-size: 0.8125rem;
font-weight: 500;
color: #374151;
background: #fff;
border: 1px solid #d1d5db;
border-radius: 0.5rem;
cursor: pointer;
transition: all 0.15s ease;
white-space: nowrap;
}
.export-btn:hover {
background: #f9fafb;
border-color: #9ca3af;
}
/* โโ Responsive โโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
@media (max-width: 1024px) {
.metrics-row {
grid-template-columns: repeat(2, 1fr);
}
.two-col {
grid-template-columns: 1fr;
}
}
@media (max-width: 640px) {
.top-nav {
flex-direction: column;
align-items: flex-start;
gap: 0.75rem;
padding: 0.75rem 1rem;
}
.date-range-selector {
width: 100%;
overflow-x: auto;
}
.metrics-row {
grid-template-columns: 1fr;
}
.dashboard {
padding: 1rem;
gap: 1rem;
}
.metric-value {
font-size: 1.5rem;
}
.chart-card {
padding: 1rem;
}
.chart-header {
flex-direction: column;
gap: 0.5rem;
}
}/* โโ Analytics Dashboard โ script.js โโโโโโโโโ */
(function () {
"use strict";
/* โโ Date Range Selector โโโโโโโโโโโโโโโโโโโโ */
const pills = document.querySelectorAll(".date-pill");
pills.forEach(function (pill) {
pill.addEventListener("click", function () {
pills.forEach(function (p) {
p.classList.remove("active");
});
pill.classList.add("active");
});
});
/* โโ Metric Card Number Animation โโโโโโโโโโโ */
function animateMetrics() {
var cards = document.querySelectorAll(".metric-card");
cards.forEach(function (card) {
var target = parseFloat(card.dataset.target);
var suffix = card.dataset.suffix || "";
var format = card.dataset.format || "";
var valueEl = card.querySelector(".metric-value");
var duration = 1200;
var start = performance.now();
function tick(now) {
var elapsed = now - start;
var progress = Math.min(elapsed / duration, 1);
var eased = 1 - Math.pow(1 - progress, 3);
var current = eased * target;
if (format === "duration") {
var mins = Math.floor(current / 60);
var secs = Math.floor(current % 60);
valueEl.textContent = mins + "m " + (secs < 10 ? "0" : "") + secs + "s";
} else if (suffix === "%") {
valueEl.textContent = current.toFixed(1) + "%";
} else {
valueEl.textContent = Math.floor(current).toLocaleString("en-US");
}
if (progress < 1) {
requestAnimationFrame(tick);
}
}
requestAnimationFrame(tick);
});
}
/* โโ Area Chart โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
function drawAreaChart() {
var canvas = document.getElementById("areaChart");
if (!canvas) return;
var dpr = window.devicePixelRatio || 1;
var rect = canvas.parentElement.getBoundingClientRect();
var w = rect.width;
var h = 300;
canvas.width = w * dpr;
canvas.height = h * dpr;
canvas.style.width = w + "px";
canvas.style.height = h + "px";
var ctx = canvas.getContext("2d");
ctx.scale(dpr, dpr);
var data = [
3200, 4100, 3800, 4600, 5200, 4900, 5800, 6100, 5400, 6800, 7200, 6500, 7800, 8100, 7400,
8600, 7900, 8200, 9100, 8400, 9600, 10200, 9800, 10800, 11200, 10400, 11800, 12400, 11600,
12800,
];
var labels = [];
var today = new Date();
for (var i = 29; i >= 0; i--) {
var d = new Date(today);
d.setDate(d.getDate() - i);
labels.push(d.getMonth() + 1 + "/" + d.getDate());
}
var padLeft = 50;
var padRight = 20;
var padTop = 20;
var padBottom = 40;
var chartW = w - padLeft - padRight;
var chartH = h - padTop - padBottom;
var maxVal = Math.max.apply(null, data) * 1.1;
var stepX = chartW / (data.length - 1);
function xPos(i) {
return padLeft + i * stepX;
}
function yPos(v) {
return padTop + chartH - (v / maxVal) * chartH;
}
// Grid lines
ctx.strokeStyle = "#f3f4f6";
ctx.lineWidth = 1;
var gridLines = 5;
for (var g = 0; g <= gridLines; g++) {
var gy = padTop + (chartH / gridLines) * g;
ctx.beginPath();
ctx.moveTo(padLeft, gy);
ctx.lineTo(w - padRight, gy);
ctx.stroke();
// Y-axis labels
var gridVal = Math.round(maxVal - (maxVal / gridLines) * g);
ctx.fillStyle = "#9ca3af";
ctx.font = "11px -apple-system, sans-serif";
ctx.textAlign = "right";
ctx.fillText(
gridVal >= 1000 ? (gridVal / 1000).toFixed(1) + "k" : gridVal.toString(),
padLeft - 8,
gy + 4
);
}
// Gradient fill
var gradient = ctx.createLinearGradient(0, padTop, 0, padTop + chartH);
gradient.addColorStop(0, "rgba(99, 102, 241, 0.25)");
gradient.addColorStop(1, "rgba(99, 102, 241, 0.02)");
ctx.beginPath();
ctx.moveTo(xPos(0), yPos(data[0]));
for (var j = 1; j < data.length; j++) {
ctx.lineTo(xPos(j), yPos(data[j]));
}
ctx.lineTo(xPos(data.length - 1), padTop + chartH);
ctx.lineTo(xPos(0), padTop + chartH);
ctx.closePath();
ctx.fillStyle = gradient;
ctx.fill();
// Line
ctx.beginPath();
ctx.moveTo(xPos(0), yPos(data[0]));
for (var k = 1; k < data.length; k++) {
ctx.lineTo(xPos(k), yPos(data[k]));
}
ctx.strokeStyle = "#6366f1";
ctx.lineWidth = 2;
ctx.lineJoin = "round";
ctx.stroke();
// Dots
for (var m = 0; m < data.length; m++) {
ctx.beginPath();
ctx.arc(xPos(m), yPos(data[m]), 3, 0, Math.PI * 2);
ctx.fillStyle = "#6366f1";
ctx.fill();
ctx.strokeStyle = "#fff";
ctx.lineWidth = 1.5;
ctx.stroke();
}
// X-axis labels (show every 5th)
ctx.fillStyle = "#9ca3af";
ctx.font = "11px -apple-system, sans-serif";
ctx.textAlign = "center";
for (var n = 0; n < labels.length; n++) {
if (n % 5 === 0 || n === labels.length - 1) {
ctx.fillText(labels[n], xPos(n), h - 10);
}
}
}
/* โโ Heatmap โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
function buildHeatmap() {
var grid = document.getElementById("heatmapGrid");
if (!grid) return;
var weeks = 52;
var daysPerWeek = 7;
var today = new Date();
var startDate = new Date(today);
startDate.setDate(startDate.getDate() - (weeks * daysPerWeek - 1));
// Seed a deterministic-looking random
function seededRandom(seed) {
var x = Math.sin(seed) * 10000;
return x - Math.floor(x);
}
for (var w = 0; w < weeks; w++) {
for (var d = 0; d < daysPerWeek; d++) {
var dayIndex = w * daysPerWeek + d;
var cellDate = new Date(startDate);
cellDate.setDate(cellDate.getDate() + dayIndex);
var rand = seededRandom(dayIndex * 31 + 7);
var count = Math.floor(rand * 20);
var level;
if (count === 0) level = 0;
else if (count <= 5) level = 1;
else if (count <= 12) level = 2;
else level = 3;
var cell = document.createElement("div");
cell.className = "heatmap-cell level-" + level;
var dateStr = cellDate.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
});
var tooltip = document.createElement("span");
tooltip.className = "tooltip";
tooltip.textContent = count + " contributions on " + dateStr;
cell.appendChild(tooltip);
grid.appendChild(cell);
}
}
}
/* โโ Funnel Animation โโโโโโโโโโโโโโโโโโโโโโโ */
function animateFunnel() {
var bars = document.querySelectorAll(".funnel-bar");
bars.forEach(function (bar, index) {
setTimeout(function () {
bar.style.width = bar.style.getPropertyValue("--target-width");
}, index * 150);
});
}
/* โโ CSV Export โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
function setupExport() {
var btn = document.getElementById("exportCsv");
if (!btn) return;
btn.addEventListener("click", function () {
var table = document.getElementById("pagesTable");
if (!table) return;
var rows = table.querySelectorAll("tr");
var csvContent = "";
rows.forEach(function (row) {
var cols = row.querySelectorAll("th, td");
var rowData = [];
cols.forEach(function (col) {
var text = col.textContent.replace(/"/g, '""');
rowData.push('"' + text + '"');
});
csvContent += rowData.join(",") + "\n";
});
var blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
var url = URL.createObjectURL(blob);
var link = document.createElement("a");
link.href = url;
link.download = "analytics-top-pages.csv";
link.style.display = "none";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
});
}
/* โโ Resize Handler โโโโโโโโโโโโโโโโโโโโโโโโโ */
var resizeTimer;
window.addEventListener("resize", function () {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(drawAreaChart, 200);
});
/* โโ Init โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
function init() {
animateMetrics();
drawAreaChart();
buildHeatmap();
animateFunnel();
setupExport();
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
})();<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Analytics Dashboard</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<!-- Top Nav -->
<nav class="top-nav">
<div class="nav-left">
<svg class="nav-logo" viewBox="0 0 24 24" width="28" height="28" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 3v18h18"/>
<path d="M7 16l4-8 4 4 4-6"/>
</svg>
<h1 class="nav-title">Analytics</h1>
</div>
<div class="date-range-selector" role="group" aria-label="Date range">
<button class="date-pill" data-range="7">Last 7 days</button>
<button class="date-pill active" data-range="30">Last 30 days</button>
<button class="date-pill" data-range="90">Last 90 days</button>
<button class="date-pill" data-range="custom">Custom</button>
</div>
</nav>
<main class="dashboard">
<!-- Metric Cards -->
<section class="metrics-row" aria-label="Key metrics">
<article class="metric-card" data-target="124892">
<p class="metric-label">Page Views</p>
<p class="metric-value" data-count="0">0</p>
<p class="metric-trend trend-up">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 11V3m0 0L3 7m4-4l4 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
<span>+18.2%</span> vs previous period
</p>
</article>
<article class="metric-card" data-target="45210">
<p class="metric-label">Sessions</p>
<p class="metric-value" data-count="0">0</p>
<p class="metric-trend trend-up">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 11V3m0 0L3 7m4-4l4 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
<span>+12.4%</span> vs previous period
</p>
</article>
<article class="metric-card" data-target="32.1" data-suffix="%">
<p class="metric-label">Bounce Rate</p>
<p class="metric-value" data-count="0">0%</p>
<p class="metric-trend trend-down">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 3v8m0 0l4-4m-4 4L3 7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
<span>-3.2%</span> vs previous period
</p>
</article>
<article class="metric-card" data-target="165" data-format="duration">
<p class="metric-label">Avg Duration</p>
<p class="metric-value" data-count="0">0s</p>
<p class="metric-trend trend-up">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 11V3m0 0L3 7m4-4l4 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
<span>+8.7%</span> vs previous period
</p>
</article>
</section>
<!-- Area Chart -->
<section class="chart-card" aria-label="Page views over time">
<header class="chart-header">
<h2 class="chart-title">Page Views</h2>
<p class="chart-subtitle">Daily page views over the selected period</p>
</header>
<div class="chart-container">
<canvas id="areaChart" width="900" height="300"></canvas>
</div>
</section>
<!-- Two-column: Funnel + Heatmap -->
<div class="two-col">
<!-- Conversion Funnel -->
<section class="chart-card" aria-label="Conversion funnel">
<header class="chart-header">
<h2 class="chart-title">Conversion Funnel</h2>
<p class="chart-subtitle">User journey from visit to paid</p>
</header>
<div class="funnel-container">
<div class="funnel-step" data-percent="100">
<div class="funnel-info">
<span class="funnel-label">Visits</span>
<span class="funnel-count">124,892</span>
</div>
<div class="funnel-bar-track">
<div class="funnel-bar" style="--target-width: 100%;">100%</div>
</div>
</div>
<div class="funnel-step" data-percent="24">
<div class="funnel-info">
<span class="funnel-label">Signups</span>
<span class="funnel-count">29,974</span>
</div>
<div class="funnel-bar-track">
<div class="funnel-bar" style="--target-width: 24%;">24%</div>
</div>
</div>
<div class="funnel-step" data-percent="12">
<div class="funnel-info">
<span class="funnel-label">Trial Start</span>
<span class="funnel-count">14,987</span>
</div>
<div class="funnel-bar-track">
<div class="funnel-bar" style="--target-width: 12%;">12%</div>
</div>
</div>
<div class="funnel-step" data-percent="4.8">
<div class="funnel-info">
<span class="funnel-label">Paid</span>
<span class="funnel-count">5,995</span>
</div>
<div class="funnel-bar-track">
<div class="funnel-bar" style="--target-width: 4.8%;">4.8%</div>
</div>
</div>
</div>
</section>
<!-- Activity Heatmap -->
<section class="chart-card" aria-label="Activity heatmap">
<header class="chart-header">
<h2 class="chart-title">Activity</h2>
<p class="chart-subtitle">Daily activity over the past year</p>
</header>
<div class="heatmap-wrapper">
<div class="heatmap-days">
<span>Mon</span><span>Wed</span><span>Fri</span>
</div>
<div class="heatmap-grid" id="heatmapGrid"></div>
<div class="heatmap-legend">
<span>Less</span>
<span class="heatmap-cell level-0"></span>
<span class="heatmap-cell level-1"></span>
<span class="heatmap-cell level-2"></span>
<span class="heatmap-cell level-3"></span>
<span>More</span>
</div>
</div>
</section>
</div>
<!-- Data Table -->
<section class="chart-card" aria-label="Top pages">
<header class="chart-header">
<div>
<h2 class="chart-title">Top Pages</h2>
<p class="chart-subtitle">Most visited pages in the selected period</p>
</div>
<button class="export-btn" id="exportCsv" type="button">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M2 11v2a1 1 0 001 1h10a1 1 0 001-1v-2M5 7l3 3 3-3M8 2v8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
Export CSV
</button>
</header>
<div class="table-wrap">
<table class="data-table" id="pagesTable">
<thead>
<tr>
<th>Page</th>
<th>Views</th>
<th>Unique Views</th>
<th>Bounce Rate</th>
<th>Avg Duration</th>
</tr>
</thead>
<tbody>
<tr><td>/</td><td>34,210</td><td>28,104</td><td>24.3%</td><td>3m 12s</td></tr>
<tr><td>/pricing</td><td>18,432</td><td>15,890</td><td>18.7%</td><td>4m 05s</td></tr>
<tr><td>/features</td><td>15,678</td><td>12,340</td><td>28.1%</td><td>2m 48s</td></tr>
<tr><td>/blog</td><td>12,905</td><td>10,218</td><td>42.5%</td><td>1m 55s</td></tr>
<tr><td>/docs/getting-started</td><td>11,240</td><td>9,870</td><td>15.2%</td><td>5m 30s</td></tr>
<tr><td>/about</td><td>8,764</td><td>7,102</td><td>35.8%</td><td>2m 10s</td></tr>
<tr><td>/contact</td><td>6,321</td><td>5,890</td><td>22.4%</td><td>1m 42s</td></tr>
<tr><td>/changelog</td><td>4,512</td><td>3,980</td><td>30.6%</td><td>2m 22s</td></tr>
</tbody>
</table>
</div>
</section>
</main>
<script src="script.js"></script>
</body>
</html>Analytics Page
A comprehensive analytics dashboard focused on data exploration. Features date range filtering, multiple chart types, metric comparison cards, and an exportable data table.
Features
- Date range picker โ preset ranges (7d, 30d, 90d, Custom) with calendar dropdown
- Metric comparison row โ 4 cards comparing current vs previous period with % change
- Area chart โ page views / sessions over time with gradient fill
- Funnel chart โ conversion funnel (Visits โ Signups โ Trial โ Paid)
- Activity heatmap โ GitHub-style contribution grid showing daily activity
- Data table โ top pages with views, bounce rate, avg duration, export CSV button
- Responsive โ stacks vertically on mobile
When to use it
- Web analytics dashboard
- Marketing performance reports
- Product usage analytics