Add dish CRUD to the UI, including inline from Kirjaa

The catalog could only be filled by importing JSON, which is a poor way to
add the one dish you are about to eat.

Ruoat now covers PRD §7.3 in full: add and edit mains with their categories
and has_sides, add and edit sides, and delete either. Deletes are soft, so a
log entry keeps resolving the dish it used and the freed name can be reused.
Validation messages are Finnish and the rejected form comes back filled in
rather than blank. Bulk import moves into a details element, since it is now
the occasional path rather than the only one.

Kirjaa gets the same ability without the detour: a search that finds nothing
offers to add what was typed, and saving creates the dish and continues
straight to the sides step. An empty catalog shows the same card instead of
dead-ending on a link to another tab, and the search box is no longer hidden
behind the empty state.

The importer's own insert is gone; it and the UI both go through createMain
and createSide, so duplicate detection lives in one place and reason() can
match on errNameTaken instead of poking at driver strings.
This commit is contained in:
Esa Kataja
2026-09-05 18:44:09 +03:00
parent d95b9f9f91
commit d15f741ab1
9 changed files with 836 additions and 73 deletions
+4 -3
View File
@@ -21,13 +21,14 @@ Working:
by how often they are eaten. Edit or delete the day's entry.
- **Historia** — every day back to the first entry, with unlogged days shown
as explicit gaps.
- **Ruoat** — import a bundle of dishes by paste or file upload.
- **Ruoat** — add, edit and delete mains and sides, or import a whole bundle
by paste or file upload. Deletes are soft, so old log entries keep showing
the dish they used.
Still to build:
- Adding, editing and deleting dishes **in the UI** (PRD §7.3). Right now the
catalog can only be filled by importing a bundle.
- Light / dark theme switch, saved per device (PRD §7.4).
- A proper app header and a `favicon.svg`.
- Stage 2: the seven-meal suggester, which starts once there is history to
weight against.