add items to outfit thumbnails

Now that wasn't so hard! :3
This commit is contained in:
Emi Matchu 2021-01-04 08:26:05 +00:00
parent 9a2308fd41
commit b01feba038
3 changed files with 73 additions and 6 deletions

View file

@ -7,6 +7,7 @@ import { ErrorMessage, Heading1 } from "./util";
import {
getVisibleLayers,
petAppearanceFragmentForGetVisibleLayers,
itemAppearanceFragmentForGetVisibleLayers,
} from "./components/useOutfitAppearance";
import HangerSpinner from "./components/HangerSpinner";
import useRequireLogin from "./components/useRequireLogin";
@ -43,10 +44,20 @@ function UserOutfitsPageContent() {
}
...PetAppearanceForGetVisibleLayers
}
itemAppearances {
id
layers {
id
svgUrl
imageUrl(size: $size)
}
...ItemAppearanceForGetVisibleLayers
}
}
}
}
${petAppearanceFragmentForGetVisibleLayers}
${itemAppearanceFragmentForGetVisibleLayers}
`,
{ variables: { size: "SIZE_" + getBestImageSize() }, skip: userLoading }
);
@ -77,7 +88,10 @@ function UserOutfitsPageContent() {
}
function OutfitCard({ outfit }) {
const thumbnailUrl = buildOutfitThumbnailUrl(outfit.petAppearance, []);
const thumbnailUrl = buildOutfitThumbnailUrl(
outfit.petAppearance,
outfit.itemAppearances
);
return (
<Flex
@ -105,6 +119,14 @@ function buildOutfitThumbnailUrl(petAppearance, itemAppearances) {
return `/api/outfitImage?size=${size}&layerUrls=${layerUrls.join(",")}`;
}
/**
* getBestImageSize returns the right image size to render at 150x150, for the
* current device.
*
* On high-DPI devices, we'll download a 300x300 image to render at 150x150
* scale. On standard-DPI devices, we'll download a 150x150 image, to save
* bandwidth.
*/
function getBestImageSize() {
if (window.devicePixelRatio > 1) {
return 300;

View file

@ -137,6 +137,22 @@ export function getVisibleLayers(petAppearance, itemAppearances) {
return visibleLayers;
}
export const itemAppearanceFragmentForGetVisibleLayers = gql`
fragment ItemAppearanceForGetVisibleLayers on ItemAppearance {
id
layers {
id
zone {
id
depth @client
}
}
restrictedZones {
id
}
}
`;
export const itemAppearanceFragment = gql`
fragment ItemAppearanceForOutfitPreview on ItemAppearance {
id
@ -149,15 +165,13 @@ export const itemAppearanceFragment = gql`
swfUrl # HACK: This is for Support tools, but other views don't need it
bodyId
zone {
id
depth @client
label @client # HACK: This is for Support tools, but other views don't need it
}
}
restrictedZones {
id
}
...ItemAppearanceForGetVisibleLayers
}
${itemAppearanceFragmentForGetVisibleLayers}
`;
export const petAppearanceFragmentForGetVisibleLayers = gql`

View file

@ -7,6 +7,10 @@ const typeDefs = gql`
petAppearance: PetAppearance!
wornItems: [Item!]!
closetedItems: [Item!]!
# This is a convenience field: you could query this from the combination of
# petAppearance and wornItems, but this gets you it in one shot!
itemAppearances: [ItemAppearance!]!
}
extend type Query {
@ -24,6 +28,33 @@ const resolvers = {
const outfit = await outfitLoader.load(id);
return { id: outfit.petStateId };
},
itemAppearances: async (
{ id },
_,
{
outfitLoader,
petStateLoader,
petTypeLoader,
itemOutfitRelationshipsLoader,
}
) => {
const [petType, relationships] = await Promise.all([
outfitLoader
.load(id)
.then((outfit) => petStateLoader.load(outfit.petStateId))
.then((petState) => petTypeLoader.load(petState.petTypeId)),
itemOutfitRelationshipsLoader.load(id),
]);
const wornItemIds = relationships
.filter((oir) => oir.isWorn)
.map((oir) => oir.itemId);
return wornItemIds.map((itemId) => ({
item: { id: itemId },
bodyId: petType.bodyId,
}));
},
wornItems: async ({ id }, _, { itemOutfitRelationshipsLoader }) => {
const relationships = await itemOutfitRelationshipsLoader.load(id);
return relationships