Last active
November 20, 2023 08:56
-
-
Save donnes/38ca81f3c0d7c1e81dd7c4f883268d28 to your computer and use it in GitHub Desktop.
Uploadthing custom UploadDropzone implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useState } from 'react' | |
import { UploadDropzone } from "~/components/upload-dropzone"; | |
import { useUploadThing } from "~/hooks/use-uploadthing"; | |
import type { FileRouter } from "~/server/uploadthing"; | |
const Home: NextPage = () => { | |
const [files, setFiles] = useState<File[]>([]); | |
const { startUpload, isUploading, permittedFileInfo } = useUploadThing({ | |
endpoint: "upload", | |
onClientUploadComplete: () => console.log("Upload completed"), | |
onUploadError: () => console.log("Something went wrong"), | |
}); | |
return ( | |
<> | |
<Head> | |
<title>How to Use</title> | |
</Head> | |
<UploadDropzone | |
onChange={(acceptedFiles) => setFiles(acceptedFiles)} | |
permittedFileInfo={permittedFileInfo} | |
/> | |
{Boolean(files.length) && ( | |
<button | |
type="button" | |
onClick={() => { | |
if (!files) return; | |
void startUpload(files); | |
}} | |
disabled={isUploading} | |
> | |
{isUploading ? 'Uploading...' : 'Upload'} | |
</button> | |
)} | |
</> | |
); | |
}; | |
export default Home; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useCallback } from "react"; | |
import { type FileWithPath, useDropzone } from "react-dropzone"; | |
import { classNames, generateClientDropzoneAccept } from "uploadthing/client"; | |
import { UploadCloud } from "lucide-react"; | |
import { Button } from "~/components/ui/button"; | |
export function UploadDropzone(props: { | |
onChange?: (files: File[]) => void; | |
maxFiles?: number; | |
permittedFileInfo?: { | |
maxSize: string; | |
fileTypes: string[]; | |
}; | |
className?: string; | |
}) { | |
const onDrop = useCallback( | |
(acceptedFiles: FileWithPath[]) => { | |
props.onChange?.(acceptedFiles); | |
}, | |
[props] | |
); | |
const { maxSize, fileTypes } = props.permittedFileInfo ?? {}; | |
const { getRootProps, getInputProps, isDragActive } = useDropzone({ | |
onDrop, | |
accept: fileTypes ? generateClientDropzoneAccept(fileTypes) : undefined, | |
maxFiles: props.maxFiles ?? 1, | |
}); | |
return ( | |
<div className={classNames("min-h-[450px]", props?.className ?? "")}> | |
<label | |
htmlFor="file-upload" | |
className={classNames( | |
"flex h-full w-full cursor-pointer flex-col items-center justify-center rounded-lg border-2 border-dashed border-violet-300", | |
"bg-violet-50 text-primary/80 hover:bg-violet-100 hover:text-primary", | |
isDragActive ? "border-sky-600 bg-sky-50 hover:bg-sky-100" : "", | |
)} | |
{...getRootProps()} | |
> | |
<div className="flex flex-col items-center justify-center pb-6 pt-5"> | |
<UploadCloud className="h-14 w-14" /> | |
<p className="mb-2 cursor-pointer text-center text-base"> | |
To get started,{" "} | |
<span className="font-semibold">click to upload</span> | |
<br /> | |
or <span className="font-semibold">drag and drop</span> here | |
</p> | |
<div className="h-[1.25rem]"> | |
{fileTypes && ( | |
<p className="text-sm leading-5 text-primary/60"> | |
<span className="capitalize">{`${fileTypes.join(", ")}`}</span>{" "} | |
{maxSize && `up to ${maxSize}`} | |
</p> | |
)} | |
</div> | |
</div> | |
<input className="sr-only" {...getInputProps()} /> | |
</label> | |
</div> | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as React from 'react'; | |
import { Trash } from "lucide-react"; | |
import { classNames } from "uploadthing/client"; | |
import { Button } from "~/components/ui/button"; | |
export function UploadItem(props: { | |
file: File; | |
onRemove?: (file: File) => void; | |
className?: string; | |
}) { | |
const { file, onRemove } = props; | |
return ( | |
<div | |
className={classNames( | |
"relative h-40 w-full overflow-hidden rounded-md shadow-lg", | |
props?.className ?? "" | |
)} | |
> | |
<Button | |
type="button" | |
className="absolute right-2 top-2 z-10 h-6 w-6 p-0" | |
onClick={() => onRemove?.(file)} | |
aria-label="Remove file" | |
variant="secondary" | |
size="sm" | |
> | |
<Trash className="h-4 w-4 text-destructive" /> | |
</Button> | |
{file.type.startsWith("video/") && ( | |
<video | |
key={file.name} | |
src={URL.createObjectURL(file)} | |
className="pointer-events-none h-full w-full object-cover" | |
controls={false} | |
/> | |
)} | |
{file.type.startsWith("image/") && ( | |
<Image | |
src={URL.createObjectURL(file)} | |
alt={file.name} | |
width={200} | |
height={200} | |
className="pointer-events-none h-full w-full object-cover" | |
/> | |
)} | |
<div className="absolute inset-0 flex items-end bg-gradient-to-t from-slate-950/60 to-transparent"> | |
<span className="p-2 text-sm font-semibold text-white"> | |
{file.name} | |
</span> | |
</div> | |
</div> | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { generateReactHelpers } from "@uploadthing/react/hooks"; | |
import type { FileRouter } from "~/server/uploadthing"; | |
const { useUploadThing } = generateReactHelpers<FileRouter>(); | |
export { useUploadThing }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
awesome