~martijnbraam/fathub-data

6f4dad60b296e44dd00a5f2851676000334cd5e8 — Martijn Braam 2 years ago d4e8577
Add format documentation
1 files changed, 148 insertions(+), 0 deletions(-)

A README.md
A README.md => README.md +148 -0
@@ 0,0 1,148 @@
# Fathub.org dataset

These are the data files for all the recipes and info on fathub.org

## Data structure

The second version of fathub.org supports internationalisation. This is accomplished by having translated copies of the
dataset. The root folder of the repository contains a subdirectory for every language. The english language is the
canonical dataset and if a translated version in another subdirectory exists that file will be preferred.

```
dataset
├── en
│   ├── ingredients
│   │   ├── example-ingredient.md
│   │   ├── category
│   │   │   ├── detailed-ingredient.md
│   │   │   └── another.md
│   └── recipes
│       ├── dutch # Cuisine subdirectory
│       │   └── main # Course subdirectory
│       │       └── boerenkool.toml # Recipe
├── nl
│   ├── ingredients
│   │   ├── example-ingredient.md # Translation of the EN page
│   └── recipes
│       └── dutch
│           └── main
│               └── boerenkool.toml # Dutch translated recipe
├── README.md
└── tools
    └── lint.py
```

## Recipe file format

The recipes are described in toml. Here's an example recipe:

```toml
name = "Stamppot Boerenkool"
author =  "Martijn Braam <martijn@brixit.nl>"
created = 2021-08-01
cuisine =  "Dutch"
course = "main dish"
preptime = 5
cooktime = 35
serves = 4

tips = [
    "If the [kale] isn't pre-cut you need about [kale:1:kg] and wash/cut it",
    "This dish can be made vegetarian by substituting the fried bacon with peanuts, add some butter to compensate for the lack of grease",
    "The dish works best with some floury potatoes such as Russet and Yukon Gold",
    "Traditionally this dish is served with 'rookworst' which doesn't seem to be really available internationally"
]

[ingredients]
  [ingredients.potatoes]
  id = "potatoes"
  amount = 2000
  unit = "g"
  prep = "peeled"
  [ingredients.kale]
  id = "vegetables/kale/curly"
  amount = 600
  unit = "g"
  [ingredients.water]
  id = "water"
  amount = 100
  unit = "mL"
  [ingredients.salt]
  id = "salt"
  amount = 10
  unit = "g"
  [ingredients.bacon]
  id = "meat/pork/bacon"
  amount = 250
  unit = "g"

[[instructions]]
    name = "cooking"
    steps = [
        "Put the [kale,water] and [salt] in a large pan with a lid and bring to a boil",
        "When the [kale] has shrunk enough, put the [potatoes] on top of them",
        "Cut the [bacon] in small strips and fry them until crispy",
        "Once the [potatoes] are done, pour off the cooking liquid, but keep it",
        "Crush the mass (with a potato masher) and mix them",
        "Add the cooking water back and add the [bacon] with all the grease"
    ]
```

The first keys in the file contain the main metadata of the recipe. Then a `tips` list that is rendered at the end of
the recipe normally but has to be at the start of the recipe for toml syntax reasons.

### Recipe ingredients

Then the ingredient list is added as a dictionary. The name inside the brackets is the name used to refer to the
ingredient _inside_ the recipe. The `id` is the path to the ingredient file inside the database.

For ingredients the following properties are supported:

**amount:** For ingredients that have a specific amount that needs to be added. The unit for this field is described in
the `unit` field.  
**unit:** When the amount is specified this sets the unit. This can be one of:

* L
* mL
* cup
* teaspoon
* tablespoon
* fl oz
* g
* ounce
* kg
* piece

The frontend is able to convert the unit to whatever the user desires. If the specific weight for an ingredient is known
in the database it's also possible to swich the display value between the weight and volume units.

In translated recipes the units should still be defined by these english terms

**prep**: This is a single line description of specific preperation of the ingredient. This can be "sliced" to denote
the ingredient is assumed to be pre-sliced to avoid a list of these tasks in the recipe steps themselves.

### Recipe steps

The next section in the file is the `[[instructions]]` list. There can be multiple of these sections to break up larger
recipes into "chapters". The two supported properties are:

**name**: The name for this section. This can be a free text field for complicated recipes but should just be the
"cooking" string for simple recipes to make it auto-translatable. Another predefined option is "preparation" for
recipes with an extra preperation step.

**steps**: This is a list of strings, one for each of the steps in the recipe. The frontend will render every line in
this as a step with a checkbox to mark your progress while cooking. The recipe lines are mostly plain text but there
is a DSL for making references:

When square brackets are put around a word it's a reference to an ingredient in the list. This is used to have translated
ingredient names in recipes even before the recipe itself is translated. It also stylizes the name of the ingredient slightly
to make it stand out in the recipe listing. Multiple names can be added seperated by a comma as a shorthand for adding
a list of ingredients.

It's also possible to reference a specific amount of the ingredient by using the `[ingredient:amount:unit]` format that
will render the ingredient in the page consistently with changes done in the ingredient list by the user like swapping
the unit or multiplying the recipe amounts by a factor.

The last part of the DSL is the double brackets for referring to another recipe. with `[[dutch/main/boerenkool]]` a link
would be generated to the recipe with that specific path. This is mainly useful for referring to other recipes in the
`tips` section.
\ No newline at end of file