feat: image list in submit form

This commit is contained in:
trafficlunar 2025-04-06 22:47:09 +01:00
parent e83d7fadb5
commit a1fcd46bda
5 changed files with 168 additions and 9 deletions

View file

@ -2,8 +2,8 @@
import { redirect } from "next/navigation";
import { useEffect, useState } from "react";
import { useDropzone } from "react-dropzone";
import { useCallback, useEffect, useState } from "react";
import { FileWithPath, useDropzone } from "react-dropzone";
import { Icon } from "@iconify/react";
import { AES_CCM } from "@trafficlunar/asmcrypto.js";
@ -16,11 +16,20 @@ import Mii from "@/utils/mii.js/mii";
import TomodachiLifeMii from "@/utils/tomodachi-life-mii";
import TagSelector from "./submit/tag-selector";
import ImageList from "./submit/image-list";
import QrUpload from "./submit/qr-upload";
import QrScanner from "./submit/qr-scanner";
export default function SubmitForm() {
const { acceptedFiles, getRootProps, getInputProps } = useDropzone({
const [files, setFiles] = useState<FileWithPath[]>([]);
const handleDrop = useCallback((acceptedFiles: FileWithPath[]) => {
setFiles((prev) => [...prev, ...acceptedFiles]);
}, []);
const { getRootProps, getInputProps } = useDropzone({
onDrop: handleDrop,
maxFiles: 3,
accept: {
"image/*": [".png", ".jpg", ".jpeg", ".bmp", ".webp"],
},
@ -154,14 +163,14 @@ export default function SubmitForm() {
/>
</div>
<div className="p-2 border-2 bg-orange-100 border-amber-500 rounded-2xl shadow-lg h-48">
<div className="p-2 border-2 bg-orange-200 border-amber-500 rounded-2xl shadow-lg h-48">
<div
{...getRootProps({
className:
"bg-orange-100 flex flex-col justify-center items-center gap-2 p-4 rounded-xl border border-2 border-dashed border-amber-500 select-none h-full",
"bg-orange-200 flex flex-col justify-center items-center gap-2 p-4 rounded-xl border border-2 border-dashed border-amber-500 select-none h-full",
})}
>
<input {...getInputProps({ multiple: false })} />
<input {...getInputProps()} />
<Icon icon="material-symbols:upload" fontSize={64} />
<p className="text-center">
Drag and drop your images here
@ -171,7 +180,7 @@ export default function SubmitForm() {
</div>
</div>
{/* todo: show file list here */}
<ImageList files={files} setFiles={setFiles} />
</div>
<div className="p-4 flex flex-col gap-2">

View file

@ -0,0 +1,71 @@
import { FileWithPath } from "react-dropzone";
import { DragDropContext, Draggable, Droppable, DropResult } from "@hello-pangea/dnd";
import { Icon } from "@iconify/react";
interface Props {
files: readonly FileWithPath[];
setFiles: React.Dispatch<React.SetStateAction<FileWithPath[]>>;
}
export default function ImageList({ files, setFiles }: Props) {
const handleDelete = (index: number) => {
const newFiles = [...files];
newFiles.splice(index, 1);
setFiles(newFiles);
};
const handleDragEnd = (result: DropResult) => {
if (!result.destination) return;
const items = Array.from(files);
const [reorderedItem] = items.splice(result.source.index, 1);
items.splice(result.destination.index, 0, reorderedItem);
setFiles(items);
};
return (
<DragDropContext onDragEnd={handleDragEnd}>
<Droppable droppableId="imageDroppable">
{(provided) => (
<div ref={provided.innerRef} {...provided.droppableProps} className="flex flex-col px-12">
{files.map((file, index) => (
<Draggable key={file.name} draggableId={file.name} index={index}>
{(provided) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
className="w-full p-4 rounded-xl bg-orange-100 border-2 border-amber-500 flex gap-2 shadow-md my-1"
>
<img
src={URL.createObjectURL(file)}
alt={file.name}
className="aspect-[3/2] object-contain w-24 rounded-md bg-orange-300 border-2 border-orange-400"
/>
<div className="flex flex-col justify-center w-full min-w-0">
<span className="font-semibold text overflow-hidden text-ellipsis">{file.name}</span>
<button
onClick={() => handleDelete(index)}
className="pill button text-xs w-min !px-3 !py-1 !bg-red-300 !border-red-400 hover:!bg-red-400"
>
Delete
</button>
</div>
<div
{...provided.dragHandleProps}
className="h-full w-11 px-1 cursor-grab flex items-center justify-center rounded transition-colors hover:bg-black/10"
>
<Icon icon="tabler:grip-horizontal" className="size-6 text-black/50" />
</div>
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
);
}

View file

@ -44,11 +44,11 @@ export default function QrUpload({ setQrBytesRaw }: Props) {
});
return (
<div className="p-2 border-2 bg-orange-100 border-amber-500 rounded-2xl shadow-lg w-full">
<div className="p-2 border-2 bg-orange-200 border-amber-500 rounded-2xl shadow-lg w-full">
<div
{...getRootProps({
className:
"bg-orange-100 flex flex-col justify-center items-center gap-2 p-4 rounded-xl border border-2 border-dashed border-amber-500 select-none h-full",
"bg-orange-200 flex flex-col justify-center items-center gap-2 p-4 rounded-xl border border-2 border-dashed border-amber-500 select-none h-full",
})}
>
<input {...getInputProps({ multiple: false })} />