dhruvsrawat's picture
Upload 8 files
e6dc045 verified
Raw
History Blame Contribute Delete
24.3 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Smart Waste Management System</title>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&display=swap" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--green: #16a34a;
--green-d: #064e3b;
--green-l: #dcfce7;
--blue: #2563eb;
--blue-l: #dbeafe;
--red: #dc2626;
--red-l: #fee2e2;
--gray: #6b7280;
--gray-l: #f3f4f6;
--bg: #f8faf8;
--surface: #ffffff;
--border: #e2ede2;
--text: #0d1a0d;
--muted: #6b7280;
}
body {
font-family: 'Plus Jakarta Sans', sans-serif;
background: var(--bg);
color: var(--text);
display: flex;
min-height: 100vh;
}
/* ── SIDEBAR ── */
.sidebar {
width: 230px;
min-height: 100vh;
background: var(--surface);
border-right: 1px solid var(--border);
padding: 28px 16px;
position: fixed;
top: 0; left: 0;
display: flex;
flex-direction: column;
gap: 4px;
z-index: 100;
}
.sidebar-logo {
text-align: center;
padding-bottom: 24px;
border-bottom: 1px solid var(--border);
margin-bottom: 16px;
}
.sidebar-logo .icon { font-size: 2.6rem; }
.sidebar-logo .name {
font-weight: 800;
font-size: 1rem;
color: var(--green-d);
margin-top: 6px;
}
.sidebar-logo .sub { font-size: 0.72rem; color: var(--muted); margin-top: 2px; }
.nav-btn {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 14px;
border-radius: 12px;
border: none;
background: transparent;
color: var(--muted);
font-family: inherit;
font-size: 0.9rem;
font-weight: 600;
cursor: pointer;
width: 100%;
text-align: left;
transition: background 0.15s, color 0.15s;
}
.nav-btn:hover { background: var(--green-l); color: var(--green-d); }
.nav-btn.active { background: var(--green-l); color: var(--green-d); }
.sidebar-footer {
margin-top: auto;
padding-top: 20px;
border-top: 1px solid var(--border);
font-size: 0.72rem;
color: #9ca3af;
line-height: 1.9;
}
/* ── MAIN ── */
.main {
margin-left: 230px;
flex: 1;
padding: 32px 36px;
max-width: calc(100vw - 230px);
}
/* ── PAGES ── */
.page { display: none; }
.page.active { display: block; }
/* ── HERO ── */
.hero {
background: linear-gradient(135deg, #064e3b 0%, #065f46 50%, #047857 100%);
border-radius: 22px;
padding: 52px 44px;
margin-bottom: 28px;
position: relative;
overflow: hidden;
}
.hero::before {
content: '';
position: absolute;
top: -70px; right: -70px;
width: 280px; height: 280px;
border-radius: 50%;
background: rgba(255,255,255,0.06);
pointer-events: none;
}
.hero::after {
content: '';
position: absolute;
bottom: -90px; left: 38%;
width: 200px; height: 200px;
border-radius: 50%;
background: rgba(255,255,255,0.04);
pointer-events: none;
}
.hero-badge {
display: inline-block;
background: rgba(255,255,255,0.18);
color: #d1fae5;
border: 1px solid rgba(255,255,255,0.28);
border-radius: 20px;
padding: 4px 16px;
font-size: 0.72rem;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
margin-bottom: 16px;
}
.hero h1 { font-size: 2.2rem; font-weight: 800; color: #fff; margin-bottom: 8px; line-height: 1.15; }
.hero p { color: #a7f3d0; font-size: 0.97rem; font-weight: 400; }
/* ── CARDS ── */
.card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 18px;
padding: 24px;
margin-bottom: 16px;
box-shadow: 0 2px 14px rgba(0,0,0,0.05);
}
/* ── GRID ── */
.grid-4 { display: grid; grid-template-columns: repeat(4,1fr); gap: 16px; margin-bottom: 24px; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; margin-bottom: 24px; }
/* ── CATEGORY CHIPS ── */
.chip {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 18px;
padding: 18px 10px;
text-align: center;
box-shadow: 0 2px 10px rgba(0,0,0,0.04);
}
.chip .c-icon { font-size: 1.8rem; }
.chip .c-name { font-weight: 700; font-size: 0.92rem; margin-top: 6px; }
.chip .c-sub { font-size: 0.72rem; color: var(--muted); }
/* ── STAT BOXES ── */
.stat-box {
background: linear-gradient(135deg, #064e3b, #047857);
border-radius: 18px;
padding: 26px 20px;
text-align: center;
color: white;
box-shadow: 0 4px 14px rgba(6,78,59,0.25);
}
.stat-box .s-icon { font-size: 1.6rem; margin-bottom: 4px; }
.stat-box .s-num { font-size: 2.4rem; font-weight: 800; line-height: 1; }
.stat-box .s-lbl { font-size: 0.78rem; opacity: 0.75; margin-top: 4px; }
/* ── SECTION TITLE ── */
.sec-title {
font-size: 0.82rem;
font-weight: 700;
color: #14532d;
margin-bottom: 14px;
text-transform: uppercase;
letter-spacing: 0.07em;
}
/* ── UPLOAD ZONE ── */
.upload-zone {
border: 2px dashed #86efac;
border-radius: 16px;
background: #f0fdf4;
padding: 40px 20px;
text-align: center;
cursor: pointer;
transition: background 0.2s;
margin-bottom: 16px;
}
.upload-zone:hover { background: #dcfce7; }
.upload-zone .uz-icon { font-size: 2.5rem; margin-bottom: 10px; }
.upload-zone .uz-text { font-size: 0.9rem; color: var(--muted); font-weight: 500; }
#file-input { display: none; }
#img-preview {
width: 100%;
border-radius: 14px;
object-fit: cover;
max-height: 260px;
display: none;
margin-bottom: 16px;
}
/* ── BUTTON ── */
.btn {
background: linear-gradient(135deg, #15803d, #16a34a);
color: white;
border: none;
border-radius: 12px;
padding: 12px 28px;
font-family: inherit;
font-size: 0.95rem;
font-weight: 700;
cursor: pointer;
width: 100%;
box-shadow: 0 3px 10px rgba(21,128,61,0.3);
transition: opacity 0.2s;
}
.btn:hover { opacity: 0.86; }
/* ── RESULT CARD ── */
.result-empty {
text-align: center;
padding: 70px 20px;
color: var(--muted);
}
.result-empty .r-icon { font-size: 3.2rem; margin-bottom: 12px; }
.result-empty .r-text { font-weight: 700; font-size: 1rem; }
.result-empty .r-sub { font-size: 0.82rem; margin-top: 6px; }
.result-pill {
display: inline-flex;
align-items: center;
gap: 10px;
border-radius: 50px;
padding: 12px 26px;
font-size: 1.2rem;
font-weight: 800;
margin: 10px 0;
}
.conf-bar-bg {
background: #f0f7f0;
border-radius: 8px;
height: 12px;
width: 100%;
overflow: hidden;
margin-top: 6px;
}
.conf-bar-fill { height: 100%; border-radius: 8px; transition: width 0.8s ease; }
.bin-tag {
display: inline-flex;
align-items: center;
gap: 10px;
border-radius: 12px;
padding: 10px 20px;
margin-top: 8px;
font-weight: 800;
font-size: 1rem;
}
.tip-item {
background: #f0fdf4;
border-left: 4px solid var(--green);
border-radius: 0 10px 10px 0;
padding: 9px 14px;
margin-bottom: 8px;
font-size: 0.86rem;
color: #166534;
}
/* ── META LABELS ── */
.meta-label {
font-size: 0.68rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.09em;
color: var(--muted);
margin-bottom: 4px;
margin-top: 18px;
}
.meta-label:first-child { margin-top: 0; }
/* ── SENSOR CARD ── */
.sensor-row {
display: grid;
grid-template-columns: 2fr 1fr 1fr;
gap: 20px;
margin-top: 14px;
}
.s-label { font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.09em; color: var(--muted); margin-bottom: 4px; }
.s-value { font-size: 1.45rem; font-weight: 800; }
.fill-bg { background: #f0f7f0; border-radius: 6px; height: 10px; width: 100%; overflow: hidden; margin-top: 8px; }
.fill-bar { height: 100%; border-radius: 6px; }
.status-badge {
border-radius: 20px;
padding: 3px 14px;
font-size: 0.75rem;
font-weight: 700;
}
.sensor-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.sensor-title { font-weight: 800; font-size: 1rem; }
/* ── CHART CONTAINER ── */
.chart-wrap { position: relative; height: 300px; }
/* ── SKELETON ── */
@keyframes shimmer {
0% { background-position: -600px 0; }
100% { background-position: 600px 0; }
}
.skel {
background: linear-gradient(90deg, #e8f0e8 25%, #d4e8d4 50%, #e8f0e8 75%);
background-size: 600px 100%;
animation: shimmer 1.6s infinite linear;
border-radius: 8px;
}
.skel-pill { height: 46px; width: 180px; border-radius: 50px; }
.skel-score { height: 38px; width: 90px; border-radius: 8px; }
.skel-bar { height: 12px; width: 100%; border-radius: 8px; }
.skel-bin { height: 44px; width: 160px; border-radius: 12px; }
.skel-tip { height: 36px; width: 100%; border-radius: 8px; }
.loading-overlay {
display: none;
position: fixed;
inset: 0;
background: rgba(0,0,0,0.35);
z-index: 999;
align-items: center;
justify-content: center;
flex-direction: column;
gap: 16px;
}
.loading-overlay.show { display: flex; }
.spinner {
width: 52px; height: 52px;
border: 5px solid rgba(255,255,255,0.3);
border-top-color: #fff;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.loading-text { color: #fff; font-weight: 700; font-size: 1rem; }
/* ── HOME TWO-COL ── */
.home-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 28px; }
@media (max-width: 900px) {
.sidebar { width: 64px; padding: 16px 8px; }
.sidebar .sidebar-logo .name,
.sidebar .sidebar-logo .sub,
.sidebar .nav-btn span,
.sidebar .sidebar-footer { display: none; }
.main { margin-left: 64px; max-width: calc(100vw - 64px); padding: 20px 16px; }
.grid-4 { grid-template-columns: repeat(2,1fr); }
.grid-2, .home-cols { grid-template-columns: 1fr; }
.sensor-row { grid-template-columns: 1fr 1fr; }
}
</style>
</head>
<body>
<!-- ═══════════════════════ SIDEBAR ═══════════════════════ -->
<aside class="sidebar">
<div class="sidebar-logo">
<div class="icon">♻️</div>
<div class="name">SmartWaste AI</div>
<div class="sub">Frontend Demo</div>
</div>
<button class="nav-btn active" onclick="showPage('home', this)">
<span>🏠</span><span>Home</span>
</button>
<button class="nav-btn" onclick="showPage('dashboard', this)">
<span>πŸ“Š</span><span>Dashboard</span>
</button>
<button class="nav-btn" onclick="showPage('iot', this)">
<span>πŸ“‘</span><span>IoT Sensors</span>
</button>
<div class="sidebar-footer">
πŸ“‘ IoT Sensors (simulated)<br>
🐍 Pure HTML · Chart.js
</div>
</aside>
<!-- ═══════════════════════ MAIN ═══════════════════════ -->
<main class="main">
<!-- ══════════════ PAGE: HOME ══════════════ -->
<div class="page active" id="page-home">
<div class="hero">
<div class="hero-badge">✨ AI + IoT Powered</div>
<h1>Smart Waste Management System</h1>
<p>Upload a photo of your waste β€” our AI classifier recommends<br>the correct bin for safe, eco-friendly disposal.</p>
</div>
<!-- Category chips -->
<div class="grid-4">
<div class="chip"><div class="c-icon">🌿</div><div class="c-name">Organic</div><div class="c-sub">Green Bin</div></div>
<div class="chip"><div class="c-icon">♻️</div><div class="c-name">Recyclable</div><div class="c-sub">Blue Bin</div></div>
<div class="chip"><div class="c-icon">⚠️</div><div class="c-name">Hazardous</div><div class="c-sub">Red Bin</div></div>
<div class="chip"><div class="c-icon">πŸ—‘οΈ</div><div class="c-name">General</div><div class="c-sub">Gray Bin</div></div>
</div>
<!-- Upload + Result -->
<div class="home-cols">
<!-- LEFT: Upload -->
<div>
<div class="sec-title">πŸ“€ Upload Waste Image</div>
<input type="file" id="file-input" accept="image/*" onchange="handleUpload(event)"/>
<div class="upload-zone" onclick="document.getElementById('file-input').click()">
<div class="uz-icon">πŸ–ΌοΈ</div>
<div class="uz-text">Drag & drop or <strong>click to browse</strong><br><span style="font-size:0.78rem;">JPG, PNG, WEBP, BMP Β· Max 10 MB</span></div>
</div>
<img id="img-preview" src="" alt="Preview"/>
<button class="btn" id="classify-btn" style="display:none;">
πŸ” Classify Waste
</button>
</div>
<!-- RIGHT: Result -->
<div>
<div class="sec-title">🎯 Classification Result</div>
<div class="card" id="result-panel">
<!-- Skeleton placeholder β€” connect a model to populate this -->
<div class="meta-label" style="margin-bottom:10px;">Detected Category</div>
<div class="skel skel-pill"></div>
<div class="meta-label" style="margin-top:18px;margin-bottom:10px;">Confidence Score</div>
<div class="skel skel-score"></div>
<div class="skel skel-bar" style="margin-top:10px;"></div>
<div class="meta-label" style="margin-top:18px;margin-bottom:10px;">Recommended Bin</div>
<div class="skel skel-bin"></div>
<div class="meta-label" style="margin-top:18px;margin-bottom:10px;">Disposal Tips</div>
<div class="skel skel-tip"></div>
<div class="skel skel-tip" style="width:80%;margin-top:8px;"></div>
<div class="skel skel-tip" style="width:65%;margin-top:8px;"></div>
</div>
</div>
</div>
</div><!-- /page-home -->
<!-- ══════════════ PAGE: DASHBOARD ══════════════ -->
<div class="page" id="page-dashboard">
<div class="hero">
<div class="hero-badge">πŸ“Š Analytics</div>
<h1>Waste Analytics Dashboard</h1>
<p>Overview of waste classification statistics and bin performance.</p>
</div>
<!-- Stat boxes -->
<div class="grid-4">
<div class="stat-box"><div class="s-icon">πŸ—‚οΈ</div><div class="s-num">1,284</div><div class="s-lbl">Total Processed</div></div>
<div class="stat-box"><div class="s-icon">🌿</div><div class="s-num">512</div><div class="s-lbl">Organic</div></div>
<div class="stat-box"><div class="s-icon">♻️</div><div class="s-num">430</div><div class="s-lbl">Recyclable</div></div>
<div class="stat-box"><div class="s-icon">⚠️</div><div class="s-num">97</div><div class="s-lbl">Hazardous</div></div>
</div>
<!-- Charts -->
<div class="grid-2">
<div class="card">
<div class="sec-title">πŸ₯§ Waste Type Distribution</div>
<div class="chart-wrap"><canvas id="pieChart"></canvas></div>
</div>
<div class="card">
<div class="sec-title">πŸ“ˆ Weekly Waste Volume</div>
<div class="chart-wrap"><canvas id="barChart"></canvas></div>
</div>
</div>
<!-- Bin fill levels -->
<div class="sec-title">πŸ—‘οΈ Current Bin Fill Levels</div>
<div class="grid-4">
<div class="card" style="padding:18px 16px;">
<div class="s-label">Organic (Green)</div>
<div class="s-value" style="color:#16a34a;">72%</div>
<div class="fill-bg"><div class="fill-bar" style="width:72%;background:#16a34a;"></div></div>
<div style="font-size:0.72rem;margin-top:8px;color:#f59e0b;font-weight:700;">● Warning</div>
</div>
<div class="card" style="padding:18px 16px;">
<div class="s-label">Recyclable (Blue)</div>
<div class="s-value" style="color:#2563eb;">45%</div>
<div class="fill-bg"><div class="fill-bar" style="width:45%;background:#2563eb;"></div></div>
<div style="font-size:0.72rem;margin-top:8px;color:#16a34a;font-weight:700;">● Normal</div>
</div>
<div class="card" style="padding:18px 16px;">
<div class="s-label">Hazardous (Red)</div>
<div class="s-value" style="color:#dc2626;">88%</div>
<div class="fill-bg"><div class="fill-bar" style="width:88%;background:#dc2626;"></div></div>
<div style="font-size:0.72rem;margin-top:8px;color:#dc2626;font-weight:700;">● Critical</div>
</div>
<div class="card" style="padding:18px 16px;">
<div class="s-label">General (Gray)</div>
<div class="s-value" style="color:#6b7280;">33%</div>
<div class="fill-bg"><div class="fill-bar" style="width:33%;background:#6b7280;"></div></div>
<div style="font-size:0.72rem;margin-top:8px;color:#16a34a;font-weight:700;">● Normal</div>
</div>
</div>
</div><!-- /page-dashboard -->
<!-- ══════════════ PAGE: IoT SENSORS ══════════════ -->
<div class="page" id="page-iot">
<div class="hero">
<div class="hero-badge">πŸ“‘ Live Monitoring</div>
<h1>IoT Sensor Panel</h1>
<p>Simulated real-time sensor data from smart bin hardware.</p>
</div>
<!-- Organic -->
<div class="card" style="border-left:5px solid #16a34a; margin-bottom:16px;">
<div class="sensor-header">
<div class="sensor-title">Organic (Green)</div>
<div class="status-badge" style="background:#f59e0b1a;color:#f59e0b;border:1.5px solid #f59e0b55;">● Warning</div>
</div>
<div class="sensor-row">
<div>
<div class="s-label">Fill Level</div>
<div class="s-value" style="color:#16a34a;">72%</div>
<div class="fill-bg"><div class="fill-bar" style="width:72%;background:#16a34a;"></div></div>
</div>
<div>
<div class="s-label">Gas Detected</div>
<div class="s-value" style="color:#16a34a;font-size:1.1rem;">βœ… NO</div>
</div>
<div>
<div class="s-label">Temperature</div>
<div class="s-value">28.4Β°C</div>
</div>
</div>
</div>
<!-- Recyclable -->
<div class="card" style="border-left:5px solid #2563eb; margin-bottom:16px;">
<div class="sensor-header">
<div class="sensor-title">Recyclable (Blue)</div>
<div class="status-badge" style="background:#16a34a1a;color:#16a34a;border:1.5px solid #16a34a55;">● Normal</div>
</div>
<div class="sensor-row">
<div>
<div class="s-label">Fill Level</div>
<div class="s-value" style="color:#2563eb;">45%</div>
<div class="fill-bg"><div class="fill-bar" style="width:45%;background:#2563eb;"></div></div>
</div>
<div>
<div class="s-label">Gas Detected</div>
<div class="s-value" style="color:#16a34a;font-size:1.1rem;">βœ… NO</div>
</div>
<div>
<div class="s-label">Temperature</div>
<div class="s-value">23.1Β°C</div>
</div>
</div>
</div>
<!-- Hazardous -->
<div class="card" style="border-left:5px solid #dc2626; margin-bottom:16px;">
<div class="sensor-header">
<div class="sensor-title">Hazardous (Red)</div>
<div class="status-badge" style="background:#dc26261a;color:#dc2626;border:1.5px solid #dc262655;">● Critical</div>
</div>
<div class="sensor-row">
<div>
<div class="s-label">Fill Level</div>
<div class="s-value" style="color:#dc2626;">88%</div>
<div class="fill-bg"><div class="fill-bar" style="width:88%;background:#dc2626;"></div></div>
</div>
<div>
<div class="s-label">Gas Detected</div>
<div class="s-value" style="color:#dc2626;font-size:1.1rem;">⚠️ YES</div>
</div>
<div>
<div class="s-label">Temperature</div>
<div class="s-value" style="color:#dc2626;">41.7Β°C</div>
</div>
</div>
</div>
<!-- General -->
<div class="card" style="border-left:5px solid #6b7280; margin-bottom:16px;">
<div class="sensor-header">
<div class="sensor-title">General (Gray)</div>
<div class="status-badge" style="background:#16a34a1a;color:#16a34a;border:1.5px solid #16a34a55;">● Normal</div>
</div>
<div class="sensor-row">
<div>
<div class="s-label">Fill Level</div>
<div class="s-value" style="color:#6b7280;">33%</div>
<div class="fill-bg"><div class="fill-bar" style="width:33%;background:#6b7280;"></div></div>
</div>
<div>
<div class="s-label">Gas Detected</div>
<div class="s-value" style="color:#16a34a;font-size:1.1rem;">βœ… NO</div>
</div>
<div>
<div class="s-label">Temperature</div>
<div class="s-value">22.5Β°C</div>
</div>
</div>
</div>
</div><!-- /page-iot -->
</main>
<script>
// ── NAVIGATION ──────────────────────────────────────────────
function showPage(id, btn) {
document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
document.querySelectorAll('.nav-btn').forEach(b => b.classList.remove('active'));
document.getElementById('page-' + id).classList.add('active');
btn.classList.add('active');
}
// ── IMAGE UPLOAD ─────────────────────────────────────────────
function handleUpload(e) {
const file = e.target.files[0];
if (!file) return;
if (file.size > 10 * 1024 * 1024) {
alert('❌ File exceeds 10 MB. Please upload a smaller image.');
return;
}
const reader = new FileReader();
reader.onload = ev => {
const img = document.getElementById('img-preview');
img.src = ev.target.result;
img.style.display = 'block';
document.getElementById('classify-btn').style.display = 'block';
};
reader.readAsDataURL(file);
}
// ── CHARTS (Dashboard) ────────────────────────────────────────
window.addEventListener('DOMContentLoaded', () => {
// Pie chart
new Chart(document.getElementById('pieChart'), {
type: 'doughnut',
data: {
labels: ['Organic', 'Recyclable', 'Hazardous', 'General'],
datasets: [{
data: [512, 430, 97, 245],
backgroundColor: ['#16a34a','#2563eb','#dc2626','#6b7280'],
borderColor: '#ffffff',
borderWidth: 3,
}]
},
options: {
responsive: true, maintainAspectRatio: false,
plugins: { legend: { position: 'bottom', labels: { font: { family: 'Plus Jakarta Sans', size: 12 } } } },
cutout: '44%',
}
});
// Bar chart
new Chart(document.getElementById('barChart'), {
type: 'bar',
data: {
labels: ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'],
datasets: [
{ label: 'Organic', data: [48,55,62,44,70,38,52], backgroundColor: '#16a34a' },
{ label: 'Recyclable', data: [35,42,38,50,45,30,40], backgroundColor: '#2563eb' },
{ label: 'Hazardous', data: [8,5,12,7,9,4,6], backgroundColor: '#dc2626' },
]
},
options: {
responsive: true, maintainAspectRatio: false,
plugins: { legend: { position: 'top', labels: { font: { family: 'Plus Jakarta Sans', size: 12 } } } },
scales: {
x: { stacked: true, grid: { display: false }, ticks: { font: { family: 'Plus Jakarta Sans' } } },
y: { stacked: true, grid: { color: 'rgba(0,0,0,0.05)' }, ticks: { font: { family: 'Plus Jakarta Sans' } } },
}
}
});
});
</script>
</body>
</html>