better handling of missing poses
This commit is contained in:
parent
2300fe4fbe
commit
5ea717c391
2 changed files with 87 additions and 48 deletions
|
@ -25,14 +25,20 @@ function OutfitPreview({ outfitState }) {
|
|||
);
|
||||
}
|
||||
|
||||
return <OutfitLayers loading={loading} visibleLayers={visibleLayers} />;
|
||||
return (
|
||||
<OutfitLayers
|
||||
loading={loading}
|
||||
visibleLayers={visibleLayers}
|
||||
doAnimations
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 }) {
|
||||
export function OutfitLayers({ loading, visibleLayers, doAnimations = false }) {
|
||||
return (
|
||||
<Box pos="relative" height="100%" width="100%">
|
||||
<TransitionGroup>
|
||||
|
@ -41,6 +47,7 @@ export function OutfitLayers({ loading, visibleLayers }) {
|
|||
// happens here, when the layer exits the DOM.
|
||||
<CSSTransition
|
||||
key={layer.id}
|
||||
exit={doAnimations}
|
||||
classNames={css`
|
||||
&-exit {
|
||||
opacity: 1;
|
||||
|
@ -62,14 +69,17 @@ export function OutfitLayers({ loading, visibleLayers }) {
|
|||
// We manage the fade-in and fade-out separately! The fade-in
|
||||
// happens here, when the <Image> finishes preloading and
|
||||
// applies the src to the underlying <img>.
|
||||
className={css`
|
||||
className={
|
||||
doAnimations &&
|
||||
css`
|
||||
opacity: 0.01;
|
||||
|
||||
&[src] {
|
||||
opacity: 1;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
`}
|
||||
`
|
||||
}
|
||||
// This sets up the cache to not need to reload images during
|
||||
// download!
|
||||
// TODO: Re-enable this once we get our change into Chakra
|
||||
|
|
|
@ -46,7 +46,8 @@ function PosePicker({
|
|||
}
|
||||
|
||||
// If there's only one pose anyway, don't bother showing a picker!
|
||||
const numAvailablePoses = Object.values(poses).filter((p) => p).length;
|
||||
const numAvailablePoses = Object.values(poses).filter((p) => p.isAvailable)
|
||||
.length;
|
||||
if (numAvailablePoses <= 1) {
|
||||
return null;
|
||||
}
|
||||
|
@ -206,15 +207,15 @@ const GENDER_PRESENTATION_STRINGS = {
|
|||
|
||||
function PoseButton({ pose, onChange, inputRef }) {
|
||||
const theme = useTheme();
|
||||
|
||||
if (!pose) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const genderPresentationStr =
|
||||
GENDER_PRESENTATION_STRINGS[pose.genderPresentation];
|
||||
const emotionStr = EMOTION_STRINGS[pose.emotion];
|
||||
|
||||
let label = `${emotionStr} and ${genderPresentationStr}`;
|
||||
if (!pose.isAvailable) {
|
||||
label += ` (not modeled yet)`;
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
as="label"
|
||||
|
@ -228,24 +229,28 @@ function PoseButton({ pose, onChange, inputRef }) {
|
|||
<VisuallyHidden
|
||||
as="input"
|
||||
type="radio"
|
||||
aria-label={`${emotionStr} and ${genderPresentationStr}`}
|
||||
aria-label={label}
|
||||
name="pose"
|
||||
value={`${pose.emotion}-${pose.genderPresentation}`}
|
||||
checked={pose.isSelected}
|
||||
disabled={!pose.isAvailable}
|
||||
onChange={onChange}
|
||||
ref={inputRef || null}
|
||||
/>
|
||||
<Box
|
||||
aria-hidden
|
||||
rounded="full"
|
||||
boxShadow="md"
|
||||
overflow="hidden"
|
||||
width="50px"
|
||||
height="50px"
|
||||
title={
|
||||
// A lil debug output, so that we can quickly identify glitched
|
||||
pose.isAvailable
|
||||
? // A lil debug output, so that we can quickly identify glitched
|
||||
// PetStates and manually mark them as glitched!
|
||||
window.location.hostname.includes("localhost") &&
|
||||
`#${pose.petStateId}`
|
||||
: "Not modeled yet"
|
||||
}
|
||||
position="relative"
|
||||
className={css`
|
||||
|
@ -267,10 +272,16 @@ function PoseButton({ pose, onChange, inputRef }) {
|
|||
left="0"
|
||||
right="0"
|
||||
zIndex="2"
|
||||
className={css`
|
||||
className={cx(
|
||||
css`
|
||||
border: 0px solid ${theme.colors.green["600"]};
|
||||
transition: border-width 0.2s;
|
||||
|
||||
&.not-available {
|
||||
border-color: ${theme.colors.gray["500"]};
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
input:checked + * & {
|
||||
border-width: 1px;
|
||||
}
|
||||
|
@ -278,8 +289,11 @@ function PoseButton({ pose, onChange, inputRef }) {
|
|||
input:focus + * & {
|
||||
border-width: 3px;
|
||||
}
|
||||
`}
|
||||
`,
|
||||
!pose.isAvailable && "not-available"
|
||||
)}
|
||||
/>
|
||||
{pose.isAvailable ? (
|
||||
<Box
|
||||
width="50px"
|
||||
height="50px"
|
||||
|
@ -290,6 +304,18 @@ function PoseButton({ pose, onChange, inputRef }) {
|
|||
>
|
||||
<OutfitLayers visibleLayers={getVisibleLayers(pose, [])} />
|
||||
</Box>
|
||||
) : (
|
||||
<Flex align="center" justify="center">
|
||||
<Box
|
||||
fontFamily="Delicious"
|
||||
fontSize="3xl"
|
||||
fontWeight="900"
|
||||
color="gray.600"
|
||||
>
|
||||
?
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
|
@ -320,15 +346,18 @@ function usePoses(outfitState) {
|
|||
);
|
||||
|
||||
const petAppearances = data?.petAppearances || [];
|
||||
const buildPose = (e, gp) => ({
|
||||
...petAppearances.find(
|
||||
const buildPose = (e, gp) => {
|
||||
const appearance = petAppearances.find(
|
||||
(pa) => pa.emotion === e && pa.genderPresentation === gp
|
||||
),
|
||||
);
|
||||
return {
|
||||
...appearance,
|
||||
speciesId,
|
||||
isAvailable: Boolean(appearance),
|
||||
isSelected:
|
||||
outfitState.emotion === e && outfitState.genderPresentation === gp,
|
||||
});
|
||||
console.log(outfitState.emotion, outfitState.genderPresentation, outfitState);
|
||||
};
|
||||
};
|
||||
|
||||
const poses = {
|
||||
happyMasc: buildPose("HAPPY", "MASCULINE"),
|
||||
|
|
Loading…
Reference in a new issue