diff --git a/src/components/dropzone.tsx b/src/components/dropzone.tsx new file mode 100644 index 0000000..53e619d --- /dev/null +++ b/src/components/dropzone.tsx @@ -0,0 +1,51 @@ +"use client"; + +import { ReactNode, useState } from "react"; +import { DropzoneOptions, FileWithPath, useDropzone } from "react-dropzone"; +import { Icon } from "@iconify/react"; + +interface Props { + onDrop: (acceptedFiles: FileWithPath[]) => void; + options?: DropzoneOptions; + children?: ReactNode; +} + +export default function Dropzone({ onDrop, options, children }: Props) { + const [isDraggingOver, setIsDraggingOver] = useState(false); + + const handleDrop = (acceptedFiles: FileWithPath[]) => { + setIsDraggingOver(false); + onDrop(acceptedFiles); + }; + + const { getRootProps, getInputProps } = useDropzone({ + onDrop: handleDrop, + maxFiles: 3, + accept: { + "image/*": [".png", ".jpg", ".jpeg", ".bmp", ".webp", ".heic"], + }, + ...options, + }); + + return ( +
setIsDraggingOver(true)} + onDragLeave={() => setIsDraggingOver(false)} + className={`relative bg-orange-200 flex flex-col justify-center items-center gap-2 p-4 rounded-xl border-2 border-dashed border-amber-500 select-none h-full transition-all duration-200 ${ + isDraggingOver && "scale-105 brightness-90 shadow-xl" + }`} + > + {/* Used to transition from border-dashed to border-solid */} +
+ + 1 : false })} /> + + {children} +
+ ); +} diff --git a/src/components/profile-settings/profile-picture.tsx b/src/components/profile-settings/profile-picture.tsx index 3bca613..cb29813 100644 --- a/src/components/profile-settings/profile-picture.tsx +++ b/src/components/profile-settings/profile-picture.tsx @@ -2,12 +2,13 @@ import { useRouter } from "next/navigation"; import Image from "next/image"; import { useCallback, useState } from "react"; -import { FileWithPath, useDropzone } from "react-dropzone"; +import { FileWithPath } from "react-dropzone"; import { Icon } from "@iconify/react"; import dayjs from "dayjs"; import SubmitDialogButton from "./submit-dialog-button"; +import Dropzone from "../dropzone"; export default function ProfilePictureSettings() { const router = useRouter(); @@ -41,14 +42,6 @@ export default function ProfilePictureSettings() { setNewPicture(acceptedFiles[0]); }, []); - const { getRootProps, getInputProps } = useDropzone({ - onDrop: handleDrop, - maxFiles: 1, - accept: { - "image/*": [".png", ".jpg", ".jpeg", ".bmp", ".webp", ".heic"], - }, - }); - return (
@@ -58,32 +51,21 @@ export default function ProfilePictureSettings() {
-
- {newPicture ? ( - new profile picture - ) : ( - <> - - -

- Drag and drop your profile picture here -
- or click to open -

- - )} -
+ +

+ Drag and drop your profile picture here +
+ or click to open +

+ + new profile picture +
diff --git a/src/components/submit-form/edit-form.tsx b/src/components/submit-form/edit-form.tsx index 3379feb..3c0c5d2 100644 --- a/src/components/submit-form/edit-form.tsx +++ b/src/components/submit-form/edit-form.tsx @@ -3,8 +3,7 @@ import { redirect } from "next/navigation"; import { useCallback, useEffect, useRef, useState } from "react"; -import { FileWithPath, useDropzone } from "react-dropzone"; -import { Icon } from "@iconify/react"; +import { FileWithPath } from "react-dropzone"; import { Mii } from "@prisma/client"; import { nameSchema, tagsSchema } from "@/lib/schemas"; @@ -14,6 +13,7 @@ import ImageList from "./image-list"; import LikeButton from "../like-button"; import Carousel from "../carousel"; import SubmitButton from "../submit-button"; +import Dropzone from "../dropzone"; interface Props { mii: Mii; @@ -33,14 +33,6 @@ export default function EditForm({ mii, likes }: Props) { [files.length] ); - const { getRootProps, getInputProps } = useDropzone({ - onDrop: handleDrop, - maxFiles: 3, - accept: { - "image/*": [".png", ".jpg", ".jpeg", ".bmp", ".webp"], - }, - }); - const [error, setError] = useState(undefined); const [name, setName] = useState(mii.name); @@ -197,20 +189,13 @@ export default function EditForm({ mii, likes }: Props) {
-
- - +

Drag and drop your images here
or click to open

-
+
diff --git a/src/components/submit-form/index.tsx b/src/components/submit-form/index.tsx index 89e6012..d8ed8b1 100644 --- a/src/components/submit-form/index.tsx +++ b/src/components/submit-form/index.tsx @@ -3,7 +3,7 @@ import { redirect } from "next/navigation"; import { useCallback, useEffect, useState } from "react"; -import { FileWithPath, useDropzone } from "react-dropzone"; +import { FileWithPath } from "react-dropzone"; import { Icon } from "@iconify/react"; import qrcode from "qrcode-generator"; @@ -21,6 +21,7 @@ import SubmitTutorialButton from "../tutorial/submit"; import LikeButton from "../like-button"; import Carousel from "../carousel"; import SubmitButton from "../submit-button"; +import Dropzone from "../dropzone"; export default function SubmitForm() { const [files, setFiles] = useState([]); @@ -33,14 +34,6 @@ export default function SubmitForm() { [files.length] ); - const { getRootProps, getInputProps } = useDropzone({ - onDrop: handleDrop, - maxFiles: 3, - accept: { - "image/*": [".png", ".jpg", ".jpeg", ".bmp", ".webp"], - }, - }); - const [isQrScannerOpen, setIsQrScannerOpen] = useState(false); const [studioUrl, setStudioUrl] = useState(); const [generatedQrCodeUrl, setGeneratedQrCodeUrl] = useState(); @@ -234,20 +227,13 @@ export default function SubmitForm() {
-
- - +

Drag and drop your images here
or click to open

-
+
diff --git a/src/components/submit-form/qr-upload.tsx b/src/components/submit-form/qr-upload.tsx index 36078d6..a53db68 100644 --- a/src/components/submit-form/qr-upload.tsx +++ b/src/components/submit-form/qr-upload.tsx @@ -1,9 +1,9 @@ "use client"; import { useCallback, useRef } from "react"; -import { FileWithPath, useDropzone } from "react-dropzone"; -import { Icon } from "@iconify/react"; +import { FileWithPath } from "react-dropzone"; import jsQR from "jsqr"; +import Dropzone from "../dropzone"; interface Props { setQrBytesRaw: React.Dispatch>; @@ -12,7 +12,7 @@ interface Props { export default function QrUpload({ setQrBytesRaw }: Props) { const canvasRef = useRef(null); - const onDrop = useCallback( + const handleDrop = useCallback( (acceptedFiles: FileWithPath[]) => { acceptedFiles.forEach((file) => { // Scan QR code @@ -44,30 +44,17 @@ export default function QrUpload({ setQrBytesRaw }: Props) { [setQrBytesRaw] ); - const { getRootProps, getInputProps } = useDropzone({ - onDrop, - accept: { - "image/*": [".png", ".jpg", ".jpeg", ".bmp", ".webp", ".heic"], - }, - }); - return (
-
- - +

Drag and drop your QR code image here
or click to open

-
+ + {/* Canvas is used to scan the QR code */}
);