From 4954d4adcf1dfcf8dcbc54854b1e3d9b3a6396f4 Mon Sep 17 00:00:00 2001 From: Matt Dunn-Rankin Date: Sat, 2 May 2020 15:41:02 -0700 Subject: [PATCH] pose picker foundational UI! --- api/assetProxy.js | 1 + src/app/Item.js | 7 +- src/app/OutfitControls.js | 46 ++++++++---- src/app/PosePicker.js | 147 ++++++++++++++++++++++++++++++++++++++ src/app/util.js | 7 ++ 5 files changed, 191 insertions(+), 17 deletions(-) create mode 100644 src/app/PosePicker.js diff --git a/api/assetProxy.js b/api/assetProxy.js index 5ed22ce..dda53a8 100644 --- a/api/assetProxy.js +++ b/api/assetProxy.js @@ -6,6 +6,7 @@ const streamPipeline = util.promisify(stream.pipeline); const VALID_URL_PATTERNS = [ /^http:\/\/images\.neopets\.com\/items\/[a-zA-Z0-9_ -]+\.gif$/, + /^http:\/\/pets\.neopets\.com\/cp\/[a-z0-9]+\/[0-9]+\/[0-9]+\.png$/, ]; export default async (req, res) => { diff --git a/src/app/Item.js b/src/app/Item.js index 9580f9b..42593bf 100644 --- a/src/app/Item.js +++ b/src/app/Item.js @@ -10,6 +10,8 @@ import { useTheme, } from "@chakra-ui/core"; +import { safeImageUrl } from "./util"; + /** * Item show a basic summary of an item, in the context of the current outfit! * @@ -29,10 +31,7 @@ export function Item({ item, itemNameId, outfitState, dispatchToOutfit }) { return ( - + diff --git a/src/app/OutfitControls.js b/src/app/OutfitControls.js index 5fbd046..8a43915 100644 --- a/src/app/OutfitControls.js +++ b/src/app/OutfitControls.js @@ -1,5 +1,5 @@ import React from "react"; -import { css } from "emotion"; +import { css, cx } from "emotion"; import { Box, Flex, @@ -11,6 +11,7 @@ import { } from "@chakra-ui/core"; import OutfitResetModal from "./OutfitResetModal"; +import PosePicker from "./PosePicker"; import SpeciesColorPicker from "./SpeciesColorPicker"; import useOutfitAppearance from "./useOutfitAppearance"; @@ -19,6 +20,8 @@ import useOutfitAppearance from "./useOutfitAppearance"; * control things like species/color and sharing links! */ function OutfitControls({ outfitState, dispatchToOutfit }) { + const [focusIsLocked, setFocusIsLocked] = React.useState(false); + return ( @@ -62,10 +69,23 @@ function OutfitControls({ outfitState, dispatchToOutfit }) { - + {/** + * We try to center the species/color picker, but the left spacer will + * shrink more than the pose picker container if we run out of space! + */} + + + + + + setFocusIsLocked(true)} + onUnlockFocus={() => setFocusIsLocked(false)} + /> + ); diff --git a/src/app/PosePicker.js b/src/app/PosePicker.js new file mode 100644 index 0000000..1b9bb78 --- /dev/null +++ b/src/app/PosePicker.js @@ -0,0 +1,147 @@ +import React from "react"; +import { css, cx } from "emotion"; +import { + Box, + Button, + Flex, + Image, + Popover, + PopoverArrow, + PopoverContent, + PopoverTrigger, + useTheme, +} from "@chakra-ui/core"; + +import { safeImageUrl } from "./util"; + +function PosePicker({ onLockFocus, onUnlockFocus }) { + const theme = useTheme(); + + return ( + + {({ isOpen }) => ( + <> + + + + + + + + + + + + + + 🙍‍♂️ + + + + + + + + + + + + + + 🙍‍♀️ + + + + + + + + + + + + +
+ + 😊 + + + 😢 + + + 🤒 + +
+
+ +
+ + )} +
+ ); +} + +function PoseCell({ children }) { + return ( + + + {children} + + + ); +} + +function PoseButton({ src }) { + return ( + + + + ); +} + +export default PosePicker; diff --git a/src/app/util.js b/src/app/util.js index 4758829..4c4484a 100644 --- a/src/app/util.js +++ b/src/app/util.js @@ -51,6 +51,13 @@ export function Heading2({ children, ...props }) { ); } +/** + * safeImageUrl returns an HTTPS-safe image URL for Neopets assets! + */ +export function safeImageUrl(url) { + return `/api/assetProxy?url=${encodeURIComponent(url)}`; +} + /** * useDebounce helps make a rapidly-changing value change less! It waits for a * pause in the incoming data before outputting the latest value.