81c7825937
Three deliberately differentiated takes on the dashboard so we can
lock the visual register before the UI work starts (P1-23 onwards).
v1 — Operator console (Linear/Datadog dark register).
Dense table, monospace numerics, restrained colour, pulsing
status dot only when a job is running. The natural fit for
the audience and the most defensible choice.
v2 — Editorial calm (Stripe/Notion light register).
Serif hero headline that humanises the data, cards with
breathing room in a 2-up grid, demoted "quiet hosts" strip,
subtle rust accent. Reads as trustworthy infrastructure.
v3 — Print spec (Tufte/aerospace monospace register).
Pure monospace, near-monochrome, status as typeset glyphs
(●▶▲○✗) so the screen survives greyscale. "Requires
attention" block groups problem hosts at the top; activity
tail reads like a real log. Most polarising; highest
craft ceiling.
Each file is self-contained (Tailwind via CDN + Google Fonts) and
includes a philosophy preamble + the dashboard hero + a component
vocabulary section so we can read the system, not just one screen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
667 lines
35 KiB
HTML
667 lines
35 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>restic-manager · v3 Print Spec</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@300;400;500;600&family=IBM+Plex+Sans:wght@400;500&display=swap" rel="stylesheet">
|
|
<style>
|
|
:root {
|
|
--paper: oklch(0.985 0.011 82);
|
|
--paper-2: oklch(0.974 0.012 82);
|
|
--rule: oklch(0.20 0.008 60);
|
|
--rule-soft:oklch(0.78 0.014 75);
|
|
--rule-fade:oklch(0.88 0.012 75);
|
|
--ink: oklch(0.16 0.008 60);
|
|
--ink-mid: oklch(0.36 0.010 60);
|
|
--ink-mute: oklch(0.50 0.010 60);
|
|
--ink-fade: oklch(0.66 0.010 60);
|
|
|
|
/* Single state colour. Used only for `failed` / `alert`. Everything else
|
|
is type weight, brackets, and rule emphasis. */
|
|
--warn: oklch(0.50 0.20 28);
|
|
}
|
|
html, body {
|
|
background: var(--paper);
|
|
color: var(--ink);
|
|
font-family: 'IBM Plex Mono', ui-monospace, Menlo, Consolas, monospace;
|
|
font-feature-settings: 'kern', 'liga', 'tnum';
|
|
font-variant-numeric: tabular-nums;
|
|
-webkit-font-smoothing: antialiased;
|
|
}
|
|
/* The 120% detail in this direction is rule discipline — every horizontal
|
|
line falls on a strict baseline grid, and the rule weight encodes
|
|
hierarchy more reliably than colour ever does. */
|
|
.rule { border-bottom: 1.5px solid var(--rule); }
|
|
.rule-soft { border-bottom: 1px solid var(--rule-soft); }
|
|
.rule-fade { border-bottom: 1px solid var(--rule-fade); }
|
|
.rule-double {
|
|
border-bottom: 1.5px solid var(--rule);
|
|
box-shadow: 0 4px 0 -2.5px var(--rule);
|
|
}
|
|
|
|
.sans { font-family: 'IBM Plex Sans', ui-sans-serif, sans-serif; }
|
|
|
|
::selection { background: var(--ink); color: var(--paper); }
|
|
|
|
/* status as text glyph + label — no dots, no colour (except WARN) */
|
|
.st { display: inline-flex; align-items: baseline; gap: 4px; font-size: 12px; }
|
|
.st-glyph { font-weight: 600; letter-spacing: 0; }
|
|
.st-online .st-glyph { color: var(--ink); }
|
|
.st-degraded .st-glyph { color: var(--warn); }
|
|
.st-offline .st-glyph { color: var(--ink-fade); }
|
|
.st-failed .st-glyph { color: var(--warn); }
|
|
.st-never .st-glyph { color: var(--ink-fade); }
|
|
.st-running .st-glyph { color: var(--ink); }
|
|
|
|
.tag {
|
|
display: inline-block; font-size: 11px; padding: 0 6px;
|
|
color: var(--ink-mid);
|
|
border: 1px solid var(--rule-soft);
|
|
border-radius: 0;
|
|
line-height: 18px;
|
|
letter-spacing: 0.02em;
|
|
}
|
|
|
|
/* bracket buttons — visually a typed command */
|
|
.btn {
|
|
font-family: 'IBM Plex Mono', monospace;
|
|
font-size: 12px; padding: 4px 10px;
|
|
border: 1px solid var(--rule);
|
|
background: var(--paper);
|
|
color: var(--ink);
|
|
border-radius: 0;
|
|
transition: all 80ms linear;
|
|
cursor: pointer;
|
|
letter-spacing: 0.01em;
|
|
}
|
|
.btn::before { content: '['; margin-right: 4px; color: var(--ink-mid); }
|
|
.btn::after { content: ']'; margin-left: 4px; color: var(--ink-mid); }
|
|
.btn:hover { background: var(--ink); color: var(--paper); }
|
|
.btn:hover::before, .btn:hover::after { color: var(--paper); }
|
|
.btn-primary { background: var(--ink); color: var(--paper); }
|
|
.btn-primary::before, .btn-primary::after { color: var(--paper); }
|
|
.btn-primary:hover { filter: brightness(1.4); }
|
|
.btn-quiet {
|
|
border-color: transparent;
|
|
padding: 4px 6px;
|
|
}
|
|
.btn-quiet::before, .btn-quiet::after { color: var(--ink-fade); }
|
|
.btn-quiet:hover { background: var(--paper-2); color: var(--ink); }
|
|
|
|
.doc { max-width: 1200px; margin: 0 auto; padding: 0 32px; }
|
|
.num { font-feature-settings: 'tnum', 'kern'; }
|
|
|
|
.philosophy { padding: 56px 0 32px; }
|
|
.philosophy h1 {
|
|
font-size: 22px; font-weight: 500;
|
|
letter-spacing: -0.005em;
|
|
}
|
|
.philosophy p {
|
|
color: var(--ink-mid); max-width: 640px;
|
|
margin-top: 16px; line-height: 1.65;
|
|
text-wrap: pretty;
|
|
}
|
|
.philosophy .meta { color: var(--ink-mute); font-size: 12px; margin-top: 14px; }
|
|
|
|
.stage-frame {
|
|
margin: 48px -32px;
|
|
border-top: 1.5px solid var(--rule);
|
|
border-bottom: 1.5px solid var(--rule);
|
|
background: var(--paper);
|
|
}
|
|
|
|
/* hosts table layout — fixed columns so numbers line up cleanly */
|
|
.hosts-grid {
|
|
display: grid;
|
|
grid-template-columns:
|
|
14ch /* status */
|
|
1fr /* host name */
|
|
14ch /* os/arch */
|
|
18ch /* last backup */
|
|
9ch /* size */
|
|
9ch /* snapshots */
|
|
6ch /* alerts */
|
|
14ch /* tags */
|
|
11ch; /* action */
|
|
align-items: baseline;
|
|
column-gap: 12px;
|
|
padding: 7px 16px;
|
|
font-size: 13px;
|
|
line-height: 1.55;
|
|
}
|
|
.hosts-grid > .ralign { text-align: right; }
|
|
.hosts-grid > .ralign-tags {
|
|
display: flex; gap: 4px; flex-wrap: nowrap; overflow: hidden;
|
|
}
|
|
.hosts-grid:hover { background: var(--paper-2); }
|
|
|
|
.col-head {
|
|
font-size: 11px; color: var(--ink-mute);
|
|
text-transform: uppercase; letter-spacing: 0.08em;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.components-section { margin: 64px 0 96px; }
|
|
.components-section h2 {
|
|
font-size: 14px; font-weight: 600;
|
|
text-transform: uppercase; letter-spacing: 0.12em;
|
|
margin-bottom: 22px;
|
|
color: var(--ink-mid);
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="doc">
|
|
|
|
<!-- Philosophy preamble -->
|
|
<header class="philosophy">
|
|
<div class="text-xs uppercase tracking-[0.18em]" style="color: var(--ink-mute); margin-bottom: 12px;">v3 · Direction C</div>
|
|
<h1 class="sans" style="font-weight: 600;">Print spec.</h1>
|
|
<p>
|
|
Optimised for legibility under any condition: bright sunlight, copy-pasted
|
|
into Slack as a screenshot, printed on A4 and stuck to a server cabinet.
|
|
Monospace throughout so columns line up without effort. Status conveyed by
|
|
typeset glyph (<span class="num" style="color: var(--ink); font-weight:600;">●</span>
|
|
online · <span class="num" style="color: var(--warn); font-weight:600;">▲</span>
|
|
degraded · <span class="num" style="color: var(--ink-fade); font-weight:600;">○</span>
|
|
offline) so the screen survives being read in greyscale. One accent
|
|
colour, used only when something is wrong. Every horizontal rule earns its
|
|
weight; weight encodes hierarchy.
|
|
</p>
|
|
<p>
|
|
Reference: Edward Tufte, vintage aerospace datasheets, restic's own
|
|
<span class="num" style="color: var(--ink); font-weight: 500;">--json</span>
|
|
output, the wireframe register but at maximum craft.
|
|
</p>
|
|
<p class="meta">
|
|
Risk: the most polarising of the three. Some readers will love the
|
|
typographic discipline; others will read it as cold. There is no middle.
|
|
</p>
|
|
</header>
|
|
|
|
<!-- Stage: full hi-fi dashboard -->
|
|
<div class="stage-frame">
|
|
|
|
<!-- Top header — print-style with rules above and below -->
|
|
<div style="background: var(--paper);">
|
|
<div class="rule-fade">
|
|
<div class="doc flex items-baseline justify-between" style="padding: 10px 0;">
|
|
<div class="flex items-baseline gap-3" style="font-size: 11px; color: var(--ink-mute); letter-spacing: 0.04em;">
|
|
<span>RESTIC-MANAGER · DASHBOARD</span>
|
|
<span style="color: var(--ink-fade);">/</span>
|
|
<span>v0.1.0-alpha</span>
|
|
<span style="color: var(--ink-fade);">/</span>
|
|
<span>generated 2026-05-01 14:23 UTC</span>
|
|
</div>
|
|
<div class="flex items-baseline gap-3" style="font-size: 11px; color: var(--ink-mute); letter-spacing: 0.04em;">
|
|
<span>steve@dcglab</span>
|
|
<span style="color: var(--ink-fade);">/</span>
|
|
<a style="color: var(--ink-mid); text-decoration: underline; text-underline-offset: 3px;">sign out</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Big title row -->
|
|
<div class="rule" style="background: var(--paper);">
|
|
<div class="doc flex items-end justify-between" style="padding: 18px 0 12px;">
|
|
<h1 class="sans" style="font-size: 28px; font-weight: 600; letter-spacing: -0.015em;">restic-manager <span style="color: var(--ink-fade); font-weight: 400;">/ fleet dashboard</span></h1>
|
|
<div class="flex items-center gap-2">
|
|
<button class="btn btn-quiet">repos</button>
|
|
<button class="btn btn-quiet">alerts <span class="num" style="color: var(--warn); font-weight:600; padding-left:4px;">5</span></button>
|
|
<button class="btn btn-quiet">audit</button>
|
|
<button class="btn btn-quiet">settings</button>
|
|
<span style="width: 12px;"></span>
|
|
<button class="btn btn-primary">+ add host</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Fleet summary as a print-style ledger -->
|
|
<div class="doc" style="padding: 28px 32px 8px;">
|
|
<div class="grid grid-cols-4 gap-px" style="background: var(--rule-fade); border: 1px solid var(--rule-fade);">
|
|
<div style="background: var(--paper); padding: 18px 20px;">
|
|
<div class="col-head">FLEET</div>
|
|
<div class="num sans" style="font-size: 32px; font-weight: 500; letter-spacing: -0.02em; margin-top: 6px;">12 <span style="font-size: 13px; color: var(--ink-mute); font-weight: 400; font-family: 'IBM Plex Mono';">hosts</span></div>
|
|
<div style="font-size: 12px; margin-top: 10px; color: var(--ink-mid);">
|
|
<span class="num" style="color: var(--ink); font-weight: 500;">10</span> online
|
|
<span class="num" style="color: var(--warn); font-weight: 500;">1</span> degraded
|
|
<span class="num" style="color: var(--ink-fade); font-weight: 500;">1</span> offline
|
|
</div>
|
|
</div>
|
|
<div style="background: var(--paper); padding: 18px 20px;">
|
|
<div class="col-head">BACKED UP</div>
|
|
<div class="num sans" style="font-size: 32px; font-weight: 500; letter-spacing: -0.02em; margin-top: 6px;">4.9 <span style="font-size: 13px; color: var(--ink-mute); font-weight: 400; font-family: 'IBM Plex Mono';">TB · 12 repos</span></div>
|
|
<div style="font-size: 12px; margin-top: 10px; color: var(--ink-mid);">
|
|
<span class="num" style="color: var(--ink); font-weight: 500;">23,649</span> snapshots
|
|
</div>
|
|
</div>
|
|
<div style="background: var(--paper); padding: 18px 20px;">
|
|
<div class="col-head">LAST 24H</div>
|
|
<div class="num sans" style="font-size: 32px; font-weight: 500; letter-spacing: -0.02em; margin-top: 6px;">147 <span style="font-size: 13px; color: var(--ink-mute); font-weight: 400; font-family: 'IBM Plex Mono';">jobs</span></div>
|
|
<div style="font-size: 12px; margin-top: 10px; color: var(--ink-mid);">
|
|
<span class="num" style="color: var(--ink); font-weight: 500;">144</span> ok
|
|
<span class="num" style="color: var(--warn); font-weight: 500;">2</span> failed
|
|
<span class="num" style="color: var(--ink-mid); font-weight: 500;">1</span> cancelled
|
|
</div>
|
|
</div>
|
|
<div style="background: var(--paper); padding: 18px 20px;">
|
|
<div class="col-head">OPEN ALERTS</div>
|
|
<div class="num sans" style="font-size: 32px; font-weight: 500; letter-spacing: -0.02em; margin-top: 6px; color: var(--warn);">5 <span style="font-size: 13px; color: var(--ink-mute); font-weight: 400; font-family: 'IBM Plex Mono';">unresolved</span></div>
|
|
<div style="font-size: 12px; margin-top: 10px; color: var(--ink-mid);">
|
|
oldest <span class="num" style="color: var(--ink); font-weight: 500;">3h</span> · review →
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Hosts ledger -->
|
|
<div class="doc" style="padding: 32px 32px 12px;">
|
|
|
|
<div class="flex items-baseline justify-between" style="padding-bottom: 8px;">
|
|
<div class="flex items-baseline gap-4">
|
|
<h2 class="sans" style="font-size: 14px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.08em;">Hosts</h2>
|
|
<span style="font-size: 12px; color: var(--ink-mute);">12 of 12 — sorted by status, then last activity</span>
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
<span style="font-size: 12px; color: var(--ink-mute);">filter:</span>
|
|
<input
|
|
type="text"
|
|
placeholder="name | tag | status…"
|
|
style="font-family: 'IBM Plex Mono'; font-size: 12px; padding: 4px 10px; background: var(--paper); border: 1px solid var(--rule-soft); border-radius: 0; color: var(--ink); width: 220px; outline: none;"
|
|
value=""
|
|
/>
|
|
<button class="btn btn-quiet">group: tag</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rule"></div>
|
|
|
|
<!-- table head -->
|
|
<div class="hosts-grid col-head" style="padding-top: 8px; padding-bottom: 8px;">
|
|
<div></div>
|
|
<div>host</div>
|
|
<div>os/arch</div>
|
|
<div>last backup</div>
|
|
<div class="ralign">size</div>
|
|
<div class="ralign">snaps</div>
|
|
<div class="ralign">alerts</div>
|
|
<div>tags</div>
|
|
<div class="ralign"></div>
|
|
</div>
|
|
|
|
<div class="rule-soft"></div>
|
|
|
|
<!-- ATTENTION block: degraded + failed + offline up top -->
|
|
<div style="font-size: 11px; color: var(--warn); padding: 10px 16px 4px; letter-spacing: 0.06em; text-transform: uppercase; font-weight: 600;">▲ requires attention</div>
|
|
|
|
<!-- prod-cache-01 — degraded -->
|
|
<div class="hosts-grid">
|
|
<div class="st st-degraded"><span class="st-glyph">▲</span><span style="color: var(--ink-mid);">degraded</span></div>
|
|
<div style="color: var(--ink); font-weight: 500;">prod-cache-01</div>
|
|
<div style="color: var(--ink-mid);">linux/amd64</div>
|
|
<div style="color: var(--ink-mid);"><span style="color: var(--ink);">ok</span> 1h ago</div>
|
|
<div class="ralign num" style="color: var(--ink);">128<span style="color: var(--ink-mute);">G</span></div>
|
|
<div class="ralign num" style="color: var(--ink-mid);">1,402</div>
|
|
<div class="ralign num" style="color: var(--warn); font-weight: 600;">3</div>
|
|
<div class="ralign-tags"><span class="tag">prod</span><span class="tag">cache</span></div>
|
|
<div class="ralign"><button class="btn">run</button></div>
|
|
</div>
|
|
|
|
<div class="rule-fade" style="margin-left: 16px; margin-right: 16px;"></div>
|
|
|
|
<!-- build-runner — failed -->
|
|
<div class="hosts-grid">
|
|
<div class="st st-failed"><span class="st-glyph">✗</span><span style="color: var(--ink-mid);">failed</span></div>
|
|
<div style="color: var(--ink); font-weight: 500;">build-runner</div>
|
|
<div style="color: var(--ink-mid);">linux/amd64</div>
|
|
<div style="color: var(--warn);">repo locked 47m ago</div>
|
|
<div class="ralign num" style="color: var(--ink);">97<span style="color: var(--ink-mute);">G</span></div>
|
|
<div class="ralign num" style="color: var(--ink-mid);">2,847</div>
|
|
<div class="ralign num" style="color: var(--warn); font-weight: 600;">1</div>
|
|
<div class="ralign-tags"><span class="tag">ci</span><span class="tag">build</span></div>
|
|
<div class="ralign"><button class="btn">retry</button></div>
|
|
</div>
|
|
|
|
<div class="rule-fade" style="margin-left: 16px; margin-right: 16px;"></div>
|
|
|
|
<!-- dev-laptop — offline -->
|
|
<div class="hosts-grid">
|
|
<div class="st st-offline"><span class="st-glyph">○</span><span style="color: var(--ink-mid);">offline</span></div>
|
|
<div style="color: var(--ink-mid); font-weight: 500;">dev-laptop</div>
|
|
<div style="color: var(--ink-mute);">linux/amd64</div>
|
|
<div style="color: var(--ink-mute);">last seen 2d ago</div>
|
|
<div class="ralign num" style="color: var(--ink-mid);">64<span style="color: var(--ink-mute);">G</span></div>
|
|
<div class="ralign num" style="color: var(--ink-mute);">127</div>
|
|
<div class="ralign num" style="color: var(--warn); font-weight: 600;">1</div>
|
|
<div class="ralign-tags"><span class="tag">dev</span><span class="tag">personal</span></div>
|
|
<div class="ralign" style="color: var(--ink-fade); font-size: 11px;">offline</div>
|
|
</div>
|
|
|
|
<div class="rule"></div>
|
|
|
|
<!-- HEALTHY hosts -->
|
|
<div style="font-size: 11px; color: var(--ink-mute); padding: 10px 16px 4px; letter-spacing: 0.06em; text-transform: uppercase; font-weight: 500;">● online · last 24h</div>
|
|
|
|
<!-- prod-db-01 — running -->
|
|
<div class="hosts-grid">
|
|
<div class="st st-running"><span class="st-glyph">▶</span><span style="color: var(--ink-mid);">running</span></div>
|
|
<div style="color: var(--ink); font-weight: 500;">prod-db-01</div>
|
|
<div style="color: var(--ink-mid);">linux/amd64</div>
|
|
<div style="color: var(--ink);">backup · 38% · ETA 2m</div>
|
|
<div class="ralign num" style="color: var(--ink);">412<span style="color: var(--ink-mute);">G</span></div>
|
|
<div class="ralign num" style="color: var(--ink-mid);">1,847</div>
|
|
<div class="ralign num" style="color: var(--ink-fade);">—</div>
|
|
<div class="ralign-tags"><span class="tag">prod</span><span class="tag">db</span></div>
|
|
<div class="ralign"><button class="btn btn-quiet">view</button></div>
|
|
</div>
|
|
<div class="rule-fade" style="margin-left: 16px; margin-right: 16px;"></div>
|
|
|
|
<!-- prod-db-02 -->
|
|
<div class="hosts-grid">
|
|
<div class="st st-online"><span class="st-glyph">●</span><span style="color: var(--ink-mid);">online</span></div>
|
|
<div style="color: var(--ink); font-weight: 500;">prod-db-02</div>
|
|
<div style="color: var(--ink-mid);">linux/amd64</div>
|
|
<div style="color: var(--ink-mid);">ok 4m ago</div>
|
|
<div class="ralign num" style="color: var(--ink);">389<span style="color: var(--ink-mute);">G</span></div>
|
|
<div class="ralign num" style="color: var(--ink-mid);">1,802</div>
|
|
<div class="ralign num" style="color: var(--ink-fade);">—</div>
|
|
<div class="ralign-tags"><span class="tag">prod</span><span class="tag">db</span></div>
|
|
<div class="ralign"><button class="btn">run</button></div>
|
|
</div>
|
|
<div class="rule-fade" style="margin-left: 16px; margin-right: 16px;"></div>
|
|
|
|
<!-- edge-node-eu -->
|
|
<div class="hosts-grid">
|
|
<div class="st st-online"><span class="st-glyph">●</span><span style="color: var(--ink-mid);">online</span></div>
|
|
<div style="color: var(--ink); font-weight: 500;">edge-node-eu</div>
|
|
<div style="color: var(--ink-mid);">linux/arm64</div>
|
|
<div style="color: var(--ink-mid);">ok 7m ago</div>
|
|
<div class="ralign num" style="color: var(--ink);">23<span style="color: var(--ink-mute);">G</span></div>
|
|
<div class="ralign num" style="color: var(--ink-mid);">934</div>
|
|
<div class="ralign num" style="color: var(--ink-fade);">—</div>
|
|
<div class="ralign-tags"><span class="tag">edge</span><span class="tag">prod</span></div>
|
|
<div class="ralign"><button class="btn">run</button></div>
|
|
</div>
|
|
<div class="rule-fade" style="margin-left: 16px; margin-right: 16px;"></div>
|
|
|
|
<!-- prod-web-01 -->
|
|
<div class="hosts-grid">
|
|
<div class="st st-online"><span class="st-glyph">●</span><span style="color: var(--ink-mid);">online</span></div>
|
|
<div style="color: var(--ink); font-weight: 500;">prod-web-01</div>
|
|
<div style="color: var(--ink-mid);">linux/amd64</div>
|
|
<div style="color: var(--ink-mid);">ok 11m ago</div>
|
|
<div class="ralign num" style="color: var(--ink);">87<span style="color: var(--ink-mute);">G</span></div>
|
|
<div class="ralign num" style="color: var(--ink-mid);">2,103</div>
|
|
<div class="ralign num" style="color: var(--ink-fade);">—</div>
|
|
<div class="ralign-tags"><span class="tag">prod</span><span class="tag">web</span></div>
|
|
<div class="ralign"><button class="btn">run</button></div>
|
|
</div>
|
|
<div class="rule-fade" style="margin-left: 16px; margin-right: 16px;"></div>
|
|
|
|
<!-- prod-web-02 -->
|
|
<div class="hosts-grid">
|
|
<div class="st st-online"><span class="st-glyph">●</span><span style="color: var(--ink-mid);">online</span></div>
|
|
<div style="color: var(--ink); font-weight: 500;">prod-web-02</div>
|
|
<div style="color: var(--ink-mid);">linux/amd64</div>
|
|
<div style="color: var(--ink-mid);">ok 12m ago</div>
|
|
<div class="ralign num" style="color: var(--ink);">87<span style="color: var(--ink-mute);">G</span></div>
|
|
<div class="ralign num" style="color: var(--ink-mid);">2,098</div>
|
|
<div class="ralign num" style="color: var(--ink-fade);">—</div>
|
|
<div class="ralign-tags"><span class="tag">prod</span><span class="tag">web</span></div>
|
|
<div class="ralign"><button class="btn">run</button></div>
|
|
</div>
|
|
<div class="rule-fade" style="margin-left: 16px; margin-right: 16px;"></div>
|
|
|
|
<!-- windows-vm -->
|
|
<div class="hosts-grid">
|
|
<div class="st st-online"><span class="st-glyph">●</span><span style="color: var(--ink-mid);">online</span></div>
|
|
<div style="color: var(--ink); font-weight: 500;">windows-vm</div>
|
|
<div style="color: var(--ink-mid);">windows/amd64</div>
|
|
<div style="color: var(--ink-mid);">ok 28m ago</div>
|
|
<div class="ralign num" style="color: var(--ink);">44<span style="color: var(--ink-mute);">G</span></div>
|
|
<div class="ralign num" style="color: var(--ink-mid);">156</div>
|
|
<div class="ralign num" style="color: var(--ink-fade);">—</div>
|
|
<div class="ralign-tags"><span class="tag">staging</span><span class="tag">vm</span></div>
|
|
<div class="ralign"><button class="btn">run</button></div>
|
|
</div>
|
|
<div class="rule-fade" style="margin-left: 16px; margin-right: 16px;"></div>
|
|
|
|
<!-- homelab-nas -->
|
|
<div class="hosts-grid">
|
|
<div class="st st-online"><span class="st-glyph">●</span><span style="color: var(--ink-mid);">online</span></div>
|
|
<div style="color: var(--ink); font-weight: 500;">homelab-nas</div>
|
|
<div style="color: var(--ink-mid);">linux/arm64</div>
|
|
<div style="color: var(--ink-mid);">ok 2h ago</div>
|
|
<div class="ralign num" style="color: var(--ink);">3.7<span style="color: var(--ink-mute);">T</span></div>
|
|
<div class="ralign num" style="color: var(--ink-mid);">8,912</div>
|
|
<div class="ralign num" style="color: var(--ink-fade);">—</div>
|
|
<div class="ralign-tags"><span class="tag">homelab</span><span class="tag">storage</span></div>
|
|
<div class="ralign"><button class="btn">run</button></div>
|
|
</div>
|
|
<div class="rule-fade" style="margin-left: 16px; margin-right: 16px;"></div>
|
|
|
|
<!-- homelab-pi -->
|
|
<div class="hosts-grid">
|
|
<div class="st st-online"><span class="st-glyph">●</span><span style="color: var(--ink-mid);">online</span></div>
|
|
<div style="color: var(--ink); font-weight: 500;">homelab-pi</div>
|
|
<div style="color: var(--ink-mid);">linux/arm64</div>
|
|
<div style="color: var(--ink-mid);">ok 6h ago</div>
|
|
<div class="ralign num" style="color: var(--ink);">8.4<span style="color: var(--ink-mute);">G</span></div>
|
|
<div class="ralign num" style="color: var(--ink-mid);">421</div>
|
|
<div class="ralign num" style="color: var(--ink-fade);">—</div>
|
|
<div class="ralign-tags"><span class="tag">homelab</span><span class="tag">iot</span></div>
|
|
<div class="ralign"><button class="btn">run</button></div>
|
|
</div>
|
|
<div class="rule-fade" style="margin-left: 16px; margin-right: 16px;"></div>
|
|
|
|
<!-- backup-test — never -->
|
|
<div class="hosts-grid">
|
|
<div class="st st-never"><span class="st-glyph">○</span><span style="color: var(--ink-mid);">never</span></div>
|
|
<div style="color: var(--ink); font-weight: 500;">backup-test</div>
|
|
<div style="color: var(--ink-mid);">linux/amd64</div>
|
|
<div style="color: var(--ink-fade); font-style: italic;">no backup yet</div>
|
|
<div class="ralign num" style="color: var(--ink-fade);">—</div>
|
|
<div class="ralign num" style="color: var(--ink-fade);">—</div>
|
|
<div class="ralign num" style="color: var(--ink-fade);">—</div>
|
|
<div class="ralign-tags"><span class="tag">test</span></div>
|
|
<div class="ralign"><button class="btn">run first</button></div>
|
|
</div>
|
|
|
|
<div class="rule"></div>
|
|
</div>
|
|
|
|
<!-- Recent activity log — log-tail style -->
|
|
<div class="doc" style="padding: 24px 32px 56px;">
|
|
<div class="flex items-baseline justify-between mb-3">
|
|
<h2 class="sans" style="font-size: 14px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.08em;">Activity tail</h2>
|
|
<span style="font-size: 12px; color: var(--ink-mute);">last 5 jobs · all hosts · <a style="text-decoration: underline; text-underline-offset: 3px; color: var(--ink-mid);">view all</a></span>
|
|
</div>
|
|
<div class="rule"></div>
|
|
|
|
<div style="font-size: 13px; padding: 6px 16px 0; line-height: 1.85;">
|
|
<div style="display: grid; grid-template-columns: 16ch 18ch 14ch 1fr 9ch 7ch; column-gap: 18px; padding: 4px 0;">
|
|
<span class="num" style="color: var(--ink-mute);">14:23:01.382</span>
|
|
<span style="color: var(--ink); font-weight:500;">prod-db-01</span>
|
|
<span class="num" style="color: var(--ink);">▶ running</span>
|
|
<span style="color: var(--ink-mid);">backup · 38% · 1.4 GB · ETA 2m</span>
|
|
<span class="num ralign" style="color: var(--ink-mid);">3m ago</span>
|
|
<span class="ralign" style="font-size: 11px; color: var(--ink-fade);">…E59B</span>
|
|
</div>
|
|
<div class="rule-fade"></div>
|
|
<div style="display: grid; grid-template-columns: 16ch 18ch 14ch 1fr 9ch 7ch; column-gap: 18px; padding: 4px 0;">
|
|
<span class="num" style="color: var(--ink-mute);">14:22:17.011</span>
|
|
<span style="color: var(--ink); font-weight:500;">prod-db-02</span>
|
|
<span class="num" style="color: var(--ink);">● ok</span>
|
|
<span style="color: var(--ink-mid);">backup succeeded · 1.2 GB</span>
|
|
<span class="num ralign" style="color: var(--ink-mid);">4m ago</span>
|
|
<span class="ralign" style="font-size: 11px; color: var(--ink-fade);">…D9XK</span>
|
|
</div>
|
|
<div class="rule-fade"></div>
|
|
<div style="display: grid; grid-template-columns: 16ch 18ch 14ch 1fr 9ch 7ch; column-gap: 18px; padding: 4px 0;">
|
|
<span class="num" style="color: var(--ink-mute);">14:19:44.227</span>
|
|
<span style="color: var(--ink); font-weight:500;">edge-node-eu</span>
|
|
<span class="num" style="color: var(--ink);">● ok</span>
|
|
<span style="color: var(--ink-mid);">backup succeeded · 18 MB</span>
|
|
<span class="num ralign" style="color: var(--ink-mid);">7m ago</span>
|
|
<span class="ralign" style="font-size: 11px; color: var(--ink-fade);">…7P2R</span>
|
|
</div>
|
|
<div class="rule-fade"></div>
|
|
<div style="display: grid; grid-template-columns: 16ch 18ch 14ch 1fr 9ch 7ch; column-gap: 18px; padding: 4px 0;">
|
|
<span class="num" style="color: var(--ink-mute);">14:15:08.946</span>
|
|
<span style="color: var(--ink); font-weight:500;">prod-web-01</span>
|
|
<span class="num" style="color: var(--ink);">● ok</span>
|
|
<span style="color: var(--ink-mid);">backup succeeded · 42 MB</span>
|
|
<span class="num ralign" style="color: var(--ink-mid);">11m ago</span>
|
|
<span class="ralign" style="font-size: 11px; color: var(--ink-fade);">…M4QQ</span>
|
|
</div>
|
|
<div class="rule-fade"></div>
|
|
<div style="display: grid; grid-template-columns: 16ch 18ch 14ch 1fr 9ch 7ch; column-gap: 18px; padding: 4px 0;">
|
|
<span class="num" style="color: var(--ink-mute);">13:39:12.604</span>
|
|
<span style="color: var(--ink); font-weight:500;">build-runner</span>
|
|
<span class="num" style="color: var(--warn); font-weight:600;">✗ failed</span>
|
|
<span style="color: var(--warn);">repo locked — concurrent operation</span>
|
|
<span class="num ralign" style="color: var(--ink-mid);">47m ago</span>
|
|
<span class="ralign" style="font-size: 11px; color: var(--ink-fade);">…9F8C</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- Component vocabulary -->
|
|
<section class="components-section">
|
|
<h2 class="sans">Component vocabulary</h2>
|
|
|
|
<div class="grid grid-cols-2 gap-x-10 gap-y-12">
|
|
|
|
<!-- statuses -->
|
|
<div>
|
|
<div class="col-head" style="margin-bottom: 12px;">Status glyphs</div>
|
|
<div class="rule"></div>
|
|
<div style="display: grid; grid-template-columns: 4ch 14ch 1fr; padding: 10px 0; column-gap: 16px; font-size: 13px;">
|
|
<span class="num" style="color: var(--ink); font-weight: 600;">●</span>
|
|
<span style="color: var(--ink); font-weight: 500;">online</span>
|
|
<span style="color: var(--ink-mute);">heartbeat < 90s</span>
|
|
</div>
|
|
<div class="rule-fade"></div>
|
|
<div style="display: grid; grid-template-columns: 4ch 14ch 1fr; padding: 10px 0; column-gap: 16px; font-size: 13px;">
|
|
<span class="num" style="color: var(--ink); font-weight: 600;">▶</span>
|
|
<span style="color: var(--ink); font-weight: 500;">online · running</span>
|
|
<span style="color: var(--ink-mute);">a job is in flight</span>
|
|
</div>
|
|
<div class="rule-fade"></div>
|
|
<div style="display: grid; grid-template-columns: 4ch 14ch 1fr; padding: 10px 0; column-gap: 16px; font-size: 13px;">
|
|
<span class="num" style="color: var(--warn); font-weight: 600;">▲</span>
|
|
<span style="color: var(--ink); font-weight: 500;">degraded</span>
|
|
<span style="color: var(--ink-mute);">open alerts > 0</span>
|
|
</div>
|
|
<div class="rule-fade"></div>
|
|
<div style="display: grid; grid-template-columns: 4ch 14ch 1fr; padding: 10px 0; column-gap: 16px; font-size: 13px;">
|
|
<span class="num" style="color: var(--ink-fade); font-weight: 600;">○</span>
|
|
<span style="color: var(--ink-mid); font-weight: 500;">offline</span>
|
|
<span style="color: var(--ink-mute);">no heartbeat > 90s</span>
|
|
</div>
|
|
<div class="rule-fade"></div>
|
|
<div style="display: grid; grid-template-columns: 4ch 14ch 1fr; padding: 10px 0; column-gap: 16px; font-size: 13px;">
|
|
<span class="num" style="color: var(--warn); font-weight: 600;">✗</span>
|
|
<span style="color: var(--ink); font-weight: 500;">last job failed</span>
|
|
<span style="color: var(--ink-mute);">distinct from offline</span>
|
|
</div>
|
|
<div class="rule-fade"></div>
|
|
<div style="display: grid; grid-template-columns: 4ch 14ch 1fr; padding: 10px 0; column-gap: 16px; font-size: 13px;">
|
|
<span class="num" style="color: var(--ink-fade); font-weight: 600;">○</span>
|
|
<span style="color: var(--ink-mid); font-weight: 500;">never</span>
|
|
<span style="color: var(--ink-mute);">enrolled but cold</span>
|
|
</div>
|
|
<div class="rule"></div>
|
|
</div>
|
|
|
|
<!-- buttons -->
|
|
<div>
|
|
<div class="col-head" style="margin-bottom: 12px;">Buttons</div>
|
|
<div class="rule"></div>
|
|
<div style="padding: 16px 0; display: flex; flex-wrap: wrap; gap: 8px; align-items: center;">
|
|
<button class="btn btn-primary">+ add host</button>
|
|
<button class="btn">run</button>
|
|
<button class="btn">retry</button>
|
|
<button class="btn btn-quiet">view</button>
|
|
<button class="btn" style="color: var(--warn); border-color: var(--warn);">cancel</button>
|
|
</div>
|
|
<div class="rule"></div>
|
|
<p style="font-size: 12px; color: var(--ink-mute); padding-top: 14px; line-height: 1.7;" class="text-pretty">
|
|
Bracketed verbs read as commands. One filled "primary" per page (<span class="num" style="color: var(--ink); font-weight: 500;">+ add host</span>),
|
|
everything else outline. Ghost variant for inline view links.
|
|
</p>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- host row, 3 states -->
|
|
<div class="mt-14">
|
|
<div class="col-head" style="margin-bottom: 12px;">Host row · 3 states</div>
|
|
<div class="rule"></div>
|
|
<div class="hosts-grid col-head" style="padding: 8px 16px;">
|
|
<div></div>
|
|
<div>host</div>
|
|
<div>os/arch</div>
|
|
<div>last backup</div>
|
|
<div class="ralign">size</div>
|
|
<div class="ralign">snaps</div>
|
|
<div class="ralign">alerts</div>
|
|
<div>tags</div>
|
|
<div class="ralign"></div>
|
|
</div>
|
|
<div class="rule-soft"></div>
|
|
<!-- healthy -->
|
|
<div class="hosts-grid">
|
|
<div class="st st-online"><span class="st-glyph">●</span><span style="color: var(--ink-mid);">online</span></div>
|
|
<div style="color: var(--ink); font-weight: 500;">healthy-host</div>
|
|
<div style="color: var(--ink-mid);">linux/amd64</div>
|
|
<div style="color: var(--ink-mid);">ok 5m ago</div>
|
|
<div class="ralign num" style="color: var(--ink);">87<span style="color: var(--ink-mute);">G</span></div>
|
|
<div class="ralign num" style="color: var(--ink-mid);">2,103</div>
|
|
<div class="ralign num" style="color: var(--ink-fade);">—</div>
|
|
<div class="ralign-tags"><span class="tag">prod</span></div>
|
|
<div class="ralign"><button class="btn">run</button></div>
|
|
</div>
|
|
<div class="rule-fade" style="margin-left: 16px; margin-right: 16px;"></div>
|
|
<!-- degraded -->
|
|
<div class="hosts-grid">
|
|
<div class="st st-degraded"><span class="st-glyph">▲</span><span style="color: var(--ink-mid);">degraded</span></div>
|
|
<div style="color: var(--ink); font-weight: 500;">degraded-host</div>
|
|
<div style="color: var(--ink-mid);">linux/amd64</div>
|
|
<div style="color: var(--ink-mid);">ok 1h ago</div>
|
|
<div class="ralign num" style="color: var(--ink);">128<span style="color: var(--ink-mute);">G</span></div>
|
|
<div class="ralign num" style="color: var(--ink-mid);">1,402</div>
|
|
<div class="ralign num" style="color: var(--warn); font-weight: 600;">3</div>
|
|
<div class="ralign-tags"><span class="tag">prod</span></div>
|
|
<div class="ralign"><button class="btn">run</button></div>
|
|
</div>
|
|
<div class="rule-fade" style="margin-left: 16px; margin-right: 16px;"></div>
|
|
<!-- offline -->
|
|
<div class="hosts-grid">
|
|
<div class="st st-offline"><span class="st-glyph">○</span><span style="color: var(--ink-mid);">offline</span></div>
|
|
<div style="color: var(--ink-mid); font-weight: 500;">offline-host</div>
|
|
<div style="color: var(--ink-mute);">linux/amd64</div>
|
|
<div style="color: var(--ink-mute);">last seen 2d ago</div>
|
|
<div class="ralign num" style="color: var(--ink-mid);">64<span style="color: var(--ink-mute);">G</span></div>
|
|
<div class="ralign num" style="color: var(--ink-mute);">127</div>
|
|
<div class="ralign num" style="color: var(--warn); font-weight: 600;">1</div>
|
|
<div class="ralign-tags"><span class="tag">dev</span></div>
|
|
<div class="ralign" style="color: var(--ink-fade); font-size: 11px;">offline</div>
|
|
</div>
|
|
<div class="rule"></div>
|
|
</div>
|
|
|
|
</section>
|
|
|
|
</div>
|
|
|
|
</body>
|
|
</html>
|