WIP pose picker support
This commit is contained in:
parent
5334801aba
commit
10a6eff299
5 changed files with 195 additions and 85 deletions
|
@ -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,89 +136,28 @@ function PosePicker({
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<Portal>
|
<Portal>
|
||||||
<PopoverContent>
|
<PopoverContent>
|
||||||
<Box p="4">
|
<Box p="4" position="relative">
|
||||||
<table width="100%">
|
{isInSupportMode ? (
|
||||||
<thead>
|
<PosePickerSupport
|
||||||
<tr>
|
speciesId={speciesId}
|
||||||
<th />
|
colorId={colorId}
|
||||||
<Cell as="th">
|
onChange={onChange}
|
||||||
<EmojiImage src={twemojiSmile} alt="Happy" />
|
/>
|
||||||
</Cell>
|
) : (
|
||||||
<Cell as="th">
|
<PosePickerTable
|
||||||
<EmojiImage src={twemojiCry} alt="Sad" />
|
poseInfos={poseInfos}
|
||||||
</Cell>
|
onChange={onChange}
|
||||||
<Cell as="th">
|
checkedInputRef={checkedInputRef}
|
||||||
<EmojiImage src={twemojiSick} alt="Sick" />
|
/>
|
||||||
</Cell>
|
)}
|
||||||
</tr>
|
<SupportOnly>
|
||||||
</thead>
|
<Box position="absolute" top="5" left="3">
|
||||||
<tbody>
|
<PosePickerSupportSwitch
|
||||||
<tr>
|
isChecked={isInSupportMode}
|
||||||
<Cell as="th">
|
onChange={(e) => setIsInSupportMode(e.target.checked)}
|
||||||
<EmojiImage src={twemojiMasc} alt="Masculine" />
|
/>
|
||||||
</Cell>
|
</Box>
|
||||||
<Cell as="td">
|
</SupportOnly>
|
||||||
<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>
|
</Box>
|
||||||
<PopoverArrow />
|
<PopoverArrow />
|
||||||
</PopoverContent>
|
</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 }) {
|
function Cell({ children, as }) {
|
||||||
const Tag = as;
|
const Tag = as;
|
||||||
return (
|
return (
|
||||||
|
|
87
src/app/WardrobePage/support/PosePickerSupport.js
Normal file
87
src/app/WardrobePage/support/PosePickerSupport.js
Normal 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;
|
|
@ -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>
|
||||||
|
|
|
@ -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 }),
|
||||||
|
|
|
@ -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
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue