feat(gui): Systemanzeige in der Kopfzeile (Speicherring + Turbine)

Zwei Symbole zwischen Bluetooth-Tab und Hell/Dunkel-Schalter: ein Ring mit
der Plattenbelegung in Prozent und eine Turbine, deren Drehzahl der CPU-Last
folgt. Beide klappen bei Mauskontakt eine Karte mit Zahlen auf (belegt/frei/
gesamt bzw. CPU, RAM, Temperatur).

Neues Modul sysstat.js liest alles aus /proc bzw. fs.statfsSync, damit die
GUI im Sekundentakt fragen kann, ohne df/top-Prozesse zu starten. CPU-% aus
zwei /proc/stat-Messpunkten mit eigenem 2-s-Ticker, RAM ueber MemAvailable,
Temperatur als waermste SoC-/Core-Zone.

Doku: Kapitel 07 + Changelog.
This commit is contained in:
Claude
2026-08-17 21:52:21 +02:00
parent 0f530b575a
commit 47288c0479
6 changed files with 334 additions and 1 deletions
+51
View File
@@ -127,6 +127,57 @@ nav { display: flex; gap: 6px; flex-wrap: wrap; }
.tab.active { color: var(--accent); background: var(--accent-soft); font-weight: 600; }
.btn.icon.theme { border-radius: 999px; font-size: 15px; line-height: 1; }
/* ---- Systemanzeige: Plattenring + Turbine (zwischen Tabs und Theme-Schalter) ---- */
.sysmon { display: flex; align-items: center; gap: 6px; }
.sys-chip {
position: relative; display: inline-flex; align-items: center; gap: 6px;
padding: 4px 9px 4px 6px; border: 1px solid var(--line); border-radius: 999px;
background: var(--surface); color: var(--muted); cursor: default; outline: none;
transition: border-color .15s, background .15s, color .15s;
}
.sys-chip.ok { color: var(--ok); }
.sys-chip.warn { color: var(--warn); background: var(--warn-soft); border-color: var(--warn); }
.sys-chip.danger { color: var(--danger); background: var(--danger-soft); border-color: var(--danger); }
.sys-chip.off { opacity: .55; }
.sys-chip:hover, .sys-chip:focus-visible { border-color: currentColor; }
.sys-val { font-size: 12px; font-variant-numeric: tabular-nums; color: var(--fg); }
/* Plattenbelegung als Ring: r = 15.9155 ⇒ Umfang 100, dasharray = Prozent */
.ring { width: 20px; height: 20px; flex: none; transform: rotate(-90deg); }
.ring circle { fill: none; stroke-width: 4; }
.ring-bg { stroke: var(--line); }
.ring-fg { stroke: currentColor; stroke-linecap: round; transition: stroke-dasharray .4s ease; }
/* Turbine: Drehdauer kommt als --spin aus main.js (je mehr Last, desto kürzer) */
.turbine { width: 21px; height: 21px; flex: none; }
.tb-blades { fill: currentColor; transform-origin: 12px 12px; animation: tbspin var(--spin, 7s) linear infinite; }
.tb-hub { fill: var(--surface); stroke: currentColor; stroke-width: 1.4; }
@keyframes tbspin { to { transform: rotate(360deg); } }
.sys-chip.off .tb-blades { animation: none; }
@media (prefers-reduced-motion: reduce) { .tb-blades { animation: none; } }
/* Klappkarte bei Mauskontakt (oder Tastaturfokus) */
.sys-pop {
display: none; position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
min-width: 215px; padding: 10px 12px; color: var(--fg);
background: var(--surface); border: 1px solid var(--line); border-radius: 12px;
box-shadow: 0 8px 24px rgba(0, 0, 0, .28);
}
.sys-chip:hover .sys-pop, .sys-chip:focus .sys-pop, .sys-chip:focus-within .sys-pop { display: block; }
.sys-pop-h {
font-size: 11px; font-weight: 700; color: var(--muted);
text-transform: uppercase; letter-spacing: .05em; margin-bottom: 7px;
}
.sys-row { display: flex; justify-content: space-between; gap: 14px; font-size: 13px; padding: 2px 0; }
.sys-row span { color: var(--muted); }
.sys-row b { font-weight: 600; font-variant-numeric: tabular-nums; }
.sys-bar { height: 5px; border-radius: 3px; background: var(--inset); overflow: hidden; margin: 3px 0 7px; }
.sys-bar i { display: block; height: 100%; background: var(--accent); transition: width .4s ease; }
.sys-chip.ok .sys-bar i { background: var(--ok); }
.sys-chip.warn .sys-bar i { background: var(--warn); }
.sys-chip.danger .sys-bar i { background: var(--danger); }
@media (max-width: 900px) { .sys-val { display: none; } }
/* ---- Bausteine ---- */
.card {
background: var(--surface); border: 1px solid var(--line); border-radius: 14px;