Spaces:
Runtime error
Runtime error
| <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> | |