feat: add plans, design system, CONSIGNE and brainstorm assets

Ajoute les trois plans d'implémentation (agent Rust, serveur Go, dashboard),
les consignes de design, les fichiers de brainstorming et le .gitignore.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gilles Soulier
2026-05-22 08:13:53 +02:00
co-authored by Claude Sonnet 4.6
parent 8e44b2f335
commit a0f47bf966
29 changed files with 13068 additions and 0 deletions
@@ -0,0 +1,541 @@
<!DOCTYPE html>
<html data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Nanometrics — Layout v4</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Share+Tech+Mono:wght@400&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<script src="/helper.js"></script>
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root[data-theme="dark"] {
--accent:#fe8019; --accent-soft:#d65d0e; --accent-glow:rgba(254,128,25,0.3);
--bg-0:#1d1813; --bg-1:#2a231d; --bg-2:#32291f; --bg-3:#3c332a; --bg-4:#4a3f33; --bg-5:#57493c;
--ink-1:#f2e5c7; --ink-2:#d5c4a1; --ink-3:#a89984; --ink-4:#7c6f64;
--ok:#4dbb26; --warn:#fabd2f; --err:#fb4934; --info:#83a598; --blue:#3db0d1; --purple:#c882c8;
--border-1:rgba(255,255,255,0.06); --border-2:rgba(255,255,255,0.12); --border-3:rgba(255,255,255,0.22);
--tile-3d:0 1px 0 rgba(255,255,255,0.08) inset,0 -1px 0 rgba(0,0,0,0.3) inset,0 4px 16px rgba(0,0,0,0.5);
--font-ui:'Inter',system-ui,sans-serif; --font-mono:'JetBrains Mono',monospace; --font-terminal:'Share Tech Mono',monospace;
}
:root[data-theme="light"] {
--accent:#af3a03; --accent-soft:#d65d0e; --accent-glow:rgba(175,58,3,0.2);
--bg-0:#d5c4a1; --bg-1:#ebdbb2; --bg-2:#d5c4a1; --bg-3:#bdae93; --bg-4:#a89984; --bg-5:#928374;
--ink-1:#3c3836; --ink-2:#504945; --ink-3:#665c54; --ink-4:#7c6f64;
--ok:#3c911c; --warn:#b57614; --err:#9d0006; --blue:#2d82a3; --purple:#8c468c;
--border-1:rgba(0,0,0,0.08); --border-2:rgba(0,0,0,0.15); --border-3:rgba(0,0,0,0.25);
--tile-3d:0 1px 0 rgba(255,255,255,0.5) inset,0 -1px 0 rgba(0,0,0,0.1) inset,0 4px 16px rgba(0,0,0,0.12);
--font-ui:'Inter',system-ui,sans-serif; --font-mono:'JetBrains Mono',monospace; --font-terminal:'Share Tech Mono',monospace;
}
body { background:var(--bg-1); color:var(--ink-1); font-family:var(--font-ui); font-size:13px; height:100vh; display:flex; flex-direction:column; overflow:hidden; transition:background .2s,color .2s; }
/* HEADER */
.header { background:var(--bg-2); border-bottom:1px solid var(--border-2); padding:0 20px; height:48px; display:flex; align-items:center; gap:14px; flex-shrink:0; }
.logo { display:flex; align-items:center; gap:8px; }
.logo-led { width:9px; height:9px; border-radius:50%; background:var(--accent); box-shadow:0 0 8px var(--accent-glow); animation:blink 2s infinite; }
@keyframes blink{0%,100%{opacity:1}50%{opacity:.4}}
.logo-name { font-weight:700; font-size:14px; letter-spacing:.05em; font-family:var(--font-terminal); }
.logo-ver { font-size:10px; color:var(--ink-4); font-family:var(--font-terminal); }
.h-sep { width:1px; height:24px; background:var(--border-2); }
.h-spacer { flex:1; }
.h-stats { display:flex; gap:14px; }
.h-stat { display:flex; align-items:center; gap:5px; }
.h-stat .lbl { font-size:9px; color:var(--ink-4); font-family:var(--font-terminal); letter-spacing:.06em; }
.h-stat .val { font-family:var(--font-mono); font-weight:700; font-size:13px; }
.c-ok{color:var(--ok)}.c-warn{color:var(--warn)}.c-err{color:var(--err)}.c-n{color:var(--ink-2)}
.hbtn { width:34px; height:34px; border-radius:8px; border:1px solid var(--border-2); background:var(--bg-3); color:var(--ink-2); font-size:14px; display:flex; align-items:center; justify-content:center; cursor:pointer; position:relative; transition:background .12s,color .12s; }
.hbtn:hover { background:var(--bg-4); color:var(--accent); }
.hbtn .tip { position:absolute; top:calc(100%+6px); right:0; z-index:50; background:var(--bg-0); color:var(--ink-1); font-size:11px; padding:4px 8px; border-radius:5px; border:1px solid var(--border-2); white-space:nowrap; opacity:0; pointer-events:none; transition:opacity .12s; font-family:var(--font-ui); }
.hbtn:hover .tip { opacity:1; }
/* GRID */
.main { flex:1; padding:14px 16px; overflow-y:auto; }
.agents-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(220px,1fr)); gap:10px; }
/* TILE */
.tile { background:var(--bg-3); border-radius:10px; padding:12px 14px; border:1px solid var(--border-1); box-shadow:var(--tile-3d); cursor:pointer; transition:border-color .15s; display:flex; flex-direction:column; gap:9px; }
.tile:hover { border-color:var(--border-3); }
.tile.t-warn { border-color:rgba(250,189,47,.28); }
.tile.t-err { border-color:rgba(251,73,52,.32); box-shadow:var(--tile-3d),0 0 16px rgba(251,73,52,.1); }
.tile.t-off { opacity:.5; cursor:default; }
.tile-head { display:flex; align-items:center; gap:8px; }
.t-icon { width:28px; height:28px; border-radius:7px; background:var(--bg-4); display:flex; align-items:center; justify-content:center; color:var(--accent); font-size:13px; flex-shrink:0; overflow:hidden; }
.t-icon img { width:100%; height:100%; object-fit:cover; border-radius:7px; }
.t-names { flex:1; min-width:0; }
.t-host { font-weight:600; font-size:13px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.t-ip { font-family:var(--font-mono); font-size:10px; color:var(--ink-4); }
.t-led { width:8px; height:8px; border-radius:50%; flex-shrink:0; }
.s-ok{background:var(--ok);box-shadow:0 0 6px var(--ok)}.s-warn{background:var(--warn);box-shadow:0 0 6px var(--warn);animation:blink 1.5s infinite}.s-err{background:var(--err);box-shadow:0 0 8px var(--err);animation:blink 1s infinite}.s-off{background:var(--ink-4)}
.tile-gauges { display:flex; flex-direction:column; gap:5px; }
.g-row { display:flex; align-items:center; gap:7px; }
.g-ico { width:18px; height:18px; display:flex; align-items:center; justify-content:center; font-size:11px; color:var(--ink-3); flex-shrink:0; position:relative; cursor:help; }
.g-ico .g-tip { position:absolute; bottom:calc(100%+5px); left:50%; transform:translateX(-50%); background:var(--bg-0); color:var(--ink-1); font-size:10px; padding:3px 7px; border-radius:4px; border:1px solid var(--border-2); white-space:nowrap; opacity:0; pointer-events:none; transition:opacity .12s; z-index:10; font-family:var(--font-ui); }
.g-ico:hover .g-tip { opacity:1; }
.g-bar { flex:1; height:5px; border-radius:3px; background:var(--bg-1); overflow:hidden; }
.g-fill { height:100%; border-radius:3px; background:var(--ok); transition:width .4s; }
.g-fill.w{background:var(--warn)}.g-fill.e{background:var(--err)}
.g-val { font-family:var(--font-mono); font-size:11px; color:var(--ink-2); width:34px; text-align:right; flex-shrink:0; }
.tile-foot { font-family:var(--font-terminal); font-size:10px; color:var(--ink-4); display:flex; align-items:center; gap:5px; }
.tile-foot i { font-size:9px; }
.tile-foot.offline { color:var(--err); }
/* FOOTER */
.footer { background:var(--bg-0); border-top:1px solid var(--border-2); height:26px; display:flex; align-items:center; font-family:var(--font-terminal); font-size:11px; color:var(--ink-4); flex-shrink:0; }
.f-mode { background:var(--accent); color:var(--bg-0); padding:0 12px; height:100%; display:flex; align-items:center; font-weight:700; letter-spacing:.04em; }
.f-cell { padding:0 12px; border-right:1px solid var(--border-1); display:flex; align-items:center; gap:5px; height:100%; }
.f-val { font-family:var(--font-mono); color:var(--ink-2); }
.f-val.w { color:var(--warn); }
.f-minibar { width:36px; height:4px; border-radius:2px; background:var(--bg-3); overflow:hidden; }
.f-minifill { height:100%; border-radius:2px; background:var(--ok); }
.f-minifill.w { background:var(--warn); }
.f-spacer { flex:1; }
.f-right { padding:0 12px; display:flex; align-items:center; gap:6px; color:var(--ink-3); }
.f-time { font-family:var(--font-mono); color:var(--ink-2); }
/* ══ POPUP ══ */
.overlay { position:fixed; inset:0; background:rgba(0,0,0,.65); z-index:100; display:flex; align-items:center; justify-content:center; backdrop-filter:blur(2px); }
.popup { background:var(--bg-2); border:1px solid var(--border-3); border-radius:12px; width:540px; max-width:96vw; max-height:92vh; box-shadow:0 24px 64px rgba(0,0,0,.7); display:flex; flex-direction:column; overflow:hidden; }
/* popup header */
.pop-head { background:var(--bg-3); padding:14px 18px; border-bottom:1px solid var(--border-2); display:flex; align-items:center; gap:12px; }
/* agent icon — cliquable pour upload */
.agent-icon-wrap {
position:relative; width:44px; height:44px; border-radius:10px; flex-shrink:0;
cursor:pointer; overflow:hidden;
background:var(--bg-4); display:flex; align-items:center; justify-content:center;
color:var(--accent); font-size:18px;
border:2px solid var(--border-2); transition:border-color .15s;
}
.agent-icon-wrap:hover { border-color:var(--accent); }
.agent-icon-wrap img { width:100%; height:100%; object-fit:cover; }
.agent-icon-overlay {
position:absolute; inset:0; background:rgba(0,0,0,.6);
display:flex; flex-direction:column; align-items:center; justify-content:center; gap:2px;
opacity:0; transition:opacity .15s;
font-size:10px; color:#fff; font-family:var(--font-ui);
}
.agent-icon-overlay i { font-size:14px; }
.agent-icon-wrap:hover .agent-icon-overlay { opacity:1; }
#icon-upload { display:none; }
.pop-head-info { flex:1; }
.pop-host { font-weight:700; font-size:15px; }
.pop-ip { font-family:var(--font-mono); font-size:11px; color:var(--ink-4); }
.pop-led { width:10px; height:10px; border-radius:50%; background:var(--ok); box-shadow:0 0 8px var(--ok); flex-shrink:0; }
.pop-close { width:28px; height:28px; border-radius:6px; background:var(--bg-5); color:var(--ink-3); display:flex; align-items:center; justify-content:center; cursor:pointer; font-size:12px; transition:background .12s,color .12s; }
.pop-close:hover { background:var(--err); color:#fff; }
/* upload feedback */
.upload-hint { font-size:10px; color:var(--ink-4); font-family:var(--font-terminal); margin-top:3px; }
/* popup body */
.pop-body { padding:16px 18px; display:flex; flex-direction:column; gap:14px; overflow-y:auto; }
.sec-title { font-size:9px; color:var(--ink-4); font-family:var(--font-terminal); letter-spacing:.08em; margin-bottom:8px; }
/* KPI row */
.kpi-grid { display:grid; grid-template-columns:repeat(4,1fr); gap:7px; }
.kpi { background:var(--bg-3); border-radius:8px; padding:10px 12px; border:1px solid var(--border-1); box-shadow:var(--tile-3d); }
.kpi-lbl { font-size:9px; color:var(--ink-4); font-family:var(--font-terminal); letter-spacing:.06em; }
.kpi-val { font-family:var(--font-mono); font-size:20px; font-weight:700; line-height:1.1; margin-top:2px; }
.kpi-val .u { font-size:10px; color:var(--ink-3); font-weight:400; }
.kpi-sub { font-size:10px; color:var(--ink-4); font-family:var(--font-mono); margin-top:2px; }
/* ── COURBES HISTORIQUES ── */
.charts-grid { display:grid; grid-template-columns:1fr 1fr; gap:10px; }
.chart-card { background:var(--bg-3); border-radius:8px; padding:10px 12px; border:1px solid var(--border-1); box-shadow:var(--tile-3d); }
.chart-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:8px; }
.chart-label { display:flex; align-items:center; gap:6px; font-size:10px; font-family:var(--font-terminal); letter-spacing:.06em; color:var(--ink-3); }
.chart-label i { font-size:11px; }
.chart-cur { font-family:var(--font-mono); font-size:16px; font-weight:700; }
.chart-svg { width:100%; height:56px; display:block; }
.chart-axis { display:flex; justify-content:space-between; margin-top:3px; font-family:var(--font-terminal); font-size:9px; color:var(--ink-4); }
/* disk jauge conservée */
.det-gauges { display:flex; flex-direction:column; gap:7px; }
.dg-row { display:flex; align-items:center; gap:10px; }
.dg-ico { width:22px; text-align:center; font-size:13px; position:relative; cursor:help; }
.dg-ico .dg-tip { position:absolute; bottom:calc(100%+5px); left:50%; transform:translateX(-50%); background:var(--bg-0); color:var(--ink-1); font-size:10px; padding:3px 8px; border-radius:4px; border:1px solid var(--border-2); white-space:nowrap; opacity:0; pointer-events:none; transition:opacity .1s; z-index:10; font-family:var(--font-ui); }
.dg-ico:hover .dg-tip { opacity:1; }
.dg-bar { flex:1; height:7px; border-radius:4px; background:var(--bg-1); overflow:hidden; }
.dg-fill { height:100%; border-radius:4px; background:var(--ok); }
.dg-fill.w{background:var(--warn)}.dg-fill.e{background:var(--err)}
.dg-val { font-family:var(--font-mono); font-size:12px; color:var(--ink-2); width:90px; text-align:right; }
/* meta */
.meta-grid { display:grid; grid-template-columns:1fr 1fr; gap:6px; }
.meta { background:var(--bg-3); border-radius:6px; padding:8px 10px; border:1px solid var(--border-1); }
.meta-lbl { font-size:9px; color:var(--ink-4); font-family:var(--font-terminal); letter-spacing:.06em; }
.meta-val { font-family:var(--font-mono); font-size:12px; color:var(--ink-2); margin-top:2px; }
/* popup footer — pas de bouton Fermer */
.pop-foot { padding:10px 18px; border-top:1px solid var(--border-2); background:var(--bg-3); display:flex; align-items:center; gap:8px; }
.pop-uptime { font-family:var(--font-terminal); font-size:11px; color:var(--ink-4); flex:1; }
.btn { padding:6px 14px; border-radius:8px; border:1px solid var(--border-2); background:var(--bg-4); color:var(--ink-2); font-size:12px; font-family:var(--font-ui); cursor:pointer; display:flex; align-items:center; gap:6px; transition:background .1s; }
.btn:hover { background:var(--bg-5); }
.btn.primary { background:var(--accent); color:var(--bg-0); border-color:var(--accent-soft); font-weight:600; }
.btn.primary:hover { background:var(--accent-soft); }
/* scrollbar */
::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:var(--bg-1)}::-webkit-scrollbar-thumb{background:var(--bg-4);border-radius:3px}
</style>
</head>
<body>
<!-- HEADER -->
<div class="header">
<div class="logo">
<div class="logo-led"></div>
<span class="logo-name">NANOMETRICS</span>
<span class="logo-ver">v1.0</span>
</div>
<div class="h-sep"></div>
<div class="h-stats">
<div class="h-stat"><span class="lbl">AGENTS</span><span class="val c-n">8</span></div>
<div class="h-stat"><span class="lbl">OK</span><span class="val c-ok">5</span></div>
<div class="h-stat"><span class="lbl">WARN</span><span class="val c-warn">2</span></div>
<div class="h-stat"><span class="lbl">ERR</span><span class="val c-err">1</span></div>
</div>
<div class="h-spacer"></div>
<div class="hbtn" onclick="toggleTheme()">
<i class="fa-solid fa-moon" id="theme-icon"></i>
<span class="tip">Thème clair / sombre</span>
</div>
<div class="hbtn" onclick="alert('Config panel')">
<i class="fa-solid fa-sliders"></i>
<span class="tip">Configuration interface</span>
</div>
</div>
<!-- GRID -->
<div class="main">
<div class="agents-grid">
<div class="tile" onclick="showPopup()">
<div class="tile-head">
<div class="t-icon"><i class="fa-solid fa-server"></i></div>
<div class="t-names"><div class="t-host">srv-prod-01</div><div class="t-ip">10.0.0.11</div></div>
<div class="t-led s-ok"></div>
</div>
<div class="tile-gauges">
<div class="g-row"><div class="g-ico"><i class="fa-solid fa-microchip"></i><span class="g-tip">Processeur (CPU)</span></div><div class="g-bar"><div class="g-fill" style="width:42%"></div></div><span class="g-val">42%</span></div>
<div class="g-row"><div class="g-ico"><i class="fa-solid fa-memory"></i><span class="g-tip">Mémoire RAM</span></div><div class="g-bar"><div class="g-fill" style="width:58%"></div></div><span class="g-val">58%</span></div>
<div class="g-row"><div class="g-ico"><i class="fa-solid fa-hard-drive"></i><span class="g-tip">Espace disque</span></div><div class="g-bar"><div class="g-fill" style="width:31%"></div></div><span class="g-val">31%</span></div>
</div>
<div class="tile-foot"><i class="fa-solid fa-clock"></i>14j 6h</div>
</div>
<div class="tile t-warn">
<div class="tile-head">
<div class="t-icon"><i class="fa-solid fa-server"></i></div>
<div class="t-names"><div class="t-host">srv-backup-02</div><div class="t-ip">10.0.0.12</div></div>
<div class="t-led s-warn"></div>
</div>
<div class="tile-gauges">
<div class="g-row"><div class="g-ico" style="color:var(--warn)"><i class="fa-solid fa-microchip"></i><span class="g-tip">CPU — élevé</span></div><div class="g-bar"><div class="g-fill w" style="width:78%"></div></div><span class="g-val" style="color:var(--warn)">78%</span></div>
<div class="g-row"><div class="g-ico" style="color:var(--warn)"><i class="fa-solid fa-memory"></i><span class="g-tip">RAM — élevée</span></div><div class="g-bar"><div class="g-fill w" style="width:72%"></div></div><span class="g-val" style="color:var(--warn)">72%</span></div>
<div class="g-row"><div class="g-ico"><i class="fa-solid fa-hard-drive"></i><span class="g-tip">Espace disque</span></div><div class="g-bar"><div class="g-fill" style="width:20%"></div></div><span class="g-val">20%</span></div>
</div>
<div class="tile-foot"><i class="fa-solid fa-clock"></i>3j 14h</div>
</div>
<div class="tile t-err">
<div class="tile-head">
<div class="t-icon" style="color:var(--err)"><i class="fa-solid fa-microchip"></i></div>
<div class="t-names"><div class="t-host">rpi-sensor-03</div><div class="t-ip">10.0.0.23</div></div>
<div class="t-led s-err"></div>
</div>
<div class="tile-gauges">
<div class="g-row"><div class="g-ico"><i class="fa-solid fa-microchip"></i><span class="g-tip">CPU</span></div><div class="g-bar"><div class="g-fill" style="width:12%"></div></div><span class="g-val">12%</span></div>
<div class="g-row"><div class="g-ico"><i class="fa-solid fa-memory"></i><span class="g-tip">RAM</span></div><div class="g-bar"><div class="g-fill" style="width:38%"></div></div><span class="g-val">38%</span></div>
<div class="g-row"><div class="g-ico" style="color:var(--err)"><i class="fa-solid fa-hard-drive"></i><span class="g-tip">Disque critique !</span></div><div class="g-bar"><div class="g-fill e" style="width:94%"></div></div><span class="g-val" style="color:var(--err)">94%</span></div>
</div>
<div class="tile-foot"><i class="fa-solid fa-clock"></i>62j 1h</div>
</div>
<div class="tile">
<div class="tile-head">
<div class="t-icon"><i class="fa-solid fa-hard-drive"></i></div>
<div class="t-names"><div class="t-host">nas-storage-04</div><div class="t-ip">10.0.0.30</div></div>
<div class="t-led s-ok"></div>
</div>
<div class="tile-gauges">
<div class="g-row"><div class="g-ico"><i class="fa-solid fa-microchip"></i><span class="g-tip">CPU</span></div><div class="g-bar"><div class="g-fill" style="width:8%"></div></div><span class="g-val">8%</span></div>
<div class="g-row"><div class="g-ico"><i class="fa-solid fa-memory"></i><span class="g-tip">RAM</span></div><div class="g-bar"><div class="g-fill" style="width:45%"></div></div><span class="g-val">45%</span></div>
<div class="g-row"><div class="g-ico"><i class="fa-solid fa-hard-drive"></i><span class="g-tip">Disque</span></div><div class="g-bar"><div class="g-fill" style="width:66%"></div></div><span class="g-val">66%</span></div>
</div>
<div class="tile-foot"><i class="fa-solid fa-clock"></i>128j 3h</div>
</div>
<div class="tile">
<div class="tile-head">
<div class="t-icon"><i class="fa-solid fa-database"></i></div>
<div class="t-names"><div class="t-host">db-primary-05</div><div class="t-ip">10.0.0.40</div></div>
<div class="t-led s-ok"></div>
</div>
<div class="tile-gauges">
<div class="g-row"><div class="g-ico"><i class="fa-solid fa-microchip"></i><span class="g-tip">CPU</span></div><div class="g-bar"><div class="g-fill" style="width:25%"></div></div><span class="g-val">25%</span></div>
<div class="g-row"><div class="g-ico"><i class="fa-solid fa-memory"></i><span class="g-tip">RAM</span></div><div class="g-bar"><div class="g-fill" style="width:61%"></div></div><span class="g-val">61%</span></div>
<div class="g-row"><div class="g-ico"><i class="fa-solid fa-hard-drive"></i><span class="g-tip">Disque</span></div><div class="g-bar"><div class="g-fill" style="width:48%"></div></div><span class="g-val">48%</span></div>
</div>
<div class="tile-foot"><i class="fa-solid fa-clock"></i>7j 22h</div>
</div>
<div class="tile t-warn">
<div class="tile-head">
<div class="t-icon"><i class="fa-solid fa-globe"></i></div>
<div class="t-names"><div class="t-host">web-front-06</div><div class="t-ip">10.0.0.51</div></div>
<div class="t-led s-warn"></div>
</div>
<div class="tile-gauges">
<div class="g-row"><div class="g-ico" style="color:var(--warn)"><i class="fa-solid fa-microchip"></i><span class="g-tip">CPU — élevé</span></div><div class="g-bar"><div class="g-fill w" style="width:71%"></div></div><span class="g-val" style="color:var(--warn)">71%</span></div>
<div class="g-row"><div class="g-ico"><i class="fa-solid fa-memory"></i><span class="g-tip">RAM</span></div><div class="g-bar"><div class="g-fill" style="width:55%"></div></div><span class="g-val">55%</span></div>
<div class="g-row"><div class="g-ico"><i class="fa-solid fa-hard-drive"></i><span class="g-tip">Disque</span></div><div class="g-bar"><div class="g-fill" style="width:28%"></div></div><span class="g-val">28%</span></div>
</div>
<div class="tile-foot"><i class="fa-solid fa-clock"></i>21j 8h</div>
</div>
<div class="tile t-off">
<div class="tile-head">
<div class="t-icon" style="color:var(--ink-4)"><i class="fa-solid fa-server"></i></div>
<div class="t-names"><div class="t-host">srv-dev-07</div><div class="t-ip">10.0.0.60</div></div>
<div class="t-led s-off"></div>
</div>
<div class="tile-gauges">
<div class="g-row"><div class="g-ico"><i class="fa-solid fa-microchip"></i></div><div class="g-bar"></div><span class="g-val" style="color:var(--ink-4)">—</span></div>
<div class="g-row"><div class="g-ico"><i class="fa-solid fa-memory"></i></div><div class="g-bar"></div><span class="g-val" style="color:var(--ink-4)">—</span></div>
<div class="g-row"><div class="g-ico"><i class="fa-solid fa-hard-drive"></i></div><div class="g-bar"></div><span class="g-val" style="color:var(--ink-4)">—</span></div>
</div>
<div class="tile-foot offline"><i class="fa-solid fa-circle-xmark"></i>Hors ligne · vu il y a 2h</div>
</div>
<div class="tile">
<div class="tile-head">
<div class="t-icon"><i class="fa-solid fa-network-wired"></i></div>
<div class="t-names"><div class="t-host">gateway-08</div><div class="t-ip">10.0.0.1</div></div>
<div class="t-led s-ok"></div>
</div>
<div class="tile-gauges">
<div class="g-row"><div class="g-ico"><i class="fa-solid fa-microchip"></i><span class="g-tip">CPU</span></div><div class="g-bar"><div class="g-fill" style="width:5%"></div></div><span class="g-val">5%</span></div>
<div class="g-row"><div class="g-ico"><i class="fa-solid fa-memory"></i><span class="g-tip">RAM</span></div><div class="g-bar"><div class="g-fill" style="width:22%"></div></div><span class="g-val">22%</span></div>
<div class="g-row"><div class="g-ico"><i class="fa-solid fa-hard-drive"></i><span class="g-tip">Disque</span></div><div class="g-bar"><div class="g-fill" style="width:15%"></div></div><span class="g-val">15%</span></div>
</div>
<div class="tile-foot"><i class="fa-solid fa-clock"></i>365j 0h</div>
</div>
</div>
</div>
<!-- FOOTER -->
<div class="footer">
<div class="f-mode">LIVE</div>
<div class="f-cell"><i class="fa-solid fa-server" style="font-size:10px"></i><span>SERVEUR</span></div>
<div class="f-cell"><i class="fa-solid fa-microchip" style="font-size:10px"></i><span class="f-val">18%</span><div class="f-minibar"><div class="f-minifill" style="width:18%"></div></div></div>
<div class="f-cell"><i class="fa-solid fa-memory" style="font-size:10px"></i><span class="f-val w">71%</span><div class="f-minibar"><div class="f-minifill w" style="width:71%"></div></div></div>
<div class="f-spacer"></div>
<div class="f-right"><i class="fa-solid fa-rotate"></i><span>Actualisation : <span class="f-time">22:14:07</span></span></div>
</div>
<!-- ══ POPUP ══ -->
<div class="overlay" id="popup-overlay" style="display:flex" onclick="if(event.target===this)this.style.display='none'">
<div class="popup" onclick="event.stopPropagation()">
<!-- HEADER POPUP -->
<div class="pop-head">
<!-- Icône agent — cliquer pour uploader -->
<div class="agent-icon-wrap" onclick="document.getElementById('icon-upload').click()" title="Changer l'icône">
<i class="fa-solid fa-server" id="agent-icon-fa"></i>
<img id="agent-icon-img" src="" style="display:none">
<div class="agent-icon-overlay">
<i class="fa-solid fa-camera"></i>
<span>Changer</span>
</div>
</div>
<input type="file" id="icon-upload" accept=".svg,.jpg,.jpeg,.png,.webp" onchange="handleIconUpload(event)">
<div class="pop-head-info">
<div class="pop-host">srv-prod-01</div>
<div class="pop-ip">10.0.0.11</div>
<div class="upload-hint" id="upload-hint">Cliquer sur l'icône pour personnaliser · SVG, JPG, PNG, WEBP · max 128×128 px</div>
</div>
<div class="pop-led"></div>
<div class="pop-close" onclick="document.getElementById('popup-overlay').style.display='none'">
<i class="fa-solid fa-xmark"></i>
</div>
</div>
<!-- BODY -->
<div class="pop-body">
<!-- KPIs actuels -->
<div>
<div class="sec-title">MÉTRIQUES ACTUELLES</div>
<div class="kpi-grid">
<div class="kpi"><div class="kpi-lbl">CPU</div><div class="kpi-val c-ok">42<span class="u">%</span></div><div class="kpi-sub">4 cœurs</div></div>
<div class="kpi"><div class="kpi-lbl">MÉMOIRE</div><div class="kpi-val">3.7<span class="u">Go</span></div><div class="kpi-sub">/ 8 Go · 46%</div></div>
<div class="kpi"><div class="kpi-lbl">DISQUE</div><div class="kpi-val">62<span class="u">Go</span></div><div class="kpi-sub">/ 200 Go · 31%</div></div>
<div class="kpi"><div class="kpi-lbl">UPTIME</div><div class="kpi-val" style="font-size:15px;color:var(--ink-1)">14j 6h</div><div class="kpi-sub">depuis boot</div></div>
</div>
</div>
<!-- COURBES HISTORIQUES CPU + RAM -->
<div>
<div class="sec-title">HISTORIQUE — 30 DERNIÈRES MINUTES</div>
<div class="charts-grid">
<!-- CPU chart -->
<div class="chart-card">
<div class="chart-header">
<div class="chart-label" style="color:var(--accent)"><i class="fa-solid fa-microchip"></i>CPU</div>
<span class="chart-cur c-ok">42%</span>
</div>
<svg class="chart-svg" viewBox="0 0 200 56" preserveAspectRatio="none" id="cpu-chart"></svg>
<div class="chart-axis"><span>-30min</span><span>-15min</span><span>maintenant</span></div>
</div>
<!-- RAM chart -->
<div class="chart-card">
<div class="chart-header">
<div class="chart-label" style="color:var(--blue)"><i class="fa-solid fa-memory"></i>RAM</div>
<span class="chart-cur" style="color:var(--blue)">46%</span>
</div>
<svg class="chart-svg" viewBox="0 0 200 56" preserveAspectRatio="none" id="ram-chart"></svg>
<div class="chart-axis"><span>-30min</span><span>-15min</span><span>maintenant</span></div>
</div>
</div>
</div>
<!-- DISQUE — jauge barre conservée (pas de série temporelle pertinente) -->
<div>
<div class="sec-title">STOCKAGE</div>
<div class="det-gauges">
<div class="dg-row">
<div class="dg-ico"><i class="fa-solid fa-hard-drive"></i><span class="dg-tip">Disque utilisé</span></div>
<div class="dg-bar"><div class="dg-fill" style="width:31%"></div></div>
<span class="dg-val">62 / 200 Go</span>
</div>
<div class="dg-row">
<div class="dg-ico" style="color:var(--blue)"><i class="fa-solid fa-floppy-disk"></i><span class="dg-tip">Espace libre</span></div>
<div class="dg-bar"><div class="dg-fill" style="width:69%;background:var(--blue)"></div></div>
<span class="dg-val">138 Go libre</span>
</div>
</div>
</div>
<!-- INFOS -->
<div>
<div class="sec-title">INFORMATIONS</div>
<div class="meta-grid">
<div class="meta"><div class="meta-lbl">HOSTNAME</div><div class="meta-val">srv-prod-01</div></div>
<div class="meta"><div class="meta-lbl">ADRESSE IP</div><div class="meta-val">10.0.0.11</div></div>
<div class="meta"><div class="meta-lbl">DERNIER CONTACT</div><div class="meta-val">22:14:07</div></div>
<div class="meta"><div class="meta-lbl">FRÉQUENCE</div><div class="meta-val">CPU 2s · Disk 60s</div></div>
</div>
</div>
</div>
<!-- FOOTER popup — pas de bouton Fermer -->
<div class="pop-foot">
<span class="pop-uptime"><i class="fa-solid fa-clock" style="margin-right:4px"></i>En ligne depuis 14 jours 6 heures</span>
<button class="btn"><i class="fa-solid fa-chart-line"></i> Historique complet</button>
</div>
</div>
</div>
<script>
/* ── thème ── */
function toggleTheme() {
const h = document.documentElement;
const i = document.getElementById('theme-icon');
h.dataset.theme = h.dataset.theme === 'dark' ? 'light' : 'dark';
i.className = h.dataset.theme === 'dark' ? 'fa-solid fa-moon' : 'fa-solid fa-sun';
drawCharts();
}
/* ── upload icône ── */
function handleIconUpload(e) {
const file = e.target.files[0];
if (!file) return;
const allowed = ['image/svg+xml','image/jpeg','image/png','image/webp'];
if (!allowed.includes(file.type)) { alert('Format non supporté'); return; }
const reader = new FileReader();
reader.onload = function(ev) {
if (file.type === 'image/svg+xml') {
// SVG : afficher directement
showAgentIcon(ev.target.result, true);
} else {
// Raster : redimensionner canvas max 128×128 en respectant le ratio
const img = new Image();
img.onload = function() {
const canvas = document.createElement('canvas');
const ratio = Math.min(128 / img.width, 128 / img.height, 1);
canvas.width = Math.round(img.width * ratio);
canvas.height = Math.round(img.height * ratio);
canvas.getContext('2d').drawImage(img, 0, 0, canvas.width, canvas.height);
showAgentIcon(canvas.toDataURL(file.type === 'image/png' ? 'image/png' : 'image/jpeg', 0.9), false);
};
img.src = ev.target.result;
}
document.getElementById('upload-hint').textContent = '✓ Icône mise à jour — sauvegardée sur le serveur';
document.getElementById('upload-hint').style.color = 'var(--ok)';
};
reader.readAsDataURL(file);
}
function showAgentIcon(src, isSvg) {
document.getElementById('agent-icon-fa').style.display = 'none';
const img = document.getElementById('agent-icon-img');
img.src = src;
img.style.display = 'block';
}
/* ── courbes historiques ── */
function makeCurve(pts, color, fillColor, w, h) {
if (!pts.length) return '';
const maxV = 100, minV = 0;
const xs = pts.map((_, i) => (i / (pts.length - 1)) * w);
const ys = pts.map(v => h - ((v - minV) / (maxV - minV)) * (h - 4) - 2);
// zone de seuil warn (70%) — ligne pointillée
const warnY = h - ((70 - minV) / (maxV - minV)) * (h - 4) - 2;
let d = `M ${xs[0]} ${ys[0]}`;
for (let i = 1; i < pts.length; i++) {
const cx = (xs[i-1] + xs[i]) / 2;
d += ` C ${cx} ${ys[i-1]}, ${cx} ${ys[i]}, ${xs[i]} ${ys[i]}`;
}
const fillD = d + ` L ${xs[xs.length-1]} ${h} L ${xs[0]} ${h} Z`;
return `
<defs>
<linearGradient id="grad-${color.replace('#','')}" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="${fillColor}" stop-opacity="0.35"/>
<stop offset="100%" stop-color="${fillColor}" stop-opacity="0.02"/>
</linearGradient>
</defs>
<line x1="0" y1="${warnY}" x2="${w}" y2="${warnY}"
stroke="var(--warn)" stroke-width="0.8" stroke-dasharray="3,3" opacity="0.5"/>
<path d="${fillD}" fill="url(#grad-${color.replace('#','')})" />
<path d="${d}" fill="none" stroke="${color}" stroke-width="1.5" stroke-linejoin="round" stroke-linecap="round"/>
<circle cx="${xs[xs.length-1]}" cy="${ys[ys.length-1]}" r="2.5" fill="${color}"/>
`;
}
function drawCharts() {
const cpuPts = [38,41,35,40,44,42,39,45,50,48,43,42,44,41,40,43,47,45,42,44,41,43,42,40,43,41,44,43,41,42];
const ramPts = [44,44,45,45,46,46,47,47,46,46,45,46,46,47,47,46,46,45,46,46,46,46,46,46,46,46,46,46,46,46];
const accent = getComputedStyle(document.documentElement).getPropertyValue('--accent').trim();
const blue = getComputedStyle(document.documentElement).getPropertyValue('--blue').trim();
document.getElementById('cpu-chart').innerHTML = makeCurve(cpuPts, accent, accent, 200, 56);
document.getElementById('ram-chart').innerHTML = makeCurve(ramPts, blue, blue, 200, 56);
}
window.addEventListener('load', drawCharts);
function showPopup() {
document.getElementById('popup-overlay').style.display = 'flex';
}
</script>
</body>
</html>