1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
# Design language
The dashboard's visual identity. Every card follows it, so one glance reads the
whole board without relearning a scheme per card. Follow this file when you add
or change a widget; the primitives it names live in `lib/card.lua`.
## Card anatomy
A card is a rounded rect (`card.card`) with padding. Its content runs top to
bottom:
- **Header.** The title, or the glyph that stands in for it, sits top-left in
the `label` colour. The card's **big number** sits at the right edge, on the
same line, in `FONT_HEAVY`. Nothing else shares that line.
- **Body.** Rows follow one pattern: **label left, value right**
(`card.text` and `card.text_right`), so the eye runs down the right edge for
numbers. A row's value takes the `threshold` colour when it is a measured
quantity, and stays in `value` when it is not (a fan RPM, a total).
- **Variable band.** One element may absorb the height left over, chosen per
card: the equaliser in `system`, the daylight arc in `weather`, the ring row
in `disks`. Or the type itself fills the cell.
Failure states keep the chrome and draw a notice in it ("no cache data", `--`
for a missing sensor). An empty cell is indistinguishable from a crashed
widget, so a card never draws nothing. A missing sensor is `--`, never `0`:
zero is a legitimate reading.
## The two rules that carry the identity
1. **The big value sits at the card's top-right.**
2. **Rows run label-left, value-right.**
Everything else exists to keep those two readable at any cell size.
## Type
- **Fluid, filling the cell.** Derive one base size from the cell: the smaller
of a width fit and a height budget. `card.fit_unit` measures candidate rows
and returns the largest base size that fits the width, and a row that would
collide pulls the size down. Bigger cell, bigger type instead of empty space.
The `system`, `gpu` and `cache` cards do this; a card that cannot afford the
measuring pass may key off width with a clamped factor.
- **Roles.** `FONT_MONO` for labels and row text, `FONT_HEAVY` for the big
number, `FONT_UI` for prose (a condition description, a notice). Sizes within
a card keep their ratios.
- **Scale by the rect, not fixed pixels**, offsets included. The same widget
must compose at any cell size the grid gives it.
## Colour
One language for every measured quantity, so state is read rather than decoded:
| State | Role | Example |
|---|---|---|
| fine | `ok` | a cool sensor, an empty filesystem |
| busy | `warning` | a core under load, a filesystem past 25% |
| hot / full | `critical` | a sensor at its ceiling, a nearly full disk |
- Proportions (CPU load, filesystem and cache usage) use **25% / 75%**.
- Temperatures use a **per-sensor pair**, because 70C is unremarkable on a CPU
and alarming on an NVMe. The pairs live beside the hwmon bindings in the
widget.
- `warning` is the palette's middle role. The board should show all three
states in normal use, or the language is not earning its place.
## Glyphs
Nerd Font glyphs stand in for labels where an icon reads faster than a word:
the disks rings put a distro / house / disk / network glyph at each ring's
centre, weather puts the condition glyph in its header. A wrong-but-present
codepoint draws a plausible neighbour rather than failing, so render a new
glyph and look at it before trusting it.
|