-
Notifications
You must be signed in to change notification settings - Fork 67
Expand file tree
/
Copy pathdropTarget.tsx
More file actions
77 lines (70 loc) · 2.37 KB
/
dropTarget.tsx
File metadata and controls
77 lines (70 loc) · 2.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import { Component, createSignal, JSX, Show } from 'solid-js';
import { Icon } from 'solid-heroicons';
import { arrowDownTray } from 'solid-heroicons/outline';
interface DropTargetProps {
handleImport: (files: { name: string; source: string }[]) => void;
children: JSX.Element;
class?: string;
}
const ALLOWED_EXTENSIONS = ['.js', '.jsx', '.ts', '.tsx', '.css', '.json', '.html'];
export const DropTarget: Component<DropTargetProps> = (props) => {
const [isDragging, setIsDragging] = createSignal(false);
const onDrop = async (e: DragEvent) => {
e.preventDefault();
if (e.dataTransfer?.files && e.dataTransfer.files.length > 0) {
const files = Array.from(e.dataTransfer.files).filter((file) =>
ALLOWED_EXTENSIONS.some((ext) => file.name.toLowerCase().endsWith(ext)),
);
if (files.length === 0) {
setIsDragging(false);
return;
}
const results = await Promise.allSettled(
files.map((file) => {
return new Promise<{ name: string; source: string }>((resolve) => {
const reader = new FileReader();
reader.onload = (e) => {
resolve({
name: file.name,
source: (e.target?.result as string) || '',
});
};
reader.readAsText(file);
});
}),
);
props.handleImport(
results.filter((result) => result.status === 'fulfilled').map((result) => result.value)
);
setIsDragging(false);
}
};
return (
<div
onDragOver={(e) => {
e.preventDefault();
setIsDragging(true);
}}
onDragEnter={() => setIsDragging(true)}
onDragLeave={() => setIsDragging(false)}
onDragEnd={() => setIsDragging(false)}
onDrop={onDrop}
classList={{
[props.class || '']: true,
'relative': true,
}}
>
{props.children}
<Show when={isDragging()}>
<div
class="absolute inset-0 z-50 border-2 border-dashed border-gray-300 dark:border-gray-700 pointer-events-none content-[''] bg-black/50"
>
<div class="absolute inset-0 flex flex-col items-center justify-center">
<Icon path={arrowDownTray} class="h-10 w-10 text-gray-200 mb-2" />
<p class="text-gray-200">Drag and drop files here to import</p>
</div>
</div>
</Show>
</div>
);
}