From 9b53f6e676035b4467802846fa2c8087b912232a Mon Sep 17 00:00:00 2001 From: araemer Date: Tue, 21 Oct 2025 09:08:08 +0200 Subject: [PATCH] Refactoring --- frontend/src/App.css | 12 +- frontend/src/components/basics/Button.tsx | 57 ++-- .../components/basics/NumberedListItem.tsx | 8 +- .../recipes/IngredientGroupListEditor.tsx | 135 ++++----- .../recipes/IngredientListEditor.tsx | 113 ++++---- .../InstructionStepListDesktopEditor.tsx | 136 ++++----- .../recipes/InstructionStepListEditor.tsx | 87 ++---- .../InstructionStepListEditorMethods.ts | 41 +++ .../InstructionStepListMobileEditor.tsx | 149 +++++----- .../components/recipes/RecipeDetailPage.tsx | 4 +- .../src/components/recipes/RecipeEditor.tsx | 274 +++++++++--------- 11 files changed, 501 insertions(+), 515 deletions(-) create mode 100644 frontend/src/components/recipes/InstructionStepListEditorMethods.ts diff --git a/frontend/src/App.css b/frontend/src/App.css index 06b80ca..7b2f261 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -21,15 +21,15 @@ } .content-title { - @apply text-3xl font-black mb-8 text-blue-900; + @apply text-3xl font-black pb-6 text-blue-900; } .section-heading { - @apply text-xl font-bold mb-2; + @apply text-xl font-bold pb-2 pt-4; } .subsection-heading { - @apply font-semibold mb-2 mt-4; + @apply font-semibold pb-2 pt-4; } /* icons */ @@ -50,7 +50,7 @@ /* buttons */ .basic-button { - @apply px-4 py-2 shadow-md rounded-lg whitespace-nowrap; + @apply px-4 py-2 shadow-md rounded-lg whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed; } .default-button-bg { @@ -105,9 +105,9 @@ } .ingredient-group-card { - @apply py-4 border-b border-gray-400; + @apply pb-4 border-b border-gray-400; } - + .circular-container { @apply flex-shrink-0 w-7 h-7 rounded-full bg-blue-300 text-white flex items-center justify-center shadow-sm; } diff --git a/frontend/src/components/basics/Button.tsx b/frontend/src/components/basics/Button.tsx index edbaac3..d6ee011 100644 --- a/frontend/src/components/basics/Button.tsx +++ b/frontend/src/components/basics/Button.tsx @@ -1,35 +1,38 @@ -import { defaultIconSize } from "./SvgIcon"; -import { ButtonType, type BasicButtonProps } from "./BasicButtonDefinitions"; +import {defaultIconSize} from "./SvgIcon"; +import {type BasicButtonProps, ButtonType} from "./BasicButtonDefinitions"; -type ButtonProps = BasicButtonProps & { - onClick: () => void; +type ButtonProps = BasicButtonProps & { + onClick: () => void; + disabled?: boolean; }; /** * Button component. Styles are defined in BasicButtonDefinitions.ts */ export default function Button({ - onClick, - icon: Icon, - text, - buttonType = ButtonType.DefaultButton, - className = "", - ...props -}: ButtonProps) { - return ( - - ); + onClick, + icon: Icon, + text, + buttonType = ButtonType.DefaultButton, + className = "", + disabled = false, + ...props + }: ButtonProps) { + return ( + + ); } diff --git a/frontend/src/components/basics/NumberedListItem.tsx b/frontend/src/components/basics/NumberedListItem.tsx index 1aad1f1..b41d760 100644 --- a/frontend/src/components/basics/NumberedListItem.tsx +++ b/frontend/src/components/basics/NumberedListItem.tsx @@ -1,6 +1,6 @@ type NumberedListItemProps = { - /** Number to be displayed in front of text */ - elementNumber: number; + /** Index of the element. Index + 1 is displayed in circle */ + index: number; /** List item text */ text: string; } @@ -10,11 +10,11 @@ type NumberedListItemProps = { * @param elementNumber Number to be displayed * @param text Text to be displayed */ -export function NumberedListItem({elementNumber, text}: NumberedListItemProps) { +export function NumberedListItem({index, text}: NumberedListItemProps) { return
  • {/* Step number circle */}
    - {elementNumber} + {index + 1}
    {/* Step text */} diff --git a/frontend/src/components/recipes/IngredientGroupListEditor.tsx b/frontend/src/components/recipes/IngredientGroupListEditor.tsx index 0b40de1..21344f7 100644 --- a/frontend/src/components/recipes/IngredientGroupListEditor.tsx +++ b/frontend/src/components/recipes/IngredientGroupListEditor.tsx @@ -2,85 +2,68 @@ * Editor for ingredient groups */ -import type { IngredientModel } from "../../models/IngredientModel" -import type { IngredientGroupModel } from "../../models/IngredientGroupModel" +import type {IngredientModel} from "../../models/IngredientModel" +import type {IngredientGroupModel} from "../../models/IngredientGroupModel" import Button from "../basics/Button" -import { IngredientListEditor } from "./IngredientListEditor" -import { Plus } from "lucide-react" -import { ButtonType } from "../basics/BasicButtonDefinitions" +import {IngredientListEditor} from "./IngredientListEditor" +import {Plus} from "lucide-react" +import {ButtonType} from "../basics/BasicButtonDefinitions" type IngredientGroupListEditorProps = { - ingredientGroupList: IngredientGroupModel[] - onChange: (ingredientGroupList: IngredientGroupModel[]) => void + ingredientGroupList: IngredientGroupModel[] + onChange: (ingredientGroupList: IngredientGroupModel[]) => void } -export function IngredientGroupListEditor({ ingredientGroupList, onChange }: IngredientGroupListEditorProps) { - const handleUpdate = (index: number, field: keyof IngredientGroupModel, value: string|IngredientModel[] ) => { - const updated = ingredientGroupList.map((ingGrp, i) => - i === index ? { ...ingGrp, [field]: value} : ingGrp +export function IngredientGroupListEditor({ingredientGroupList, onChange}: IngredientGroupListEditorProps) { + const handleUpdate = (index: number, field: keyof IngredientGroupModel, value: string | IngredientModel[]) => { + const updated = ingredientGroupList.map((ingGrp, i) => + i === index ? {...ingGrp, [field]: value} : ingGrp + ) + onChange(updated) + } + const updateIngredientList = (index: number, ingredientList: IngredientModel[]) => { + handleUpdate(index, "ingredientList", ingredientList) + } + + const handleAdd = () => { + onChange([...ingredientGroupList, {title: "", ingredientList: []}]) + } + + const handleRemove = (index: number) => { + onChange(ingredientGroupList.filter((_, i) => i !== index)) + } + return ( +
    +

    Zutaten

    +
    + {ingredientGroupList.map((ingGrp, index) => ( +
    +
    + handleUpdate(index, "title", e.target.value)} + /> +
    + updateIngredientList(index, list)} + /> +
    + ))} +
    +
    ) - onChange(updated) - } - const updateIngredientList = (index: number, ingredientList: IngredientModel[]) => { - handleUpdate(index, "ingredientList", ingredientList) - } - - const handleAdd = () => { - onChange([...ingredientGroupList, { title: "", ingredientList: [] }]) - } - - const handleRemove = (index: number) => { - onChange(ingredientGroupList.filter((_, i) => i !== index)) - } - return ( -
    - {/* remove bottom margin from this headings the group card has a top padding */} -

    Ingredient Groups

    - {ingredientGroupList.map((ingGrp, index) => ( -
    -
    - handleUpdate(index, "title", e.target.value)} - /> -
    - updateIngredientList(index,list)} - /> -
    - ))} -
    - ) -} - -/* - -*/ \ No newline at end of file +} \ No newline at end of file diff --git a/frontend/src/components/recipes/IngredientListEditor.tsx b/frontend/src/components/recipes/IngredientListEditor.tsx index 17955ec..3ddaf34 100644 --- a/frontend/src/components/recipes/IngredientListEditor.tsx +++ b/frontend/src/components/recipes/IngredientListEditor.tsx @@ -1,70 +1,69 @@ -import { Plus, X } from "lucide-react" -import type { IngredientModel } from "../../models/IngredientModel" +import {Plus, X} from "lucide-react" +import type {IngredientModel} from "../../models/IngredientModel" import Button from "../basics/Button" -import { ButtonType } from "../basics/BasicButtonDefinitions" +import {ButtonType} from "../basics/BasicButtonDefinitions" -/** +/** * Editor for handling the ingredient list * Ingredients can be edited, added and removed */ type IngredientListEditorProps = { - ingredients: IngredientModel[] - onChange: (ingredients: IngredientModel[]) => void + ingredients: IngredientModel[] + onChange: (ingredients: IngredientModel[]) => void } -export function IngredientListEditor({ ingredients, onChange }: IngredientListEditorProps) { - const handleUpdate = (index: number, field: keyof IngredientModel, value: string | number) => { - const updated = ingredients.map((ing, i) => - i === index ? { ...ing, [field]: field === "amount" ? Number(value) : value } : ing - ) - onChange(updated) - } +export function IngredientListEditor({ingredients, onChange}: IngredientListEditorProps) { + const handleUpdate = (index: number, field: keyof IngredientModel, value: string | number) => { + const updated = ingredients.map((ing, i) => + i === index ? {...ing, [field]: field === "amount" ? Number(value) : value} : ing + ) + onChange(updated) + } - const handleAdd = () => { - onChange([...ingredients, { name: "", amount: 0, unit: "" }]) - } + const handleAdd = () => { + onChange([...ingredients, {name: "", amount: 0, unit: ""}]) + } - const handleRemove = (index: number) => { - onChange(ingredients.filter((_, i) => i !== index)) - } + const handleRemove = (index: number) => { + onChange(ingredients.filter((_, i) => i !== index)) + } - return ( -
    -

    Ingredients

    - {ingredients.map((ing, index) => ( -
    - handleUpdate(index, "amount", e.target.value)} - /> - handleUpdate(index, "unit", e.target.value)} - /> - handleUpdate(index, "name", e.target.value)} - /> -
    + ))} +
    - ))} -