diff --git a/docs/server.md b/docs/server.md index 43575b8a..525b2f5a 100644 --- a/docs/server.md +++ b/docs/server.md @@ -50,3 +50,51 @@ cook server --host - The web interface supports recipe browsing, scaling, search, and shopping list management - The UI language is negotiated per request from the browser's `Accept-Language` header — each visitor sees the interface in their own language (supported: `en-US`, `de-DE`, `nl-NL`, `fr-FR`, `es-ES`, `eu-ES`, `sv-SE`). For static sites, see the `--lang` flag of [`cook build web`](build.md#localization). - Mobile-friendly responsive layout + +## Custom Metadata Families (e.g. Nutrition) + +Beyond the [standard Cooklang metadata keys](https://cooklang.org/docs/spec/#canonical-metadata) (`servings`, `time`, `course`, `author`, ...), any YAML frontmatter key whose value is a **list** or a **mapping** is shown on the recipe page as its own line below the tags, grouped by key — one line per family. This works for any such key, not just `nutrition` — e.g. `allergens:` below renders as its own "Allergens" line automatically, with no code changes required. + +```yaml +--- +tags: + - vegan + - gluten-free +nutrition: + kcal: 258 + proteins: 4.2 + lipids: 4.8 + sugars: 39.4 + fibers: 5.3 +file: + created-by: Yannick + created-at: 2026-08-20 + modified-by: Yannick + modified-at: 2026-08-24 +allergens: + - gluten + - tree nuts +--- +``` + +### Two forms + +- **Mapping** (recommended, shown above): `field: value`. A bare number gets its unit inferred from the field name for `nutrition` (`kcal` → `kcal`, everything else → `g`); `field: "45.3%g"` also works if you want to spell out a different unit. +- **List** (legacy, still supported): `- "258%kcal"`. The `%` is replaced with a space when displayed (`258 kcal`); entries without a `%` are shown as-is. Because list entries are free text, they aren't translated — write them in whichever language you want displayed. + +### Hiding a family or a single entry + +Prefix a key with `.` to hide it from the recipe page: `.internal-notes:` hides the whole family, and `.lipids:` (inside `nutrition:`) hides just that one entry while the rest of the family still shows. `tags` is never treated as a custom family — it keeps its own dedicated row above, and can't be hidden this way. + +### Specific renderers: `nutrition` and `file`/`meta` + +Two families get dedicated icons and (for `nutrition`) localized labels, matched on their fields: + +- **`nutrition`**: `kcal`/`cal`/`energy` (flame), `proteins` (meat), `lipids`/`fat` (droplet), `saturated-fat` (filled droplet), `carbohydrates`/`carbs` (bread), `sugars` (candy), `fibers`/`fibre` (wheat), `salt`/`sodium` (salt shaker). The nutrient name (everything but `kcal`, which needs none) is translated into the viewer's UI language — see [Localization](build.md#localization) for the supported locales. +- **`file`** (or `meta`, both work): `created-by`/`created-at`/`modified-by`/`modified-at` — person, calendar, pencil, and history icons respectively, with a translated `"Label: value"` line (e.g. `"Modified at: 2026-08-24"`, `"Modifié le : 2026-08-24"` in French, with the French space before `:`). + +Every other family (like `allergens` above) falls back to a generic rendering: list entries as-authored, mapping entries as `"field: value"`, no icon. Adding a third specific renderer means adding a case in `src/web/family_renderers/mod.rs`'s `renderer_for` plus a small renderer file next to `nutrition.rs`/`file.rs` — there's no filename-based auto-discovery (Rust has no runtime filesystem scanning for this), so that match statement is always the definitive list of which families get special treatment. + +### Recipe list page + +Only the calorie entry from `nutrition` (`kcal`) is shown, as a compact badge next to the tags — the other custom families are only shown on the recipe detail page, to keep list cards compact. diff --git a/locales/de-DE/recipes.ftl b/locales/de-DE/recipes.ftl index c80a1f2a..6beca9cd 100644 --- a/locales/de-DE/recipes.ftl +++ b/locales/de-DE/recipes.ftl @@ -36,6 +36,20 @@ meta-total-time = Gesamtzeit meta-servings = Portionen meta-difficulty = Schwierigkeit meta-description = Beschreibung +meta-created-by = Erstellt von +meta-created-at = Erstellt am +meta-modified-by = Geändert von +meta-modified-at = Geändert am + +# Nutrition (benutzerdefinierte `nutrition:`-Metadaten) +nutrition-per-serving = pro Portion +nutrition-proteins = Eiweiß +nutrition-lipids = Fett +nutrition-saturated-fat = gesättigte Fettsäuren +nutrition-carbohydrates = Kohlenhydrate +nutrition-sugars = Zucker +nutrition-fibers = Ballaststoffe +nutrition-salt = Salz # Recipe Types recipe-type-menu = Menü diff --git a/locales/en-US/recipes.ftl b/locales/en-US/recipes.ftl index 1b4efd52..f07d99df 100644 --- a/locales/en-US/recipes.ftl +++ b/locales/en-US/recipes.ftl @@ -36,6 +36,20 @@ meta-total-time = Total Time meta-servings = Servings meta-difficulty = Difficulty meta-description = Description +meta-created-by = Created by +meta-created-at = Created at +meta-modified-by = Modified by +meta-modified-at = Modified at + +# Nutrition (custom `nutrition:` metadata) +nutrition-per-serving = per serving +nutrition-proteins = proteins +nutrition-lipids = fat +nutrition-saturated-fat = saturated fat +nutrition-carbohydrates = carbohydrates +nutrition-sugars = sugars +nutrition-fibers = fiber +nutrition-salt = salt # Recipe Types recipe-type-menu = Menu diff --git a/locales/es-ES/recipes.ftl b/locales/es-ES/recipes.ftl index 171455b1..d96c134f 100644 --- a/locales/es-ES/recipes.ftl +++ b/locales/es-ES/recipes.ftl @@ -36,6 +36,20 @@ meta-total-time = Tiempo Total meta-servings = Porciones meta-difficulty = Dificultad meta-description = Descripción +meta-created-by = Creado por +meta-created-at = Creado el +meta-modified-by = Modificado por +meta-modified-at = Modificado el + +# Nutrición (metadatos personalizados `nutrition:`) +nutrition-per-serving = por porción +nutrition-proteins = proteínas +nutrition-lipids = grasas +nutrition-saturated-fat = grasas saturadas +nutrition-carbohydrates = hidratos de carbono +nutrition-sugars = azúcares +nutrition-fibers = fibra +nutrition-salt = sal # Recipe Types recipe-type-menu = Menú diff --git a/locales/eu-ES/recipes.ftl b/locales/eu-ES/recipes.ftl index 688acca8..79fa252c 100644 --- a/locales/eu-ES/recipes.ftl +++ b/locales/eu-ES/recipes.ftl @@ -36,6 +36,20 @@ meta-total-time = Denbora guztira meta-servings = Anoak meta-difficulty = Zailtasuna meta-description = Deskribapena +meta-created-by = Sortzailea +meta-created-at = Sortze data +meta-modified-by = Aldatzailea +meta-modified-at = Aldatze data + +# Nutrizioa (`nutrition:` metadatu pertsonalizatuak) +nutrition-per-serving = anoko +nutrition-proteins = proteinak +nutrition-lipids = gantzak +nutrition-saturated-fat = gantz aseak +nutrition-carbohydrates = karbohidratoak +nutrition-sugars = azukreak +nutrition-fibers = zuntza +nutrition-salt = gatza # Recipe Types recipe-type-menu = Menua diff --git a/locales/fr-FR/recipes.ftl b/locales/fr-FR/recipes.ftl index 899ef28c..3bac963b 100644 --- a/locales/fr-FR/recipes.ftl +++ b/locales/fr-FR/recipes.ftl @@ -36,6 +36,20 @@ meta-total-time = Temps Total meta-servings = Portions meta-difficulty = Difficulté meta-description = Description +meta-created-by = Créé par +meta-created-at = Créé le +meta-modified-by = Modifié par +meta-modified-at = Modifié le + +# Nutrition (métadonnées personnalisées `nutrition:`) +nutrition-per-serving = par portion +nutrition-proteins = protéines +nutrition-lipids = lipides +nutrition-saturated-fat = graisses saturées +nutrition-carbohydrates = glucides +nutrition-sugars = sucres +nutrition-fibers = fibres +nutrition-salt = sel # Recipe Types recipe-type-menu = Menu diff --git a/locales/nl-NL/recipes.ftl b/locales/nl-NL/recipes.ftl index b6c84fda..b44dfa78 100644 --- a/locales/nl-NL/recipes.ftl +++ b/locales/nl-NL/recipes.ftl @@ -36,6 +36,20 @@ meta-total-time = Totale tijd meta-servings = Porties meta-difficulty = Moeilijkheidsgraad meta-description = Beschrijving +meta-created-by = Aangemaakt door +meta-created-at = Aangemaakt op +meta-modified-by = Gewijzigd door +meta-modified-at = Gewijzigd op + +# Nutrition (aangepaste `nutrition:`-metadata) +nutrition-per-serving = per portie +nutrition-proteins = eiwitten +nutrition-lipids = vetten +nutrition-saturated-fat = verzadigd vet +nutrition-carbohydrates = koolhydraten +nutrition-sugars = suikers +nutrition-fibers = vezels +nutrition-salt = zout # Recipe Types recipe-type-menu = Menu diff --git a/locales/sv-SE/recipes.ftl b/locales/sv-SE/recipes.ftl index 77256c5d..8533e7e5 100644 --- a/locales/sv-SE/recipes.ftl +++ b/locales/sv-SE/recipes.ftl @@ -36,6 +36,20 @@ meta-total-time = Total tid meta-servings = Portioner meta-difficulty = Svårighet meta-description = Beskrivning +meta-created-by = Skapad av +meta-created-at = Skapad +meta-modified-by = Ändrad av +meta-modified-at = Ändrad + +# Nutrition (anpassad `nutrition:`-metadata) +nutrition-per-serving = per portion +nutrition-proteins = protein +nutrition-lipids = fett +nutrition-saturated-fat = mättat fett +nutrition-carbohydrates = kolhydrater +nutrition-sugars = socker +nutrition-fibers = fibrer +nutrition-salt = salt # Recipe Types recipe-type-menu = Meny diff --git a/src/web/builders.rs b/src/web/builders.rs index 494cb534..e6396c0f 100644 --- a/src/web/builders.rs +++ b/src/web/builders.rs @@ -68,7 +68,7 @@ pub fn build_recipes_template(input: RecipesBuildInput<'_>) -> Result) -> Result) -> Result) -> Result