Skip to content

Commit 1cdc1a4

Browse files
feat: previews draggable across screens
1 parent c77c5f8 commit 1cdc1a4

1 file changed

Lines changed: 35 additions & 22 deletions

File tree

src/app/upload/page.tsx

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
DndContext,
1111
closestCenter,
1212
PointerSensor,
13+
TouchSensor,
1314
useSensor,
1415
useSensors,
1516
DragEndEvent,
@@ -36,7 +37,6 @@ export default function Page() {
3637
{ id: string; file: File; preview: string }[]
3738
>([]);
3839
const [isUploading, setIsUploading] = useState(false);
39-
const [setIsDragging] = useState(false);
4040
const [isGlobalDragging, setIsGlobalDragging] = useState(false);
4141
const [zoomIndex, setZoomIndex] = useState<number | null>(null);
4242

@@ -160,6 +160,7 @@ export default function Page() {
160160
},
161161
[files],
162162
);
163+
163164
const onDrop = useCallback(
164165
(acceptedFiles: File[]) => {
165166
fileCheckAndSelect(acceptedFiles);
@@ -168,7 +169,15 @@ export default function Page() {
168169
);
169170

170171
const sensors = useSensors(
171-
useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
172+
useSensor(PointerSensor, {
173+
activationConstraint: { distance: 5 },
174+
}),
175+
useSensor(TouchSensor, {
176+
activationConstraint: {
177+
delay: 200,
178+
tolerance: 10,
179+
},
180+
}),
172181
);
173182

174183
function SortablePreview({
@@ -191,6 +200,7 @@ export default function Page() {
191200
transform: CSS.Transform.toString(transform),
192201
transition,
193202
zIndex: isDragging ? 1000 : 1,
203+
touchAction: "none", // Prevent scrolling during touch drag
194204
};
195205

196206
return (
@@ -234,7 +244,6 @@ export default function Page() {
234244
};
235245

236246
const clearAllFiles = useCallback(() => {
237-
// Clean up all URLs
238247
previews.forEach((item) => {
239248
try {
240249
URL.revokeObjectURL(item.preview);
@@ -322,7 +331,7 @@ export default function Page() {
322331
isDragActive || isGlobalDragging
323332
? "border-solid border-[#6D28D9] bg-purple-50 dark:bg-[#130E1F]"
324333
: "border-dashed border-gray-300"
325-
} p-8 text-center transition-all duration-200`}
334+
} p-8 text-center transition-all duration-200 touch-none`}
326335
>
327336
<input {...getInputProps()} />
328337
{isDragActive || isGlobalDragging ? (
@@ -375,9 +384,13 @@ export default function Page() {
375384
}}
376385
multiple={true}
377386
>
378-
{({ getRootProps, getInputProps }) => (
387+
{({ getRootProps, getInputProps, isDragActive }) => (
379388
<div
380-
className="relative h-20 w-20 flex-shrink-0 cursor-pointer"
389+
className={`relative h-20 w-20 flex-shrink-0 cursor-pointer touch-none ${
390+
isDragActive || isGlobalDragging
391+
? "border-2 border-solid border-[#6D28D9]"
392+
: ""
393+
}`}
381394
{...getRootProps()}
382395
>
383396
<input {...getInputProps()} />
@@ -397,10 +410,7 @@ export default function Page() {
397410
{previews.length > 0 && (
398411
<section className="mt-6 flex w-full flex-col items-center">
399412
<div className="flex w-max gap-4">
400-
<div
401-
className="scrollbar-hide flex w-full max-w-4xl flex-col justify-between overflow-x-auto overflow-y-hidden rounded-[40px] border-[6px] border-indigo-900 bg-indigo-900/10 p-8"
402-
style={{ minHeight: 340, maxHeight: 340 }}
403-
>
413+
<div className="scrollbar-hide w-[80vw] flex md:w-max max-w-4xl flex-col justify-between overflow-x-auto overflow-y-hidden rounded-[40px] border-[6px] border-indigo-900 bg-indigo-900/10 p-4 sm:p-6 md:p-8">
404414
<DndContext
405415
sensors={sensors}
406416
collisionDetection={closestCenter}
@@ -410,17 +420,19 @@ export default function Page() {
410420
items={previews.map((item) => item.id)}
411421
strategy={horizontalListSortingStrategy}
412422
>
413-
<div className="flex w-max gap-5">
423+
<div className="flex w-full snap-x snap-mandatory gap-3 sm:gap-4 md:gap-5">
414424
{previews.map((item, index) => (
415425
<SortablePreview key={item.id} id={item.id}>
416-
<div className="group relative flex-shrink-0">
417-
<div className="relative h-60 w-48 overflow-hidden rounded-2xl outline outline-2 outline-white">
418-
<div className="absolute left-0 top-0 z-20 flex h-10 w-10 items-center justify-center rounded-br-2xl rounded-tl-2xl bg-slate-600">
419-
<span className="text-xl font-bold text-white">
426+
<div className="group relative w-full flex-shrink-0 snap-start sm:w-1/2 md:w-1/3 lg:w-1/4">
427+
<div className="relative h-64 w-48 overflow-hidden rounded-xl outline outline-2 outline-white sm:h-60">
428+
{/* Index badge */}
429+
<div className="absolute left-0 top-0 z-20 flex h-8 w-8 items-center justify-center rounded-br-xl rounded-tl-xl bg-slate-600 sm:h-10 sm:w-10">
430+
<span className="text-sm font-bold text-white sm:text-xl">
420431
{index + 1}
421432
</span>
422433
</div>
423434

435+
{/* Delete button */}
424436
<Button
425437
onClick={(e) => {
426438
e.preventDefault();
@@ -429,12 +441,13 @@ export default function Page() {
429441
}}
430442
variant="destructive"
431443
size="icon"
432-
className="absolute right-0 top-0 z-20 h-10 w-10 rounded-bl-2xl rounded-tr-2xl bg-pink-800 hover:bg-red-900"
444+
className="absolute right-0 top-0 z-20 h-8 w-8 rounded-bl-xl rounded-tr-xl bg-pink-800 hover:bg-red-900 sm:h-10 sm:w-10"
433445
title="Delete"
434446
>
435-
<FiTrash className="h-5 w-5" />
447+
<FiTrash className="h-4 w-4 sm:h-5 sm:w-5" />
436448
</Button>
437449

450+
{/* Preview */}
438451
<div className="absolute inset-0 z-10">
439452
{item.file.type.startsWith("image/") ? (
440453
<Image
@@ -443,7 +456,6 @@ export default function Page() {
443456
fill
444457
className="object-cover"
445458
unoptimized
446-
sizes="192px"
447459
/>
448460
) : (
449461
<iframe
@@ -457,10 +469,11 @@ export default function Page() {
457469
</div>
458470
</SortablePreview>
459471
))}
460-
</div>{" "}
472+
</div>
473+
461474
{previews.length > 2 && (
462-
<div className="text-l mt-4 text-right text-white/50">
463-
scroll to view more &gt;&gt;
475+
<div className="mt-3 text-center text-sm text-white/50">
476+
Swipe to view more &gt;&gt;
464477
</div>
465478
)}
466479
</SortableContext>
@@ -524,4 +537,4 @@ export default function Page() {
524537
)}
525538
</main>
526539
);
527-
}
540+
}

0 commit comments

Comments
 (0)