Files
restic-manager/design/v1-login.html
T
steve 8b7b1479a1 design: extend v1 to login / add-host / host-detail / job-log + lock components
Five hi-fi screens completing the Phase 1 surface, all in v1's dark
operator-console register.

  v1-login          Sparse centred card. Sign-in + first-error variant.
                    No marketing chrome; build version sits in footer
                    so a returning operator can spot agent drift.

  v1-add-host       Focused two-column page (form left, contextual
                    "what happens next" right) — not a modal. Two
                    states: form (state A) and minted-token result
                    with install command (state B). Backed by
                    POST /api/enrollment-tokens (P1-32).

  v1-host-detail    Persistent header (status dot, mono name, tags,
                    primary CTAs, vitals strip) over four sub-tabs
                    (Snapshots / Jobs / Repo / Settings). Snapshots
                    is the default — the thing 90% of operators
                    want when they click a host name. Right rail
                    holds Recent activity, run-now stack, and a
                    danger-zone panel.

  v1-job-log        WS-streamed log view. Three states: running (live
                    progress bar + auto-scroll cursor), succeeded
                    (summary stats + final lines), failed (error
                    panel + tail). Backed by WS /api/jobs/{id}/stream
                    (P1-21 remainder).

  v1-components     The load-bearing reference. 14 sections covering
                    tokens (colour + type scale), status, buttons,
                    form fields, tags, tabs, host row, log viewer,
                    progress bar, stat tile, modal, toast, install
                    snippet, empty-state pattern. Every CSS class is
                    real and copy-able into the Go template build.

This locks the visual register before P1-23 onwards. Each Phase 1
template gets a {{define}} matching a section in v1-components.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 19:05:39 +01:00

149 lines
7.2 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>restic-manager · v1 Login</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=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
:root {
--bg: oklch(0.17 0.006 250); --panel: oklch(0.20 0.007 250);
--panel-hi: oklch(0.23 0.008 250);
--line: oklch(0.27 0.010 250); --line-soft: oklch(0.23 0.008 250);
--ink: oklch(0.96 0.005 250); --ink-mid: oklch(0.78 0.005 250);
--ink-mute: oklch(0.58 0.006 250); --ink-fade: oklch(0.42 0.006 250);
--ok: oklch(0.78 0.14 155); --bad: oklch(0.70 0.20 25);
--accent: oklch(0.82 0.12 195);
}
html, body { background: var(--bg); color: var(--ink); }
body { font-family: 'Inter', system-ui, sans-serif; min-height: 100vh; }
.mono { font-family: 'JetBrains Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums; }
::selection { background: color-mix(in oklch, var(--accent), transparent 70%); }
.text-pretty { text-wrap: pretty; }
.field-label { font-size: 12px; color: var(--ink-mid); margin-bottom: 6px; display: block; letter-spacing: 0.005em; }
.field {
width: 100%; padding: 10px 12px;
background: var(--panel); border: 1px solid var(--line-soft);
color: var(--ink); border-radius: 5px;
font-size: 13px; font-family: inherit; outline: none;
transition: border-color 120ms ease;
}
.field:focus { border-color: var(--accent); }
.field.mono { font-family: 'JetBrains Mono', monospace; font-size: 12px; letter-spacing: 0.01em; }
.btn {
font-size: 13px; font-weight: 500;
padding: 9px 14px; border-radius: 5px;
background: transparent; border: 1px solid var(--line); color: var(--ink-mid);
transition: all 120ms ease;
}
.btn:hover { background: var(--panel-hi); color: var(--ink); }
.btn-primary { color: oklch(0.18 0.01 195); background: var(--accent); border-color: var(--accent); }
.btn-primary:hover { filter: brightness(1.08); }
.btn-block { width: 100%; padding: 10px 14px; }
.doc { max-width: 1280px; margin: 0 auto; padding: 0 32px; }
.philosophy { padding: 56px 0 32px; border-bottom: 1px solid var(--line-soft); }
.philosophy h1 { font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }
.philosophy p { color: var(--ink-mid); max-width: 680px; margin-top: 14px; line-height: 1.65; text-wrap: pretty; }
.philosophy .meta { color: var(--ink-fade); font-size: 12px; margin-top: 14px; }
.stage-frame { margin: 48px -32px; border-top: 1px solid var(--line-soft); border-bottom: 1px solid var(--line-soft); }
</style>
</head>
<body>
<div class="doc">
<header class="philosophy">
<div class="text-xs uppercase tracking-[0.18em] text-[color:var(--ink-fade)] mb-3">v1 · Login</div>
<h1>Sign in.</h1>
<p>
The first chrome an operator meets. Everything irrelevant to the act of
signing in is removed: no marketing, no “sign up”, no animated background.
The form lives where the cursor needs it; the build version sits in the
footer so a returning operator can spot a mismatch with the agents.
</p>
<p class="meta">
First-run operators land on the empty <span class="mono" style="color: var(--ink-mid);">/bootstrap</span>
page instead — see the dedicated mockup. A regular sign-in always has at
least one user already minted.
</p>
</header>
<div class="stage-frame">
<div style="background: var(--bg); min-height: 720px; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 48px 32px;">
<!-- centred card -->
<div style="width: 360px;">
<!-- wordmark -->
<div class="flex items-baseline gap-2 mb-10" style="justify-content: center;">
<div class="mono" style="font-size: 16px; color: var(--ink); font-weight: 500; letter-spacing: 0.01em;">restic-manager</div>
</div>
<h2 style="font-size: 18px; font-weight: 500; letter-spacing: -0.005em; margin-bottom: 28px; text-align: center;">Sign in to continue</h2>
<form>
<div style="margin-bottom: 14px;">
<label class="field-label" for="login-username">Username</label>
<input id="login-username" type="text" class="field mono" autocomplete="username" value="steve">
</div>
<div style="margin-bottom: 22px;">
<label class="field-label" for="login-password">Password</label>
<input id="login-password" type="password" class="field" autocomplete="current-password" value="••••••••••••••••">
</div>
<button type="submit" class="btn btn-primary btn-block">Sign in</button>
</form>
<div style="margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--line-soft); text-align: center;">
<p class="text-pretty" style="font-size: 12px; color: var(--ink-mute); line-height: 1.65;">
Forgot your password? An admin can reset it from
<span class="mono" style="color: var(--ink-mid);">Settings → Users</span>.
Theres no recovery email — this is self-hosted infrastructure.
</p>
</div>
</div>
<!-- footer -->
<div style="margin-top: 80px; display: flex; gap: 14px; align-items: center; font-size: 11px; color: var(--ink-fade);">
<span class="mono">restic-manager v0.1.0-alpha</span>
<span>·</span>
<span class="mono">build f9c2351</span>
<span>·</span>
<a class="underline underline-offset-4 decoration-1" style="text-decoration-color: var(--line);">docs</a>
<span>·</span>
<a class="underline underline-offset-4 decoration-1" style="text-decoration-color: var(--line);">source</a>
</div>
</div>
</div>
<!-- error variant -->
<section style="margin: 48px 0 96px;">
<h2 style="font-size: 14px; font-weight: 600; color: var(--ink-mute); text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 20px;">Error variant</h2>
<div style="background: var(--panel); border: 1px solid var(--line-soft); border-radius: 7px; padding: 32px;">
<div style="width: 360px; margin: 0 auto;">
<h3 style="font-size: 16px; font-weight: 500; margin-bottom: 24px; text-align: center;">Sign in to continue</h3>
<div style="background: color-mix(in oklch, var(--bad), transparent 88%); border: 1px solid color-mix(in oklch, var(--bad), transparent 70%); padding: 10px 12px; border-radius: 5px; margin-bottom: 18px; font-size: 12px; color: oklch(0.85 0.10 25);">
Invalid username or password.
</div>
<div style="margin-bottom: 14px;">
<label class="field-label">Username</label>
<input type="text" class="field mono" value="steve">
</div>
<div style="margin-bottom: 22px;">
<label class="field-label">Password</label>
<input type="password" class="field" value="••••••••">
</div>
<button class="btn btn-primary btn-block">Sign in</button>
</div>
</div>
</section>
</div>
</body>
</html>