diff --git a/package.json b/package.json index 6d519c6..0c36aed 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "react": "^16.13.1", "react-dom": "^16.13.1", "react-helmet": "^6.0.0", + "react-router-dom": "^5.1.2", "react-scripts": "3.4.1", "react-transition-group": "^4.3.0", "use-http": "^1.0.10" diff --git a/src/app/App.js b/src/app/App.js index b6b5b98..dbac302 100644 --- a/src/app/App.js +++ b/src/app/App.js @@ -1,9 +1,11 @@ import React from "react"; +import ApolloClient from "apollo-boost"; import { ApolloProvider } from "@apollo/react-hooks"; import { CSSReset, ThemeProvider, theme } from "@chakra-ui/core"; -import WardrobePage from "./WardrobePage"; +import { BrowserRouter as Router, Switch, Route } from "react-router-dom"; -import ApolloClient from "apollo-boost"; +import HomePage from "./HomePage"; +import WardrobePage from "./WardrobePage"; /** * client is the global Apollo Client instance we use for GraphQL queries. This @@ -40,12 +42,21 @@ const client = new ApolloClient({ */ function App() { return ( - - - - - - + + + + + + + + + + + + + + + ); } diff --git a/src/app/HomePage.js b/src/app/HomePage.js new file mode 100644 index 0000000..64a4406 --- /dev/null +++ b/src/app/HomePage.js @@ -0,0 +1,87 @@ +import React from "react"; +import { Box, Flex, Button, Tooltip } from "@chakra-ui/core"; +import { useHistory } from "react-router-dom"; + +import { Heading1 } from "./util"; + +import HomepageSplashImg from "../images/homepage-splash.png"; +import SpeciesColorPicker from "./SpeciesColorPicker"; + +function HomePage() { + return ( + + + + + Dress to Impress + + + + ); +} + +function StartOutfitForm() { + const history = useHistory(); + + const [speciesId, setSpeciesId] = React.useState("1"); + const [colorId, setColorId] = React.useState("8"); + const [isValid, setIsValid] = React.useState(true); + + const onSubmit = () => { + if (!isValid) { + return; + } + + const params = new URLSearchParams({ + species: speciesId, + color: colorId, + }); + + history.push(`/outfits/new?${params}`); + }; + + return ( +
+ + { + setSpeciesId(species.id); + setColorId(color.id); + setIsValid(isValid); + }} + /> + + instance. Instead, we set the max delay >< + showDelay={isValid && 2147483647} + > + + + +
+ ); +} + +export default HomePage; diff --git a/src/app/ItemsPanel.js b/src/app/ItemsPanel.js index 119f3bc..1b850cf 100644 --- a/src/app/ItemsPanel.js +++ b/src/app/ItemsPanel.js @@ -157,7 +157,7 @@ function OutfitHeading({ outfitState, dispatchToOutfit }) { dispatchToOutfit({ type: "rename", outfitName: value }) } diff --git a/src/app/OutfitControls.js b/src/app/OutfitControls.js index ef717f0..0fc1d54 100644 --- a/src/app/OutfitControls.js +++ b/src/app/OutfitControls.js @@ -8,6 +8,7 @@ import { Stack, Tooltip, useClipboard, + useToast, } from "@chakra-ui/core"; import OutfitResetModal from "./OutfitResetModal"; @@ -21,6 +22,7 @@ import useOutfitAppearance from "./useOutfitAppearance"; */ function OutfitControls({ outfitState, dispatchToOutfit }) { const [focusIsLocked, setFocusIsLocked] = React.useState(false); + const toast = useToast(); return ( { + if (isValid) { + dispatchToOutfit({ + type: "setSpeciesAndColor", + speciesId: species.id, + colorId: color.id, + }); + } else { + toast({ + title: `We haven't seen a ${color.name} ${species.name} before! πŸ˜“`, + status: "warning", + }); + } + }} /> diff --git a/src/app/SpeciesColorPicker.js b/src/app/SpeciesColorPicker.js index 6e4c21e..3c27431 100644 --- a/src/app/SpeciesColorPicker.js +++ b/src/app/SpeciesColorPicker.js @@ -2,7 +2,7 @@ import React from "react"; import gql from "graphql-tag"; import useFetch from "use-http"; import { useQuery } from "@apollo/react-hooks"; -import { Box, Flex, Select, Text, useToast } from "@chakra-ui/core"; +import { Box, Flex, Select, Text } from "@chakra-ui/core"; import { Delay } from "./util"; @@ -12,8 +12,13 @@ import { Delay } from "./util"; * It preloads all species, colors, and valid species/color pairs; and then * ensures that the outfit is always in a valid state. */ -function SpeciesColorPicker({ outfitState, dispatchToOutfit }) { - const toast = useToast(); +function SpeciesColorPicker({ + speciesId, + colorId, + showPlaceholders, + dark = false, + onChange, +}) { const { loading: loadingMeta, error: errorMeta, data: meta } = useQuery(gql` query { allSpecies { @@ -42,10 +47,28 @@ function SpeciesColorPicker({ outfitState, dispatchToOutfit }) { const allSpecies = (meta && [...meta.allSpecies]) || []; allSpecies.sort((a, b) => a.name.localeCompare(b.name)); - if (loadingMeta || loadingValids) { + const backgroundColor = dark ? "gray.600" : "white"; + const borderColor = dark ? "transparent" : "green.600"; + const textColor = dark ? "gray.50" : "inherit"; + const SpeciesColorSelect = ({ ...props }) => ( + + {allColors.length === 0 && ( + <> + {/* The default case, and a long name for sizing! */} + + + + )} {allColors.map((color) => ( ))} - + - + ); } diff --git a/src/app/useOutfitState.js b/src/app/useOutfitState.js index 7388b25..6791522 100644 --- a/src/app/useOutfitState.js +++ b/src/app/useOutfitState.js @@ -130,10 +130,12 @@ const outfitStateReducer = (apolloClient) => (baseState, action) => { switch (action.type) { case "rename": return { ...baseState, name: action.outfitName }; - case "changeColor": - return { ...baseState, colorId: action.colorId }; - case "changeSpecies": - return { ...baseState, speciesId: action.speciesId }; + case "setSpeciesAndColor": + return { + ...baseState, + speciesId: action.speciesId, + colorId: action.colorId, + }; case "wearItem": return produce(baseState, (state) => { // A hack to work around https://github.com/immerjs/immer/issues/586 @@ -348,12 +350,13 @@ function buildOutfitUrl(state) { closetedItemIds, } = state; - const params = new URLSearchParams(); - params.append("name", name); - params.append("species", speciesId); - params.append("color", colorId); - params.append("emotion", emotion); - params.append("genderPresentation", genderPresentation); + const params = new URLSearchParams({ + name: name || "", + species: speciesId, + color: colorId, + emotion, + genderPresentation, + }); for (const itemId of wornItemIds) { params.append("objects[]", itemId); } diff --git a/src/images/homepage-splash.png b/src/images/homepage-splash.png new file mode 100644 index 0000000..cba1e78 Binary files /dev/null and b/src/images/homepage-splash.png differ diff --git a/yarn.lock b/yarn.lock index 76d0dd3..bd8b085 100644 --- a/yarn.lock +++ b/yarn.lock @@ -954,6 +954,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.1.2", "@babel/runtime@^7.4.0": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.6.tgz#a9102eb5cadedf3f31d08a9ecf294af7827ea29f" + integrity sha512-64AF1xY3OAkFHqOb9s4jpgk1Mm5vDZ4L3acHvAml+53nO1XbXLuDodsVpO4OIUsmemlUHMxNdYMNJmsvOwLrvQ== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.4": version "7.9.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06" @@ -5801,6 +5808,11 @@ growly@^1.3.0: resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= +gud@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0" + integrity sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw== + gzip-size@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274" @@ -5918,6 +5930,18 @@ hex-color-regex@^1.1.0: resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== +history@^4.9.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" + integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== + dependencies: + "@babel/runtime" "^7.1.2" + loose-envify "^1.2.0" + resolve-pathname "^3.0.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + value-equal "^1.0.1" + hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -5927,7 +5951,7 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^3.3.0: +hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -6630,6 +6654,11 @@ is-wsl@^2.1.1: resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.1.1.tgz#4a1c152d429df3d441669498e2486d3596ebaf1d" integrity sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog== +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -7497,7 +7526,7 @@ long@^4.0.0: resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -7709,6 +7738,15 @@ min-indent@^1.0.0: resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.0.tgz#cfc45c37e9ec0d8f0a0ec3dd4ef7f7c3abe39256" integrity sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY= +mini-create-react-context@^0.3.0: + version "0.3.2" + resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.3.2.tgz#79fc598f283dd623da8e088b05db8cddab250189" + integrity sha512-2v+OeetEyliMt5VHMXsBhABoJ0/M4RCe7fatd/fBy6SMiKazUSEt3gxxypfnk2SHMkdBYvorHRoQxuGoiwbzAw== + dependencies: + "@babel/runtime" "^7.4.0" + gud "^1.0.0" + tiny-warning "^1.0.2" + mini-css-extract-plugin@0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz#47f2cf07aa165ab35733b1fc97d4c46c0564339e" @@ -8527,6 +8565,13 @@ path-to-regexp@0.1.7: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= +path-to-regexp@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" + integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== + dependencies: + isarray "0.0.1" + path-type@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" @@ -9674,11 +9719,40 @@ react-helmet@^6.0.0: react-fast-compare "^2.0.4" react-side-effect "^2.1.0" -react-is@^16.12.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4: +react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-router-dom@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.1.2.tgz#06701b834352f44d37fbb6311f870f84c76b9c18" + integrity sha512-7BPHAaIwWpZS074UKaw1FjVdZBSVWEk8IuDXdB+OkLb8vd/WRQIpA4ag9WQk61aEfQs47wHyjWUoUGGZxpQXew== + dependencies: + "@babel/runtime" "^7.1.2" + history "^4.9.0" + loose-envify "^1.3.1" + prop-types "^15.6.2" + react-router "5.1.2" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + +react-router@5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.1.2.tgz#6ea51d789cb36a6be1ba5f7c0d48dd9e817d3418" + integrity sha512-yjEuMFy1ONK246B+rsa0cUam5OeAQ8pyclRDgpxuSCrAlJ1qN9uZ5IgyKC7gQg0w8OM50NXHEegPh/ks9YuR2A== + dependencies: + "@babel/runtime" "^7.1.2" + history "^4.9.0" + hoist-non-react-statics "^3.1.0" + loose-envify "^1.3.1" + mini-create-react-context "^0.3.0" + path-to-regexp "^1.7.0" + prop-types "^15.6.2" + react-is "^16.6.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + react-scripts@3.4.1: version "3.4.1" resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-3.4.1.tgz#f551298b5c71985cc491b9acf3c8e8c0ae3ada0a" @@ -10067,6 +10141,11 @@ resolve-from@^4.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== +resolve-pathname@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" + integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== + resolve-url-loader@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/resolve-url-loader/-/resolve-url-loader-3.1.1.tgz#28931895fa1eab9be0647d3b2958c100ae3c0bf0" @@ -11136,6 +11215,16 @@ timsort@^0.3.0: resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= +tiny-invariant@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" + integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== + +tiny-warning@^1.0.0, tiny-warning@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" + integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -11549,6 +11638,11 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" +value-equal@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" + integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== + vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"