zone badges on items
These are nice! :) The `hideSimpleZones` option I'm not sure about yet, but I figure that: 1. For a new user just doing simple outfits, I feel like the double data on the items page just looks silly, so I want to streamline for that 2. But I _do_ want to let the user think about zone complexity when things _are_ multi-zone. I did also consider just hiding the zone badge for the header you're under, but I figured the consistency of having the item and its badges look the same in all the places in the list was more important.
This commit is contained in:
parent
3a6e3fac8e
commit
dec9d76601
4 changed files with 94 additions and 3 deletions
|
@ -8,10 +8,16 @@ import {
|
|||
Image,
|
||||
Skeleton,
|
||||
Tooltip,
|
||||
Wrap,
|
||||
useColorModeValue,
|
||||
useTheme,
|
||||
} from "@chakra-ui/core";
|
||||
import { EditIcon, DeleteIcon, InfoIcon } from "@chakra-ui/icons";
|
||||
import {
|
||||
EditIcon,
|
||||
DeleteIcon,
|
||||
InfoIcon,
|
||||
NotAllowedIcon,
|
||||
} from "@chakra-ui/icons";
|
||||
import loadable from "@loadable/component";
|
||||
|
||||
import { safeImageUrl } from "../util";
|
||||
|
@ -39,9 +45,27 @@ const LoadableItemSupportDrawer = loadable(() =>
|
|||
* wearing/unwearing items being noticeably slower on lower-power
|
||||
* devices.
|
||||
*/
|
||||
function Item({ item, itemNameId, isWorn, isInOutfit, dispatchToOutfit }) {
|
||||
function Item({
|
||||
item,
|
||||
itemNameId,
|
||||
isWorn,
|
||||
isInOutfit,
|
||||
dispatchToOutfit,
|
||||
hideSimpleZones = false,
|
||||
}) {
|
||||
const [supportDrawerIsOpen, setSupportDrawerIsOpen] = React.useState(false);
|
||||
|
||||
const occupiedZoneLabels = getZoneLabels(
|
||||
item.appearanceOn.layers.map((l) => l.zone)
|
||||
);
|
||||
const restrictedZoneLabels = getZoneLabels(
|
||||
item.appearanceOn.restrictedZones.filter((z) => z.isCommonlyUsedByItems)
|
||||
);
|
||||
const zonesAreSimple =
|
||||
occupiedZoneLabels.length <= 1 && restrictedZoneLabels.length === 0;
|
||||
const shouldHideZones = hideSimpleZones && zonesAreSimple;
|
||||
const shouldShowZones = !shouldHideZones;
|
||||
|
||||
return (
|
||||
<>
|
||||
<ItemContainer>
|
||||
|
@ -55,7 +79,36 @@ function Item({ item, itemNameId, isWorn, isInOutfit, dispatchToOutfit }) {
|
|||
<ItemName id={itemNameId} isWorn={isWorn}>
|
||||
{item.name}
|
||||
</ItemName>
|
||||
<Box>{item.isNc && <Badge colorScheme="cyan">NC</Badge>}</Box>
|
||||
<Wrap spacing="2" marginTop="1">
|
||||
{shouldShowZones &&
|
||||
occupiedZoneLabels.map((zoneLabel) => (
|
||||
<Badge key={zoneLabel}>{getZoneShorthand(zoneLabel)}</Badge>
|
||||
))}
|
||||
{shouldShowZones &&
|
||||
restrictedZoneLabels.map((zoneLabel) => (
|
||||
<Tooltip
|
||||
label={
|
||||
<Box textAlign="center">
|
||||
Restricted: This isn't a {zoneLabel} item, but you can't
|
||||
wear {zoneLabel} items with it
|
||||
</Box>
|
||||
}
|
||||
placement="top"
|
||||
openDelay={250}
|
||||
>
|
||||
<Badge
|
||||
key={zoneLabel}
|
||||
display="flex"
|
||||
flexDirection="row"
|
||||
alignItems="center"
|
||||
>
|
||||
{getZoneShorthand(zoneLabel)}
|
||||
<NotAllowedIcon marginLeft="1" />
|
||||
</Badge>
|
||||
</Tooltip>
|
||||
))}
|
||||
{item.isNc && <Badge colorScheme="cyan">NC</Badge>}
|
||||
</Wrap>
|
||||
</Box>
|
||||
<Box flex="0 0 auto">
|
||||
<SupportOnly>
|
||||
|
@ -328,6 +381,32 @@ export function ItemListSkeleton({ count }) {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* getZoneLabels returns the set of labels for the given zones. Sometimes an
|
||||
* item occupies multiple zones of the same name, so it's especially important
|
||||
* to de-duplicate them here!
|
||||
*/
|
||||
function getZoneLabels(zones) {
|
||||
let labels = zones.map((z) => z.label);
|
||||
labels = new Set(labels);
|
||||
labels = [...labels].sort();
|
||||
return labels;
|
||||
}
|
||||
|
||||
/**
|
||||
* getZoneShorthand returns a potentially shortened version of the zone label,
|
||||
* to make the Item badges a bit less bulky!
|
||||
*/
|
||||
function getZoneShorthand(zoneLabel) {
|
||||
return zoneLabel
|
||||
.replace("Background Item", "BG Item")
|
||||
.replace("Foreground Item", "FG Item")
|
||||
.replace("Lower-body", "Lower")
|
||||
.replace("Upper-body", "Upper")
|
||||
.replace("Transient", "Trans")
|
||||
.replace("Biology", "Bio");
|
||||
}
|
||||
|
||||
/**
|
||||
* containerHasFocus is a common CSS selector, for the case where our parent
|
||||
* .item-container is hovered or the adjacent hidden radio/checkbox is
|
||||
|
|
|
@ -123,6 +123,7 @@ function ItemZoneGroup({ zoneLabel, items, outfitState, dispatchToOutfit }) {
|
|||
isWorn={outfitState.wornItemIds.includes(item.id)}
|
||||
isInOutfit={outfitState.allItemIds.includes(item.id)}
|
||||
dispatchToOutfit={dispatchToOutfit}
|
||||
hideSimpleZones
|
||||
/>
|
||||
</label>
|
||||
</CSSTransition>
|
||||
|
|
|
@ -229,6 +229,7 @@ function useSearchResults(query, outfitState) {
|
|||
id
|
||||
name
|
||||
thumbnailUrl
|
||||
isNc
|
||||
|
||||
appearanceOn(speciesId: $speciesId, colorId: $colorId) {
|
||||
# This enables us to quickly show the item when the user clicks it!
|
||||
|
@ -242,6 +243,11 @@ function useSearchResults(query, outfitState) {
|
|||
label @client
|
||||
}
|
||||
}
|
||||
restrictedZones {
|
||||
id
|
||||
label @client
|
||||
isCommonlyUsedByItems @client
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,11 @@ function useOutfitState() {
|
|||
label @client
|
||||
}
|
||||
}
|
||||
restrictedZones {
|
||||
id
|
||||
label @client
|
||||
isCommonlyUsedByItems @client
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue