96 lines
No EOL
4.2 KiB
TypeScript
96 lines
No EOL
4.2 KiB
TypeScript
import Button from "../basics/Button.tsx";
|
|
import {X} from "lucide-react";
|
|
import {ButtonType} from "../basics/BasicButtonDefinitions.ts";
|
|
import type {InstructionStepModel} from "../../models/InstructionStepModel.ts";
|
|
import {MoveButtonControl} from "../basics/MoveButtonControl.tsx";
|
|
|
|
type InstructionStepMobileListItemProps = {
|
|
/** Index of the instruction step */
|
|
index: number;
|
|
/** Model holding the instruction step data, e.g., instruction text */
|
|
stepModel: InstructionStepModel;
|
|
/**
|
|
* Method to call on moving the instruction step.
|
|
* @param index Current index of the step to move
|
|
* @param direction Direction to move the step in (either "up" or "down")
|
|
*/
|
|
onMove(index: number, direction: "up" | "down"): void;
|
|
/**
|
|
* Method to call on updating the instruction step.
|
|
* @param index Index of the step to be updated.
|
|
* @param instructionText new instruction text
|
|
*/
|
|
onUpdate: (index: number, instructionText: string) => void;
|
|
/**
|
|
* Method to call on removing the instruction step.
|
|
* @param index Index of the instruction step to be removed.
|
|
*/
|
|
onRemove: (index: number) => void;
|
|
/** Indicates whether this is the first instruction step. Used to restrict movement. */
|
|
isFirst: boolean;
|
|
/** Indicates whether this is the last instruction step. Used to restrict movement. */
|
|
isLast: boolean;
|
|
};
|
|
|
|
/**
|
|
* Numbered list item for instructions step list editor for mobile devices.
|
|
*
|
|
* Describes a single instruction step of a recipe. As drag & drop usually is a bit clumsy on
|
|
* mobile devices, the steps can be reordered with small up and down buttons below the step number.
|
|
* @param index Index of this instruction step
|
|
* @param stepModel Model containing the data for the current instruction step, e.g., instruction text.
|
|
* @param onMove Method to call on moving the instruction step.
|
|
* @param onUpdate Method to call on updating the instruction step.
|
|
* @param onRemove Method to call on removing the instruction step.
|
|
* @param isFirst Indicates whether this is the first instruction step. In this case, the step cannot be moved up.
|
|
* @param isLast Indicates whether this is the last instruction step. In this case, the step cannot be moved down.
|
|
*/
|
|
export function InstructionStepMobileListItem({
|
|
index,
|
|
stepModel,
|
|
onMove,
|
|
onUpdate,
|
|
onRemove,
|
|
isFirst,
|
|
isLast
|
|
}: InstructionStepMobileListItemProps) {
|
|
return (
|
|
<div
|
|
key={stepModel.id}
|
|
className="flex items-start gap-3 bg-gray-50 rounded-xl p-3 shadow-sm"
|
|
>
|
|
{/* Left column: Number of the instruction step and move controls */}
|
|
<div className="flex flex-col items-center pt-1">
|
|
<div className="circular-container">
|
|
{index + 1}
|
|
</div>
|
|
<MoveButtonControl
|
|
isUpDisabled={isFirst}
|
|
isDownDisabled={isLast}
|
|
onMoveUp={() => onMove(index, "up")}
|
|
onMoveDown={() => onMove(index, "down")}
|
|
/>
|
|
</div>
|
|
|
|
{/* Center column: Instruction step */}
|
|
<textarea
|
|
className="input-field w-full min-h-[120px] resize-none overflow-hidden"
|
|
placeholder={`Schritt ${index + 1}`}
|
|
value={stepModel.text}
|
|
onChange={(e) => onUpdate(index, e.target.value)}
|
|
onInput={(e) => {
|
|
const el = e.target as HTMLTextAreaElement;
|
|
el.style.height = "auto";
|
|
el.style.height = `${el.scrollHeight}px`;
|
|
}}
|
|
/>
|
|
|
|
{/* Right column: Remove step button */}
|
|
<Button
|
|
onClick={() => onRemove(index)}
|
|
icon={X}
|
|
buttonType={ButtonType.DarkButton}
|
|
/>
|
|
</div>
|
|
);
|
|
} |