Add field help dialog with cultivar/process reference notes
Test and deploy / test-and-deploy (push) Successful in 1m32s

Adds a help-dialog UI (field-help.js/field-help-content.js) surfacing
per-field guidance, expands cultivar and process reference data with
cup notes, sweet-spot width, and watch-fors, and adds a Makefile for
common npm tasks.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-07-31 06:37:33 -04:00
co-authored by Claude Sonnet 5
parent df5c4aef48
commit 84fb396c7d
8 changed files with 1443 additions and 36 deletions
+26 -1
View File
@@ -5,7 +5,12 @@ import {
formatSigned,
parseRangeMidpoint,
} from "/shared/time.js?v=__ASSET_VERSION__";
import { CULTIVARS, findCultivar } from "/shared/reference-data.js?v=__ASSET_VERSION__";
import {
CULTIVARS,
findCultivar,
findProcess,
findRoastLevel,
} from "/shared/reference-data.js?v=__ASSET_VERSION__";
import { buildPlanCurve, pointsToPathD, tToX, tempToY } from "/shared/curve.js?v=__ASSET_VERSION__";
import { initPrefillPanel } from "./prefill-ui.js?v=__ASSET_VERSION__";
import { initAlogPanel } from "./alog-ui.js?v=__ASSET_VERSION__";
@@ -14,6 +19,7 @@ import { initLotPicker } from "./lot-picker.js?v=__ASSET_VERSION__";
import { protectedFetch, csrfToken } from "./api.js?v=__ASSET_VERSION__";
import { initSideNav } from "./nav.js?v=__ASSET_VERSION__";
import { wireWhyPanels } from "./why-panels.js?v=__ASSET_VERSION__";
import { initFieldHelp } from "./field-help.js?v=__ASSET_VERSION__";
const FIELD_ID_SET = new Set(FIELD_IDS);
const STORAGE_PREFIX = "roastPlannerPlan.v2";
@@ -597,6 +603,22 @@ function cultivarAutofill(name) {
renderFormFromPlan();
}
// Mirrors cultivarAutofill(): picking a process/roast level should feed the same reference
// numbers into the ledger that selecting a cultivar does, not just record the choice as text.
function processAutofill(key) {
const row = findProcess(key);
if (!row) return;
setValueForName("3.2", formatSigned(row.devModS));
renderFormFromPlan();
}
function roastLevelAutofill(key) {
const row = findRoastLevel(key);
if (!row) return;
setValueForName("4.3", formatDuration(parseRangeMidpoint(row.devBand)));
renderFormFromPlan();
}
function wireCultivarDatalist() {
const list = document.getElementById("cultivar-list");
list.replaceChildren(
@@ -619,6 +641,8 @@ function wireForm() {
);
if (el.name === "1.1") cultivarAutofill(el.value);
if (el.name === "2.1") updateBlendVisibility(el.value);
if (el.name === "3.1") processAutofill(el.value);
if (el.name === "4.1") roastLevelAutofill(el.value);
if (el.name.startsWith("blendComponents.")) updateBlendTotal();
recompute();
});
@@ -1010,6 +1034,7 @@ async function init() {
renderActuators();
wireCultivarDatalist();
wireWhyPanels();
initFieldHelp({ getPlan: () => state.plan });
renderBandRanges();
renderFormFromPlan();
wireForm();