Files
scalesApp/.claude/plans/main-weighing-row-five-groups.md

7.5 KiB

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 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):

<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):

.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:

@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

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