diff --git a/dev-todos.txt b/dev-todos.txt
index 5e18a98..33f3e64 100644
--- a/dev-todos.txt
+++ b/dev-todos.txt
@@ -1,3 +1,4 @@
* Use accessible click targets for item lists! Honestly, can they be checkboxes?
* Pagination for search queries, right now we LIMIT 30
* Search needs to restrict by fit!
+* Undo the local linking we did for @chakra-ui/core, react, and react-dom on Matchu's machine 😅
diff --git a/src/OutfitPreview.js b/src/OutfitPreview.js
index bfef3de..b3c637a 100644
--- a/src/OutfitPreview.js
+++ b/src/OutfitPreview.js
@@ -2,7 +2,17 @@ import React from "react";
import { CSSTransition, TransitionGroup } from "react-transition-group";
import gql from "graphql-tag";
import { useQuery } from "@apollo/react-hooks";
-import { Flex, Image, Spinner, Text, Icon, Box } from "@chakra-ui/core";
+import {
+ Box,
+ Flex,
+ Icon,
+ IconButton,
+ Image,
+ PseudoBox,
+ Spinner,
+ Text,
+ Tooltip,
+} from "@chakra-ui/core";
import { Delay } from "./util";
@@ -49,6 +59,11 @@ function OutfitPreview({ outfitState }) {
}
);
+ const visibleLayers = getVisibleLayers(data);
+ const [downloadImageUrl, prepareDownload] = useDownloadableImage(
+ visibleLayers
+ );
+
if (error) {
return (
@@ -62,9 +77,9 @@ function OutfitPreview({ outfitState }) {
}
return (
-
+
- {getVisibleLayers(data).map((layer) => (
+ {visibleLayers.map((layer) => (
@@ -101,7 +118,39 @@ function OutfitPreview({ outfitState }) {
)}
-
+
+
+
+
);
}
@@ -152,4 +201,49 @@ function FullScreenCenter({ children }) {
);
}
+function useDownloadableImage(visibleLayers) {
+ const [downloadImageUrl, setDownloadImageUrl] = React.useState(null);
+ const [preparedForLayerIds, setPreparedForLayerIds] = React.useState([]);
+
+ const prepareDownload = React.useCallback(async () => {
+ // Skip if the current image URL is already correct for these layers.
+ const layerIds = visibleLayers.map((l) => l.id);
+ if (layerIds.join(",") === preparedForLayerIds.join(",")) {
+ return;
+ }
+
+ const imagePromises = visibleLayers.map(
+ (layer) =>
+ new Promise((resolve, reject) => {
+ const image = new window.Image();
+ image.crossOrigin = "Anonymous"; // Requires S3 CORS config!
+ image.addEventListener("load", () => resolve(image), false);
+ image.addEventListener("error", (e) => reject(e), false);
+ image.src = layer.imageUrl;
+ })
+ );
+
+ const images = await Promise.all(imagePromises);
+
+ const canvas = document.createElement("canvas");
+ const context = canvas.getContext("2d");
+ canvas.width = 600;
+ canvas.height = 600;
+
+ for (const image of images) {
+ context.drawImage(image, 0, 0);
+ }
+
+ console.log(
+ "Generated image for download",
+ layerIds,
+ canvas.toDataURL("image/png")
+ );
+ setDownloadImageUrl(canvas.toDataURL("image/png"));
+ setPreparedForLayerIds(layerIds);
+ }, [preparedForLayerIds, visibleLayers]);
+
+ return [downloadImageUrl, prepareDownload];
+}
+
export default OutfitPreview;
diff --git a/yarn.lock b/yarn.lock
index 2e57e44..ecc790b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5403,9 +5403,9 @@ flush-write-stream@^1.0.0:
readable-stream "^2.3.6"
focus-lock@^0.6.7:
- version "0.6.7"
- resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.6.7.tgz#65e298f2ba2a3372ab57a4e4c4bdc19e1e32a4e5"
- integrity sha512-KRo93U/afEqt7w5tBm4t0FHf/Li8tEYav3n4GUiZdeRlRfrtMbL8yQg0xRVnY/kmBRmQ4xkqIlbaMvuqlu53kg==
+ version "0.6.8"
+ resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.6.8.tgz#61985fadfa92f02f2ee1d90bc738efaf7f3c9f46"
+ integrity sha512-vkHTluRCoq9FcsrldC0ulQHiyBYgVJB2CX53I8r0nTC6KnEij7Of0jpBspjt3/CuNb6fyoj3aOh9J2HgQUM0og==
follow-redirects@^1.0.0:
version "1.10.0"