82 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			82 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { Signal } from "@preact/signals";
 | |
| import type { Ingredient, IngredientGroup } from "@lib/recipeSchema.ts";
 | |
| import { FunctionalComponent } from "preact";
 | |
| import { unitsOfMeasure } from "@lib/parseIngredient.ts";
 | |
| import { renderMarkdown } from "@lib/documents.ts";
 | |
| 
 | |
| function formatAmount(num: number) {
 | |
|   if (num === 0) return "";
 | |
|   return (Math.floor(num * 4) / 4).toString();
 | |
| }
 | |
| 
 | |
| function formatUnit(unit: string, amount: number) {
 | |
|   const unitKey = unit.toLowerCase() as keyof typeof unitsOfMeasure;
 | |
|   if (unitKey in unitsOfMeasure) {
 | |
|     if (amount > 1 && unitsOfMeasure[unitKey].plural !== undefined) {
 | |
|       return unitsOfMeasure[unitKey].plural;
 | |
|     }
 | |
|     if (unitKey !== "cup") {
 | |
|       return unitsOfMeasure[unitKey].short;
 | |
|     }
 | |
| 
 | |
|     return unitKey.toString();
 | |
|   } else {
 | |
|     return unit;
 | |
|   }
 | |
| }
 | |
| 
 | |
| const Ingredient = (
 | |
|   { ingredient, amount, key = "", portion = 1 }: {
 | |
|     ingredient: Ingredient;
 | |
|     amount: Signal<number>;
 | |
|     key?: string | number;
 | |
|     portion?: number;
 | |
|   },
 | |
| ) => {
 | |
|   const { name, quantity, unit } = ingredient;
 | |
| 
 | |
|   const parsedQuantity = parseFloat(quantity);
 | |
| 
 | |
|   const finalAmount = (typeof parsedQuantity === "number" && amount)
 | |
|     ? (parsedQuantity / portion) * (amount?.value || 1)
 | |
|     : "";
 | |
| 
 | |
|   return (
 | |
|     <tr key={key}>
 | |
|       <td class="pr-4 py-2">
 | |
|         {formatAmount(finalAmount || 0)}
 | |
|         <span class="ml-0.5 opacity-50">
 | |
|           {formatUnit(unit, finalAmount || 0)}
 | |
|         </span>
 | |
|       </td>
 | |
|       <td class="px-4 py-2">{name}</td>
 | |
|     </tr>
 | |
|   );
 | |
| };
 | |
| 
 | |
| export const IngredientsList: FunctionalComponent<
 | |
|   {
 | |
|     ingredients: (Ingredient | IngredientGroup)[];
 | |
|     amount: Signal<number>;
 | |
|     portion?: number;
 | |
|   }
 | |
| > = (
 | |
|   { ingredients, amount, portion },
 | |
| ) => {
 | |
|     return (
 | |
|       <table class="w-full border-collapse table-auto">
 | |
|         <tbody>
 | |
|           {ingredients.filter((s) => !!s?.length).map((item) => {
 | |
|             return (
 | |
|               <div dangerouslySetInnerHTML={{ __html: renderMarkdown(item) }}>
 | |
|               </div>
 | |
|             );
 | |
|             // return (
 | |
|             //   <Ingredient ingredient={item} amount={amount} portion={portion} />
 | |
|             // );
 | |
|           })}
 | |
|         </tbody>
 | |
|       </table>
 | |
|     );
 | |
|   };
 |