Refactor item page preview to grid layout
because I wanna add zones to the area below the faces!
This commit is contained in:
parent
67784bd5e3
commit
048fb29c14
1 changed files with 132 additions and 106 deletions
|
@ -20,6 +20,7 @@ import {
|
||||||
WrapItem,
|
WrapItem,
|
||||||
Flex,
|
Flex,
|
||||||
usePrefersReducedMotion,
|
usePrefersReducedMotion,
|
||||||
|
Grid,
|
||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
import {
|
import {
|
||||||
CheckIcon,
|
CheckIcon,
|
||||||
|
@ -681,108 +682,130 @@ function ItemPageOutfitPreview({ itemId }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack
|
<Grid
|
||||||
direction={{ base: "column", md: "row" }}
|
templateAreas={{
|
||||||
align={{ base: "center", md: "flex-start" }}
|
base: `
|
||||||
justify="center"
|
"preview"
|
||||||
spacing="8"
|
"speciesColorPicker"
|
||||||
width="100%"
|
"speciesFacesPicker"
|
||||||
|
"zones"
|
||||||
|
`,
|
||||||
|
md: `
|
||||||
|
"preview speciesFacesPicker"
|
||||||
|
"speciesColorPicker zones"
|
||||||
|
`,
|
||||||
|
}}
|
||||||
|
templateRows={{
|
||||||
|
base: "auto auto 400px auto",
|
||||||
|
md: "400px auto",
|
||||||
|
}}
|
||||||
|
templateColumns={{
|
||||||
|
base: "minmax(min-content, 400px)",
|
||||||
|
md: "minmax(min-content, 400px) fit-content(480px)",
|
||||||
|
}}
|
||||||
|
rowGap="4"
|
||||||
|
columnGap="6"
|
||||||
|
justifyContent="center"
|
||||||
>
|
>
|
||||||
<VStack spacing="3" maxWidth="100%">
|
<AspectRatio
|
||||||
<AspectRatio
|
gridArea="preview"
|
||||||
width="400px"
|
maxWidth="400px"
|
||||||
maxWidth="100%"
|
maxHeight="400px"
|
||||||
ratio="1"
|
ratio="1"
|
||||||
border="1px"
|
border="1px"
|
||||||
borderColor={borderColor}
|
borderColor={borderColor}
|
||||||
transition="border-color 0.2s"
|
transition="border-color 0.2s"
|
||||||
borderRadius="lg"
|
borderRadius="lg"
|
||||||
boxShadow="lg"
|
boxShadow="lg"
|
||||||
overflow="hidden"
|
overflow="hidden"
|
||||||
>
|
>
|
||||||
<Box>
|
<Box>
|
||||||
{petState.isValid && preview}
|
{petState.isValid && preview}
|
||||||
<CustomizeMoreButton
|
<CustomizeMoreButton
|
||||||
speciesId={petState.speciesId}
|
|
||||||
colorId={petState.colorId}
|
|
||||||
pose={petState.pose}
|
|
||||||
itemId={itemId}
|
|
||||||
isDisabled={!petState.isValid}
|
|
||||||
/>
|
|
||||||
{hasAnimations && (
|
|
||||||
<PlayPauseButton
|
|
||||||
isPaused={isPaused}
|
|
||||||
onClick={() => setIsPaused(!isPaused)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</AspectRatio>
|
|
||||||
<Box display="flex" width="100%" alignItems="center">
|
|
||||||
<Box
|
|
||||||
// This box grows at the same rate as the box on the right, so the
|
|
||||||
// middle box will be centered, if there's space!
|
|
||||||
flex="1 0 0"
|
|
||||||
display="flex"
|
|
||||||
justifyContent="center"
|
|
||||||
paddingRight="2"
|
|
||||||
>
|
|
||||||
<HTML5Badge
|
|
||||||
usesHTML5={usesHTML5}
|
|
||||||
// If we're not compatible, act the same as if we're loading:
|
|
||||||
// don't change the badge, but don't show one yet if we don't
|
|
||||||
// have one yet.
|
|
||||||
isLoading={appearance.loading || !isCompatible}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<SpeciesColorPicker
|
|
||||||
speciesId={petState.speciesId}
|
speciesId={petState.speciesId}
|
||||||
colorId={petState.colorId}
|
colorId={petState.colorId}
|
||||||
pose={petState.pose}
|
pose={petState.pose}
|
||||||
idealPose={idealPose}
|
itemId={itemId}
|
||||||
onChange={(species, color, isValid, closestPose) => {
|
isDisabled={!petState.isValid}
|
||||||
setPetStateFromUserAction({
|
|
||||||
speciesId: species.id,
|
|
||||||
colorId: color.id,
|
|
||||||
pose: closestPose,
|
|
||||||
isValid,
|
|
||||||
appearanceId: null,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
speciesIsDisabled={isProbablySpeciesSpecific}
|
|
||||||
size="sm"
|
|
||||||
showPlaceholders
|
|
||||||
/>
|
/>
|
||||||
<Box flex="1 0 0" lineHeight="1" paddingLeft="1">
|
{hasAnimations && (
|
||||||
{
|
<PlayPauseButton
|
||||||
// Wait for us to start _requesting_ the appearance, and _then_
|
isPaused={isPaused}
|
||||||
// for it to load, and _then_ check compatibility.
|
onClick={() => setIsPaused(!isPaused)}
|
||||||
!loadingGQL &&
|
/>
|
||||||
!appearance.loading &&
|
)}
|
||||||
petState.isValid &&
|
|
||||||
!isCompatible && (
|
|
||||||
<Tooltip
|
|
||||||
label={
|
|
||||||
couldProbablyModelMoreData
|
|
||||||
? "Item needs models"
|
|
||||||
: "Not compatible"
|
|
||||||
}
|
|
||||||
placement="top"
|
|
||||||
>
|
|
||||||
<WarningIcon
|
|
||||||
color={errorColor}
|
|
||||||
transition="color 0.2"
|
|
||||||
marginLeft="2"
|
|
||||||
borderRadius="full"
|
|
||||||
tabIndex="0"
|
|
||||||
_focus={{ outline: "none", boxShadow: "outline" }}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</Box>
|
|
||||||
</Box>
|
</Box>
|
||||||
</VStack>
|
</AspectRatio>
|
||||||
<Box maxWidth="460px" paddingTop="2">
|
<Box gridArea="speciesColorPicker" display="flex" alignItems="center">
|
||||||
|
<Box
|
||||||
|
// This box grows at the same rate as the box on the right, so the
|
||||||
|
// middle box will be centered, if there's space!
|
||||||
|
flex="1 0 0"
|
||||||
|
display="flex"
|
||||||
|
justifyContent="center"
|
||||||
|
paddingRight="2"
|
||||||
|
>
|
||||||
|
<HTML5Badge
|
||||||
|
usesHTML5={usesHTML5}
|
||||||
|
// If we're not compatible, act the same as if we're loading:
|
||||||
|
// don't change the badge, but don't show one yet if we don't
|
||||||
|
// have one yet.
|
||||||
|
isLoading={appearance.loading || !isCompatible}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<SpeciesColorPicker
|
||||||
|
speciesId={petState.speciesId}
|
||||||
|
colorId={petState.colorId}
|
||||||
|
pose={petState.pose}
|
||||||
|
idealPose={idealPose}
|
||||||
|
onChange={(species, color, isValid, closestPose) => {
|
||||||
|
setPetStateFromUserAction({
|
||||||
|
speciesId: species.id,
|
||||||
|
colorId: color.id,
|
||||||
|
pose: closestPose,
|
||||||
|
isValid,
|
||||||
|
appearanceId: null,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
speciesIsDisabled={isProbablySpeciesSpecific}
|
||||||
|
size="sm"
|
||||||
|
showPlaceholders
|
||||||
|
/>
|
||||||
|
<Box flex="1 0 0" lineHeight="1" paddingLeft="1">
|
||||||
|
{
|
||||||
|
// Wait for us to start _requesting_ the appearance, and _then_
|
||||||
|
// for it to load, and _then_ check compatibility.
|
||||||
|
!loadingGQL &&
|
||||||
|
!appearance.loading &&
|
||||||
|
petState.isValid &&
|
||||||
|
!isCompatible && (
|
||||||
|
<Tooltip
|
||||||
|
label={
|
||||||
|
couldProbablyModelMoreData
|
||||||
|
? "Item needs models"
|
||||||
|
: "Not compatible"
|
||||||
|
}
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
|
<WarningIcon
|
||||||
|
color={errorColor}
|
||||||
|
transition="color 0.2"
|
||||||
|
marginLeft="2"
|
||||||
|
borderRadius="full"
|
||||||
|
tabIndex="0"
|
||||||
|
_focus={{ outline: "none", boxShadow: "outline" }}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
gridArea="speciesFacesPicker"
|
||||||
|
paddingTop="2"
|
||||||
|
overflow="auto"
|
||||||
|
padding="8px"
|
||||||
|
>
|
||||||
<SpeciesFacesPicker
|
<SpeciesFacesPicker
|
||||||
selectedSpeciesId={petState.speciesId}
|
selectedSpeciesId={petState.speciesId}
|
||||||
selectedColorId={petState.colorId}
|
selectedColorId={petState.colorId}
|
||||||
|
@ -802,7 +825,10 @@ function ItemPageOutfitPreview({ itemId }) {
|
||||||
isLoading={loadingGQL || loadingValids}
|
isLoading={loadingGQL || loadingValids}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
<Box gridArea="zones" alignSelf="center" justifySelf="center">
|
||||||
|
<ItemZonesInfo />
|
||||||
|
</Box>
|
||||||
|
</Grid>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -983,15 +1009,7 @@ function SpeciesFacesPicker({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Wrap
|
<Wrap spacing="0" justify="center">
|
||||||
spacing="0"
|
|
||||||
justify="center"
|
|
||||||
// On mobile, give this a scroll container, and some extra padding so
|
|
||||||
// the selected-face effects still fit inside.
|
|
||||||
maxHeight={{ base: "200px", md: "none" }}
|
|
||||||
overflow={{ base: "auto", md: "visible" }}
|
|
||||||
padding={{ base: "8px", md: "0" }}
|
|
||||||
>
|
|
||||||
{allSpeciesFaces.map((speciesFace) => (
|
{allSpeciesFaces.map((speciesFace) => (
|
||||||
<WrapItem key={speciesFace.speciesId}>
|
<WrapItem key={speciesFace.speciesId}>
|
||||||
<SpeciesFaceOption
|
<SpeciesFaceOption
|
||||||
|
@ -1237,6 +1255,14 @@ function SpeciesFaceOption({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ItemZonesInfo() {
|
||||||
|
return (
|
||||||
|
<Box fontSize="sm" textAlign="center">
|
||||||
|
{/* TODO */}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CrossFadeImage is like <img>, but listens for successful load events, and
|
* CrossFadeImage is like <img>, but listens for successful load events, and
|
||||||
* fades from the previous image to the new image once it loads.
|
* fades from the previous image to the new image once it loads.
|
||||||
|
|
Loading…
Reference in a new issue