Skip to content

feat(server): display custom list metadata (e.g. nutrition) on recipe pages - #458

Open
Tloxipeuhca wants to merge 3 commits into
cooklang:mainfrom
Tloxipeuhca:feat/nutrition-metadata-display
Open

feat(server): display custom list metadata (e.g. nutrition) on recipe pages#458
Tloxipeuhca wants to merge 3 commits into
cooklang:mainfrom
Tloxipeuhca:feat/nutrition-metadata-display

Conversation

@Tloxipeuhca

@Tloxipeuhca Tloxipeuhca commented Aug 24, 2026

Copy link
Copy Markdown

Closes #459

Summary

  • Any non-standard YAML frontmatter key whose value is a list (e.g. nutrition:) is now shown as its own line below the tags on the recipe and menu pages — one line per family, no code changes needed to support new families.
  • nutrition: entries get a matching icon (Tabler Icons, MIT license, inlined as SVG — no new dependency) picked by keyword in the unit text: kcal/energy → flame, protein → meat, lipid/fat → droplet, sugar → candy, fiber → wheat. Unrecognized families/units render as a plain bullet.
  • The recipe list page shows a compact 🔥 X kcal badge next to the tags when a recipe has nutrition: with a kcal entry.
  • Entries are written as value%unit (e.g. 258%kcal) and displayed as 258 kcal.
  • New: nutrition: also supports a mapping form (nutrition: {kcal: 234, proteins: 9.8, ...}) alongside the original list form, with per-field unit inference (kcal → kcal, everything else → g) and 3 additional nutrient fields (saturated-fat, carbohydrates, salt) with matching icons.
  • New: a file family (created-by/created-at/modified-by/modified-at) is now recognized, with person/calendar/pencil/history icons.
  • New: nutrient and file-metadata field names are translated into the viewer's UI language via the existing Fluent i18n system, across all 7 supported locales (de-DE, en-US, es-ES, eu-ES, fr-FR, nl-NL, sv-SE).
  • New: a YAML key prefixed with . is hidden from the recipe page, at either the family level (.file:) or a single mapping entry (.lipids:) — useful for metadata you want in the file but not shown to readers.
  • Refactored per-family rendering into src/web/family_renderers/ (mod.rs + generic.rs + nutrition.rs + file.rs): a small FamilyRenderer trait with a generic fallback, and an explicit renderer_for() registry so adding a future specific renderer only touches one match arm.
  • Documented the convention in docs/server.md ("Custom Metadata Families").

Test plan

  • cargo build, cargo clippy --all-targets (clean, no warnings), cargo fmt --check — all pass.
  • Manually tested with a real ~250-recipe collection using both the list and mapping nutrition: forms, via cargo run -- server:
    • Recipe detail page renders one "Nutrition" line with correct icons for kcal/protein/lipid/carbs/salt/sugar/fiber, in both YAML forms.
    • file:/meta: metadata renders with the expected icons and translated labels.
    • Switching the UI locale correctly translates nutrient/file-metadata labels.
    • Keys prefixed with . (family-level and entry-level) are correctly hidden.
    • Nested non-list, non-mapping metadata is correctly ignored — does not render as a spurious line.
    • List page shows the kcal badge next to tags.
  • Screenshots on request if useful for review.

🤖 Generated with Claude Code

Tloxipeuhca and others added 2 commits August 24, 2026 19:35
… pages

Any non-standard YAML frontmatter key whose value is a list (e.g. `nutrition:`)
is now shown as its own line below the tags on the recipe and menu pages, one
line per family. Nutrition entries get a matching icon (Tabler Icons, MIT)
based on keyword: kcal/energy, protein, lipid/fat, sugar, fiber. The recipe
list page shows a compact kcal badge next to tags when `nutrition:` is present.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…-hiding

Extends the custom metadata family display added in the previous commit:

- Supports a mapping form (`nutrition: {kcal: 234, proteins: 9.8, ...}`)
  alongside the original list form, with per-field unit inference
  (kcal -> kcal, everything else -> g) and 3 new nutrient fields
  (saturated-fat, carbohydrates, salt) plus matching icons.
- Nutrient names and a new `file`/`meta` family (created-by/created-at/
  modified-by/modified-at, with person/calendar/pencil/history icons) are
  translated into the viewer's UI language via the existing Fluent i18n
  system, across all 7 supported locales.
- A YAML key prefixed with "." is hidden from the recipe page, at either
  the family level (`.file:`) or a single mapping entry (`.lipids:`).
- Refactors the per-family rendering into src/web/family_renderers/
  (mod.rs + generic.rs + nutrition.rs + file.rs): a small FamilyRenderer
  trait with a generic fallback, and an explicit renderer_for() registry
  so adding a future specific renderer only touches one match arm.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Tloxipeuhca
Tloxipeuhca force-pushed the feat/nutrition-metadata-display branch from fabb100 to eeca3ec Compare August 24, 2026 17:58
@Tloxipeuhca

Tloxipeuhca commented Aug 24, 2026

Copy link
Copy Markdown
Author

Update: mapping form, i18n, dot-hiding, generic fallback

Following review discussion, this PR now also supports:

Mapping form + 3 new nutrition fields

nutrition: can now be written as a mapping (recommended) instead of a list, with per-field unit inference (kcalkcal, everything else → g):

nutrition:
  kcal: 234
  proteins: 9.8
  lipids: 17.6
  saturated-fat: 6.2
  carbohydrates: 18.4
  sugars: 8.9
  fibers: 0.9
  salt: 1.85

The original list form (- "258%kcal") still works too, unchanged.

New file: family

file:
  created-by: Yannick
  created-at: 2026-08-20
  modified-by: Yannick
  modified-at: 2026-08-24

Renders as its own line with person/calendar/pencil/history icons and a translated "Label: value" per entry. file: and meta: are both accepted as the family key.

Generic fallback (any other family, still works exactly as before)

allergens:
  - gluten
  - tree nuts
origin:
  country: France
  region: Alsace

Any YAML key that isn't nutrition or file/meta still renders automatically — list entries as-authored, mapping entries as field: value, no icon, no code change required. nutrition and file/meta are just the two families that opted into specific icons/formatting.

.-prefix hiding

Prefix a key with . to hide it from the recipe page:

.internal-notes:
  - draft, not ready for print
nutrition:
  kcal: 234
  .lipids: 17.6   # hidden; the rest of the nutrition line still shows

Works at the family level (.internal-notes: hides the whole line) and at the single-entry level inside a mapping (.lipids: hides just that one chip).

i18n

Nutrient names and the file/meta labels are translated into the viewer's UI language across all 7 supported locales, including correct French typography (space before :).

Refactor

Renderer logic moved to src/web/family_renderers/ (mod.rs + generic.rs + nutrition.rs + file.rs) — a small FamilyRenderer trait, generic default, and an explicit renderer_for() registry so a future specific renderer is one match arm + one file.

cargo build, cargo clippy --all-targets, cargo fmt --check all clean.

@Tloxipeuhca

Tloxipeuhca commented Aug 24, 2026

Copy link
Copy Markdown
Author

Screenshot of the mapping-form nutrition + file metadata rendering (fr-FR locale):

  1. Recipe list page — the Tarte Flambée card shows a compact 🔥 1443 kcal badge next to its tags, pulled from the nutrition.kcal mapping entry; other cards without nutrition: show no badge. list-en
  2. English locale (Accept-Language: en-US) — same recipe, same FILE/NUTRITION lines in English (Modified at, Modified by, fat, saturated fat, carbohydrates, sugars, fiber, proteins, salt).final-en
  3. French locale (Accept-Language: fr-FR) — recipe page showing the FILE line (Modifié le : 2026-08-24, Modifié par : Yannick, note the French space before :) and the NUTRITION line with all 8 fields translated (lipides, graisses saturées, glucides, sucres, fibres, protéines, sel) plus their icons. final-fr

Nutrition values apply to a single serving, which wasn't stated anywhere
on the page. A hover-only tooltip was considered but rejected: the site
is explicitly mobile-friendly, and tooltips don't work on touch.

Instead, adds a small always-visible qualifier stacked under the
"NUTRITION" label (translated across all 7 locales), via a new `note()`
method on FamilyRenderer (default None, overridden by NutritionRenderer)
so the mechanism stays available to any future family that needs one.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Tloxipeuhca

Copy link
Copy Markdown
Author

Closes #459

@dubadub

dubadub commented Aug 26, 2026

Copy link
Copy Markdown
Member

Thanks for that, will review in a day or two

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.

Display custom recipe metadata (e.g. nutrition) on the recipe page

2 participants