show a preview of color/species on the homepage
Using the newly extracted OutfitPreview! I'm really happy with how this turned out :3 It also makes the pageload after clicking Start super smooth, no spinner! Thanks Apollo cache!!
This commit is contained in:
parent
9164d89240
commit
5a9d2f6566
3 changed files with 72 additions and 11 deletions
|
@ -6,6 +6,7 @@ import { useHistory } from "react-router-dom";
|
|||
import { useLazyQuery } from "@apollo/react-hooks";
|
||||
|
||||
import { Heading1, usePageTitle } from "./util";
|
||||
import OutfitPreview from "./components/OutfitPreview";
|
||||
|
||||
import HomepageSplashImg from "../images/homepage-splash.png";
|
||||
import HomepageSplashImg2x from "../images/homepage-splash@2x.png";
|
||||
|
@ -14,6 +15,8 @@ import SpeciesColorPicker from "./components/SpeciesColorPicker";
|
|||
function HomePage() {
|
||||
usePageTitle("Dress to Impress");
|
||||
|
||||
const [previewState, setPreviewState] = React.useState(null);
|
||||
|
||||
return (
|
||||
<Flex
|
||||
color="green.800"
|
||||
|
@ -24,19 +27,31 @@ function HomePage() {
|
|||
>
|
||||
<Box height="8" />
|
||||
<Box
|
||||
as="img"
|
||||
src={HomepageSplashImg}
|
||||
srcSet={`${HomepageSplashImg} 1x, ${HomepageSplashImg2x} 2x`}
|
||||
alt=""
|
||||
width="200px"
|
||||
height="200px"
|
||||
borderRadius="lg"
|
||||
boxShadow="md"
|
||||
/>
|
||||
overflow="hidden"
|
||||
>
|
||||
<OutfitPreview
|
||||
speciesId={previewState?.speciesId}
|
||||
colorId={previewState?.colorId}
|
||||
pose={previewState?.pose}
|
||||
wornItemIds={[]}
|
||||
placeholder={
|
||||
<Box
|
||||
as="img"
|
||||
src={HomepageSplashImg}
|
||||
srcSet={`${HomepageSplashImg} 1x, ${HomepageSplashImg2x} 2x`}
|
||||
alt=""
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
<Box height="4" />
|
||||
<Heading1>Dress to Impress</Heading1>
|
||||
<Box height="8" />
|
||||
<StartOutfitForm />
|
||||
<StartOutfitForm onChange={setPreviewState} />
|
||||
<Box height="4" />
|
||||
<Box fontStyle="italic" fontSize="sm">
|
||||
or
|
||||
|
@ -47,7 +62,7 @@ function HomePage() {
|
|||
);
|
||||
}
|
||||
|
||||
function StartOutfitForm() {
|
||||
function StartOutfitForm({ onChange }) {
|
||||
const history = useHistory();
|
||||
|
||||
const idealPose = React.useMemo(
|
||||
|
@ -89,6 +104,14 @@ function StartOutfitForm() {
|
|||
setColorId(color.id);
|
||||
setIsValid(isValid);
|
||||
setClosestPose(closestPose);
|
||||
|
||||
if (isValid) {
|
||||
onChange({
|
||||
speciesId: species.id,
|
||||
colorId: color.id,
|
||||
pose: closestPose,
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Box width="4" />
|
||||
|
|
|
@ -12,10 +12,16 @@ import useOutfitAppearance from "./useOutfitAppearance";
|
|||
* fetches the appearance data for it, and preloads and renders the layers
|
||||
* together.
|
||||
*
|
||||
* If the species/color/pose fields are null and a `placeholder` node is
|
||||
* provided instead, we'll render the placeholder. And then, once those props
|
||||
* become non-null, we'll keep showing the placeholder below the loading
|
||||
* overlay until loading completes. (We use this on the homepage to show the
|
||||
* beach splash until outfit data arrives!)
|
||||
*
|
||||
* TODO: There's some duplicate work happening in useOutfitAppearance and
|
||||
* useOutfitState both getting appearance data on first load...
|
||||
*/
|
||||
function OutfitPreview({ speciesId, colorId, pose, wornItemIds }) {
|
||||
function OutfitPreview({ speciesId, colorId, pose, wornItemIds, placeholder }) {
|
||||
const { loading, error, visibleLayers } = useOutfitAppearance({
|
||||
speciesId,
|
||||
colorId,
|
||||
|
@ -43,6 +49,7 @@ function OutfitPreview({ speciesId, colorId, pose, wornItemIds }) {
|
|||
<OutfitLayers
|
||||
loading={loading || loading2}
|
||||
visibleLayers={loadedLayers}
|
||||
placeholder={placeholder}
|
||||
doAnimations
|
||||
/>
|
||||
);
|
||||
|
@ -52,9 +59,34 @@ function OutfitPreview({ speciesId, colorId, pose, wornItemIds }) {
|
|||
* OutfitLayers is the raw UI component for rendering outfit layers. It's
|
||||
* used both in the main outfit preview, and in other minor UIs!
|
||||
*/
|
||||
export function OutfitLayers({ loading, visibleLayers, doAnimations = false }) {
|
||||
export function OutfitLayers({
|
||||
loading,
|
||||
visibleLayers,
|
||||
placeholder,
|
||||
doAnimations = false,
|
||||
}) {
|
||||
const [isMounted, setIsMounted] = React.useState(false);
|
||||
React.useEffect(() => {
|
||||
setTimeout(() => setIsMounted(true), 0);
|
||||
}, []);
|
||||
|
||||
console.log("opacity", isMounted && loading ? 1 : 0);
|
||||
console.log("transition delay", loading ? "0.5s" : "0s");
|
||||
|
||||
return (
|
||||
<Box pos="relative" height="100%" width="100%">
|
||||
{placeholder && (
|
||||
<FullScreenCenter>
|
||||
<Box
|
||||
// We show the placeholder until there are visible layers, at which
|
||||
// point we fade it out.
|
||||
opacity={visibleLayers.length === 0 ? 1 : 0}
|
||||
transition="opacity 0.2s"
|
||||
>
|
||||
{placeholder}
|
||||
</Box>
|
||||
</FullScreenCenter>
|
||||
)}
|
||||
<TransitionGroup enter={false} exit={doAnimations}>
|
||||
{visibleLayers.map((layer) => (
|
||||
<CSSTransition
|
||||
|
@ -114,8 +146,13 @@ export function OutfitLayers({ loading, visibleLayers, doAnimations = false }) {
|
|||
</TransitionGroup>
|
||||
<Box
|
||||
// This is similar to our Delay util component, but Delay disappears
|
||||
// immediately on load, whereas we want this to fade out smoothly.
|
||||
opacity={loading ? 1 : 0}
|
||||
// immediately on load, whereas we want this to fade out smoothly. We
|
||||
// also delay the fade-in by 0.5s, but don't delay the fade-out at all.
|
||||
//
|
||||
// We also use `isMounted` here to make sure it actually _fades_ in!
|
||||
// (This starts the opacity at 0, then fires an immediate callback to
|
||||
// set it to 1, triggering the transition.)
|
||||
opacity={isMounted && loading ? 1 : 0}
|
||||
transition={`opacity 0.2s ${loading ? "0.5s" : "0s"}`}
|
||||
>
|
||||
<FullScreenCenter>
|
||||
|
|
|
@ -38,6 +38,7 @@ export default function useOutfitAppearance(outfitState) {
|
|||
colorId,
|
||||
pose,
|
||||
},
|
||||
skip: speciesId == null || colorId == null || pose == null,
|
||||
}
|
||||
);
|
||||
|
||||
|
|
Loading…
Reference in a new issue