Move the console onto ReUI PRO

Install ReUI (MCP, skill, @reui registry, Tailwind v4, shadcn base-nova) and move
the shared UI onto it: Button, Tag, Check, Input/Textarea, Segmented, Alert, Panel,
Dialog, Tooltip, Menu and Select (Popover), Toast (sonner), the Table frame
(DataGrid), the Dashboard KPI strip, the shnt Ops palette, Geist and the type scale.

Design only: behaviour, texts and roles are unchanged. Tests that asserted the old
DOM were updated; the tests now format numbers in English wherever they run.
docs/reui-migration-plan.md records the plan and its decisions.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
DenozordecandClaude Sonnet 5.5 committed 2026-10-27 00:06:06 +07:00
commit f3531c64f9
680 files changed
+139836

No files matched your search

+191
View File
@@ -0,0 +1,191 @@
/*
The label + control row, a single one. There were four grids (210 px on pages,
180 px in the Zones modals, 170 px in the Administration ones, 110 px in the Logs
filter) and two different labels: 600 and `--ink` on pages, 400 and `--mute` in
the Zones modals. With the muted one, in "Add Zone" the label receded behind the
value; with the strong one, in "Add User" it competed with it.
The strong one wins: in a long form the label is what you look for when scanning,
not what you read afterwards.
*/
/*
THREE columns: label, control and help.
It is the dense-form design's decision, and the one that holds it up: in a dense form
**the surface is the text**. `General` has 41 paragraphs of help against 39
controls, and under each field they made a page twice as long in which the text
weighed more than the fields.
The third column is `--help-col` and **only `.row` carries it**. `.mrow` (the
dialog) stays at two: there are 560 px of width there, and the design measured a
panel, not a modal.
*/
.row {
display: grid;
grid-template-columns: 210px minmax(0, 1fr) var(--help-col);
gap: var(--s-8);
padding: var(--s-7) var(--s-9);
align-items: start;
border-bottom: 1px solid var(--line);
}
/* The help as the control's sibling and not inside it: that is what moves it into
its own column. In the modal it stays nested, and that is why it still falls
underneath. */
.rowHelp {
grid-column: 3;
}
.row:last-child { border-bottom: 0; }
/* Inside a modal there is less room and fewer rows: no separator, no 210 px. */
.mrow {
display: grid;
grid-template-columns: 180px minmax(0, 1fr);
gap: var(--s-8);
padding: var(--s-3) 0;
align-items: start;
}
.rowLabel,
.mrowLabel {
font-size: var(--t-4);
color: var(--ink);
font-weight: 600;
padding-top: var(--s-5);
line-height: 1.35;
}
.rowCtl,
.mrowCtl {
min-width: 0;
display: flex;
flex-direction: column;
gap: var(--s-3);
}
/*
A one-line field gains nothing from being 640 px wide.
The control column is `1fr`, so it eats everything left over, and that did not
show while every dialog was 560 wide. Once "User Details" got the 880 its sessions
table asks for, the box for typing "admin" grew to 640 px. The cap is 420, which
is what the page forms were already using in practice: measured across the
console's 46 fields, the median is 174 px and the maximum 420.
The cap also reaches a table that is a row's control: "Member Of" in My Profile is
ONE column and measured 831 px for an 82 px group name. Upstream does not stretch
it either: it puts it in a `col-sm-7`. What stays outside is the `textarea` (IP
lists, which do use the width) and tables that are NOT a row's control, like the
sessions one, which needs everything it can get.
*/
.mrow input:not([type='checkbox']):not([type='radio']),
.mrow select,
.mrow table {
max-width: 420px;
}
/*
The breakpoints, and why the panel and the modal no longer share one.
This breakpoint was a SINGLE one at 720 for both rows. What motivated it is still
true and is written down: at 390 the 210 px grid left 20 px for the field and made
seventeen Settings fields invisible. **But that proves 390 had to be protected,
not that 720 was the right threshold.**
So they part company:
· `.row` follows the breakpoints the dense-form design measured: 1180 and 560.
· `.mrow` **keeps its 720 and its geometry**: the design measured a dense form,
not a dialog, and does not authorise touching the modal. That 720 stands as
**modal** debt, with its figure, and not mixed in with the dense form.
At 1180 the help leaves the third column and drops to a second line of its own row.
It stays visible and stays complete: **no width hides it**.
*/
@media (max-width: 1180px) {
.row {
grid-template-columns: 210px minmax(0, 1fr);
}
/* Second line, aligned with the control and not with the label. */
.rowHelp {
grid-column: 2;
}
}
/* At 560 it stacks completely: label, control and help, in that order. */
@media (max-width: 560px) {
.row {
grid-template-columns: minmax(0, 1fr);
gap: var(--s-4);
padding: var(--s-7) var(--s-8);
}
.rowLabel { padding-top: 0; }
.rowHelp { grid-column: 1; }
}
/* 720: the MODAL's, which stays where it was. */
@media (max-width: 720px) {
.mrow {
grid-template-columns: minmax(0, 1fr);
gap: var(--s-4);
}
.mrowLabel { padding-top: 0; }
}
/*
The help under a field, and the group of checkboxes in a row.
Both were defined three times (in Settings, in DHCP and in Administration) with
the same values copied by hand. It is the same story as the table and the panel:
what gets repeated ends up drifting apart.
*/
.help {
composes: withCode from './text.module.css';
font-size: var(--t-3);
color: var(--mute);
line-height: 1.55;
max-width: 720px;
}
.help a { color: var(--acc-ink); }
/* Several checkboxes or radios inside a single row. */
.group {
display: flex;
flex-direction: column;
gap: var(--s-6);
}
/*
The row switched off by its master switch.
An amber edge on the side, and nothing else here: the opacity already comes with
the control's own `disabled`, and the pill that NAMES it is drawn by `Row` next to
the label. The three pieces together are the master-switch signal, and none is
spare: the edge is seen without reading, the pill says which switch it is, and the
opacity says it is not active.
Amber and not red, and amber and not a padlock: *amber = you can*. The user can
switch this on themselves. If the permission were missing as well, **the padlock
wins** and this edge is not drawn: what you cannot touch does not need two
explanations of why it is off.
The edge is an INNER SHADOW and not a `border-left`, and the measurement decided
that, not taste. With `border-left: 2px` the grid of those five rows became
`210px 540px 360px` against the `210px 542px 360px` of the other 34: the border
eats two pixels of the box and **shifts the control**. In a dense form that is a
column that stops being aligned, and `dev/uniformity.js` caught it as a third
`grid-panel` signature that existed only in `/settings/general/`.
A state signal cannot move the content it points at. The inner shadow paints
exactly the same edge and takes up no grid: the family is back to two signatures
and the 39 rows stay aligned.
*/
.dependent { box-shadow: inset 2px 0 0 0 var(--acc-ink); }
.withPill { display: flex; align-items: center; gap: var(--s-4); flex-wrap: wrap; }