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,
useTheme,
} from "@chakra-ui/core";
import loadable from "@loadable/component";
import {
getVisibleLayers,
petAppearanceFragment,
} from "../components/useOutfitAppearance";
import { OutfitLayers } from "../components/OutfitPreview";
import SupportOnly from "./support/SupportOnly";
// From https://twemoji.twitter.com/, thank you!
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 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
* lets the user choose which want they want!
@ -53,6 +61,7 @@ function PosePicker({
const theme = useTheme();
const checkedInputRef = React.useRef();
const { loading, error, poseInfos } = usePoses(speciesId, colorId, pose);
const [isInSupportMode, setIsInSupportMode] = React.useState(false);
if (loading) {
return null;
@ -127,89 +136,28 @@ function PosePicker({
</PopoverTrigger>
<Portal>
<PopoverContent>
<Box p="4">
<table width="100%">
<thead>
<tr>
<th />
<Cell as="th">
<EmojiImage src={twemojiSmile} alt="Happy" />
</Cell>
<Cell as="th">
<EmojiImage src={twemojiCry} alt="Sad" />
</Cell>
<Cell as="th">
<EmojiImage src={twemojiSick} alt="Sick" />
</Cell>
</tr>
</thead>
<tbody>
<tr>
<Cell as="th">
<EmojiImage src={twemojiMasc} alt="Masculine" />
</Cell>
<Cell as="td">
<PoseOption
poseInfo={poseInfos.happyMasc}
onChange={onChange}
inputRef={
poseInfos.happyMasc.isSelected && checkedInputRef
}
/>
</Cell>
<Cell as="td">
<PoseOption
poseInfo={poseInfos.sadMasc}
onChange={onChange}
inputRef={
poseInfos.sadMasc.isSelected && checkedInputRef
}
/>
</Cell>
<Cell as="td">
<PoseOption
poseInfo={poseInfos.sickMasc}
onChange={onChange}
inputRef={
poseInfos.sickMasc.isSelected && checkedInputRef
}
/>
</Cell>
</tr>
<tr>
<Cell as="th">
<EmojiImage src={twemojiFem} alt="Feminine" />
</Cell>
<Cell as="td">
<PoseOption
poseInfo={poseInfos.happyFem}
onChange={onChange}
inputRef={
poseInfos.happyFem.isSelected && checkedInputRef
}
/>
</Cell>
<Cell as="td">
<PoseOption
poseInfo={poseInfos.sadFem}
onChange={onChange}
inputRef={
poseInfos.sadFem.isSelected && checkedInputRef
}
/>
</Cell>
<Cell as="td">
<PoseOption
poseInfo={poseInfos.sickFem}
onChange={onChange}
inputRef={
poseInfos.sickFem.isSelected && checkedInputRef
}
/>
</Cell>
</tr>
</tbody>
</table>
<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>
@ -220,6 +168,81 @@ function PosePicker({
);
}
function PosePickerTable({ poseInfos, onChange, checkedInputRef }) {
return (
<table width="100%">
<thead>
<tr>
<th />
<Cell as="th">
<EmojiImage src={twemojiSmile} alt="Happy" />
</Cell>
<Cell as="th">
<EmojiImage src={twemojiCry} alt="Sad" />
</Cell>
<Cell as="th">
<EmojiImage src={twemojiSick} alt="Sick" />
</Cell>
</tr>
</thead>
<tbody>
<tr>
<Cell as="th">
<EmojiImage src={twemojiMasc} alt="Masculine" />
</Cell>
<Cell as="td">
<PoseOption
poseInfo={poseInfos.happyMasc}
onChange={onChange}
inputRef={poseInfos.happyMasc.isSelected && checkedInputRef}
/>
</Cell>
<Cell as="td">
<PoseOption
poseInfo={poseInfos.sadMasc}
onChange={onChange}
inputRef={poseInfos.sadMasc.isSelected && checkedInputRef}
/>
</Cell>
<Cell as="td">
<PoseOption
poseInfo={poseInfos.sickMasc}
onChange={onChange}
inputRef={poseInfos.sickMasc.isSelected && checkedInputRef}
/>
</Cell>
</tr>
<tr>
<Cell as="th">
<EmojiImage src={twemojiFem} alt="Feminine" />
</Cell>
<Cell as="td">
<PoseOption
poseInfo={poseInfos.happyFem}
onChange={onChange}
inputRef={poseInfos.happyFem.isSelected && checkedInputRef}
/>
</Cell>
<Cell as="td">
<PoseOption
poseInfo={poseInfos.sadFem}
onChange={onChange}
inputRef={poseInfos.sadFem.isSelected && checkedInputRef}
/>
</Cell>
<Cell as="td">
<PoseOption
poseInfo={poseInfos.sickFem}
onChange={onChange}
inputRef={poseInfos.sickFem.isSelected && checkedInputRef}
/>
</Cell>
</tr>
</tbody>
</table>
);
}
function Cell({ children, as }) {
const Tag = as;
return (

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;
}
`}
{...props}
>
<HangerIcon color="green.300" {...props} />
</Box>

View file

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

View file

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