start adding appearance layers support tool

right now it just shows stuff. next step is to make them clickable to open tools for managing the layer!
This commit is contained in:
Emi Matchu 2020-08-01 01:35:27 -07:00
parent 0cdb6d0da1
commit 63b865ef7c
4 changed files with 87 additions and 18 deletions

View file

@ -82,6 +82,7 @@ export function Item({ item, itemNameId, outfitState, dispatchToOutfit }) {
<SupportOnly>
<LoadableItemSupportDrawer
item={item}
outfitState={outfitState}
isOpen={supportDrawerIsOpen}
onClose={() => setSupportDrawerIsOpen(false)}
/>

View file

@ -14,13 +14,17 @@ import {
FormErrorMessage,
FormHelperText,
FormLabel,
HStack,
Link,
Select,
Spinner,
Stack,
useBreakpointValue,
} from "@chakra-ui/core";
import { CheckCircleIcon, ExternalLinkIcon } from "@chakra-ui/icons";
import { OutfitLayers } from "../../components/OutfitPreview";
import useOutfitAppearance from "../../components/useOutfitAppearance";
import useSupportSecret from "./useSupportSecret";
/**
@ -29,7 +33,7 @@ import useSupportSecret from "./useSupportSecret";
* This component controls the drawer element. The actual content is imported
* from another lazy-loaded component!
*/
function ItemSupportDrawer({ item, isOpen, onClose }) {
function ItemSupportDrawer({ item, outfitState, isOpen, onClose }) {
const placement = useBreakpointValue({
base: "bottom",
lg: "right",
@ -53,17 +57,26 @@ function ItemSupportDrawer({ item, isOpen, onClose }) {
blockScrollOnMount={false}
>
<DrawerOverlay>
<DrawerContent>
<DrawerContent
maxHeight={placement === "bottom" ? "90vh" : undefined}
overflow="auto"
>
<DrawerCloseButton />
<DrawerHeader>
<DrawerHeader color="green.800">
{item.name}
<Badge colorScheme="pink" marginLeft="3">
Support <span aria-hidden="true">💖</span>
</Badge>
</DrawerHeader>
<DrawerBody>
<DrawerBody color="green.800">
<Box paddingBottom="5">
<SpecialColorFields item={item} />
<Stack spacing="8">
<ItemSupportSpecialColorFields item={item} />
<ItemSupportAppearanceFields
item={item}
outfitState={outfitState}
/>
</Stack>
</Box>
</DrawerBody>
</DrawerContent>
@ -72,7 +85,7 @@ function ItemSupportDrawer({ item, isOpen, onClose }) {
);
}
function SpecialColorFields({ item }) {
function ItemSupportSpecialColorFields({ item }) {
const supportSecret = useSupportSecret();
const { loading: itemLoading, error: itemError, data: itemData } = useQuery(
@ -215,4 +228,54 @@ function SpecialColorFields({ item }) {
);
}
function ItemSupportAppearanceFields({ item, outfitState }) {
const { speciesId, colorId, pose } = outfitState;
const { error, visibleLayers } = useOutfitAppearance({
speciesId,
colorId,
pose,
wornItemIds: [item.id],
});
const biologyLayers = visibleLayers.filter((l) => l.source === "pet");
const itemLayers = visibleLayers.filter((l) => l.source === "item");
itemLayers.sort((a, b) => a.zone.depth - b.zone.depth);
return (
<FormControl>
<FormLabel>Appearance layers</FormLabel>
<HStack spacing="4" overflow="auto">
{itemLayers.map((itemLayer) => (
<ItemSupportAppearanceLayer
biologyLayers={biologyLayers}
itemLayer={itemLayer}
/>
))}
</HStack>
{error && <FormErrorMessage>{error.message}</FormErrorMessage>}
</FormControl>
);
}
function ItemSupportAppearanceLayer({ biologyLayers, itemLayer }) {
return (
<Box width="150px" textAlign="center" fontSize="xs">
<Box
width="150px"
height="150px"
marginBottom="1"
boxShadow="md"
borderRadius="md"
>
<OutfitLayers visibleLayers={[...biologyLayers, itemLayer]} />
</Box>
<Box>
<b>{itemLayer.zone.label}</b>
</Box>
<Box>Zone ID: {itemLayer.zone.id}</Box>
<Box>Layer ID: {itemLayer.id}</Box>
</Box>
);
}
export default ItemSupportDrawer;

View file

@ -80,7 +80,13 @@ export function OutfitLayers({
}, []);
return (
<Box pos="relative" height="100%" width="100%">
<Box
pos="relative"
height="100%"
width="100%"
// Create a stacking context, so the z-indexed layers don't escape!
zIndex="0"
>
{placeholder && (
<FullScreenCenter>
<Box
@ -111,7 +117,7 @@ export function OutfitLayers({
`}
timeout={200}
>
<FullScreenCenter>
<FullScreenCenter zIndex={layer.zone.depth}>
<img
src={getBestImageUrlForLayer(layer)}
alt=""
@ -177,7 +183,7 @@ export function OutfitLayers({
);
}
export function FullScreenCenter({ children }) {
export function FullScreenCenter({ children, zIndex }) {
return (
<Flex
pos="absolute"
@ -187,6 +193,7 @@ export function FullScreenCenter({ children }) {
left="0"
alignItems="center"
justifyContent="center"
zIndex={zIndex}
>
{children}
</Flex>

View file

@ -91,15 +91,12 @@ export function getVisibleLayers(petAppearance, itemAppearances) {
const validItemAppearances = itemAppearances.filter((a) => a);
const allAppearances = [petAppearance, ...validItemAppearances];
let allLayers = allAppearances.map((a) => a.layers).flat();
// Clean up our data a bit, by ensuring only one layer per zone. This
// shouldn't happen in theory, but sometimes our database doesn't clean up
// after itself correctly :(
allLayers = allLayers.filter((l, i) => {
return allLayers.findIndex((l2) => l2.zone.id === l.zone.id) === i;
});
const petLayers = petAppearance.layers.map((l) => ({ ...l, source: "pet" }));
const itemLayers = validItemAppearances
.map((a) => a.layers)
.flat()
.map((l) => ({ ...l, source: "item" }));
let allLayers = [...petLayers, ...itemLayers];
const allRestrictedZoneIds = validItemAppearances
.map((l) => l.restrictedZones)
@ -123,6 +120,7 @@ export const itemAppearanceFragment = gql`
zone {
id
depth
label # HACK: This is for Support tools, but other views don't need it
}
}