WIP pose picker support

This commit is contained in:
Emi Matchu 2020-08-26 18:43:54 -07:00
parent 5334801aba
commit 10a6eff299
5 changed files with 195 additions and 85 deletions

View file

@ -15,12 +15,14 @@ import {
useColorModeValue, useColorModeValue,
useTheme, useTheme,
} from "@chakra-ui/core"; } from "@chakra-ui/core";
import loadable from "@loadable/component";
import { import {
getVisibleLayers, getVisibleLayers,
petAppearanceFragment, petAppearanceFragment,
} from "../components/useOutfitAppearance"; } from "../components/useOutfitAppearance";
import { OutfitLayers } from "../components/OutfitPreview"; import { OutfitLayers } from "../components/OutfitPreview";
import SupportOnly from "./support/SupportOnly";
// From https://twemoji.twitter.com/, thank you! // From https://twemoji.twitter.com/, thank you!
import twemojiSmile from "../../images/twemoji/smile.svg"; import twemojiSmile from "../../images/twemoji/smile.svg";
@ -29,6 +31,12 @@ import twemojiSick from "../../images/twemoji/sick.svg";
import twemojiMasc from "../../images/twemoji/masc.svg"; import twemojiMasc from "../../images/twemoji/masc.svg";
import twemojiFem from "../../images/twemoji/fem.svg"; import twemojiFem from "../../images/twemoji/fem.svg";
const PosePickerSupport = loadable(() => import("./support/PosePickerSupport"));
const PosePickerSupportSwitch = loadable(() =>
import("./support/PosePickerSupport").then((m) => m.PosePickerSupportSwitch)
);
/** /**
* PosePicker shows the pet poses available on the current species/color, and * PosePicker shows the pet poses available on the current species/color, and
* lets the user choose which want they want! * lets the user choose which want they want!
@ -53,6 +61,7 @@ function PosePicker({
const theme = useTheme(); const theme = useTheme();
const checkedInputRef = React.useRef(); const checkedInputRef = React.useRef();
const { loading, error, poseInfos } = usePoses(speciesId, colorId, pose); const { loading, error, poseInfos } = usePoses(speciesId, colorId, pose);
const [isInSupportMode, setIsInSupportMode] = React.useState(false);
if (loading) { if (loading) {
return null; return null;
@ -127,7 +136,40 @@ function PosePicker({
</PopoverTrigger> </PopoverTrigger>
<Portal> <Portal>
<PopoverContent> <PopoverContent>
<Box p="4"> <Box p="4" position="relative">
{isInSupportMode ? (
<PosePickerSupport
speciesId={speciesId}
colorId={colorId}
onChange={onChange}
/>
) : (
<PosePickerTable
poseInfos={poseInfos}
onChange={onChange}
checkedInputRef={checkedInputRef}
/>
)}
<SupportOnly>
<Box position="absolute" top="5" left="3">
<PosePickerSupportSwitch
isChecked={isInSupportMode}
onChange={(e) => setIsInSupportMode(e.target.checked)}
/>
</Box>
</SupportOnly>
</Box>
<PopoverArrow />
</PopoverContent>
</Portal>
</>
)}
</Popover>
);
}
function PosePickerTable({ poseInfos, onChange, checkedInputRef }) {
return (
<table width="100%"> <table width="100%">
<thead> <thead>
<tr> <tr>
@ -152,27 +194,21 @@ function PosePicker({
<PoseOption <PoseOption
poseInfo={poseInfos.happyMasc} poseInfo={poseInfos.happyMasc}
onChange={onChange} onChange={onChange}
inputRef={ inputRef={poseInfos.happyMasc.isSelected && checkedInputRef}
poseInfos.happyMasc.isSelected && checkedInputRef
}
/> />
</Cell> </Cell>
<Cell as="td"> <Cell as="td">
<PoseOption <PoseOption
poseInfo={poseInfos.sadMasc} poseInfo={poseInfos.sadMasc}
onChange={onChange} onChange={onChange}
inputRef={ inputRef={poseInfos.sadMasc.isSelected && checkedInputRef}
poseInfos.sadMasc.isSelected && checkedInputRef
}
/> />
</Cell> </Cell>
<Cell as="td"> <Cell as="td">
<PoseOption <PoseOption
poseInfo={poseInfos.sickMasc} poseInfo={poseInfos.sickMasc}
onChange={onChange} onChange={onChange}
inputRef={ inputRef={poseInfos.sickMasc.isSelected && checkedInputRef}
poseInfos.sickMasc.isSelected && checkedInputRef
}
/> />
</Cell> </Cell>
</tr> </tr>
@ -184,39 +220,26 @@ function PosePicker({
<PoseOption <PoseOption
poseInfo={poseInfos.happyFem} poseInfo={poseInfos.happyFem}
onChange={onChange} onChange={onChange}
inputRef={ inputRef={poseInfos.happyFem.isSelected && checkedInputRef}
poseInfos.happyFem.isSelected && checkedInputRef
}
/> />
</Cell> </Cell>
<Cell as="td"> <Cell as="td">
<PoseOption <PoseOption
poseInfo={poseInfos.sadFem} poseInfo={poseInfos.sadFem}
onChange={onChange} onChange={onChange}
inputRef={ inputRef={poseInfos.sadFem.isSelected && checkedInputRef}
poseInfos.sadFem.isSelected && checkedInputRef
}
/> />
</Cell> </Cell>
<Cell as="td"> <Cell as="td">
<PoseOption <PoseOption
poseInfo={poseInfos.sickFem} poseInfo={poseInfos.sickFem}
onChange={onChange} onChange={onChange}
inputRef={ inputRef={poseInfos.sickFem.isSelected && checkedInputRef}
poseInfos.sickFem.isSelected && checkedInputRef
}
/> />
</Cell> </Cell>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</Box>
<PopoverArrow />
</PopoverContent>
</Portal>
</>
)}
</Popover>
); );
} }

View file

@ -0,0 +1,87 @@
import React from "react";
import gql from "graphql-tag";
import { useQuery } from "@apollo/client";
import { Box, Select, Switch } from "@chakra-ui/core";
import { petAppearanceFragment } from "../../components/useOutfitAppearance";
import HangerSpinner from "../../components/HangerSpinner";
function PosePickerSupport({ speciesId, colorId }) {
const { loading, error, data } = useQuery(
gql`
query PosePickerSupport($speciesId: ID!, $colorId: ID!) {
petAppearances(speciesId: $speciesId, colorId: $colorId) {
id
petStateId
bodyId
pose
...PetAppearanceForOutfitPreview
}
}
${petAppearanceFragment}
`,
{ variables: { speciesId, colorId } }
);
if (loading) {
return (
<Box display="flex" justifyContent="center">
<HangerSpinner boxSize="32px" />
</Box>
);
}
if (error) {
return (
<Box color="red.400" marginTop="8">
{error.message}
</Box>
);
}
return (
<Box>
<Box display="flex" justifyContent="flex-end">
<Select size="sm" width="auto">
{data.petAppearances.map((pa) => (
<option key={pa.petStateId}>
{POSE_NAMES[pa.pose]} ({pa.petStateId})
</option>
))}
</Select>
</Box>
</Box>
);
}
export function PosePickerSupportSwitch({ isChecked, onChange }) {
return (
<Box as="label" display="flex" flexDirection="row" alignItems="center">
<Box fontSize="sm">
<span role="img" aria-label="Support">
💖
</span>
</Box>
<Switch
colorScheme="pink"
marginLeft="1"
size="sm"
isChecked={isChecked}
onChange={onChange}
/>
</Box>
);
}
const POSE_NAMES = {
HAPPY_MASC: "Happy Masc",
SAD_MASC: "Sad Masc",
SICK_MASC: "Sick Masc",
HAPPY_FEM: "Happy Fem",
SAD_FEM: "Sad Fem",
SICK_FEM: "Sick Fem",
UNCONVERTED: "Unconverted",
UNKNOWN: "Unknown",
};
export default PosePickerSupport;

View file

@ -81,6 +81,7 @@ function HangerSpinner(props) {
animation: 1.6s infinite fade-pulse; animation: 1.6s infinite fade-pulse;
} }
`} `}
{...props}
> >
<HangerIcon color="green.300" {...props} /> <HangerIcon color="green.300" {...props} />
</Box> </Box>

View file

@ -587,7 +587,6 @@ const resolvers = {
colorId, colorId,
}); });
const petStates = await petStatesForPetTypeLoader.load(petType.id); const petStates = await petStatesForPetTypeLoader.load(petType.id);
petStates.sort((a, b) => a.id - b.id);
return petStates.map((petState) => ({ id: petState.id })); return petStates.map((petState) => ({ id: petState.id }));
}, },
outfit: (_, { id }) => ({ id }), outfit: (_, { id }) => ({ id }),

View file

@ -355,7 +355,7 @@ const buildPetStatesForPetTypeLoader = (db, loaders) =>
const [rows, _] = await db.execute( const [rows, _] = await db.execute(
`SELECT * FROM pet_states `SELECT * FROM pet_states
WHERE pet_type_id IN (${qs}) AND glitched = 0 WHERE pet_type_id IN (${qs}) AND glitched = 0
ORDER BY (mood_id = 1) DESC`, ORDER BY (mood_id = 1) DESC, id`,
petTypeIds petTypeIds
); );