Alerts tab, Docker tab, nine new skins including HUD, a colour for every machine

Alerts: rules over sensors, watched fleet-wide from the hub; ntfy and webhook channels;
firing count on the rail. Docker: containers by stack with live use, start/stop/restart,
following logs, inspect, images/volumes/networks. Skins: HUD, Nord, Gruvbox, Catppuccin
(+Latte), Dracula, Tokyo Night, Solarized (+Light). Accents: per-machine colour.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Mitchell-Johnson
2026-09-19 15:07:15 -07:00
co-authored by Claude Fable 5.1
parent 63fcba6077
commit cb1617c2b8
17 changed files with 1185 additions and 15 deletions
+45
View File
@@ -438,3 +438,48 @@ a.btn { text-decoration: none; display: inline-flex; align-items: center; }
.ttab.drop { box-shadow: inset 3px 0 0 var(--accent2); }
.ttab-move { display: none; } .ttab-move .icon-btn:disabled { opacity: .3; }
@media (pointer: coarse) { .ttab-move { display: inline-flex; } } /* no drag and drop on a touch screen */
/* each machine's colour */
.header { box-shadow: inset 0 3px 0 var(--machine, var(--accent)); }
.mswitch-btn .mname, .header .host { color: var(--machine, var(--accent)); }
.swatches { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: 8px; }
.swatch { width: 26px; height: 26px; border-radius: 50%; border: 2px solid transparent; cursor: pointer; padding: 0; }
.swatch.on { border-color: var(--fg); box-shadow: 0 0 0 2px var(--bg2) inset; }
.swatches input[type=color] { width: 30px; height: 30px; padding: 0; border: 1px solid var(--border); border-radius: 50%; background: none; cursor: pointer; }
.themes { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
/* HUD: light drawn on glass — hairlines, no fills, thin type */
[data-theme="hud"] .tile, [data-theme="hud"] .card, [data-theme="hud"] .box, [data-theme="hud"] .modal { background: rgba(53, 214, 255, .03); border-color: rgba(53, 214, 255, .28); border-radius: 2px; box-shadow: 0 0 0 1px rgba(53, 214, 255, .05), inset 0 0 24px rgba(53, 214, 255, .04); }
[data-theme="hud"] .tile::before, [data-theme="hud"] .card::before { content: ''; position: absolute; top: -1px; left: -1px; width: 12px; height: 12px; border-top: 2px solid var(--accent); border-left: 2px solid var(--accent); }
[data-theme="hud"] .tile, [data-theme="hud"] .card { position: relative; }
[data-theme="hud"] body { font-weight: 300; letter-spacing: .2px; }
[data-theme="hud"] .tile .value, [data-theme="hud"] .brand { font-weight: 300; letter-spacing: 1.5px; text-shadow: 0 0 10px rgba(53, 214, 255, .55); }
[data-theme="hud"] .tile .label, [data-theme="hud"] .card h2, [data-theme="hud"] h2.section { letter-spacing: 2px; color: var(--accent); opacity: .8; }
[data-theme="hud"] .meter { height: 3px; border-radius: 0; } [data-theme="hud"] .meter .fill { border-radius: 0; box-shadow: 0 0 8px var(--s1); }
[data-theme="hud"] .rail, [data-theme="hud"] .header, [data-theme="hud"] .footer { background: rgba(3, 7, 12, .92); border-color: rgba(53, 214, 255, .22); }
[data-theme="hud"] .group-head.active { background: linear-gradient(90deg, rgba(53, 214, 255, .16), transparent); box-shadow: inset 2px 0 0 var(--accent); }
[data-theme="hud"] .btn, [data-theme="hud"] .chip { background: transparent; border-color: rgba(53, 214, 255, .35); border-radius: 2px; } [data-theme="hud"] .btn.on, [data-theme="hud"] .chip.on { background: rgba(53, 214, 255, .16); color: var(--accent2); border-color: var(--accent); }
[data-theme="hud"] .app { background: radial-gradient(ellipse at 50% -20%, rgba(53, 214, 255, .10), transparent 60%), var(--bg); }
[data-theme="hud"] .gauge-svg path:first-child { stroke-width: 3; } [data-theme="hud"] .gauge-svg path:nth-child(2) { stroke-width: 5; filter: drop-shadow(0 0 4px var(--s1)); }
/* alerts */
.card.all-clear { padding: 16px; } .card.firing { border-color: var(--s2); } .card.firing.bad { border-color: var(--bad); box-shadow: 0 0 0 1px var(--bad) inset; }
.rule { display: flex; align-items: center; gap: 10px; padding: 9px 0; border-top: 1px solid var(--border); } .rule:first-child { border-top: 0; padding-top: 0; } .rule.off .rule-body { opacity: .5; }
.rule-body { flex: 1; min-width: 0; cursor: pointer; } .rule-name { display: flex; align-items: center; gap: 8px; } .rule-body .mono { overflow-wrap: anywhere; margin-top: 2px; }
.toggle { width: 38px; height: 22px; border-radius: 11px; background: var(--bg3); border: 1px solid var(--border); position: relative; flex-shrink: 0; padding: 0; } .toggle i { position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 50%; background: var(--muted); transition: left .15s, background .15s; }
.toggle.on { background: color-mix(in srgb, var(--ok) 25%, var(--bg3)); border-color: var(--ok); } .toggle.on i { left: 18px; background: var(--ok); }
.rule-cond { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; } .rule-cond select, .rule-cond input, .chan-add select, .chan-add input { padding: 8px 9px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; color: var(--fg); font-size: 14px; } .rule-cond input.mono { flex: 1 1 120px; min-width: 0; }
.chan-add { display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; } .chan-add input { flex: 1 1 220px; min-width: 0; }
.ev { display: flex; align-items: baseline; gap: 8px; padding: 6px 0; border-top: 1px solid var(--border); font-size: 13px; } .ev:first-child { border-top: 0; } .ev-main { flex: 1; min-width: 0; overflow-wrap: anywhere; } .bad-text { color: var(--bad) !important; }
.rail-badge { margin-left: auto; min-width: 18px; padding: 0 5px; border-radius: 9px; background: var(--bad); color: #fff; font-size: 11px; font-weight: 700; text-align: center; line-height: 18px; }
@media (pointer: coarse) { .toggle { width: 46px; height: 28px; border-radius: 14px; } .toggle i { width: 22px; height: 22px; } .toggle.on i { left: 20px; } }
/* docker */
.stack-head { margin: 0; padding: 8px 12px 4px; font-size: 11px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: .5px; background: var(--bg2); position: sticky; top: 0; z-index: 1; }
.docker .svc-state { text-align: right; line-height: 1.35; }
.dtable { width: 100%; border-collapse: collapse; } .dtable th { text-align: left; padding: 8px 12px; font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: .5px; position: sticky; top: 0; background: var(--bg2); }
.dtable td { padding: 7px 12px; border-top: 1px solid var(--border); overflow-wrap: anywhere; }
.docker:not(.has-sel) .svc-list { flex: 1; width: auto; max-width: 760px; }
.docker .svc-tools .chips { flex-wrap: wrap; } .docker .svc-name { flex: 1; min-width: 0; } .docker .svc-name .n { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.docker .svc-row { min-width: 0; } .docker .svc-state { flex-shrink: 0; }
.alerts .row { display: flex; align-items: center; gap: 8px; } .alerts .row .badge { flex: 0 0 auto; } .alerts .row .k { flex: 1; min-width: 0; overflow-wrap: anywhere; }