Skip to content

fix(app): fix layout, focus, heading and copy issues on web and phone - #423

Open
simonvanlierde wants to merge 20 commits into
mainfrom
fix/app-ui-review
Open

simonvanlierde wants to merge 20 commits into
mainfrom
fix/app-ui-review

Conversation

@simonvanlierde

Copy link
Copy Markdown
Contributor

Fixes for the app on web and on a phone, mostly around the deeper component tree and page structure. Please merge this after #422, which regenerates the API types.

  • Expanded component rows stay in the page flow on web, and the deep breadcrumb and the amount stepper fit a phone screen.
  • Focus moves to the record's name when a detail page opens. The sign-in, sign-up, account and cameras screens now have exactly one h1.
  • The delete dialog says that the record's components, photos and files go with it.
  • Photos from a paired camera count toward the owner's total, and the account counts refresh after a save, delete or capture.
  • Weights under 1 kg show in grams. The API's profile total_weight_kg now has three decimals instead of two.
  • Placeholders use their own grey at 4.5:1 contrast. Edit mode hides an empty materials list, and a few labels are shorter or in sentence case.

Expanding a component row drew its children on top of the rows below
it, and deeper levels spilled out of the card. On web, Reanimated treats
an entering animation with custom initial values as a custom keyframe
and pins the element to `position: absolute` at its snapshot size once
the animation ends.

- Component rows, the edit save bar and the camera-paired icon use the
  stock presets instead.
- A source test fails if an entering animation sets custom initial
  values again.
…des in

A product or component screen fades in after its skeleton and stays
`visibility: hidden` for its first frames. The single focus() on entry
landed in that window and was ignored, so focus stayed on <body>.
Entry focus now retries for up to 30 frames while focus is still
nowhere, and leaves it alone once the user has moved it.
- A component three or more levels deep showed its whole trail in the
  phone header and pushed its own name out. The phone header now shows
  only the direct parent behind an ellipsis; lg still shows every level.
- The amount field had no width, so on web it took the browser's default
  input width and pushed the "+" button off a phone screen. It is now
  56px, enough for the 5-digit maximum.
- The edit save bar on a phone keeps the page's 16px side gutter.
…y role

- Deleting a product or component also deletes everything under it and
  every photo and file on that subtree. The confirmation now says so,
  with the number of direct components, instead of a bare "Are you
  sure?".
- A component's edit-mode name field is labelled "Component name", not
  "Product name".
- The edit and save buttons use sentence case ("Edit component",
  "Save product"), like every other button label in the app.
…ontrast

- The component weight total, a component row's type and the tree's
  "Loading components" note were in the tracked field-label step. They
  are sentences, so they use caption now.
- "This product has no subcomponents" takes muted ink instead of a 70%
  opacity, which DESIGN.md keeps for disabled controls.
- The "No photos yet" label on an image placeholder was the outline grey
  at 3.5:1 on the muted fill. It now uses muted ink, on the caption step.
- Account secondary lines asked for 13px through a class, which the text
  variant's inline size overrode, so they rendered at 16px. They use the
  caption step.
A capture pushed from a paired camera stored the image but did not refresh
the owner's stored profile stats, so the profile kept the old photo count
until some other product change recomputed it. The upload route now
recomputes and commits the snapshot, as the app's image upload already does.
The account and profile screens cached the owner's product, photo and
weight counts and never asked again while the tab stayed open, so a new
photo did not show up in the count. Saving or deleting a record, and a
camera capture, now mark those counts stale.
The profile's total_weight_kg was rounded to two decimals, so 164 g came
back as 0.16 kg. It now keeps three decimals, which is exact for the
stored whole-gram total.
The account and profile screens printed the raw kilogram value, so 164 g
read as "0.16 kg". Below 1 kg they now show whole grams ("164 g"), and
from 1 kg kilograms to one decimal ("1.6 kg").
The switch already shows and announces whether updates are on.
Materials are recorded through the API, not the form, so an empty list in
edit mode was a heading with nothing to act on. Edit mode now leaves it
out. In view mode an empty list shows a dash, as other unset fields do.
…h1 and a main region

- Sign in has a visible "Sign in" heading under the wordmark; it had none.
- The create-account form sits in a main landmark and takes focus on entry,
  as the other auth screens do.
- On a phone, the account and cameras stack headers render their title as
  plain text, so the page's own h1 is the only one. The public profile
  screen uses the same title component.
Placeholders used muted ink, close enough to typed text to pass for a
value. They now use the input stroke grey through a new
tokens.text.placeholder, in both text field components. The theme
contrast test checks it keeps 3:1 on every input fill and stays well
below the contrast of entered text.
Placeholder text is text, so it needs the same 4.5:1 as other text. The input stroke grey reached only 4.0:1 on the light card and 3.6:1 on the dark tinted input. Typed text still keeps at least twice the placeholder's contrast.
- Use PlainHeaderTitle as the header title component instead of wrapping it in an arrow.
- Use entityRole in the "Edit" and "Save" labels; it already holds the lower-case word.
- Inline a one-use string in the delete dialog message.
- Move the focus retry limit above the hook's doc comment, which it had split from the hook.
- Point the three entering-animation notes at the test that explains the rule.
…tense

- Name the placeholder's dark backdrop the input grey, as the contrast test does.
@codecov

codecov Bot commented Oct 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant