Component for mobile instruction step editor's list item
This commit is contained in:
parent
9b53f6e676
commit
05595fba94
2 changed files with 80 additions and 43 deletions
|
|
@ -2,11 +2,12 @@
|
||||||
* Mobile editor using Up/Down buttons for reordering
|
* Mobile editor using Up/Down buttons for reordering
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ArrowDown, ArrowUp, Plus, X} from "lucide-react";
|
import {Plus} from "lucide-react";
|
||||||
import type {InstructionStepModel} from "../../models/InstructionStepModel";
|
import type {InstructionStepModel} from "../../models/InstructionStepModel";
|
||||||
import Button from "../basics/Button";
|
import Button from "../basics/Button";
|
||||||
import {ButtonType} from "../basics/BasicButtonDefinitions";
|
import {ButtonType} from "../basics/BasicButtonDefinitions";
|
||||||
import {instructionStepListEditorMethods} from "./InstructionStepListEditorMethods.ts";
|
import {instructionStepListEditorMethods} from "./InstructionStepListEditorMethods.ts";
|
||||||
|
import {InstructionStepMobileListItem} from "./InstructionStepMobileListItem.tsx";
|
||||||
|
|
||||||
type InstructionStepListEditorMobileProps = {
|
type InstructionStepListEditorMobileProps = {
|
||||||
instructionStepList: InstructionStepModel[];
|
instructionStepList: InstructionStepModel[];
|
||||||
|
|
@ -36,48 +37,15 @@ export function InstructionStepListMobileEditor({
|
||||||
<h2 className="section-heading mb-2">Zubereitung</h2>
|
<h2 className="section-heading mb-2">Zubereitung</h2>
|
||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3">
|
||||||
{instructionStepList.map((step, index) => (
|
{instructionStepList.map((step, index) => (
|
||||||
<div
|
<InstructionStepMobileListItem
|
||||||
key={step.id}
|
index={index}
|
||||||
className="flex items-start gap-3 bg-gray-50 rounded-xl p-3 shadow-sm"
|
step={step}
|
||||||
>
|
onMove={moveStep}
|
||||||
<div className="flex flex-col items-center pt-1">
|
onUpdate={handleUpdate}
|
||||||
<div className="circular-container">
|
onRemove={handleRemove}
|
||||||
{index + 1}
|
isFirst={index === 0}
|
||||||
</div>
|
isLast={index === instructionStepList.length - 1}
|
||||||
<div className="flex flex-col mt-2">
|
/>
|
||||||
<Button
|
|
||||||
icon={ArrowUp}
|
|
||||||
onClick={() => moveStep(index, "up")}
|
|
||||||
buttonType={ButtonType.TransparentButton}
|
|
||||||
disabled={index === 0} // disable if first item
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
icon={ArrowDown}
|
|
||||||
onClick={() => moveStep(index, "down")}
|
|
||||||
buttonType={ButtonType.TransparentButton}
|
|
||||||
disabled={index === instructionStepList.length - 1} // disable if last item
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<textarea
|
|
||||||
className="input-field w-full min-h-[120px] resize-none overflow-hidden"
|
|
||||||
placeholder={`Schritt ${index + 1}`}
|
|
||||||
value={step.text}
|
|
||||||
onChange={(e) => handleUpdate(index, e.target.value)}
|
|
||||||
onInput={(e) => {
|
|
||||||
const el = e.target as HTMLTextAreaElement;
|
|
||||||
el.style.height = "auto";
|
|
||||||
el.style.height = `${el.scrollHeight}px`;
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
onClick={() => handleRemove(index)}
|
|
||||||
icon={X}
|
|
||||||
buttonType={ButtonType.DarkButton}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
<Button
|
<Button
|
||||||
onClick={handleAdd}
|
onClick={handleAdd}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
import Button from "../basics/Button.tsx";
|
||||||
|
import {ArrowDown, ArrowUp, X} from "lucide-react";
|
||||||
|
import {ButtonType} from "../basics/BasicButtonDefinitions.ts";
|
||||||
|
import type {InstructionStepModel} from "../../models/InstructionStepModel.ts";
|
||||||
|
|
||||||
|
type InstructionStepMobileListItemProps = {
|
||||||
|
index: number;
|
||||||
|
step: InstructionStepModel;
|
||||||
|
onMove(index: number, direction: "up" | "down"): void;
|
||||||
|
onUpdate: (index: number, value: string) => void;
|
||||||
|
onRemove: (index: number) => void;
|
||||||
|
isFirst: boolean;
|
||||||
|
isLast: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function InstructionStepMobileListItem({
|
||||||
|
index,
|
||||||
|
step,
|
||||||
|
onMove,
|
||||||
|
onUpdate,
|
||||||
|
onRemove,
|
||||||
|
isFirst,
|
||||||
|
isLast
|
||||||
|
}: InstructionStepMobileListItemProps) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={step.id}
|
||||||
|
className="flex items-start gap-3 bg-gray-50 rounded-xl p-3 shadow-sm"
|
||||||
|
>
|
||||||
|
<div className="flex flex-col items-center pt-1">
|
||||||
|
<div className="circular-container">
|
||||||
|
{index + 1}
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col mt-2">
|
||||||
|
<Button
|
||||||
|
icon={ArrowUp}
|
||||||
|
onClick={() => onMove(index, "up")}
|
||||||
|
buttonType={ButtonType.TransparentButton}
|
||||||
|
disabled={isFirst} // disable if first item
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
icon={ArrowDown}
|
||||||
|
onClick={() => onMove(index, "down")}
|
||||||
|
buttonType={ButtonType.TransparentButton}
|
||||||
|
disabled={isLast} // disable if last item
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<textarea
|
||||||
|
className="input-field w-full min-h-[120px] resize-none overflow-hidden"
|
||||||
|
placeholder={`Schritt ${index + 1}`}
|
||||||
|
value={step.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`;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
onClick={() => onRemove(index)}
|
||||||
|
icon={X}
|
||||||
|
buttonType={ButtonType.DarkButton}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue