03 — Frontend and design system¶
The ONYX console is built on Unity, the shared Innotel theme. Unity is not a component library and not a build step: it is one palette, one theme switch and a small semantic vocabulary that every product carries as a byte-identical copy. ONYX wears the operations scheme, with light, dark and follow-the-system modes.
The console itself is deliberately dependency-free HTML, CSS and one inline
script. It is served by onyx-web (nginx); there is no bundler, no framework
runtime and no asset pipeline to keep alive on an appliance. That is a feature:
the surface that recovers a broken pool must not depend on the surface that
failed to build.
1. Principles¶
- Calm by default. Dense while you work, quiet when you are not. No decorative motion competing with capacity or health.
- One heading per screen. The masthead names the page; the content starts with the lede and the actions.
- Status is text and shape as well as colour. A green dot always has a label; an unknown state has its own token and is never painted as success.
- The rail is the only navigation, and the only collapse control. There is no second, competing sidebar or activity panel.
- Destructive actions look destructive. Erase, delete, purge and rollback are confirmed in words that name what is lost.
- Every action is one keystroke from anywhere.
Ctrl/Cmd+Kopens the same palette on every page.
2. The theme¶
The canonical files are theme/unity-theme.css and theme/unity-theme.js in
the family repository. ONYX ships byte-identical copies at:
docker/onyx-web/unity-theme.{css,js}— served beside the console at/unity-theme.{css,js}and baked into theonyx-webimage.web/landing/unity-theme.{css,js}— served beside the static landing page.
A change to the palette is a change to the canonical file and every copy. The theme's own test fails when a converted product drifts.
2.1 Schemes and modes¶
| Axis | Values | Stored as |
|---|---|---|
| Scheme | desk (violet), operations (graphite/blue), soc (navy/cyan) |
data-scheme; ONYX defaults to operations |
| Mode | light, dark, or absent (follow the machine) |
data-mode, in localStorage["ontrak.mode"] |
The pre-paint snippet in index.html applies the stored mode before the
stylesheet paints, so a dark screen never flashes white. The toggle cycles
system → light → dark and calls UnityTheme.cycle(); Settings exposes the same
choice as a select.
2.2 Tokens¶
No component names a raw colour. The semantic tokens are:
| Group | Tokens | Use |
|---|---|---|
| Canvas | --canvas, --surface, --surface-muted, --surface-sunken |
page, panels, hover, input wells |
| Lines | --line, --line-strong |
hairlines and field borders |
| Ink | --ink, --ink-soft, --ink-faint |
primary, secondary, placeholder |
| Brand | --brand, --brand-soft, --brand-ink, --brand-ring |
actions, selection, focus |
| Status | --ok, --info, --bad, --attention, --unknown and their -soft pairs |
health, refusals, capacity pressure, never-checked |
| Glass | --glass-tint, --glass-tint-strong, --glass-line, --glass-shadow |
the rail, masthead, cards |
| Shape | --radius-sm, --radius, --radius-lg, --radius-pill |
fields, panels, dialogs, pills |
| Type | --font-sans, --mono |
UI and numbers/paths |
| Spacing | --space-1…--space-6 |
4 px grid |
Feature views written before the migration still use the old
--onyx-* names inside inline styles; the shell maps each one onto a Unity
token rather than leaving a second private palette behind.
3. Shell¶
┌───────────────┬──────────────────────────────────────────────────────┐
│ ONYX │ Overview [search or jump… ⌘K] ● ◐ ON │
│ Workspace ├──────────────────────────────────────────────────────┤
│ Overview │ │
│ Files │ capacity ring · service health · attention queue │
│ Search │ pools · recent access activity · quick actions │
│ Storage │ │
│ Storage │ │
│ Snapshots │ │
│ Backups │ │
│ Platform │ │
│ Apps … │ │
│ ───────── │ │
│ ‹ Collapse │ │
│ ON Operator │ │
└───────────────┴──────────────────────────────────────────────────────┘
- Rail: 252 px expanded, 76 px collapsed. One control: the button at the
bottom of the rail, or
Ctrl/Cmd+B. The preference persists inlocalStorage["onyx.rail"]. On ≤900 px the rail becomes an off-canvas drawer with a scrim; the masthead's menu button opens it. - Sections: Workspace (Overview, Files, Search), Storage (Storage, Snapshots, Backups), Platform (Apps, Virtual machines, Objects, Shares, Users, Audit, Settings). Scrub is a maintenance action on Storage, not a destination of its own.
- Masthead: the current page title and lede, the command trigger, the live service pill, the Unity theme toggle and the account mark.
- Command palette:
Ctrl/Cmd+K. Pages, layout and theme actions, and — once there is a query — a pool-wide file search. Choosing the search command fills the Search page and runs it. - No activity rail. Activity lives on the Overview next to capacity and attention, where it can be read in context. The old right-hand rail was placeholder text and has been removed.
4. Overview¶
The landing page answers four questions without opening another page:
- How full is the box? A capacity ring plus used/free/total, read from
/storage/overview. - Is every daemon serving? The count and a per-service list from
/system/status. - What needs a decision? Offline pools, storage notices, capacity above
85 %, and refused requests from
/audit/access. - What happened recently? Grants, revocations and refusals, newest first.
Pools are listed with their own used/total and state; quick actions lead to Files, Snapshots, Shares and Audit.
5. Components in use¶
Buttons (default, primary, disabled), fields and selects, checkboxes, cards, KPI tiles, capacity ring, status pill, status dots, tags, badges, empty states, toast, modal command palette, disclosure panels (share access, share history, SMB password, scrub schedule, remote-account setup), and feature rows.
Every list has an empty state with a next action. Errors from an action appear as a toast and an inline alert; a page that cannot load says what is missing where the content would have been.
6. Accessibility¶
- A skip link precedes the shell.
- The rail uses links with
aria-current="page"; the collapse button carriesaria-controlsandaria-expanded. - The palette is a modal dialog with
role="dialog",aria-modal, a labelled input andaria-selectedoptions; arrow keys, Enter and Escape work. - Focus-visible rings use
--brand-ringat 2 px. - Status is never colour-only: every dot is paired with text.
prefers-reduced-motioncollapses transitions and animations.- The page remains usable at 390 px with no horizontal overflow.
7. Technology and delivery¶
- Server:
onyx-web(nginx) servesindex.htmlplus the two Unity files. The image is built bydocker/onyx-web/Dockerfileand published to GHCR. - API: same-origin
/api/v1; ononyx.innotel.usthe console callshttps://api.onyx.innotel.us/api/v1. - State: the URL hash is the router (
#/files,#/storage, …); preferences (rail, theme, pending search, backup source) live inlocalStorageorsessionStorage. - No build step. A change is a file change; the image copies three files.
- Testing:
scripts/web-ui-check.jsruns the inline application script in a VM with a DOM stub and asserts the render contracts that have broken before. Browser checks exercise the real page at desktop and phone sizes.
8. Later¶
The component catalog in later milestones can grow (virtualised grids, preview drawer, thumbnails, live job streams), but it does so inside this shell and vocabulary. A framework migration is not a goal in itself; the console stays static as long as that is the smaller, more reliable surface.