Files
Hammerhead/docs/design.md
T
VeillaxandClaude Opus 5.5 c585ddbf63
CI / test (push) Successful in 3m20s
Release / release (push) Successful in 5m6s
Review pass on the Lightwell redesign: layout, copy and behavior fixes
Dialog buttons are Cancel then the primary action at the bottom right, and each page has one primary
action. List pages no longer repeat their title. Dates have the month written out. Fields in a row
line up, hints sit under fields instead of inside labels, and long certificate errors are clamped.
Organizations show whether local access is on and name the action; setting a user's password uses a
dialog instead of a browser prompt. Server errors for sign-in and ranges are reworded with a next step,
and the stray scrollbar inside tables is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 18:38:56 -06:00

4.3 KiB

Hammerhead design language

The dashboard and the visitor sign-in page follow the Lightwell design language. The reference is docs/design.md in the Lightwell repository. This page records how that language is applied here and where Hammerhead needs its own pieces. When the two 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 (fail in store.go).
  • Status carries text. A status is a badge with a label ("Online", "Listening", "Down"), never a colored dot on its own.

Where it lives

File What it holds
web/index.html The dashboard. The token block sits between tokens:begin and tokens:end; raw colors are allowed only there.
web/resource.html The sign-in page that visitors see in front of a protected resource. Same token block.

Both are single files with no build step, so the token block is repeated in each. Change a token in both.

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, pageHeader Surfaces 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
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
updatePanel Progress bar and live log for an update

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: fin, mine, ports, sites, domains, access, logs, edges, orgs, users, idps, settings, audit, account, egress, alerts, 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. Smaller forms inside a page use the default button.
  • List pages show the page header, then the table in a 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 "At least 8 characters" are hints below them, not part of the label.
  • Dates have the month written out ("Nov 2, 2026"), with fmtDate and fmtTime.
  • Empty states say why the list is empty: nothing yet, or nothing matching the filters.
  • Long machine messages, such as certificate errors, wrap and stop at three lines (.clip), with the full text in a tooltip.

Layout

  • Admin 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 pages, the docs and the Go source. Then check the page in light and dark, at phone and desktop width, using only the keyboard.