"
- );
- expect(yieldQuantity).toStrictEqual(.5);
- expect(yieldString).toStrictEqual("");
- expect(yieldDisplay).toStrictEqual(asFrac(1, 2));
- });
-});
diff --git a/frontend/composables/recipes/use-scaled-amount.test.ts b/frontend/composables/recipes/use-scaled-amount.test.ts
new file mode 100644
index 00000000000..f3f0cdae52a
--- /dev/null
+++ b/frontend/composables/recipes/use-scaled-amount.test.ts
@@ -0,0 +1,68 @@
+import { describe, expect, test } from "vitest";
+import { useScaledAmount } from "./use-scaled-amount";
+
+describe("test use recipe yield", () => {
+ function asFrac(numerator: number, denominator: number): string {
+ return `
${numerator}⁄${denominator}`;
+ }
+
+ test("base case", () => {
+ const { scaledAmount, scaledAmountDisplay } = useScaledAmount(3);
+ expect(scaledAmount).toStrictEqual(3);
+ expect(scaledAmountDisplay).toStrictEqual("3");
+ });
+
+ test("base case scaled", () => {
+ const { scaledAmount, scaledAmountDisplay } = useScaledAmount(3, 2);
+ expect(scaledAmount).toStrictEqual(6);
+ expect(scaledAmountDisplay).toStrictEqual("6");
+ });
+
+ test("zero scale", () => {
+ const { scaledAmount, scaledAmountDisplay } = useScaledAmount(3, 0);
+ expect(scaledAmount).toStrictEqual(0);
+ expect(scaledAmountDisplay).toStrictEqual("");
+ });
+
+ test("zero quantity", () => {
+ const { scaledAmount, scaledAmountDisplay } = useScaledAmount(0);
+ expect(scaledAmount).toStrictEqual(0);
+ expect(scaledAmountDisplay).toStrictEqual("");
+ });
+
+ test("basic fraction", () => {
+ const { scaledAmount, scaledAmountDisplay } = useScaledAmount(0.5);
+ expect(scaledAmount).toStrictEqual(0.5);
+ expect(scaledAmountDisplay).toStrictEqual(asFrac(1, 2));
+ });
+
+ test("mixed fraction", () => {
+ const { scaledAmount, scaledAmountDisplay } = useScaledAmount(1.5);
+ expect(scaledAmount).toStrictEqual(1.5);
+ expect(scaledAmountDisplay).toStrictEqual(`1${asFrac(1, 2)}`);
+ });
+
+ test("mixed fraction scaled", () => {
+ const { scaledAmount, scaledAmountDisplay } = useScaledAmount(1.5, 9);
+ expect(scaledAmount).toStrictEqual(13.5);
+ expect(scaledAmountDisplay).toStrictEqual(`13${asFrac(1, 2)}`);
+ });
+
+ test("small scale", () => {
+ const { scaledAmount, scaledAmountDisplay } = useScaledAmount(1, 0.125);
+ expect(scaledAmount).toStrictEqual(0.125);
+ expect(scaledAmountDisplay).toStrictEqual(asFrac(1, 8));
+ });
+
+ test("small qty", () => {
+ const { scaledAmount, scaledAmountDisplay } = useScaledAmount(0.125);
+ expect(scaledAmount).toStrictEqual(0.125);
+ expect(scaledAmountDisplay).toStrictEqual(asFrac(1, 8));
+ });
+
+ test("rounded decimal", () => {
+ const { scaledAmount, scaledAmountDisplay } = useScaledAmount(1.3344559997);
+ expect(scaledAmount).toStrictEqual(1.334);
+ expect(scaledAmountDisplay).toStrictEqual(`1${asFrac(1, 3)}`);
+ });
+});
From 9c86bb2f2f985fbc2482e233b073abef8a895c3b Mon Sep 17 00:00:00 2001
From: Michael Genson <71845777+michael-genson@users.noreply.github.com>
Date: Fri, 8 Nov 2024 18:46:46 +0000
Subject: [PATCH 37/56] disable scale if empty
---
frontend/components/Domain/Recipe/RecipeScaleEditButton.vue | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/frontend/components/Domain/Recipe/RecipeScaleEditButton.vue b/frontend/components/Domain/Recipe/RecipeScaleEditButton.vue
index 97c2a04259a..01ffd3bd9ee 100644
--- a/frontend/components/Domain/Recipe/RecipeScaleEditButton.vue
+++ b/frontend/components/Domain/Recipe/RecipeScaleEditButton.vue
@@ -1,13 +1,12 @@
-
+
- x {{ scale }}
-
+
From 9ccb44c54095c1d59efce4643bb031da8dcb10b6 Mon Sep 17 00:00:00 2001
From: Michael Genson <71845777+michael-genson@users.noreply.github.com>
Date: Fri, 8 Nov 2024 18:50:48 +0000
Subject: [PATCH 38/56] sanitize yield html
---
frontend/components/Domain/Recipe/RecipeYield.vue | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/frontend/components/Domain/Recipe/RecipeYield.vue b/frontend/components/Domain/Recipe/RecipeYield.vue
index c151c7744ed..b054ec73146 100644
--- a/frontend/components/Domain/Recipe/RecipeYield.vue
+++ b/frontend/components/Domain/Recipe/RecipeYield.vue
@@ -16,6 +16,7 @@
diff --git a/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageInfoCardImage.vue b/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageInfoCardImage.vue
new file mode 100644
index 00000000000..e6c5f1312f7
--- /dev/null
+++ b/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageInfoCardImage.vue
@@ -0,0 +1,67 @@
+
+
+
+
+
diff --git a/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageInfoEditor.vue b/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageInfoEditor.vue
new file mode 100644
index 00000000000..f81aacdc8c3
--- /dev/null
+++ b/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageInfoEditor.vue
@@ -0,0 +1,125 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageTitleContent.vue b/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageTitleContent.vue
deleted file mode 100644
index b0e2ed257dd..00000000000
--- a/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageTitleContent.vue
+++ /dev/null
@@ -1,161 +0,0 @@
-
-
-
-
- {{ recipe.name }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/frontend/lang/messages/en-US.json b/frontend/lang/messages/en-US.json
index b40fcc94e48..e1dba474ba6 100644
--- a/frontend/lang/messages/en-US.json
+++ b/frontend/lang/messages/en-US.json
@@ -668,7 +668,8 @@
"no-food": "No Food"
},
"reset-servings-count": "Reset Servings Count",
- "not-linked-ingredients": "Additional Ingredients"
+ "not-linked-ingredients": "Additional Ingredients",
+ "editing-recipe": "Editing {0}"
},
"search": {
"advanced-search": "Advanced Search",
From 8699a74c47c11c70059fda6d6fb76b89ea4f91e8 Mon Sep 17 00:00:00 2001
From: Michael Genson <71845777+michael-genson@users.noreply.github.com>
Date: Sat, 16 Nov 2024 18:24:55 +0000
Subject: [PATCH 42/56] shuffle around info and move yield to info
---
.../Domain/Recipe/RecipeLastMade.vue | 12 ++--
.../Domain/Recipe/RecipePage/RecipePage.vue | 1 -
.../RecipePageParts/RecipePageInfoCard.vue | 61 ++++++++++++-------
.../Domain/Recipe/RecipeTimeCard.vue | 60 +++++++++++++-----
.../components/Domain/Recipe/RecipeYield.vue | 2 +-
5 files changed, 92 insertions(+), 44 deletions(-)
diff --git a/frontend/components/Domain/Recipe/RecipeLastMade.vue b/frontend/components/Domain/Recipe/RecipeLastMade.vue
index 9cbe30283cc..6bc81e81b1d 100644
--- a/frontend/components/Domain/Recipe/RecipeLastMade.vue
+++ b/frontend/components/Domain/Recipe/RecipeLastMade.vue
@@ -86,12 +86,6 @@
-
-
- {{ $globals.icons.chefHat }}
- {{ $t('recipe.made-this') }}
-
-
+
+
+ {{ $globals.icons.chefHat }}
+ {{ $t('recipe.made-this') }}
+
+
diff --git a/frontend/components/Domain/Recipe/RecipePage/RecipePage.vue b/frontend/components/Domain/Recipe/RecipePage/RecipePage.vue
index 69556434b99..071f8338cf8 100644
--- a/frontend/components/Domain/Recipe/RecipePage/RecipePage.vue
+++ b/frontend/components/Domain/Recipe/RecipePage/RecipePage.vue
@@ -24,7 +24,6 @@
-
+
-
diff --git a/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageHeader.vue b/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageHeader.vue
index 6464004449f..8ab58a995d4 100644
--- a/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageHeader.vue
+++ b/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageHeader.vue
@@ -1,11 +1,6 @@
-
-
-
- {{ $t("recipe.editing-recipe", [recipe.name]) }}
-
-
+
-
+
import { computed, defineComponent } from "@nuxtjs/composition-api";
-import { useLoggedInState } from "~/composables/use-logged-in-state";
-import { usePageState, usePageUser } from "~/composables/recipe-page/shared-state";
import { validators } from "~/composables/use-validators";
import { NoUndefinedField } from "~/lib/api/types/non-generated";
import { Recipe } from "~/lib/api/types/recipe";
@@ -65,10 +63,6 @@ export default defineComponent({
},
},
setup(props) {
- const { user } = usePageUser();
- const { imageKey, isEditMode } = usePageState(props.recipe.slug);
- const { isOwnGroup } = useLoggedInState();
-
const recipeServings = computed({
get() {
return props.recipe.recipeServings;
@@ -88,26 +82,22 @@ export default defineComponent({
});
function validateInput(value: string | null, property: "recipeServings" | "recipeYieldQuantity") {
- if (!value) {
- props.recipe[property] = 0;
- return;
- }
+ if (!value) {
+ props.recipe[property] = 0;
+ return;
+ }
- const number = parseFloat(value.replace(/[^0-9.]/g, ""));
- if (isNaN(number) || number <= 0) {
- props.recipe[property] = 0;
- return;
- }
+ const number = parseFloat(value.replace(/[^0-9.]/g, ""));
+ if (isNaN(number) || number <= 0) {
+ props.recipe[property] = 0;
+ return;
+ }
- props.recipe[property] = number;
- }
+ props.recipe[property] = number;
+ }
return {
- user,
- imageKey,
validators,
- isEditMode,
- isOwnGroup,
recipeServings,
recipeYieldQuantity,
validateInput,
diff --git a/frontend/lang/messages/en-US.json b/frontend/lang/messages/en-US.json
index e1dba474ba6..b40fcc94e48 100644
--- a/frontend/lang/messages/en-US.json
+++ b/frontend/lang/messages/en-US.json
@@ -668,8 +668,7 @@
"no-food": "No Food"
},
"reset-servings-count": "Reset Servings Count",
- "not-linked-ingredients": "Additional Ingredients",
- "editing-recipe": "Editing {0}"
+ "not-linked-ingredients": "Additional Ingredients"
},
"search": {
"advanced-search": "Advanced Search",
From 58274855fb24dedbde96b82ccbd76421659ed9d1 Mon Sep 17 00:00:00 2001
From: Michael Genson <71845777+michael-genson@users.noreply.github.com>
Date: Mon, 18 Nov 2024 01:32:00 +0000
Subject: [PATCH 50/56] adjust recipe timer layout
---
.../RecipePage/RecipePageParts/RecipePageInfoCard.vue | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageInfoCard.vue b/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageInfoCard.vue
index 17ccbcdd39b..1a7904dde5c 100644
--- a/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageInfoCard.vue
+++ b/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageInfoCard.vue
@@ -16,7 +16,7 @@
-
+
-
+
Date: Mon, 18 Nov 2024 01:34:53 +0000
Subject: [PATCH 51/56] fixed missing recipe prop
---
frontend/components/Domain/Recipe/RecipeLastMade.vue | 2 +-
.../Recipe/RecipePage/RecipePageParts/RecipePageInfoCard.vue | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/frontend/components/Domain/Recipe/RecipeLastMade.vue b/frontend/components/Domain/Recipe/RecipeLastMade.vue
index 6bc81e81b1d..d60de97b4f2 100644
--- a/frontend/components/Domain/Recipe/RecipeLastMade.vue
+++ b/frontend/components/Domain/Recipe/RecipeLastMade.vue
@@ -125,7 +125,7 @@ export default defineComponent({
},
recipe: {
type: Object as () => Recipe,
- default: null,
+ required: true,
},
},
setup(props, context) {
diff --git a/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageInfoCard.vue b/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageInfoCard.vue
index 1a7904dde5c..cfd027d6879 100644
--- a/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageInfoCard.vue
+++ b/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageInfoCard.vue
@@ -29,8 +29,9 @@
From 498793205a7be9217ed574881e1f650ef30db66c Mon Sep 17 00:00:00 2001
From: Michael Genson <71845777+michael-genson@users.noreply.github.com>
Date: Mon, 18 Nov 2024 01:38:55 +0000
Subject: [PATCH 52/56] restore scale for yield
---
.../Recipe/RecipePage/RecipePageParts/RecipePageHeader.vue | 2 +-
.../Recipe/RecipePage/RecipePageParts/RecipePageInfoCard.vue | 5 +++++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageHeader.vue b/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageHeader.vue
index 8ab58a995d4..e5fdcf113cc 100644
--- a/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageHeader.vue
+++ b/frontend/components/Domain/Recipe/RecipePage/RecipePageParts/RecipePageHeader.vue
@@ -1,6 +1,6 @@
-
+
@@ -76,6 +77,10 @@ export default defineComponent({
type: Object as () => NoUndefinedField
,
required: true,
},
+ recipeScale: {
+ type: Number,
+ default: 1,
+ },
landscape: {
type: Boolean,
required: true,
From a927d51f289dc53678cb5db6535923ea591beda7 Mon Sep 17 00:00:00 2001
From: Michael Genson <71845777+michael-genson@users.noreply.github.com>
Date: Mon, 18 Nov 2024 01:42:26 +0000
Subject: [PATCH 53/56] added edit icon to servings
---
frontend/components/Domain/Recipe/RecipeScaleEditButton.vue | 1 +
1 file changed, 1 insertion(+)
diff --git a/frontend/components/Domain/Recipe/RecipeScaleEditButton.vue b/frontend/components/Domain/Recipe/RecipeScaleEditButton.vue
index 01ffd3bd9ee..06955beb586 100644
--- a/frontend/components/Domain/Recipe/RecipeScaleEditButton.vue
+++ b/frontend/components/Domain/Recipe/RecipeScaleEditButton.vue
@@ -5,6 +5,7 @@
+ {{ $globals.icons.edit }}
From 633a79fb280447f5bd569cdddc28ef7685b0dece Mon Sep 17 00:00:00 2001
From: Michael Genson <71845777+michael-genson@users.noreply.github.com>
Date: Mon, 18 Nov 2024 01:57:29 +0000
Subject: [PATCH 54/56] match print view to info card
---
.../Domain/Recipe/RecipePrintView.vue | 36 +++++++++++++++----
1 file changed, 30 insertions(+), 6 deletions(-)
diff --git a/frontend/components/Domain/Recipe/RecipePrintView.vue b/frontend/components/Domain/Recipe/RecipePrintView.vue
index d9d9aa62b39..0a92e5beb9f 100644
--- a/frontend/components/Domain/Recipe/RecipePrintView.vue
+++ b/frontend/components/Domain/Recipe/RecipePrintView.vue
@@ -18,7 +18,24 @@
{{ recipe.name }}
-
+
+
+
+ {{ $globals.icons.potSteam }}
+
+
+
+
+
+
@@ -30,9 +47,6 @@
{{ $t("recipe.ingredients") }}
-
-
-
import { computed, defineComponent, useContext } from "@nuxtjs/composition-api";
import RecipeTimeCard from "~/components/Domain/Recipe/RecipeTimeCard.vue";
+import RecipeYield from "~/components/Domain/Recipe/RecipeYield.vue";
+import DOMPurify from "dompurify";
import { useStaticRoutes } from "~/composables/api";
import { Recipe, RecipeIngredient, RecipeStep} from "~/lib/api/types/recipe";
import { NoUndefinedField } from "~/lib/api/types/non-generated";
@@ -136,6 +152,7 @@ type InstructionSection = {
export default defineComponent({
components: {
RecipeTimeCard,
+ RecipeYield,
},
props: {
recipe: {
@@ -158,6 +175,13 @@ export default defineComponent({
const { imageKey } = usePageState(props.recipe.slug);
const {labels} = useNutritionLabels();
+ function sanitizeHTML(rawHtml: string) {
+ return DOMPurify.sanitize(rawHtml, {
+ USE_PROFILES: { html: true },
+ ALLOWED_TAGS: ["strong", "sup"],
+ });
+ }
+
const servingsDisplay = computed(() => {
const { scaledAmountDisplay } = useScaledAmount(props.recipe.recipeYieldQuantity, props.scale);
return scaledAmountDisplay ? i18n.t("recipe.yields-amount-with-text", {
@@ -173,9 +197,9 @@ export default defineComponent({
const recipeYield = computed(() => {
if (servingsDisplay.value && yieldDisplay.value) {
- return `${yieldDisplay.value}; ${servingsDisplay.value}`
+ return sanitizeHTML(`${yieldDisplay.value}; ${servingsDisplay.value}`);
} else {
- return yieldDisplay.value || servingsDisplay.value;
+ return sanitizeHTML(yieldDisplay.value || servingsDisplay.value);
}
})
From 9e93e104c94114ce8abf7778de14b18a1e2053ba Mon Sep 17 00:00:00 2001
From: Michael Genson <71845777+michael-genson@users.noreply.github.com>
Date: Mon, 18 Nov 2024 02:03:45 +0000
Subject: [PATCH 55/56] lint
---
frontend/components/Domain/Recipe/RecipePrintView.vue | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/frontend/components/Domain/Recipe/RecipePrintView.vue b/frontend/components/Domain/Recipe/RecipePrintView.vue
index 0a92e5beb9f..01e5b45ddb3 100644
--- a/frontend/components/Domain/Recipe/RecipePrintView.vue
+++ b/frontend/components/Domain/Recipe/RecipePrintView.vue
@@ -126,9 +126,8 @@