@@ -22,6 +22,9 @@ import {
2222 horizontalListSortingStrategy ,
2323} from "@dnd-kit/sortable" ;
2424import { CSS } from "@dnd-kit/utilities" ;
25+ import Dropzone from "react-dropzone" ;
26+ import { Upload , XIcon } from "lucide-react" ;
27+
2528
2629interface APIResponse {
2730 status : string ;
@@ -257,57 +260,54 @@ export default function Page() {
257260 }
258261 } ;
259262
260- return (
263+ return (
261264 < main className = "mx-auto max-w-3xl px-4 py-8" >
262265 < div className = "flex h-[calc(100vh-85px)] flex-col justify-center px-6 font-play" >
263266 < div className = "2xl:my-15 flex flex-col items-center" >
264267 { previews . length === 0 && (
265268 < fieldset className = "mb-4 w-full max-w-md rounded-lg border-2 border-gray-300 p-4 pr-8" >
266269 < div className = "flex w-full flex-col 2xl:gap-y-4" >
267270 < div >
268- < section
269- { ...getRootProps ( ) }
270- className = { `my-2 -mr-2 cursor-pointer rounded-2xl border-2 ${
271- isDragging || isGlobalDragging
272- ? "border-solid border-[#6D28D9] bg-purple-50 dark:bg-[#130E1F]"
273- : "border-dashed border-gray-300"
274- } p-8 text-center transition-all duration-200`}
275- onDragEnter = { ( ) => setIsDragging ( true ) }
276- onDragLeave = { ( ) => setIsDragging ( false ) }
271+ < Dropzone
272+ onDrop = { onDrop }
273+ accept = { {
274+ 'image/*' : [ '.jpeg' , '.jpg' , '.png' , '.gif' , '.bmp' , '.webp' ] ,
275+ 'application/pdf' : [ '.pdf' ]
276+ } }
277+ multiple = { true }
277278 >
278- < input { ...getInputProps ( ) } />
279- { isDragging || isGlobalDragging ? (
280- < div className = "flex flex-col items-center" >
281- < p className = "text-lg font-medium text-[#6D28D9]" >
282- Drop files here
283- </ p >
284- < svg
285- className = "mt-2 h-10 w-10 animate-bounce text-[#6D28D9]"
286- fill = "none"
287- stroke = "currentColor"
288- strokeWidth = "2"
289- viewBox = "0 0 24 24"
279+ { ( { getRootProps, getInputProps, isDragActive } ) => (
280+ < section
281+ { ...getRootProps ( ) }
282+ className = { `my-2 -mr-2 cursor-pointer rounded-2xl border-2 ${
283+ isDragActive || isGlobalDragging
284+ ? "border-solid border-[#6D28D9] bg-purple-50 dark:bg-[#130E1F]"
285+ : "border-dashed border-gray-300"
286+ } p-8 text-center transition-all duration-200`}
287+ >
288+ < input { ...getInputProps ( ) } />
289+ { isDragActive || isGlobalDragging ? (
290+ < div className = "flex flex-col items-center" >
291+ < p className = "text-lg font-medium text-[#6D28D9]" >
292+ Drop files here
293+ </ p >
294+ < Upload className = "mt-2 h-10 w-10 animate-bounce text-[#6D28D9]" />
295+ </ div >
296+ ) : (
297+ < p >
298+ Drag 'n' drop some files here, or{ " " }
299+ < span className = "text-[#6D28D9]" > click</ span > to select
300+ files
301+ </ p >
302+ ) }
303+ < div
304+ className = { `mt-2 text-xs ${ files . length === 0 ? "text-red-500" : "text-gray-600" } ` }
290305 >
291- < path
292- strokeLinecap = "round"
293- strokeLinejoin = "round"
294- d = "M4 16v2a2 2 0 002 2h12a2 2 0 002-2v-2M7 10l5-5m0 0l5 5m-5-5v12"
295- />
296- </ svg >
297- </ div >
298- ) : (
299- < p >
300- Drag 'n' drop some files here, or{ " " }
301- < span className = "text-[#6D28D9]" > click</ span > to select
302- files
303- </ p >
306+ { files . length } files selected
307+ </ div >
308+ </ section >
304309 ) }
305- < div
306- className = { `mt-2 text-xs ${ files . length === 0 ? "text-red-500" : "text-gray-600" } ` }
307- >
308- { files . length } files selected
309- </ div >
310- </ section >
310+ </ Dropzone >
311311 < label className = "mx-2 -mr-2 block text-center text-xs font-medium text-gray-700" >
312312 Only Images and PDF are allowed
313313 < sup className = "text-red-500" > *</ sup >
@@ -342,21 +342,23 @@ export default function Page() {
342342 { index + 1 }
343343 </ span >
344344 </ div >
345- < button
345+ < Button
346346 onClick = { ( ) => handleDelete ( index ) }
347- className = "absolute right-0 top-0 z-10 flex h-10 w-10 items-center justify-center rounded-bl-2xl rounded-tr-2xl bg-pink-800"
347+ variant = "destructive"
348+ size = "icon"
349+ className = "absolute right-0 top-0 z-10 h-10 w-10 rounded-bl-2xl rounded-tr-2xl bg-pink-800 hover:bg-pink-900"
348350 title = "Delete"
349351 >
350- < FiTrash className = "h-5 w-5 text-white " />
351- </ button >
352+ < FiTrash className = "h-5 w-5" />
353+ </ Button >
352354 { item . file . type . startsWith ( "image/" ) ? (
353355 < div className = "relative h-full w-full" >
354356 < Image
355357 src = { item . preview }
356358 alt = { `Page ${ index + 1 } ` }
357359 fill
358360 className = "object-cover"
359- unoptimized // Since we're using object URLs
361+ unoptimized
360362 />
361363 </ div >
362364 ) : (
@@ -370,21 +372,32 @@ export default function Page() {
370372 </ div >
371373 </ SortablePreview >
372374 ) ) }
373- < div
374- className = "relative h-20 w-20 cursor-pointer"
375- { ...getRootProps ( ) }
375+ < Dropzone
376+ onDrop = { onDrop }
377+ accept = { {
378+ 'image/*' : [ '.jpeg' , '.jpg' , '.png' , '.gif' , '.bmp' , '.webp' ] ,
379+ 'application/pdf' : [ '.pdf' ]
380+ } }
381+ multiple = { true }
376382 >
377- < input { ...getInputProps ( ) } />
378- < div className = "absolute left-4 top-4 h-16 w-16 rounded-2xl bg-violet-950" />
379- < div className = "absolute left-0 top-0 h-10 w-10 rounded-[20px] bg-violet-950" />
380- < div className = "absolute left-1 top-1 h-8 w-8 rounded-[20px] bg-black/50" />
381- < div className = "absolute left-7 top-7 text-2xl text-white" >
382- +
383- </ div >
384- < div className = "absolute left-4 top-3 text-xs font-semibold text-white" >
385- { previews . length }
386- </ div >
387- </ div >
383+ { ( { getRootProps, getInputProps } ) => (
384+ < div
385+ className = "relative h-20 w-20 cursor-pointer"
386+ { ...getRootProps ( ) }
387+ >
388+ < input { ...getInputProps ( ) } />
389+ < div className = "absolute left-4 top-4 h-16 w-16 rounded-2xl bg-violet-950" />
390+ < div className = "absolute left-0 top-0 h-10 w-10 rounded-[20px] bg-violet-950" />
391+ < div className = "absolute left-1 top-1 h-8 w-8 rounded-[20px] bg-black/50" />
392+ < div className = "absolute left-7 top-7 text-2xl text-white" >
393+ +
394+ </ div >
395+ < div className = "absolute left-4 top-3 text-xs font-semibold text-white" >
396+ { previews . length }
397+ </ div >
398+ </ div >
399+ ) }
400+ </ Dropzone >
388401 </ div >
389402 </ SortableContext >
390403 </ DndContext >
@@ -398,7 +411,8 @@ export default function Page() {
398411 < Button
399412 onClick = { handlePrint }
400413 disabled = { isUploading || files . length === 0 }
401- className = "mt-8 rounded-[40px] bg-violet-950 px-8 py-3 text-xl text-white"
414+ className = "mt-8 rounded-[40px] bg-violet-950 px-8 py-3 text-xl text-white hover:bg-violet-800"
415+ size = "lg"
402416 >
403417 { isUploading ? "Uploading..." : "Upload" }
404418 </ Button >
@@ -408,13 +422,15 @@ export default function Page() {
408422 { zoomIndex !== null && (
409423 < div className = "fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-70" >
410424 < div className = "relative flex flex-col items-center rounded-lg bg-white p-4 shadow-lg" >
411- < button
425+ < Button
412426 onClick = { ( ) => setZoomIndex ( null ) }
413- className = "absolute right-2 top-2 rounded-full bg-gray-200 p-2 hover:bg-gray-300"
427+ variant = "ghost"
428+ size = "icon"
429+ className = "absolute right-2 top-2 rounded-full bg-gray-200 hover:bg-gray-300"
414430 title = "Close"
415431 >
416- < FiX size = { 24 } />
417- </ button >
432+ < XIcon className = "h-6 w-6" />
433+ </ Button >
418434 { previews [ zoomIndex ] ?. file . type . startsWith ( "image/" ) ? (
419435 < Image
420436 src = { previews [ zoomIndex ] . preview }
@@ -441,4 +457,4 @@ export default function Page() {
441457 ) }
442458 </ main >
443459 ) ;
444- }
460+ }
0 commit comments