Work / AskCal / Wiki / Surfaces
portion
Surfacecanonicalverified 2026-09-28
SURFACE.MOBILE.FOOD.PORTIONSummary
How much of this did you have — one editor, worn as a weight, a count or a pour.
Raw wireframe
- .context/designs/mobile/food/portion-weight.html
- .context/designs/mobile/food/portion-count.html
- .context/designs/mobile/food/portion-liquid.html
Why it is drawn this way
Three files, one screen, one route. food/item.tsx renders all three. Which
face it wears is a fact about the food, not a choice the user makes, so there is
no face-picker anywhere.
They are generated from one template — scripts writes the four editors
(these three and fat) from a single anatomy, because three hand-written faces
of one screen drift, and had: different section labels, quick-picks on one face
only, and the unit-weight row on one face only.
The anatomy, top to bottom:
| Zone | What it holds |
|---|---|
| Header | item name, the meal it is in, and a bin |
| Label + mark | "Portion", and the confidence mark for this row |
| Value | the number, its unit, and the kcal it comes to |
| Derived grams | only where the unit is not already grams |
| Stepper | the one control you came here to use |
| Quick picks | four presets, so the common answer is one tap |
| Footer rows | what one piece weighs, and what share you ate — each opens a sheet |
| Macros | the macros of the portion above |
| "Not this?" | wrong amount and wrong food are one complaint to someone over a plate |
A cooking-fat row never reaches this screen. Every caller branches on
isFatComponent and sends it to fat instead, because "how much oil" is a
judgement with named answers rather than a food to weigh or re-identify.
meal.tsx always did; result.tsx did it for the row's button but not for the
tap on its name, so this editor grew a fat face whose only content was a card
linking to the screen the row already offered. The branch is in the callers now
and the face is gone.
Grams are the quantity of record. A face may speak in pieces or millilitres,
but grams is what macros scale from, and lib/measure.ts holds the invariant
grams === gramsFor(measure). The derived gram line is printed so the two can
never silently disagree, and it is never editable from here.
The share is descriptive, never arithmetic. "Half of it" records that the portion above was half of what arrived; it recomputes nothing. See the sheet below. The alternative — where choosing half halves the number — makes one control mean two different things depending on whether the stepper was already touched, and nothing can tell which the user meant.
The "You ate" sheet
Five options: all of it, most of it, half, a third, a quarter. It is a sheet rather than five rows left open, because a share is set occasionally and the quantity is set every time. Drawn in sheets.
It earns its place on things nobody can count — a curry, a bowl of rice, a plate shared between two. Half of two eggs is one egg, which the stepper says better.
Related
Sources
- .context/designs/mobile/food/portion-weight.html
Every project of mine is written down like this.
Read the résumé