diff --git a/src/components/file/GlobalImageDrop.js b/src/components/image/GlobalImageDrop.js
similarity index 56%
rename from src/components/file/GlobalImageDrop.js
rename to src/components/image/GlobalImageDrop.js
index a03578b..5287b72 100644
--- a/src/components/file/GlobalImageDrop.js
+++ b/src/components/image/GlobalImageDrop.js
@@ -1,12 +1,9 @@
import React, { useState, useRef } from "react";
-import { Box } from "theme-ui";
+import { Flex, Text } from "theme-ui";
import { useToasts } from "react-toast-notifications";
-import ImageDrop from "./ImageDrop";
-
import LoadingOverlay from "../LoadingOverlay";
-import ImageTypeModal from "../../modals/ImageTypeModal";
import ConfirmModal from "../../modals/ConfirmModal";
import { createMapFromFile } from "../../helpers/map";
@@ -17,7 +14,9 @@ import { useMapData } from "../../contexts/MapDataContext";
import { useTokenData } from "../../contexts/TokenDataContext";
import { useAssets } from "../../contexts/AssetsContext";
-function GlobalImageDrop({ children }) {
+import useImageDrop from "../../hooks/useImageDrop";
+
+function GlobalImageDrop({ children, onMapTokensStateCreate }) {
const { addToast } = useToasts();
const { userId } = useAuth();
@@ -25,20 +24,24 @@ function GlobalImageDrop({ children }) {
const { addToken } = useTokenData();
const { addAssets } = useAssets();
- const [isImageTypeModalOpen, setIsImageTypeModalOpen] = useState(false);
const [isLargeImageWarningModalOpen, setShowLargeImageWarning] = useState(
false
);
const [isLoading, setIsLoading] = useState(false);
const droppedImagesRef = useRef();
+ const dropPositionRef = useRef();
+ // maps or tokens
+ const [droppingType, setDroppingType] = useState("maps");
- async function handleDrop(files) {
+ async function handleDrop(files, dropPosition) {
if (navigator.storage) {
// Attempt to enable persistant storage
await navigator.storage.persist();
}
+ dropPositionRef.current = dropPosition;
+
droppedImagesRef.current = [];
for (let file of files) {
if (file.size > 5e7) {
@@ -54,7 +57,11 @@ function GlobalImageDrop({ children }) {
return;
}
- setIsImageTypeModalOpen(true);
+ if (droppingType === "maps") {
+ await handleMaps();
+ } else {
+ await handleTokens();
+ }
}
function handleLargeImageWarningCancel() {
@@ -64,11 +71,14 @@ function GlobalImageDrop({ children }) {
async function handleLargeImageWarningConfirm() {
setShowLargeImageWarning(false);
- setIsImageTypeModalOpen(true);
+ if (droppingType === "maps") {
+ await handleMaps();
+ } else {
+ await handleTokens();
+ }
}
async function handleMaps() {
- setIsImageTypeModalOpen(false);
setIsLoading(true);
for (let file of droppedImagesRef.current) {
const { map, assets } = await createMapFromFile(file, userId);
@@ -80,7 +90,6 @@ function GlobalImageDrop({ children }) {
}
async function handleTokens() {
- setIsImageTypeModalOpen(false);
setIsLoading(true);
for (let file of droppedImagesRef.current) {
const { token, assets } = await createTokenFromFile(file, userId);
@@ -91,21 +100,66 @@ function GlobalImageDrop({ children }) {
droppedImagesRef.current = undefined;
}
- function handleImageTypeClose() {
- droppedImagesRef.current = undefined;
- setIsImageTypeModalOpen(false);
+ function handleMapsOver() {
+ setDroppingType("maps");
}
+ function handleTokensOver() {
+ setDroppingType("tokens");
+ }
+
+ const { dragging, containerListeners, overlayListeners } = useImageDrop(
+ handleDrop
+ );
+
return (
-
- {children}
- 1}
- />
+
+ {children}
+ {dragging && (
+
+
+
+ {"Drop image to import as a map"}
+
+
+
+
+ {"Drop image to import as a token"}
+
+
+
+ )}
{isLoading && }
-
+
);
}
diff --git a/src/components/image/ImageDrop.js b/src/components/image/ImageDrop.js
new file mode 100644
index 0000000..f93aa97
--- /dev/null
+++ b/src/components/image/ImageDrop.js
@@ -0,0 +1,37 @@
+import React from "react";
+import { Box, Flex, Text } from "theme-ui";
+
+import useImageDrop from "../../hooks/useImageDrop";
+
+function ImageDrop({ onDrop, dropText, children }) {
+ const { dragging, containerListeners, overlayListeners } = useImageDrop(
+ onDrop
+ );
+ return (
+
+ {children}
+ {dragging && (
+
+
+ {dropText || "Drop image to import"}
+
+
+ )}
+
+ );
+}
+
+export default ImageDrop;
diff --git a/src/components/file/ImageDrop.js b/src/hooks/useImageDrop.js
similarity index 58%
rename from src/components/file/ImageDrop.js
rename to src/hooks/useImageDrop.js
index 85bf8af..bf38044 100644
--- a/src/components/file/ImageDrop.js
+++ b/src/hooks/useImageDrop.js
@@ -1,26 +1,34 @@
-import React, { useState } from "react";
-import { Box, Flex, Text } from "theme-ui";
+import { useState } from "react";
import { useToasts } from "react-toast-notifications";
-const supportFileTypes = ["image/jpeg", "image/gif", "image/png", "image/webp"];
+import Vector2 from "../helpers/Vector2";
-function ImageDrop({ onDrop, dropText, children }) {
+function useImageDrop(
+ onImageDrop,
+ supportFileTypes = ["image/jpeg", "image/gif", "image/png", "image/webp"]
+) {
const { addToast } = useToasts();
const [dragging, setDragging] = useState(false);
- function handleImageDragEnter(event) {
+ function onDragEnter(event) {
event.preventDefault();
event.stopPropagation();
setDragging(true);
}
- function handleImageDragLeave(event) {
+ function onDragLeave(event) {
event.preventDefault();
event.stopPropagation();
setDragging(false);
}
- async function handleImageDrop(event) {
+ function onDragOver(event) {
+ event.preventDefault();
+ event.stopPropagation();
+ event.dataTransfer.dropEffect = "copy";
+ }
+
+ async function onDrop(event) {
event.preventDefault();
event.stopPropagation();
let imageFiles = [];
@@ -63,41 +71,15 @@ function ImageDrop({ onDrop, dropText, children }) {
addToast(`Unsupported file type for ${file.name}`);
}
}
- onDrop(imageFiles);
+ const dropPosition = new Vector2(event.clientX, event.clientY);
+ onImageDrop(imageFiles, dropPosition);
setDragging(false);
}
- return (
-
- {children}
- {dragging && (
- {
- e.preventDefault();
- e.stopPropagation();
- e.dataTransfer.dropEffect = "copy";
- }}
- onDrop={handleImageDrop}
- >
-
- {dropText || "Drop image to import"}
-
-
- )}
-
- );
+ const containerListeners = { onDragEnter };
+ const overlayListeners = { onDragLeave, onDragOver, onDrop };
+
+ return { dragging, containerListeners, overlayListeners };
}
-export default ImageDrop;
+export default useImageDrop;
diff --git a/src/modals/ImageTypeModal.js b/src/modals/ImageTypeModal.js
deleted file mode 100644
index 7726494..0000000
--- a/src/modals/ImageTypeModal.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import React from "react";
-import { Box, Label, Flex, Button } from "theme-ui";
-
-import Modal from "../components/Modal";
-
-function ImageTypeModal({
- isOpen,
- onRequestClose,
- multiple,
- onTokens,
- onMaps,
-}) {
- return (
-
-
-
-
-
-
-
-
-
- );
-}
-
-export default ImageTypeModal;
diff --git a/src/modals/SelectMapModal.js b/src/modals/SelectMapModal.js
index 32a6532..dab60d0 100644
--- a/src/modals/SelectMapModal.js
+++ b/src/modals/SelectMapModal.js
@@ -9,7 +9,7 @@ import ConfirmModal from "./ConfirmModal";
import Modal from "../components/Modal";
import LoadingOverlay from "../components/LoadingOverlay";
-import ImageDrop from "../components/file/ImageDrop";
+import ImageDrop from "../components/image/ImageDrop";
import MapTiles from "../components/map/MapTiles";
import MapEditBar from "../components/map/MapEditBar";
diff --git a/src/modals/SelectTokensModal.js b/src/modals/SelectTokensModal.js
index fb0a90b..b81d3eb 100644
--- a/src/modals/SelectTokensModal.js
+++ b/src/modals/SelectTokensModal.js
@@ -9,7 +9,7 @@ import ConfirmModal from "./ConfirmModal";
import Modal from "../components/Modal";
import LoadingOverlay from "../components/LoadingOverlay";
-import ImageDrop from "../components/file/ImageDrop";
+import ImageDrop from "../components/image/ImageDrop";
import TokenTiles from "../components/token/TokenTiles";
import TokenEditBar from "../components/token/TokenEditBar";
diff --git a/src/network/NetworkedMapAndTokens.js b/src/network/NetworkedMapAndTokens.js
index 6c258d1..9f587aa 100644
--- a/src/network/NetworkedMapAndTokens.js
+++ b/src/network/NetworkedMapAndTokens.js
@@ -20,6 +20,8 @@ import Session from "./Session";
import Map from "../components/map/Map";
import TokenBar from "../components/token/TokenBar";
+import GlobalImageDrop from "../components/image/GlobalImageDrop";
+
const defaultMapActions = {
mapDrawActions: [],
mapDrawActionIndex: -1,
@@ -457,7 +459,7 @@ function NetworkedMapAndTokens({ session }) {
}
return (
- <>
+
- >
+
);
}
diff --git a/src/routes/Game.js b/src/routes/Game.js
index 113ffae..2e06da5 100644
--- a/src/routes/Game.js
+++ b/src/routes/Game.js
@@ -8,7 +8,6 @@ import OfflineBanner from "../components/banner/OfflineBanner";
import LoadingOverlay from "../components/LoadingOverlay";
import Link from "../components/Link";
import MapLoadingOverlay from "../components/map/MapLoadingOverlay";
-import GlobalImageDrop from "../components/file/GlobalImageDrop";
import AuthModal from "../modals/AuthModal";
import GameExpiredModal from "../modals/GameExpiredModal";
@@ -115,18 +114,16 @@ function Game() {
-
-
-
-
-
-
+
+
+
+
setPeerError(null)}