recipes

The recipes and recipe books used in our family
git clone git://archive.git.mtrnord.blog/MTRNord/recipes.git
Log | Files | Refs | README | LICENSE

recipe.astro (8868B)


      1 ---
      2 import type { Props } from "@astrojs/starlight/props";
      3 import { Recipe as CooklangRecipe } from "@cooklang/cooklang-ts";
      4 import Default from "@astrojs/starlight/components/MarkdownContent.astro";
      5 import InfoBox from './infobox.astro';
      6 
      7 const frontmatter = Astro.props.entry.data;
      8 const isRecipe = frontmatter.recipe;
      9 const recipe = new CooklangRecipe(Astro.props.entry.body, {
     10     defaultIngredientAmount: "etwas",
     11 });
     12 const meta_array = Array.from(Object.entries(recipe.metadata));
     13 const contains_source = meta_array.find(([key, _value]) => "source" === key.toLowerCase() || "quelle" === key.toLowerCase());
     14 const source_url_raw = (contains_source ?? [])[1] ?? "";
     15 const source_url = source_url_raw.replace("<", "").replace(">", "");
     16 const infos: {
     17     title?: string,
     18     text: string
     19 }[] | undefined = frontmatter.info;
     20 const description = frontmatter.description;
     21 ---
     22 {
     23     isRecipe ? (
     24         <Default {...Astro.props}>
     25             <article vocab="https://schema.org/" typeof="Recipe">
     26                 {description && <><p class="whitespace-pre-line">{description}</p><hr/></>}
     27                 <p class="no-margin-children">
     28                 {(contains_source?.length ?? 0) > 0 ? (
     29                     <><b>Quelle: </b>{source_url.includes("http") ?  <a href={source_url}>{source_url}</a> : <span>{source_url}</span>}<br/></>
     30                 ) : (
     31                     <><b>Quelle: </b>Keine Quelle angegeben</><br/>
     32                 )}
     33 
     34                 {
     35                     (contains_source && meta_array.length >= 2) || !contains_source && meta_array.length >= 1 ? 
     36                     (
     37                             Array.from(Object.entries(recipe.metadata)).map(
     38                                 ([key, value]) =>
     39                                     key.toLowerCase() === "source" || key.toLowerCase() === "quelle" ? null : (
     40                                         <>
     41                                             <b class="capitalize">{key}</b>:
     42                                             {value.replace("%", " ")}<br/>
     43                                         </>
     44                                     ),
     45                             )
     46                     ) :
     47                     (
     48                         <></>
     49                         )
     50                 }
     51                 </p>
     52                
     53                 <div class="grid-container">
     54                     <div class="box p-4 border border-zinc-300 rounded min-w-[10rem] w-full md:w-auto relative">
     55                         <h2 id="zutaten">Zutaten</h2>
     56                         <ul>
     57                             {recipe.ingredients.map((ingredient) => (
     58                                 <li>
     59                                     {["etwas"].includes(String(ingredient.quantity)) ? (
     60                                         <span property="recipeIngredient">
     61                                             {ingredient.quantity}&nbsp;{ingredient.name}
     62                                         </span>
     63                                     ) : (
     64                                         <span property="recipeIngredient">
     65                                             {ingredient.name} — {ingredient.quantity}{" "}
     66                                             {ingredient.units}
     67                                         </span>
     68                                     )}
     69                                 </li>
     70                             ))}
     71                         </ul>
     72                     </div>
     73 
     74                     {recipe.cookwares.length > 0 ? (
     75                     <div class="box p-4 border border-zinc-300 rounded min-w-[10rem] w-full md:w-auto relative">
     76                         <h2 id="geraete">Hilfsmittel</h2>
     77                         <ul>
     78                             {recipe.cookwares.map((cookware) => {
     79                                 if (cookware.quantity === 1) {
     80                                     return (
     81                                         <li>
     82                                             {cookware.name}
     83                                         </li>
     84                                     )
     85                                 } else {
     86                                      return (
     87                                         <li>
     88                                             {cookware.quantity}&nbsp;{cookware.name}
     89                                         </li>
     90                                     )
     91                                 }
     92                                 
     93                             })}
     94                         </ul>
     95                     </div>) : null}
     96                 </div>
     97 
     98                 {
     99                     ((infos?.length ?? 0) > 0) ? (
    100                         infos?.map((info) => (
    101                             <InfoBox info={info}></InfoBox>
    102                         ))
    103                    ): null
    104                 }
    105 
    106                 <h2 id="zubereitung">Zubereitung</h2>
    107                 <ol property="recipeInstructions">
    108                     {recipe.steps.map((step) => (
    109                         <li class="leading-loose">
    110                             {step.map((text: any) => {
    111                                 if (text.type === "text") {
    112                                     return text.value;
    113                                 } else if (text.type === "ingredient") {
    114                                     return (
    115                                         <span class="rounded-full px-2 py-1 bg-green-200 text-black whitespace-nowrap">
    116                                             {text.quantity === "etwas" ? (
    117                                                 <>{text.name}</>
    118                                             ) : (
    119                                                 <>
    120                                                     {text.quantity} {text.units}{" "}
    121                                                     {text.name}
    122                                                 </>
    123                                             )}
    124                                         </span>
    125                                     );
    126                                 } else if (text.type === "cookware") {
    127                                     if (text.quantity === 1) {
    128                                         return (
    129                                             <span class="rounded-full px-2 py-1 bg-cyan-200 text-black whitespace-nowrap">
    130                                                 {text.name}
    131                                             </span>
    132                                         );
    133                                     }else {
    134                                         return (
    135                                             <span class="rounded-full px-2 py-1 bg-cyan-200 text-black whitespace-nowrap">
    136                                                 {text.quantity}&nbsp;{text.name}
    137                                             </span>
    138                                         );
    139                                     }
    140                                 } else if (text.type === "timer") {
    141                                     return (
    142                                         <span class="rounded-full px-2 py-1 bg-red-200 text-black whitespace-nowrap">
    143                                             {
    144                                                 text.units == "minutes" ? (
    145                                                     <meta property="performTime" content={"PT"+text.quanity+"M"} />
    146                                                 ): <></>
    147                                             }
    148                                             
    149                                             {text.quantity}&nbsp;{text.units}
    150                                         </span>
    151                                     );
    152                                 } else {
    153                                     return "Error";
    154                                 }
    155                             })}
    156                         </li>
    157                     ))}
    158                 </ol>
    159             </article>
    160         </Default>
    161         <style>
    162             .grid-container {
    163                 display: grid;
    164                 grid-auto-flow: dense;
    165                 gap: 1rem;
    166                 grid-template-columns: repeat(auto-fit, minmax(min(100%, 100px), 1fr));
    167                 container-type: inline-size;
    168             }
    169 
    170             @media only screen and (max-width: 600px) {
    171                 .grid-container {
    172                     grid-template-rows: repeat(auto-fit, minmax(min(100%, 100px), 1fr));
    173                     grid-template-columns: 1fr;
    174                 }
    175             }
    176 
    177             .box {
    178                 display: grid;
    179                 grid-row: span 2;
    180                 grid-template-rows: subgrid;
    181                 margin: 0 !important;
    182             }
    183 
    184             .no-margin-children > * {
    185                 margin: 0 !important;
    186             }
    187         </style>
    188     ) : (
    189         <Default {...Astro.props}>
    190             <slot />
    191         </Default>
    192     )
    193 }