design: v1 polish — row accents, wider last-backup col, empty state
CI / Test (linux/amd64) (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Build (windows/amd64) (push) Has been cancelled
CI / Build (linux/amd64) (push) Has been cancelled
CI / Build (linux/arm64) (push) Has been cancelled

- Single .host-row CSS rule replaces 13 inline grid-template-columns
  copies; column widths bumped so "backup running…" doesn't wrap.
- Faint left-edge accent for degraded / failed / offline rows so
  problem hosts are scannable without reading.
- Empty-state hero added: top-bar + nav still present (Dashboard
  active, others dimmed) but body collapses to a calm "no hosts yet"
  prompt with the install command as the load-bearing affordance.
  Prerequisite note keeps the deliberate "restic must already be
  installed" decision visible to first-time operators.

This is the artefact P1-23/24/27 will template against.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-01 18:48:15 +01:00
parent 81c7825937
commit f9c2351ab6
+139 -16
View File
@@ -106,6 +106,54 @@
}
.components-section { margin: 64px 0 96px; }
.components-section h2 { font-size: 14px; font-weight: 600; color: var(--ink-mute); text-transform: uppercase; letter-spacing: 0.08em; }
/* Single source of truth for the host-row grid. The "last backup"
column was previously 1.1fr — too narrow for "backup running…"
to fit on one line. Bumped to 1.5fr; trimmed name to compensate. */
.host-row {
display: grid; align-items: center;
grid-template-columns: 24px 1.4fr 0.95fr 1.5fr 0.75fr 0.7fr 0.7fr 1.1fr 92px;
padding: 11px 16px; font-size: 13px;
/* Reserve the 3px the row-accent will live in so degraded/failed
rows don't shift sideways relative to healthy ones. */
border-left: 3px solid transparent;
}
.host-row.head { padding-top: 10px; padding-bottom: 10px; font-size: 11px; color: var(--ink-fade); text-transform: uppercase; letter-spacing: 0.08em; border-left-width: 3px; }
.host-row.degraded { border-left-color: color-mix(in oklch, var(--warn), transparent 50%); }
.host-row.failed { border-left-color: color-mix(in oklch, var(--bad), transparent 50%); }
.host-row.offline { border-left-color: color-mix(in oklch, var(--off), transparent 70%); }
/* Empty state: full-bleed quiet panel inside the stage. */
.empty-state {
text-align: center; padding: 88px 32px 96px;
border: 1px dashed var(--line); border-radius: 8px;
background:
radial-gradient(ellipse at top, color-mix(in oklch, var(--accent), transparent 95%), transparent 60%),
var(--panel);
}
.empty-state h3 { font-size: 18px; font-weight: 500; letter-spacing: -0.005em; }
.empty-state p {
color: var(--ink-mid); max-width: 520px; margin: 12px auto 0;
line-height: 1.65; font-size: 13px; text-wrap: pretty;
}
.empty-state .install-card {
max-width: 640px; margin: 28px auto 0;
text-align: left; background: var(--bg);
border: 1px solid var(--line-soft); border-radius: 6px;
overflow: hidden;
}
.empty-state .install-card-head {
font-size: 11px; color: var(--ink-fade);
padding: 10px 14px; border-bottom: 1px solid var(--line-soft);
display: flex; justify-content: space-between; align-items: center;
text-transform: uppercase; letter-spacing: 0.1em;
}
.empty-state .install-card pre {
margin: 0; padding: 14px; font-family: 'JetBrains Mono', monospace;
font-size: 12px; color: var(--ink-mid); line-height: 1.7;
white-space: pre-wrap; word-break: break-all;
}
.empty-state .install-card pre .var { color: var(--accent); }
</style>
</head>
<body class="bg-[color:var(--bg)]">
@@ -218,7 +266,7 @@
<!-- table -->
<div class="panel" style="border-radius: 7px; overflow: hidden;">
<!-- header row -->
<div class="grid items-center hairline" style="grid-template-columns: 24px 1.6fr 1fr 1.1fr 0.8fr 0.7fr 0.7fr 1.2fr 88px; padding: 10px 16px; font-size: 11px; color: var(--ink-fade); text-transform: uppercase; letter-spacing: 0.08em;">
<div class="host-row head hairline">
<div></div>
<div>Host</div>
<div>OS · arch</div>
@@ -231,7 +279,7 @@
</div>
<!-- row: prod-db-01 — online + currently running -->
<div class="row-hover grid items-center hairline" style="grid-template-columns: 24px 1.6fr 1fr 1.1fr 0.8fr 0.7fr 0.7fr 1.2fr 88px; padding: 11px 16px; font-size: 13px;">
<div class="row-hover host-row hairline">
<div><span class="dot dot-online pulse"></span></div>
<div class="mono" style="color: var(--ink); font-weight: 500;">prod-db-01</div>
<div class="mono" style="color: var(--ink-mid); font-size:12px;">linux/amd64</div>
@@ -247,7 +295,7 @@
</div>
<!-- row: prod-db-02 -->
<div class="row-hover grid items-center hairline" style="grid-template-columns: 24px 1.6fr 1fr 1.1fr 0.8fr 0.7fr 0.7fr 1.2fr 88px; padding: 11px 16px; font-size: 13px;">
<div class="row-hover host-row hairline">
<div><span class="dot dot-online"></span></div>
<div class="mono" style="color: var(--ink); font-weight: 500;">prod-db-02</div>
<div class="mono" style="color: var(--ink-mid); font-size:12px;">linux/amd64</div>
@@ -262,7 +310,7 @@
</div>
<!-- row: prod-web-01 -->
<div class="row-hover grid items-center hairline" style="grid-template-columns: 24px 1.6fr 1fr 1.1fr 0.8fr 0.7fr 0.7fr 1.2fr 88px; padding: 11px 16px; font-size: 13px;">
<div class="row-hover host-row hairline">
<div><span class="dot dot-online"></span></div>
<div class="mono" style="color: var(--ink); font-weight: 500;">prod-web-01</div>
<div class="mono" style="color: var(--ink-mid); font-size:12px;">linux/amd64</div>
@@ -277,7 +325,7 @@
</div>
<!-- row: prod-web-02 -->
<div class="row-hover grid items-center hairline" style="grid-template-columns: 24px 1.6fr 1fr 1.1fr 0.8fr 0.7fr 0.7fr 1.2fr 88px; padding: 11px 16px; font-size: 13px;">
<div class="row-hover host-row hairline">
<div><span class="dot dot-online"></span></div>
<div class="mono" style="color: var(--ink); font-weight: 500;">prod-web-02</div>
<div class="mono" style="color: var(--ink-mid); font-size:12px;">linux/amd64</div>
@@ -292,7 +340,7 @@
</div>
<!-- row: prod-cache-01 — degraded with alerts -->
<div class="row-hover grid items-center hairline" style="grid-template-columns: 24px 1.6fr 1fr 1.1fr 0.8fr 0.7fr 0.7fr 1.2fr 88px; padding: 11px 16px; font-size: 13px;">
<div class="row-hover host-row degraded hairline">
<div><span class="dot dot-degraded"></span></div>
<div class="mono" style="color: var(--ink); font-weight: 500;">prod-cache-01</div>
<div class="mono" style="color: var(--ink-mid); font-size:12px;">linux/amd64</div>
@@ -307,7 +355,7 @@
</div>
<!-- row: homelab-nas -->
<div class="row-hover grid items-center hairline" style="grid-template-columns: 24px 1.6fr 1fr 1.1fr 0.8fr 0.7fr 0.7fr 1.2fr 88px; padding: 11px 16px; font-size: 13px;">
<div class="row-hover host-row hairline">
<div><span class="dot dot-online"></span></div>
<div class="mono" style="color: var(--ink); font-weight: 500;">homelab-nas</div>
<div class="mono" style="color: var(--ink-mid); font-size:12px;">linux/arm64</div>
@@ -322,7 +370,7 @@
</div>
<!-- row: homelab-pi -->
<div class="row-hover grid items-center hairline" style="grid-template-columns: 24px 1.6fr 1fr 1.1fr 0.8fr 0.7fr 0.7fr 1.2fr 88px; padding: 11px 16px; font-size: 13px;">
<div class="row-hover host-row hairline">
<div><span class="dot dot-online"></span></div>
<div class="mono" style="color: var(--ink); font-weight: 500;">homelab-pi</div>
<div class="mono" style="color: var(--ink-mid); font-size:12px;">linux/arm64</div>
@@ -337,7 +385,7 @@
</div>
<!-- row: dev-laptop — offline -->
<div class="row-hover grid items-center hairline" style="grid-template-columns: 24px 1.6fr 1fr 1.1fr 0.8fr 0.7fr 0.7fr 1.2fr 88px; padding: 11px 16px; font-size: 13px;">
<div class="row-hover host-row offline hairline">
<div><span class="dot dot-offline"></span></div>
<div class="mono" style="color: var(--ink-mid); font-weight: 500;">dev-laptop</div>
<div class="mono" style="color: var(--ink-mute); font-size:12px;">linux/amd64</div>
@@ -352,7 +400,7 @@
</div>
<!-- row: windows-vm -->
<div class="row-hover grid items-center hairline" style="grid-template-columns: 24px 1.6fr 1fr 1.1fr 0.8fr 0.7fr 0.7fr 1.2fr 88px; padding: 11px 16px; font-size: 13px;">
<div class="row-hover host-row hairline">
<div><span class="dot dot-online"></span></div>
<div class="mono" style="color: var(--ink); font-weight: 500;">windows-vm</div>
<div class="mono" style="color: var(--ink-mid); font-size:12px;">windows/amd64</div>
@@ -367,7 +415,7 @@
</div>
<!-- row: build-runner — failed -->
<div class="row-hover grid items-center hairline" style="grid-template-columns: 24px 1.6fr 1fr 1.1fr 0.8fr 0.7fr 0.7fr 1.2fr 88px; padding: 11px 16px; font-size: 13px;">
<div class="row-hover host-row failed hairline">
<div><span class="dot dot-online"></span></div>
<div class="mono" style="color: var(--ink); font-weight: 500;">build-runner</div>
<div class="mono" style="color: var(--ink-mid); font-size:12px;">linux/amd64</div>
@@ -382,7 +430,7 @@
</div>
<!-- row: backup-test — never -->
<div class="row-hover grid items-center hairline" style="grid-template-columns: 24px 1.6fr 1fr 1.1fr 0.8fr 0.7fr 0.7fr 1.2fr 88px; padding: 11px 16px; font-size: 13px;">
<div class="row-hover host-row hairline">
<div><span class="dot dot-online"></span></div>
<div class="mono" style="color: var(--ink); font-weight: 500;">backup-test</div>
<div class="mono" style="color: var(--ink-mid); font-size:12px;">linux/amd64</div>
@@ -397,7 +445,7 @@
</div>
<!-- row: edge-node-eu (last row, no hairline) -->
<div class="row-hover grid items-center" style="grid-template-columns: 24px 1.6fr 1fr 1.1fr 0.8fr 0.7fr 0.7fr 1.2fr 88px; padding: 11px 16px; font-size: 13px;">
<div class="row-hover host-row">
<div><span class="dot dot-online"></span></div>
<div class="mono" style="color: var(--ink); font-weight: 500;">edge-node-eu</div>
<div class="mono" style="color: var(--ink-mid); font-size:12px;">linux/arm64</div>
@@ -470,6 +518,81 @@
</div>
</div>
<!-- Empty state — the very first screen a new user sees. The chrome,
fleet stat blocks, and table are all replaced with a single
calm prompt: enrol your first host. The install command is the
hero affordance. -->
<div style="margin-top: 64px;">
<div class="text-xs uppercase tracking-[0.18em]" style="color: var(--ink-fade); margin-bottom: 12px;">Empty state · first run</div>
</div>
<div class="stage-frame">
<div style="background: var(--bg); padding: 0;">
<!-- Top bar (still present, just with no host context) -->
<div class="hairline" style="background: var(--bg);">
<div class="doc flex items-center justify-between" style="padding: 16px 0;">
<div class="flex items-center gap-3">
<div class="mono" style="font-size:13px; letter-spacing: 0.02em; color: var(--ink); font-weight:500;">restic-manager</div>
<div class="mono" style="font-size:11px; color: var(--ink-fade);">v0.1.0-alpha</div>
</div>
<div class="flex items-center gap-5">
<div class="mono" style="font-size:12px; color: var(--ink-mute);">steve@dcglab</div>
<button class="btn btn-ghost">Sign out</button>
</div>
</div>
</div>
<!-- Nav (Dashboard active, but everything else dimmed since there's nothing to see yet) -->
<div class="hairline" style="background: var(--bg);">
<div class="doc flex items-end justify-between">
<nav class="flex items-end">
<div class="nav-tab active">Dashboard</div>
<div class="nav-tab" style="opacity: 0.45;">Repos</div>
<div class="nav-tab" style="opacity: 0.45;">Alerts</div>
<div class="nav-tab" style="opacity: 0.45;">Audit</div>
<div class="nav-tab">Settings</div>
</nav>
<div class="pb-3">
<button class="btn btn-primary">+ Add host</button>
</div>
</div>
</div>
<!-- The main empty body -->
<div class="doc" style="padding: 56px 32px 80px;">
<div class="empty-state">
<h3>No hosts yet.</h3>
<p>
<span class="mono" style="color: var(--ink);">restic-manager</span> tracks
backups across a fleet — but theres nothing to track until you enrol
your first host. Run the snippet below on a Linux box, paste the
one-time token, and itll appear here within a few seconds.
</p>
<div class="install-card">
<div class="install-card-head">
<span>Install command · expires in 1h</span>
<button class="btn btn-ghost mono" style="font-size: 11px;">Copy</button>
</div>
<pre>curl -fsSL <span class="var">https://restic.lab.example/install.sh</span> | sudo \
RM_SERVER=<span class="var">https://restic.lab.example</span> \
RM_TOKEN=<span class="var">HdqFbQh8U-I1fb52iP1M8qxvoYS5t9VZ-T-yghr_CzA</span> sh</pre>
</div>
<div style="margin-top: 28px; display: flex; justify-content: center; gap: 10px;">
<button class="btn btn-primary">+ Add host (mint another token)</button>
<button class="btn">Read the install guide →</button>
</div>
<div style="margin-top: 36px; font-size: 12px; color: var(--ink-fade);">
Prerequisites: <span class="mono" style="color: var(--ink-mute);">restic</span> ≥ 0.16 already installed on the target host. The agent will not install it for you — see <a class="underline underline-offset-4 decoration-1" style="color: var(--ink-mid); text-decoration-color: var(--line);">why</a>.
</div>
</div>
</div>
</div>
</div>
<!-- Component vocabulary -->
<section class="components-section">
<h2>Component vocabulary</h2>
@@ -531,7 +654,7 @@
<div class="mt-10">
<div style="font-size: 11px; color: var(--ink-fade); text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 12px;">Host row · 3 states</div>
<div class="panel" style="border-radius: 7px;">
<div class="row-hover grid items-center hairline" style="grid-template-columns: 24px 1.6fr 1fr 1.1fr 0.8fr 0.7fr 0.7fr 1.2fr 88px; padding: 11px 16px; font-size: 13px;">
<div class="row-hover host-row hairline">
<div><span class="dot dot-online"></span></div>
<div class="mono" style="color: var(--ink); font-weight: 500;">healthy-host</div>
<div class="mono" style="color: var(--ink-mid); font-size:12px;">linux/amd64</div>
@@ -542,7 +665,7 @@
<div class="flex gap-1.5"><span class="tag">prod</span></div>
<div class="text-right"><button class="btn">Run now</button></div>
</div>
<div class="row-hover grid items-center hairline" style="grid-template-columns: 24px 1.6fr 1fr 1.1fr 0.8fr 0.7fr 0.7fr 1.2fr 88px; padding: 11px 16px; font-size: 13px;">
<div class="row-hover host-row degraded hairline">
<div><span class="dot dot-degraded"></span></div>
<div class="mono" style="color: var(--ink); font-weight: 500;">degraded-host</div>
<div class="mono" style="color: var(--ink-mid); font-size:12px;">linux/amd64</div>
@@ -553,7 +676,7 @@
<div class="flex gap-1.5"><span class="tag">prod</span></div>
<div class="text-right"><button class="btn">Run now</button></div>
</div>
<div class="row-hover grid items-center" style="grid-template-columns: 24px 1.6fr 1fr 1.1fr 0.8fr 0.7fr 0.7fr 1.2fr 88px; padding: 11px 16px; font-size: 13px;">
<div class="row-hover host-row offline">
<div><span class="dot dot-offline"></span></div>
<div class="mono" style="color: var(--ink-mid); font-weight: 500;">offline-host</div>
<div class="mono" style="color: var(--ink-mute); font-size:12px;">linux/amd64</div>