move emotion / gender presentation to outfit state
This commit is contained in:
parent
fae2a579c2
commit
a064e5b471
3 changed files with 57 additions and 37 deletions
|
@ -83,6 +83,7 @@ function OutfitControls({ outfitState, dispatchToOutfit }) {
|
||||||
<Flex flex="1 1 0" align="center" pl="4">
|
<Flex flex="1 1 0" align="center" pl="4">
|
||||||
<PosePicker
|
<PosePicker
|
||||||
outfitState={outfitState}
|
outfitState={outfitState}
|
||||||
|
dispatchToOutfit={dispatchToOutfit}
|
||||||
onLockFocus={() => setFocusIsLocked(true)}
|
onLockFocus={() => setFocusIsLocked(true)}
|
||||||
onUnlockFocus={() => setFocusIsLocked(false)}
|
onUnlockFocus={() => setFocusIsLocked(false)}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -25,16 +25,15 @@ import twemojiMasc from "../images/twemoji/masc.svg";
|
||||||
import twemojiFem from "../images/twemoji/fem.svg";
|
import twemojiFem from "../images/twemoji/fem.svg";
|
||||||
import { OutfitLayers } from "./OutfitPreview";
|
import { OutfitLayers } from "./OutfitPreview";
|
||||||
|
|
||||||
function PosePicker({ outfitState, onLockFocus, onUnlockFocus }) {
|
function PosePicker({
|
||||||
|
outfitState,
|
||||||
|
dispatchToOutfit,
|
||||||
|
onLockFocus,
|
||||||
|
onUnlockFocus,
|
||||||
|
}) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const { speciesId, colorId } = outfitState;
|
|
||||||
const { loading, error, poses, selectPose } = usePoses({
|
|
||||||
speciesId,
|
|
||||||
colorId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const checkedInputRef = React.useRef();
|
const checkedInputRef = React.useRef();
|
||||||
|
const { loading, error, poses } = usePoses(outfitState);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -52,6 +51,15 @@ function PosePicker({ outfitState, onLockFocus, onUnlockFocus }) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onChange = (e) => {
|
||||||
|
const [emotion, genderPresentation] = e.target.value.split("-");
|
||||||
|
dispatchToOutfit({
|
||||||
|
type: "setPose",
|
||||||
|
emotion,
|
||||||
|
genderPresentation,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover
|
<Popover
|
||||||
placement="bottom-end"
|
placement="bottom-end"
|
||||||
|
@ -95,16 +103,7 @@ function PosePicker({ outfitState, onLockFocus, onUnlockFocus }) {
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent>
|
<PopoverContent>
|
||||||
<Box p="4">
|
<Box p="4">
|
||||||
<table
|
<table width="100%">
|
||||||
width="100%"
|
|
||||||
borderSpacing="8px"
|
|
||||||
onChange={(e) => {
|
|
||||||
const [emotion, genderPresentation] = e.target.value.split(
|
|
||||||
"-"
|
|
||||||
);
|
|
||||||
selectPose({ emotion, genderPresentation });
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th />
|
<th />
|
||||||
|
@ -127,21 +126,21 @@ function PosePicker({ outfitState, onLockFocus, onUnlockFocus }) {
|
||||||
<Cell as="td">
|
<Cell as="td">
|
||||||
<PoseButton
|
<PoseButton
|
||||||
pose={poses.happyMasc}
|
pose={poses.happyMasc}
|
||||||
speciesId={speciesId}
|
onChange={onChange}
|
||||||
inputRef={poses.happyMasc.isSelected && checkedInputRef}
|
inputRef={poses.happyMasc.isSelected && checkedInputRef}
|
||||||
/>
|
/>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell as="td">
|
<Cell as="td">
|
||||||
<PoseButton
|
<PoseButton
|
||||||
pose={poses.sadMasc}
|
pose={poses.sadMasc}
|
||||||
speciesId={speciesId}
|
onChange={onChange}
|
||||||
inputRef={poses.sadMasc.isSelected && checkedInputRef}
|
inputRef={poses.sadMasc.isSelected && checkedInputRef}
|
||||||
/>
|
/>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell as="td">
|
<Cell as="td">
|
||||||
<PoseButton
|
<PoseButton
|
||||||
pose={poses.sickMasc}
|
pose={poses.sickMasc}
|
||||||
speciesId={speciesId}
|
onChange={onChange}
|
||||||
inputRef={poses.sickMasc.isSelected && checkedInputRef}
|
inputRef={poses.sickMasc.isSelected && checkedInputRef}
|
||||||
/>
|
/>
|
||||||
</Cell>
|
</Cell>
|
||||||
|
@ -153,21 +152,21 @@ function PosePicker({ outfitState, onLockFocus, onUnlockFocus }) {
|
||||||
<Cell as="td">
|
<Cell as="td">
|
||||||
<PoseButton
|
<PoseButton
|
||||||
pose={poses.happyFem}
|
pose={poses.happyFem}
|
||||||
speciesId={speciesId}
|
onChange={onChange}
|
||||||
inputRef={poses.happyFem.isSelected && checkedInputRef}
|
inputRef={poses.happyFem.isSelected && checkedInputRef}
|
||||||
/>
|
/>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell as="td">
|
<Cell as="td">
|
||||||
<PoseButton
|
<PoseButton
|
||||||
pose={poses.sadFem}
|
pose={poses.sadFem}
|
||||||
speciesId={speciesId}
|
onChange={onChange}
|
||||||
inputRef={poses.sadFem.isSelected && checkedInputRef}
|
inputRef={poses.sadFem.isSelected && checkedInputRef}
|
||||||
/>
|
/>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell as="td">
|
<Cell as="td">
|
||||||
<PoseButton
|
<PoseButton
|
||||||
pose={poses.sickFem}
|
pose={poses.sickFem}
|
||||||
speciesId={speciesId}
|
onChange={onChange}
|
||||||
inputRef={poses.sickFem.isSelected && checkedInputRef}
|
inputRef={poses.sickFem.isSelected && checkedInputRef}
|
||||||
/>
|
/>
|
||||||
</Cell>
|
</Cell>
|
||||||
|
@ -205,7 +204,7 @@ const GENDER_PRESENTATION_STRINGS = {
|
||||||
FEMININE: "Feminine",
|
FEMININE: "Feminine",
|
||||||
};
|
};
|
||||||
|
|
||||||
function PoseButton({ pose, speciesId, inputRef }) {
|
function PoseButton({ pose, onChange, inputRef }) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
if (!pose) {
|
if (!pose) {
|
||||||
|
@ -233,6 +232,7 @@ function PoseButton({ pose, speciesId, inputRef }) {
|
||||||
name="pose"
|
name="pose"
|
||||||
value={`${pose.emotion}-${pose.genderPresentation}`}
|
value={`${pose.emotion}-${pose.genderPresentation}`}
|
||||||
checked={pose.isSelected}
|
checked={pose.isSelected}
|
||||||
|
onChange={onChange}
|
||||||
ref={inputRef || null}
|
ref={inputRef || null}
|
||||||
/>
|
/>
|
||||||
<Box
|
<Box
|
||||||
|
@ -279,7 +279,8 @@ function PoseButton({ pose, speciesId, inputRef }) {
|
||||||
width="50px"
|
width="50px"
|
||||||
height="50px"
|
height="50px"
|
||||||
transform={
|
transform={
|
||||||
transformsBySpeciesId[speciesId] || transformsBySpeciesId.default
|
transformsBySpeciesId[pose.speciesId] ||
|
||||||
|
transformsBySpeciesId.default
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<OutfitLayers visibleLayers={getVisibleLayers(pose, [])} />
|
<OutfitLayers visibleLayers={getVisibleLayers(pose, [])} />
|
||||||
|
@ -293,11 +294,8 @@ function EmojiImage({ src, "aria-label": ariaLabel }) {
|
||||||
return <Image src={src} aria-label={ariaLabel} width="16px" height="16px" />;
|
return <Image src={src} aria-label={ariaLabel} width="16px" height="16px" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function usePoses({ speciesId, colorId }) {
|
function usePoses(outfitState) {
|
||||||
const [selectedPose, selectPose] = React.useState({
|
const { speciesId, colorId, emotion, genderPresentation } = outfitState;
|
||||||
emotion: "HAPPY",
|
|
||||||
genderPresentation: "FEMININE",
|
|
||||||
});
|
|
||||||
|
|
||||||
const { loading, error, data } = useQuery(
|
const { loading, error, data } = useQuery(
|
||||||
gql`
|
gql`
|
||||||
|
@ -320,9 +318,11 @@ function usePoses({ speciesId, colorId }) {
|
||||||
...petAppearances.find(
|
...petAppearances.find(
|
||||||
(pa) => pa.emotion === e && pa.genderPresentation === gp
|
(pa) => pa.emotion === e && pa.genderPresentation === gp
|
||||||
),
|
),
|
||||||
|
speciesId,
|
||||||
isSelected:
|
isSelected:
|
||||||
selectedPose.emotion === e && selectedPose.genderPresentation === gp,
|
outfitState.emotion === e && outfitState.genderPresentation === gp,
|
||||||
});
|
});
|
||||||
|
console.log(outfitState.emotion, outfitState.genderPresentation, outfitState);
|
||||||
|
|
||||||
const poses = {
|
const poses = {
|
||||||
happyMasc: buildPose("HAPPY", "MASCULINE"),
|
happyMasc: buildPose("HAPPY", "MASCULINE"),
|
||||||
|
@ -333,7 +333,7 @@ function usePoses({ speciesId, colorId }) {
|
||||||
sickFem: buildPose("SICK", "FEMININE"),
|
sickFem: buildPose("SICK", "FEMININE"),
|
||||||
};
|
};
|
||||||
|
|
||||||
return { loading, error, poses, selectPose };
|
return { loading, error, poses };
|
||||||
}
|
}
|
||||||
|
|
||||||
const transformsBySpeciesId = {
|
const transformsBySpeciesId = {
|
||||||
|
|
|
@ -30,12 +30,14 @@ function useOutfitState() {
|
||||||
"74546",
|
"74546",
|
||||||
"57997",
|
"57997",
|
||||||
]),
|
]),
|
||||||
speciesId: "24", // Starry
|
speciesId: "24",
|
||||||
colorId: "62", // Zafara
|
colorId: "62",
|
||||||
|
emotion: "HAPPY",
|
||||||
|
genderPresentation: "FEMININE",
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const { name, speciesId, colorId } = state;
|
const { name, speciesId, colorId, emotion, genderPresentation } = state;
|
||||||
|
|
||||||
// It's more convenient to manage these as a Set in state, but most callers
|
// It's more convenient to manage these as a Set in state, but most callers
|
||||||
// will find it more convenient to access them as arrays! e.g. for `.map()`
|
// will find it more convenient to access them as arrays! e.g. for `.map()`
|
||||||
|
@ -94,6 +96,8 @@ function useOutfitState() {
|
||||||
allItemIds,
|
allItemIds,
|
||||||
speciesId,
|
speciesId,
|
||||||
colorId,
|
colorId,
|
||||||
|
emotion,
|
||||||
|
genderPresentation,
|
||||||
url,
|
url,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -106,6 +110,8 @@ function useOutfitState() {
|
||||||
name: urlParams.get("name"),
|
name: urlParams.get("name"),
|
||||||
speciesId: urlParams.get("species"),
|
speciesId: urlParams.get("species"),
|
||||||
colorId: urlParams.get("color"),
|
colorId: urlParams.get("color"),
|
||||||
|
emotion: urlParams.get("emotion"),
|
||||||
|
genderPresentation: urlParams.get("genderPresentation"),
|
||||||
wornItemIds: urlParams.getAll("objects[]"),
|
wornItemIds: urlParams.getAll("objects[]"),
|
||||||
closetedItemIds: urlParams.getAll("closet[]"),
|
closetedItemIds: urlParams.getAll("closet[]"),
|
||||||
});
|
});
|
||||||
|
@ -176,6 +182,9 @@ const outfitStateReducer = (apolloClient) => (baseState, action) => {
|
||||||
wornItemIds.delete(itemId);
|
wornItemIds.delete(itemId);
|
||||||
closetedItemIds.delete(itemId);
|
closetedItemIds.delete(itemId);
|
||||||
});
|
});
|
||||||
|
case "setPose":
|
||||||
|
const { emotion, genderPresentation } = action;
|
||||||
|
return { ...baseState, emotion, genderPresentation };
|
||||||
case "reset":
|
case "reset":
|
||||||
const { name, speciesId, colorId, wornItemIds, closetedItemIds } = action;
|
const { name, speciesId, colorId, wornItemIds, closetedItemIds } = action;
|
||||||
return {
|
return {
|
||||||
|
@ -315,12 +324,22 @@ function getZonesAndItems(itemsById, wornItemIds, closetedItemIds) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildOutfitUrl(state) {
|
function buildOutfitUrl(state) {
|
||||||
const { name, speciesId, colorId, wornItemIds, closetedItemIds } = state;
|
const {
|
||||||
|
name,
|
||||||
|
speciesId,
|
||||||
|
colorId,
|
||||||
|
emotion,
|
||||||
|
genderPresentation,
|
||||||
|
wornItemIds,
|
||||||
|
closetedItemIds,
|
||||||
|
} = state;
|
||||||
|
|
||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
params.append("name", name);
|
params.append("name", name);
|
||||||
params.append("species", speciesId);
|
params.append("species", speciesId);
|
||||||
params.append("color", colorId);
|
params.append("color", colorId);
|
||||||
|
params.append("emotion", emotion);
|
||||||
|
params.append("genderPresentation", genderPresentation);
|
||||||
for (const itemId of wornItemIds) {
|
for (const itemId of wornItemIds) {
|
||||||
params.append("objects[]", itemId);
|
params.append("objects[]", itemId);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue