Files
loustique-home/flask/templates/dashboard.html
2026-04-01 01:03:44 +02:00

368 lines
10 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Loustiques Home — Dashboard</title>
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: system-ui, sans-serif;
background: #1f1f1f;
color: #f0f0f0;
min-height: 100vh;
}
header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 18px 32px;
border-bottom: 1px solid #2e2e2e;
background: #1a1a1a;
}
.logo {
font-size: 17px;
font-weight: 700;
}
.header-right {
display: flex;
align-items: center;
gap: 20px;
}
.status-dot {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
color: #888;
}
.dot {
width: 7px;
height: 7px;
border-radius: 50%;
background: #4ade80;
animation: pulse 2s infinite;
}
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
.logout {
font-family: inherit;
font-size: 12px;
color: #888;
background: none;
border: 1px solid #3a3a3a;
padding: 6px 14px;
border-radius: 6px;
cursor: pointer;
transition: color 0.15s, border-color 0.15s;
}
.logout:hover { color: #f0f0f0; border-color: #666; }
main {
max-width: 1100px;
margin: 0 auto;
padding: 36px 32px;
}
.welcome {
margin-bottom: 36px;
text-align: center;
}
.welcome .label {
font-size: 14px;
letter-spacing: 0.15em;
text-transform: uppercase;
color: #2563eb;
margin-bottom: 8px;
}
.welcome h1 {
font-size: 30px;
font-weight: 700;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 14px;
margin-bottom: 32px;
}
.card {
background: #2a2a2a;
border: 1px solid #333;
border-radius: 8px;
padding: 22px;
position: relative;
}
.card-label {
font-size: 11px;
letter-spacing: 0.1em;
text-transform: uppercase;
color: #888;
margin-bottom: 10px;
}
.card-value {
font-size: 22px;
font-weight: 700;
}
.card-sub {
font-size: 12px;
color: #666;
margin-top: 6px;
}
.card-icon {
position: absolute;
top: 20px;
right: 20px;
width: 28px;
height: 28px;
opacity: 0.15;
}
.section-title {
font-size: 11px;
letter-spacing: 0.15em;
text-transform: uppercase;
color: #666;
margin-bottom: 14px;
display: flex;
align-items: center;
gap: 10px;
}
.section-title::after { content: ''; flex: 1; height: 1px; background: #2e2e2e; }
.actions {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 12px;
}
.action-btn {
background: #2a2a2a;
border: 1px solid #333;
border-radius: 8px;
padding: 18px 20px;
cursor: pointer;
text-align: left;
color: #f0f0f0;
position: relative;
transition: border-color 0.15s, background 0.15s;
}
.action-btn:hover { border-color: #2563eb; background: #2e2e3a; }
.action-btn:active { transform: scale(0.98); }
.action-btn .a-label {
font-size: 14px;
font-weight: 600;
display: block;
margin-bottom: 4px;
}
.action-btn .a-sub {
font-size: 11px;
color: #888;
}
.action-btn .a-arrow {
position: absolute;
right: 16px;
top: 50%;
transform: translateY(-50%);
color: #555;
font-size: 18px;
transition: color 0.15s, right 0.15s;
}
.action-btn:hover .a-arrow { color: #2563eb; right: 12px; }
.toast {
position: fixed;
bottom: 24px;
right: 24px;
background: #2a2a2a;
border: 1px solid #333;
border-radius: 8px;
padding: 12px 18px;
font-size: 13px;
color: #f0f0f0;
display: flex;
align-items: center;
gap: 10px;
transform: translateY(20px);
opacity: 0;
transition: transform 0.3s, opacity 0.3s;
z-index: 100;
}
.toast.show { transform: translateY(0); opacity: 1; }
.toast-dot { width: 6px; height: 6px; border-radius: 50%; background: #4ade80; flex-shrink: 0; }
</style>
</head>
<body>
<header>
<div class="logo">Loustiques Home</div>
<div class="header-right">
<div class="status-dot"><div class="dot"></div> Système actif</div>
<button class="logout" onclick="window.location.href='/'">Déconnexion</button>
</div>
</header>
<main>
<div class="welcome">
<div class="label">Tableau de bord</div>
<h1>Bienvenue chez vous</h1>
</div>
<div class="grid">
<div class="card">
<svg class="card-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
<div class="card-label">Statut</div>
<div class="card-value" style="color:#4ade80;">En ligne</div>
<div class="card-sub">Serveur opérationnel</div>
</div>
<div class="card">
<svg class="card-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
<div class="card-label">Heure locale</div>
<div class="card-value" id="clock">--:--</div>
<div class="card-sub" id="date-display">--</div>
</div>
<div class="card">
<div class="card-label">Température</div>
<div class="card-sub" id="date-display">--</div>
</div>
<div class="card">
<div class="card-label">Porte</div>
<div class="card-sub" id="date-display">--</div>
</div>
<div class="card">
<svg class="card-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
<div class="card-label">Raspberry Pi 1 (actuelle)</div>
<div class="card-value" style="color:green;">Actif</div>
<div class="card-sub">Flask 3.1</div>
</div>
<div class="card">
<svg class="card-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
<div class="card-label">Raspberry Pi 2 distant </div>
<div class="card-value" style="color:green;">Actif</div>
<div class="card-sub">FastAPi</div>
</div>
<div class="card">
<svg class="card-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
<div class="card-label">Session</div>
<div class="card-value" style="color: green;">Authentifiée</div>
<div class="card-sub">Accès autorisé</div>
</div>
</div>
<div class="section-title">Actions rapides</div>
<div class="actions">
<button class="action-btn" onclick="callLed()">
<span class="a-label">💡 LED</span>
<span class="a-sub">Contrôler la LED</span>
<span class="a-arrow"></span>
</button>
<button class="action-btn" onclick="callAlarm()">
<span class="a-label">Alarme</span>
<span class="a-sub">Armer l'alarme</span>
<span class="a-arrow"></span></button>
<button class="action-btn" onclick="callAlarm()">
<span class="a-label">Alarme</span>
<span class="a-sub">Désarmer l'alarme</span>
<span class="a-arrow"></span></button>
<button class="action-btn" onclick="go_admin()">
<span class="a-label">Administration</span>
<span class="a-sub">Administrer les loustiques</span>
<span class="a-arrow"></span>
</button>
</div>
</main>
<div class="toast" id="toast">
<div class="toast-dot"></div>
<span id="toast-text">Action effectuée</span>
</div>
<script>
function updateClock() {
const now = new Date();
document.getElementById("clock").textContent =
now.toLocaleTimeString("fr-FR", { hour: "2-digit", minute: "2-digit" });
document.getElementById("date-display").textContent =
now.toLocaleDateString("fr-FR", { weekday: "long", day: "numeric", month: "long" });
}
updateClock();
setInterval(updateClock, 1000);
async function callLed() {
try {
const res = await fetch('/led', {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
showToast("LED activée !");
} catch {
showToast("Erreur lors de l'appel LED.");
}
}
async function callAlarm() {
try {
const res = await fetch('/alarme', {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
showToast("alarme activée !");
} catch {
showToast("Erreur lors de l'appel alarme.");
}
async function call_led_down() {
try {
const res = await fetch('http://pi32.local/down_led', {
method: 'GET',
headers: { 'Content-Type': 'application/json' }
});
showToast("led activée !");
} catch {
showToast("Erreur lors de l'appel board1.");
}}
}
async function call_led_up() {
try {
const res = await fetch('http://pi32.local/up_led', {
method: 'GET',
headers: { 'Content-Type': 'application/json' }
});
showToast("led activée !");
} catch {
showToast("Erreur lors de l'appel board1.");
}
}
function go_admin() {
window.location.href = "/admin";
}
function showToast(msg) {
const toast = document.getElementById("toast");
document.getElementById("toast-text").textContent = msg;
toast.classList.add("show");
setTimeout(() => toast.classList.remove("show"), 3000);
}
</script>
</body>
</html>