699 lines
23 KiB
HTML
699 lines
23 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Pi-hole Dashboard</title>
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
:root {
|
||
--bg-dark: #1a1a1a;
|
||
--bg-sidebar: #222;
|
||
--bg-card: #2a2a2a;
|
||
--border-color: #333;
|
||
--text-primary: #e0e0e0;
|
||
--text-secondary: #888;
|
||
--pihole-red: #96060c;
|
||
--pihole-green: #4caf50;
|
||
--pihole-blue: #3c8dbc;
|
||
--pihole-yellow: #f39c12;
|
||
}
|
||
|
||
body {
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||
background: var(--bg-dark);
|
||
color: var(--text-primary);
|
||
font-size: 14px;
|
||
min-height: 100vh;
|
||
}
|
||
|
||
/* Demo Banner */
|
||
.demo-banner {
|
||
background: #1a1a1a;
|
||
color: var(--text-secondary);
|
||
text-align: center;
|
||
padding: 8px;
|
||
font-size: 12px;
|
||
border-bottom: 1px solid var(--border-color);
|
||
}
|
||
|
||
.demo-banner a {
|
||
color: var(--pihole-red);
|
||
text-decoration: none;
|
||
}
|
||
|
||
/* Layout */
|
||
.container {
|
||
display: flex;
|
||
min-height: calc(100vh - 33px);
|
||
}
|
||
|
||
/* Sidebar */
|
||
.sidebar {
|
||
width: 200px;
|
||
background: var(--bg-sidebar);
|
||
border-right: 1px solid var(--border-color);
|
||
}
|
||
|
||
.sidebar-header {
|
||
background: linear-gradient(180deg, #3c8dbc 0%, #357ca5 100%);
|
||
padding: 16px;
|
||
text-align: center;
|
||
}
|
||
|
||
.sidebar-header h1 {
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
color: white;
|
||
}
|
||
|
||
.status-box {
|
||
padding: 16px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
}
|
||
|
||
.pihole-logo {
|
||
width: 50px;
|
||
height: 50px;
|
||
background: var(--pihole-red);
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 28px;
|
||
position: relative;
|
||
}
|
||
|
||
.pihole-logo::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: -5px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 20px;
|
||
height: 15px;
|
||
background: var(--pihole-green);
|
||
border-radius: 10px 10px 0 0;
|
||
}
|
||
|
||
.status-info {
|
||
flex: 1;
|
||
}
|
||
|
||
.status-title {
|
||
font-size: 12px;
|
||
color: var(--text-secondary);
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.status-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
font-size: 11px;
|
||
color: var(--text-secondary);
|
||
margin-bottom: 2px;
|
||
}
|
||
|
||
.status-dot {
|
||
width: 8px;
|
||
height: 8px;
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.status-dot.active {
|
||
background: var(--pihole-green);
|
||
}
|
||
|
||
.nav-menu {
|
||
padding: 8px 0;
|
||
}
|
||
|
||
.nav-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
padding: 10px 16px;
|
||
color: var(--text-secondary);
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.nav-item:hover {
|
||
background: #2a2a2a;
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.nav-item.active {
|
||
background: #2a2a2a;
|
||
color: white;
|
||
border-left: 3px solid var(--pihole-red);
|
||
}
|
||
|
||
.nav-icon {
|
||
width: 18px;
|
||
text-align: center;
|
||
}
|
||
|
||
.nav-arrow {
|
||
margin-left: auto;
|
||
font-size: 10px;
|
||
}
|
||
|
||
/* Main Content */
|
||
.content {
|
||
flex: 1;
|
||
padding: 20px;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.top-bar {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.hostname {
|
||
color: var(--text-secondary);
|
||
font-size: 13px;
|
||
}
|
||
|
||
/* Stats Cards */
|
||
.stats-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 16px;
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.stat-card {
|
||
background: var(--bg-card);
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
position: relative;
|
||
overflow: hidden;
|
||
min-height: 120px;
|
||
}
|
||
|
||
.stat-card.blue {
|
||
background: linear-gradient(135deg, #3c8dbc 0%, #2c6da0 100%);
|
||
}
|
||
|
||
.stat-card.red {
|
||
background: linear-gradient(135deg, #c0392b 0%, #962d22 100%);
|
||
}
|
||
|
||
.stat-card.yellow {
|
||
background: linear-gradient(135deg, #f39c12 0%, #c27a0e 100%);
|
||
}
|
||
|
||
.stat-card.green {
|
||
background: linear-gradient(135deg, #27ae60 0%, #1e8449 100%);
|
||
}
|
||
|
||
.stat-bg-icon {
|
||
position: absolute;
|
||
right: -10px;
|
||
bottom: -10px;
|
||
font-size: 80px;
|
||
opacity: 0.2;
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: 13px;
|
||
color: rgba(255,255,255,0.9);
|
||
margin-bottom: 8px;
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.stat-value {
|
||
font-size: 36px;
|
||
font-weight: 600;
|
||
color: white;
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.stat-link {
|
||
position: absolute;
|
||
bottom: 12px;
|
||
left: 20px;
|
||
right: 20px;
|
||
font-size: 12px;
|
||
color: rgba(255,255,255,0.8);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
cursor: pointer;
|
||
z-index: 1;
|
||
}
|
||
|
||
.stat-link:hover {
|
||
color: white;
|
||
}
|
||
|
||
/* Charts */
|
||
.chart-card {
|
||
background: var(--bg-card);
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.chart-title {
|
||
font-size: 15px;
|
||
margin-bottom: 16px;
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.chart-area {
|
||
height: 200px;
|
||
position: relative;
|
||
}
|
||
|
||
/* Bar Chart */
|
||
.bar-chart {
|
||
display: flex;
|
||
align-items: flex-end;
|
||
justify-content: space-between;
|
||
height: 160px;
|
||
padding: 0 4px;
|
||
position: relative;
|
||
}
|
||
|
||
.bar-chart::before {
|
||
content: '';
|
||
position: absolute;
|
||
left: 0;
|
||
right: 0;
|
||
top: 0;
|
||
bottom: 0;
|
||
background:
|
||
linear-gradient(to bottom, transparent 19px, #333 20px),
|
||
linear-gradient(to right, transparent 19px, transparent 20px);
|
||
background-size: 100% 40px, 40px 100%;
|
||
opacity: 0.3;
|
||
}
|
||
|
||
.bar-group {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 2px;
|
||
height: 100%;
|
||
justify-content: flex-end;
|
||
position: relative;
|
||
}
|
||
|
||
.bar {
|
||
width: 6px;
|
||
border-radius: 2px 2px 0 0;
|
||
}
|
||
|
||
.bar.permitted {
|
||
background: #666;
|
||
}
|
||
|
||
.bar.blocked {
|
||
background: var(--pihole-green);
|
||
}
|
||
|
||
.bar.client {
|
||
width: 4px;
|
||
}
|
||
|
||
.chart-axis {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
padding: 8px 4px 0;
|
||
font-size: 11px;
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
.chart-axis-y {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
bottom: 24px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
font-size: 11px;
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
/* Pie Charts Grid */
|
||
.pie-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 20px;
|
||
}
|
||
|
||
.pie-chart-container {
|
||
display: flex;
|
||
gap: 20px;
|
||
}
|
||
|
||
.pie-chart {
|
||
width: 150px;
|
||
height: 150px;
|
||
position: relative;
|
||
}
|
||
|
||
.pie-chart svg {
|
||
width: 100%;
|
||
height: 100%;
|
||
transform: rotate(-90deg);
|
||
}
|
||
|
||
.pie-legend {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
justify-content: center;
|
||
}
|
||
|
||
.legend-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
font-size: 12px;
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
.legend-color {
|
||
width: 12px;
|
||
height: 12px;
|
||
border-radius: 2px;
|
||
}
|
||
|
||
.legend-checkbox {
|
||
width: 14px;
|
||
height: 14px;
|
||
accent-color: var(--pihole-blue);
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="demo-banner">
|
||
🔒 This is a dummy dashboard for showcase purposes only. <a href="/">← Back to Dashboard</a>
|
||
</div>
|
||
|
||
<div class="container">
|
||
<!-- Sidebar -->
|
||
<aside class="sidebar">
|
||
<div class="sidebar-header">
|
||
<h1>Pi-hole</h1>
|
||
</div>
|
||
|
||
<div class="status-box">
|
||
<div class="pihole-logo">🕳️</div>
|
||
<div class="status-info">
|
||
<div class="status-title">Status</div>
|
||
<div class="status-item">
|
||
<span class="status-dot active"></span>
|
||
<span>Active</span>
|
||
</div>
|
||
<div class="status-item">
|
||
<span class="status-dot active"></span>
|
||
<span>Load: 0.12 0.15 0.18</span>
|
||
</div>
|
||
<div class="status-item">
|
||
<span class="status-dot active"></span>
|
||
<span>Memory usage: 12.4%</span>
|
||
</div>
|
||
<div class="status-item">
|
||
<span>🌡️ Temp: 42.0 °C</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<nav class="nav-menu">
|
||
<div class="nav-item active">
|
||
<span class="nav-icon">🏠</span>
|
||
<span>Dashboard</span>
|
||
</div>
|
||
<div class="nav-item">
|
||
<span class="nav-icon">📋</span>
|
||
<span>Query Log</span>
|
||
</div>
|
||
<div class="nav-item">
|
||
<span class="nav-icon">📊</span>
|
||
<span>Long-term Data</span>
|
||
<span class="nav-arrow">›</span>
|
||
</div>
|
||
<div class="nav-item">
|
||
<span class="nav-icon">👥</span>
|
||
<span>Groups</span>
|
||
</div>
|
||
<div class="nav-item">
|
||
<span class="nav-icon">🖥️</span>
|
||
<span>Clients</span>
|
||
</div>
|
||
<div class="nav-item">
|
||
<span class="nav-icon">🌐</span>
|
||
<span>Domains</span>
|
||
</div>
|
||
<div class="nav-item">
|
||
<span class="nav-icon">🛡️</span>
|
||
<span>Adlists</span>
|
||
</div>
|
||
<div class="nav-item">
|
||
<span class="nav-icon">⏸️</span>
|
||
<span>Disable Blocking</span>
|
||
<span class="nav-arrow">›</span>
|
||
</div>
|
||
<div class="nav-item">
|
||
<span class="nav-icon">📝</span>
|
||
<span>Local DNS</span>
|
||
<span class="nav-arrow">›</span>
|
||
</div>
|
||
<div class="nav-item">
|
||
<span class="nav-icon">🔧</span>
|
||
<span>Tools</span>
|
||
<span class="nav-arrow">›</span>
|
||
</div>
|
||
<div class="nav-item">
|
||
<span class="nav-icon">⚙️</span>
|
||
<span>Settings</span>
|
||
</div>
|
||
<div class="nav-item">
|
||
<span class="nav-icon">❤️</span>
|
||
<span>Donate</span>
|
||
</div>
|
||
</nav>
|
||
</aside>
|
||
|
||
<!-- Main Content -->
|
||
<main class="content">
|
||
<div class="top-bar">
|
||
<button style="background: transparent; border: none; color: var(--text-secondary); font-size: 18px; cursor: pointer;">‹</button>
|
||
<span class="hostname">hostname: pihole</span>
|
||
<button style="background: transparent; border: none; color: var(--text-secondary); font-size: 18px; cursor: pointer;">☰</button>
|
||
</div>
|
||
|
||
<!-- Stats Cards -->
|
||
<div class="stats-grid">
|
||
<div class="stat-card blue">
|
||
<div class="stat-bg-icon">🌍</div>
|
||
<div class="stat-label">Total queries</div>
|
||
<div class="stat-value">73,770</div>
|
||
<div class="stat-link">
|
||
<span>23 active clients</span>
|
||
<span>›</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="stat-card red">
|
||
<div class="stat-bg-icon">🛡️</div>
|
||
<div class="stat-label">Queries Blocked</div>
|
||
<div class="stat-value">17,304</div>
|
||
<div class="stat-link">
|
||
<span>List blocked queries</span>
|
||
<span>›</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="stat-card yellow">
|
||
<div class="stat-bg-icon">📊</div>
|
||
<div class="stat-label">Percentage Blocked</div>
|
||
<div class="stat-value">23.5%</div>
|
||
<div class="stat-link">
|
||
<span>List all queries</span>
|
||
<span>›</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="stat-card green">
|
||
<div class="stat-bg-icon">📋</div>
|
||
<div class="stat-label">Domains on Adlists</div>
|
||
<div class="stat-value">254,501</div>
|
||
<div class="stat-link">
|
||
<span>Manage adlists</span>
|
||
<span>›</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Total Queries Chart -->
|
||
<div class="chart-card">
|
||
<div class="chart-title">Total queries over last 24 hours</div>
|
||
<div class="chart-area">
|
||
<div class="chart-axis-y">
|
||
<span>1,200</span>
|
||
<span>1,000</span>
|
||
<span>800</span>
|
||
<span>600</span>
|
||
<span>400</span>
|
||
<span>200</span>
|
||
<span>0</span>
|
||
</div>
|
||
<div class="bar-chart" style="margin-left: 40px;">
|
||
<script>
|
||
// Generate bars
|
||
const hours = ['13:00','14:00','15:00','16:00','17:00','18:00','19:00','20:00','21:00','22:00','23:00','00:00','01:00','02:00','03:00','04:00','05:00','06:00','07:00','08:00','09:00','10:00','11:00','12:00'];
|
||
hours.forEach((hour, i) => {
|
||
const h1 = 30 + Math.random() * 50;
|
||
const h2 = 50 + Math.random() * 70;
|
||
document.write(`
|
||
<div class="bar-group">
|
||
<div class="bar permitted" style="height: ${h1}%;"></div>
|
||
<div class="bar blocked" style="height: ${h2}%;"></div>
|
||
</div>
|
||
`);
|
||
});
|
||
</script>
|
||
</div>
|
||
</div>
|
||
<div class="chart-axis">
|
||
<script>
|
||
hours.forEach(hour => document.write(`<span>${hour}</span>`));
|
||
</script>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Client Activity Chart -->
|
||
<div class="chart-card">
|
||
<div class="chart-title">Client activity over last 24 hours</div>
|
||
<div class="chart-area">
|
||
<div class="chart-axis-y">
|
||
<span>1,200</span>
|
||
<span>1,000</span>
|
||
<span>800</span>
|
||
<span>600</span>
|
||
<span>400</span>
|
||
<span>200</span>
|
||
<span>0</span>
|
||
</div>
|
||
<div class="bar-chart" style="margin-left: 40px;">
|
||
<script>
|
||
hours.forEach((hour, i) => {
|
||
const colors = ['#9c27b0', '#e91e63', '#00bcd4', '#ff9800', '#4caf50'];
|
||
document.write(`<div class="bar-group">`);
|
||
colors.forEach(color => {
|
||
const h = 20 + Math.random() * 60;
|
||
document.write(`<div class="bar client" style="height: ${h}%; background: ${color}; width: 2px;"></div>`);
|
||
});
|
||
document.write(`</div>`);
|
||
});
|
||
</script>
|
||
</div>
|
||
</div>
|
||
<div class="chart-axis">
|
||
<script>
|
||
hours.forEach(hour => document.write(`<span>${hour}</span>`));
|
||
</script>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Pie Charts -->
|
||
<div class="pie-grid">
|
||
<div class="chart-card">
|
||
<div class="chart-title">Query Types</div>
|
||
<div class="pie-chart-container">
|
||
<div class="pie-chart">
|
||
<svg viewBox="0 0 100 100">
|
||
<circle cx="50" cy="50" r="40" fill="none" stroke="#ff7043" stroke-width="20" stroke-dasharray="100 251"/>
|
||
<circle cx="50" cy="50" r="40" fill="none" stroke="#42a5f5" stroke-width="20" stroke-dasharray="60 251" stroke-dashoffset="-100"/>
|
||
<circle cx="50" cy="50" r="40" fill="none" stroke="#66bb6a" stroke-width="20" stroke-dasharray="40 251" stroke-dashoffset="-160"/>
|
||
<circle cx="50" cy="50" r="40" fill="none" stroke="#ab47bc" stroke-width="20" stroke-dasharray="30 251" stroke-dashoffset="-200"/>
|
||
<circle cx="50" cy="50" r="40" fill="none" stroke="#26c6da" stroke-width="20" stroke-dasharray="21 251" stroke-dashoffset="-230"/>
|
||
</svg>
|
||
</div>
|
||
<div class="pie-legend">
|
||
<label class="legend-item">
|
||
<input type="checkbox" class="legend-checkbox" checked>
|
||
<div class="legend-color" style="background: #ff7043;"></div>
|
||
<span>A (IPv4)</span>
|
||
</label>
|
||
<label class="legend-item">
|
||
<input type="checkbox" class="legend-checkbox" checked>
|
||
<div class="legend-color" style="background: #42a5f5;"></div>
|
||
<span>AAAA (IPv6)</span>
|
||
</label>
|
||
<label class="legend-item">
|
||
<input type="checkbox" class="legend-checkbox" checked>
|
||
<div class="legend-color" style="background: #66bb6a;"></div>
|
||
<span>SRV</span>
|
||
</label>
|
||
<label class="legend-item">
|
||
<input type="checkbox" class="legend-checkbox" checked>
|
||
<div class="legend-color" style="background: #ab47bc;"></div>
|
||
<span>SOA</span>
|
||
</label>
|
||
<label class="legend-item">
|
||
<input type="checkbox" class="legend-checkbox" checked>
|
||
<div class="legend-color" style="background: #26c6da;"></div>
|
||
<span>PTR</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="chart-card">
|
||
<div class="chart-title">Upstream servers</div>
|
||
<div class="pie-chart-container">
|
||
<div class="pie-chart">
|
||
<svg viewBox="0 0 100 100">
|
||
<circle cx="50" cy="50" r="40" fill="none" stroke="#ff7043" stroke-width="20" stroke-dasharray="120 251"/>
|
||
<circle cx="50" cy="50" r="40" fill="none" stroke="#42a5f5" stroke-width="20" stroke-dasharray="80 251" stroke-dashoffset="-120"/>
|
||
<circle cx="50" cy="50" r="40" fill="none" stroke="#66bb6a" stroke-width="20" stroke-dasharray="51 251" stroke-dashoffset="-200"/>
|
||
</svg>
|
||
</div>
|
||
<div class="pie-legend">
|
||
<label class="legend-item">
|
||
<input type="checkbox" class="legend-checkbox" checked>
|
||
<div class="legend-color" style="background: #ff7043;"></div>
|
||
<span>blocked</span>
|
||
</label>
|
||
<label class="legend-item">
|
||
<input type="checkbox" class="legend-checkbox" checked>
|
||
<div class="legend-color" style="background: #42a5f5;"></div>
|
||
<span>cached</span>
|
||
</label>
|
||
<label class="legend-item">
|
||
<input type="checkbox" class="legend-checkbox" checked>
|
||
<div class="legend-color" style="background: #66bb6a;"></div>
|
||
<span>localhost#5335</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
</div>
|
||
</body>
|
||
</html>
|