164 lines
7.5 KiB
Markdown
164 lines
7.5 KiB
Markdown
# Main page: 5-group weighing row + form restyle
|
|
|
|
## Context
|
|
|
|
The weighing detail panel doesn't match the layout the user wants (reference
|
|
screenshot: a single row of five groups — CURRENT READING | TARE | GROSS | NET |
|
|
actions). Three things differ today:
|
|
|
|
1. **Current Reading is a separate full-width block** (`.reading-display`) sitting
|
|
*above* the card row, not part of it.
|
|
2. **There is a redundant "Scale" card** duplicating the same live weight, which
|
|
exists only to host the Measure / Manual entry buttons. The user's call:
|
|
these two are the same thing — **merge into one card**.
|
|
3. **Tare and Gross are all-or-nothing.** Today a lone first reading renders as a
|
|
single neutral "First weighing" card, and Tare/Gross only appear once both
|
|
exist. The user wants the five groups always visible, with the first reading
|
|
shown plainly in its slot.
|
|
|
|
Result: a stable five-column row that never changes its column count.
|
|
|
|
### The one behaviour being deliberately traded away
|
|
|
|
[Main.jsx:604-605](frontend/src/components/Main.jsx#L604-L605) documents why the
|
|
merged card exists: the backend parks a lone reading in `tare`, but a **lighter
|
|
second reading moves it to `gross`**. So a single reading labelled "TARE" can
|
|
later jump to the GROSS box. The user chose "show it plainly" — accepting that
|
|
jump. `firstWeighing` (Main.jsx:290-309) becomes dead and is removed.
|
|
|
|
## Approach
|
|
|
|
### 1. Merge Current Reading + Scale into one card
|
|
|
|
Delete the standalone `.reading-display` block (Main.jsx:581-600) and the Scale
|
|
card (647-677). One card takes their place as the row's first column, keeping the
|
|
**richer** of the two behaviours — the reading-display value logic, which the
|
|
Scale card lacked (disconnected state, `readingError` line):
|
|
|
|
```jsx
|
|
<div className="weight-card weight-card--reading">
|
|
<div className="weight-card-header">Current Reading</div>
|
|
<div className={`weight-card-value weight-card-value--reading ${…same ternary as today's reading-value…}`}>
|
|
{currentWeight !== null && !isNaN(currentWeight)
|
|
? `${currentWeight} kg`
|
|
: (isConnected ? 'Waiting...' : 'Disconnected')}
|
|
</div>
|
|
{isConnected && readingError && latestReading && (
|
|
<div className="reading-error" title={latestReading.data}>{readingError}</div>
|
|
)}
|
|
{canMeasure && !isFinalized && (<>
|
|
<button className="weight-set-btn" onClick={handleMeasure}
|
|
disabled={currentWeight === null || isNaN(currentWeight) || !licenseAllowed}
|
|
title={licenseAllowed ? undefined : licenseDetail}>Measure</button>
|
|
{!licenseAllowed && <div className="weight-license-block">{licenseDetail}</div>}
|
|
{currentUser?.can_manually_measure && (
|
|
<button className="weight-manual-btn" onClick={…}>Manual entry</button>
|
|
)}
|
|
</>)}
|
|
</div>
|
|
```
|
|
|
|
Keep the `.reading-value--balanced/--unbalanced` class names on the value so the
|
|
existing colour rules (Main.css:547-553) and cockpit glow keep applying
|
|
unchanged. The `--reading` modifier carries the larger font that
|
|
`.reading-value` had.
|
|
|
|
### 2. Tare / Gross / Net always render
|
|
|
|
Replace the ternary at Main.jsx:606-644 with three unconditional cards. Each
|
|
shows `—` and no meta when its value is null:
|
|
|
|
- Tare — `selectedVehicle.tare`, `tare_date`, `tare_user_name`, `tare_manual`
|
|
- Gross — same shape with `gross_*`
|
|
- Net — `netWeight` (null until both exist)
|
|
|
|
Add modifier classes `weight-card--tare`, `--gross` (Net already has `--net`).
|
|
**This is a prerequisite, not polish:** Main.css:576-578 states the cockpit rules
|
|
use `:nth-child` precisely because these cards have no distinguishing class, and
|
|
the column count is about to change. Those `:nth-child` selectors must be
|
|
rewritten to the modifiers in the same pass or cockpit chrome lands on the wrong
|
|
cards.
|
|
|
|
Net keeps Print Notice + the Design Notice split button inside it (unchanged
|
|
markup, including the dropdown menu and backdrop). Gate them on `netWeight !==
|
|
null` so an empty Net card shows no dead buttons.
|
|
|
|
### 3. Row becomes a grid
|
|
|
|
`.weighing-section` moves from `flex` + `flex-wrap` to a 5-column grid, following
|
|
the ratio proven in the concept file
|
|
([ScalesAppCyberpunk.css:94](frontend/src/components/concepts/ScalesAppCyberpunk.css#L94)):
|
|
|
|
```css
|
|
.weighing-section {
|
|
display: grid;
|
|
grid-template-columns: 1.3fr 1fr 1fr 1fr;
|
|
gap: 16px;
|
|
margin-bottom: 24px;
|
|
align-items: stretch;
|
|
}
|
|
```
|
|
|
|
Four columns, because Print/Design stay inside Net rather than becoming a
|
|
separate action column — the user kept them there. Reading gets the wider track.
|
|
|
|
Remove `.reading-display`'s `margin-bottom: 20px` block along with the element.
|
|
Lift `.vehicle-detail { max-width: 700px }` (Main.css:115) — four readouts do not
|
|
fit in 700px. The cockpit override at 851-853 that already does this then becomes
|
|
redundant and should go.
|
|
|
|
Responsive, replacing the cockpit-only `@media (max-width:1150px)` rule:
|
|
```css
|
|
@media (max-width: 1150px) { .weighing-section { grid-template-columns: 1fr 1fr; } }
|
|
@media (max-width: 620px) { .weighing-section { grid-template-columns: 1fr; } }
|
|
```
|
|
These apply to **both** themes now, so drop the `[data-theme="cockpit"]` prefix
|
|
from the wrap rules at 858-872.
|
|
|
|
### 4. Form restyle (styling only, no new capability)
|
|
|
|
Confirmed scope: the create form only. There is no edit form and none is being
|
|
added. In Main.css:
|
|
|
|
- `.extra-field input/select` — set explicit `background: var(--surface)` and
|
|
`color: var(--text)`. They currently inherit UA defaults and survive cockpit
|
|
only by accident of `color-scheme: dark`.
|
|
- `.extra-fields` — add `@media (max-width: 768px) { grid-template-columns: 1fr }`;
|
|
it is a hard `1fr 1fr` at every width today.
|
|
- `.vehicle-form-actions` — add `justify-content: flex-end` to match the
|
|
`.manual-actions` precedent (Main.css:539+).
|
|
|
|
## Critical files
|
|
|
|
- [frontend/src/components/Main.jsx](frontend/src/components/Main.jsx) — lines
|
|
581-741 replaced; `firstWeighing` memo (290-309) deleted
|
|
- [frontend/src/components/Main.css](frontend/src/components/Main.css) —
|
|
`.reading-display` block removed, `.weighing-section` → grid, `max-width` cap
|
|
lifted, cockpit `:nth-child` → modifier classes, form rules
|
|
- [frontend/src/components/concepts/ScalesAppCyberpunk.css](frontend/src/components/concepts/ScalesAppCyberpunk.css)
|
|
— reference only, not modified. Its hardcoded hex and `var(--cyan)`/`var(--green)`
|
|
must **not** be copied; translate to the semantic tokens in
|
|
[frontend/src/styles/tokens.css](frontend/src/styles/tokens.css) (`--accent`,
|
|
`--success`). tokens.css is semantic-by-rule (header comment, lines 5-9).
|
|
|
|
No backend, serializer or API change. No new dependency.
|
|
|
|
## Verification
|
|
|
|
1. `cd frontend && npx vitest run` — 201 tests still pass
|
|
2. Browser check at http://localhost:5172, **both themes** via the header toggle,
|
|
walking the full weighing lifecycle on one vehicle:
|
|
- no vehicle selected → placeholder unchanged
|
|
- fresh vehicle, no readings → 4 cards, all `—`, no dead buttons
|
|
- after first Measure → value appears in TARE, Gross/Net still `—`
|
|
- after second Measure → Tare+Gross+Net populated, Measure button gone,
|
|
Print/Design appear in Net
|
|
3. Confirm the merged card still shows: `Disconnected` when the bridge is down,
|
|
`Waiting...` when connected with no reading, and the balanced/unbalanced
|
|
colour on a live value
|
|
4. Widths 1400 / 1100 / 600px — grid collapses 4 → 2 → 1 with no overflow
|
|
5. Cockpit chrome (clipped corner, lit top edge, Net glow) lands on the right
|
|
cards after the `:nth-child` → modifier rewrite
|
|
6. Create form: 2-col above 768px, 1-col below; Cancel/Create right-aligned;
|
|
inputs readable in cockpit
|