Skip to content

Web UI: per-row unit suffixes, Fahrenheit support, dark-mode default - #18

Merged
SebastianAment merged 1 commit into
mainfrom
web-ui-units-rework
May 11, 2026
Merged

Web UI: per-row unit suffixes, Fahrenheit support, dark-mode default#18
SebastianAment merged 1 commit into
mainfrom
web-ui-units-rework

Conversation

@SebastianAment

Copy link
Copy Markdown
Contributor

Summary

Reworks how the concrete strength explorer in docs/ handles units, gives the temperature row real Fahrenheit support, and pins dark mode as the unconditional default theme. Refactors all unit conversions into a pure units.mjs module that is the single source of truth for both the UI and tests.

Changes

  • Per-row unit suffixes in the composition setter panel. Each non–Material-Source row now shows its own unit (kg/m³ / lb/yd³ for masses, °C / °F for temperature), kept right-aligned with the max-bound column on both desktop (.info-row { padding: 0 2px }) and mobile (padding: 0 7px 0 0). Previously the unit was only in the section title.

  • Fahrenheit conversion for temperature. The imperial display now uses the offset conversion F = C × 9/5 + 32. The previous implementation used a single multiplicative factor per quantity, which can't represent °C ↔ °F correctly — that's why the temperature was previously left in °C regardless of unit system. Slider min/max bounds, click-to-edit commit, blur-revert, and the unit-toggle snap all flow through the offset-aware helpers.

  • Single source of truth for units (docs/units.mjs). New pure module exporting:

    • UNITS for strength (psi ↔ MPa), mass (kg/m³ ↔ lb/yd³), gwp (kg CO₂/m³ ↔ lb CO₂/yd³), cost ($/m³ ↔ $/yd³), and temp (°C ↔ °F).
    • compToDisplay(col, internal, unitSystem) / compFromDisplay(...) — column-aware (handles mass factor and temp offset).
    • celsiusToDisplay / displayToCelsius (temperature-specific).
    • sliderUnitLabel(col, unitSystem).

    This module is imported by both docs/ui.mjs and test/test_js_units.mjs (Node), so the conversions are tested without a browser.

  • Dark mode is the unconditional default. The inline theme bootstrap in index.html previously honored prefers-color-scheme: light, so visitors with a light-mode OS landed in light mode without pressing the toggle. Now getEffectiveTheme() returns 'dark' unless the user has an explicit stored preference. The matchMedia('prefers-color-scheme: dark') change-listener that used to wipe the user's stored preference on OS appearance change is also removed.

End-to-end unit-conversion review

The native units in the data and model are: kg/m³, psi, °C, kg CO₂/m³, $/m³ (per boxcrete/units.py). All imperial conversions in the JS factor table verified against external constants:

Quantity Imperial factor / fn Sanity check
psi → MPa 1 / 145.04 matches Python PSI_TO_MPA = 0.006895
kg/m³ → lb/yd³ 1.6856 2.20462 / 1.30795 = 1.6856
GWP density 1.6856 same conversion as mass
$/m³ → $/yd³ 1 / 1.30795 ≈ 0.7646 1 yd³ = 0.7646 m³
°C → °F × 9/5 + 32 (offset) 0/100 °C → 32/212 °F

Testing

  • New: test/test_js_units.mjs — 67 Node-only assertions covering factor constants, offsets, round-trip identity for both column kinds under both unit systems, column-name dispatch, and label mapping. Run with node test/test_js_units.mjs.
  • New: test/e2e/unit-toggle.spec.ts — Playwright e2e covering: metric default labels, toggle to imperial flips both kg/m³ → lb/yd³ and °C → °F, the offset-aware temperature value (e.g. 22 °C → 71.6 °F, not 22 °F), round-trip preservation, and the temperature info-row min/max bounds (e.g. -20 °C / 22 °C → -4 °F / 72 °F).
  • Local pre-commit results: pytest 176 passed, test_js_units.mjs 67/67, test_js_gp.mjs 90/90 JS↔Python parity assertions still passing.

Files

docs/index.html | 13 +++----
docs/style.css | 38 +++++++++++++
docs/ui.mjs | 83 +++++++++++++++++++----------
docs/units.mjs | (new, ~90 lines)
test/test_js_units.mjs | (new, ~130 lines)
test/e2e/unit-toggle.spec.ts | (new, ~113 lines)

Out of scope / future

  • The hard-coded units in docs/model/mix_analyses.json (LLM-generated mix descriptions) still mention kg/m³ and psi literally; they don't currently re-render on toggle. Could be regenerated to use both, or replaced at runtime — left alone here.
  • Slump prediction is still TODO in update(); when wired up, the mm ↔ in conversion (factor 25.4 per boxcrete/units.py) would just need to be added to UNITS similarly.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label May 11, 2026
…rk default

- Extract UNITS and conversion helpers into docs/units.mjs as a pure module
  (single source of truth, importable by ui.mjs and Node-style tests).
- Add per-row unit suffixes to the composition setter panel (kg/m³ ↔ lb/yd³
  on mass rows, °C ↔ °F on the temperature row), right-aligned with the
  max-bound column on both desktop and mobile.
- Convert temperature to Fahrenheit when imperial is active using the
  offset conversion F = C × 9/5 + 32. A single multiplicative factor was
  insufficient (this is why the temperature row was previously kept in °C
  regardless of unit system). Slider min/max bounds, click-to-edit commit,
  and unit-toggle snap all flow through offset-aware helpers.
- Make dark mode the unconditional default. The inline theme bootstrap
  previously honored prefers-color-scheme: light, so visitors with a
  light-mode OS landed in light mode without pressing the toggle. The
  matchMedia listener that wiped a user's stored preference on OS
  appearance change is also removed.
- Add test/test_js_units.mjs (67 assertions, Node-only, mirrors the
  test_js_gp.mjs pattern). Covers factor constants, the °F offset,
  round-trip identity for both column kinds under both unit systems,
  column-name dispatch, and label mapping.
- Add test/e2e/unit-toggle.spec.ts (Playwright) verifying the metric
  default, toggle to imperial, offset-aware temperature display
  (22°C → 71.6°F, not 22°F), round-trip preservation, and the
  temperature info-row min/max bounds.
@SebastianAment
SebastianAment merged commit 9efd9da into main May 11, 2026
12 checks passed
@SebastianAment
SebastianAment deleted the web-ui-units-rework branch May 11, 2026 19:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant