Routes Java Edition connections by the hostname in the handshake, with wildcard domains, backend failover, PROXY protocol v2, cached server-list status from health probes, hot-reloaded config, and an admin page and metrics endpoint. Includes CI, tagged releases and a container image. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e640c5bf02
commit
b53af0e196
29 files changed
+2640
No files matched your search
@@ -0,0 +1,62 @@
|
||||
# Spinner design language
|
||||
|
||||
The admin page follows the Lightwell design language. The reference is `docs/design.md` in the Lightwell repository, and Hammerhead's `docs/design.md` records how it is applied to a dashboard. This page records what Spinner takes from them and where it needs its own pieces. When they disagree, Lightwell's document wins.
|
||||
|
||||
## What is shared with Lightwell
|
||||
|
||||
* **Tokens.** Colors, spacing (4px scale), radius (6px and 10px), type sizes (12 to 28px), the single shadow and the dark theme are the Lightwell values. The accent is Lightwell's teal, `#1f5c5c`, with white text on it. Everything derived from the accent uses `color-mix`.
|
||||
* **Principles.** Quiet neutrals with one accent, plain and specific wording, one way to do each thing, calm density, and WCAG 2.1 AA.
|
||||
* **Voice.** No emoji, no em or en dashes, no exclamation marks, sentence case, buttons that name the result, and errors that say what happened and what to do next. Errors that come from the server are capitalized in one place (`cap` in `api`).
|
||||
* **Status carries text.** A status is a badge with a label ("Online", "Offline", "Checking"), never a colored dot on its own.
|
||||
|
||||
## Where it lives
|
||||
|
||||
| File | What it holds |
|
||||
| --- | --- |
|
||||
| `web/index.html` | The whole admin page: sign in, Servers and Settings. The token block sits between `tokens:begin` and `tokens:end`; raw colors are allowed only there. |
|
||||
|
||||
It is a single file with no build step, so the token block is a copy of Hammerhead's. If Lightwell changes a token, change it in every repository.
|
||||
|
||||
## Components
|
||||
|
||||
Built from the helpers at the top of the script in `web/index.html`. Feature code uses these and does not style one-off.
|
||||
|
||||
| Helper | Use |
|
||||
| --- | --- |
|
||||
| `card`, `stat`, `pageHeader` | Surfaces, the numbers above the server list, and the page title with its one primary action |
|
||||
| `field`, `chk` | Label above the control, hint below |
|
||||
| `badge(text, tone)` | Status pill. Tones: success, warning, danger, accent, or none for neutral |
|
||||
| `emptyState(icon, title, text, action)` | Dashed outline, icon, a title that says "No X yet", one sentence |
|
||||
| `modal`, `dialogForm` | Dialogs. Focus moves in, Tab stays inside, Escape closes, focus returns to the opener. Errors from the server show inside the dialog |
|
||||
| `confirmDialog`, `ask` | Every destructive action. The title names the object, the body says what is lost and whether it can be undone |
|
||||
| `toast` | Confirmations at the bottom right. Errors stay longer and are announced as alerts |
|
||||
| `skeleton` | Placeholder rows while a page loads, not a spinner |
|
||||
|
||||
## Icons
|
||||
|
||||
Lucide style, outline only, stroke 1.75, round caps, `currentColor`. Sizes are 16, 18 and 22 pixels. They are inline in the `ICONS` table. An icon goes with a text label, and icon-only buttons carry an `aria-label`.
|
||||
|
||||
Approved names: `spinner`, `servers`, `settings`, `lock`, `out`, `menu`, `close`, `add`, `check`, `light`, `dark`, `alert`. Add a name here and in `ICONS` together.
|
||||
|
||||
## Patterns
|
||||
|
||||
* **One primary action per view.** It sits in the page header ("Add server"). Smaller forms inside a page, such as Settings, use the default button.
|
||||
* **List pages** show the page header, the numbers, then the table in a flush card with no second title.
|
||||
* **Dialogs and forms** end with Cancel and then the primary action, at the bottom right. Labels sit above fields, and rules such as "One per line" are hints below them.
|
||||
* **Empty states** say why the list is empty and offer the action that fills it.
|
||||
* **Long machine messages**, such as a refused connection, wrap and stop at three lines (`.clip`), with the full text in a tooltip.
|
||||
* **Words.** Players "use an address" to reach a server. The page says "backend" for the machine Spinner forwards to and avoids proxy jargon outside the PROXY protocol option.
|
||||
|
||||
## Layout
|
||||
|
||||
* Content is capped at 1120px. Below 860px the sidebar becomes a slide-in drawer with a top bar, and grids collapse. Phones keep a 16px side gutter.
|
||||
* On touch screens controls are at least 44px high and inputs are 16px so the page does not zoom.
|
||||
* Motion is minimal and turns off under `prefers-reduced-motion`. The theme follows the system and can be switched from the sidebar.
|
||||
|
||||
## Checking a change
|
||||
|
||||
```
|
||||
node scripts/lint-design.mjs
|
||||
```
|
||||
|
||||
It fails on em and en dashes, emoji, and raw colors outside the token block, in the page, the docs and the Go source. Then check the page in light and dark, at phone and desktop width, using only the keyboard.
|
||||
Reference in new issue
Block a user