diff --git a/src/app/WardrobePage/Item.js b/src/app/WardrobePage/Item.js index f739ff5..32c7cf3 100644 --- a/src/app/WardrobePage/Item.js +++ b/src/app/WardrobePage/Item.js @@ -52,7 +52,7 @@ function Item({ isWorn, isInOutfit, dispatchToOutfit, - hideSimpleZones = false, + isDisabled = false, }) { const [supportDrawerIsOpen, setSupportDrawerIsOpen] = React.useState(false); @@ -65,15 +65,16 @@ function Item({ return ( <> - + - + {item.name} @@ -147,7 +148,7 @@ function Item({ */ function ItemSkeleton() { return ( - + @@ -162,7 +163,7 @@ function ItemSkeleton() { * styles - including for its children, who sometimes reference it as an * .item-container parent! */ -function ItemContainer({ children, isFocusable = true }) { +function ItemContainer({ children, isDisabled = false }) { const theme = useTheme(); const focusBackgroundColor = useColorModeValue( @@ -187,12 +188,12 @@ function ItemContainer({ children, isFocusable = true }) { borderRadius="lg" d="flex" alignItems="center" - cursor={isFocusable ? "pointer" : undefined} + cursor={isDisabled ? undefined : "pointer"} border="1px" borderColor="transparent" className={cx([ "item-container", - isFocusable && + !isDisabled && css` &:hover, input:focus + & { @@ -218,7 +219,7 @@ function ItemContainer({ children, isFocusable = true }) { * ItemThumbnail shows a small preview image for the item, including some * hover/focus and worn/unworn states. */ -function ItemThumbnail({ src, isWorn }) { +function ItemThumbnail({ src, isWorn, isDisabled }) { const theme = useTheme(); const colorMode = useColorMode(); @@ -243,16 +244,18 @@ function ItemThumbnail({ src, isWorn }) { { transform: "scale(0.8)", }, - !isWorn && { - [containerHasFocus]: { - opacity: "0.9", - transform: "scale(0.9)", + !isDisabled && + !isWorn && { + [containerHasFocus]: { + opacity: "0.9", + transform: "scale(0.9)", + }, + }, + !isDisabled && + isWorn && { + opacity: 1, + transform: "none", }, - }, - isWorn && { - opacity: 1, - transform: "none", - }, ])} > @@ -283,7 +287,7 @@ function ItemThumbnail({ src, isWorn }) { * ItemName shows the item's name, including some hover/focus and worn/unworn * states. */ -function ItemName({ children, ...props }) { +function ItemName({ children, isDisabled, ...props }) { const theme = useTheme(); return ( @@ -293,17 +297,20 @@ function ItemName({ children, ...props }) { overflow="hidden" whiteSpace="nowrap" textOverflow="ellipsis" - className={css` - ${containerHasFocus} { - opacity: 0.9; - font-weight: ${theme.fontWeights.medium}; - } + className={ + !isDisabled && + css` + ${containerHasFocus} { + opacity: 0.9; + font-weight: ${theme.fontWeights.medium}; + } - input:checked + .item-container & { - opacity: 1; - font-weight: ${theme.fontWeights.bold}; - } - `} + input:checked + .item-container & { + opacity: 1; + font-weight: ${theme.fontWeights.bold}; + } + ` + } {...props} > {children} diff --git a/src/app/WardrobePage/ItemsPanel.js b/src/app/WardrobePage/ItemsPanel.js index 118ab18..666c605 100644 --- a/src/app/WardrobePage/ItemsPanel.js +++ b/src/app/WardrobePage/ItemsPanel.js @@ -8,9 +8,10 @@ import { Flex, IconButton, Skeleton, + Tooltip, VisuallyHidden, } from "@chakra-ui/core"; -import { EditIcon } from "@chakra-ui/icons"; +import { EditIcon, QuestionIcon } from "@chakra-ui/icons"; import { CSSTransition, TransitionGroup } from "react-transition-group"; import { Delay, Heading1, Heading2 } from "../util"; @@ -30,7 +31,7 @@ import Item, { ItemListContainer, ItemListSkeleton } from "./Item"; * full width of the container, it doesn't look like it! */ function ItemsPanel({ outfitState, loading, dispatchToOutfit }) { - const { zonesAndItems } = outfitState; + const { zonesAndItems, incompatibleItems } = outfitState; return ( @@ -55,6 +56,24 @@ function ItemsPanel({ outfitState, loading, dispatchToOutfit }) { /> ))} + {incompatibleItems.length > 0 && ( + + + + } + items={incompatibleItems} + outfitState={outfitState} + dispatchToOutfit={dispatchToOutfit} + isDisabled + /> + )} )} @@ -70,7 +89,14 @@ function ItemsPanel({ outfitState, loading, dispatchToOutfit }) { * the Item component (which will visually reflect the radio's state). This * makes the list screen-reader- and keyboard-accessible! */ -function ItemZoneGroup({ zoneLabel, items, outfitState, dispatchToOutfit }) { +function ItemZoneGroup({ + zoneLabel, + items, + outfitState, + dispatchToOutfit, + isDisabled = false, + afterHeader = null, +}) { // onChange is fired when the radio button becomes checked, not unchecked! const onChange = (e) => { const itemId = e.target.value; @@ -93,38 +119,52 @@ function ItemZoneGroup({ zoneLabel, items, outfitState, dispatchToOutfit }) { return ( - {zoneLabel} + + {zoneLabel} + {afterHeader && {afterHeader}} + {items.map((item) => { const itemNameId = zoneLabel.replace(/ /g, "-") + `-item-${item.id}-name`; + const itemNode = ( + + ); + return ( - + {isDisabled ? ( + itemNode + ) : ( + + )} ); })} diff --git a/src/app/WardrobePage/useOutfitState.js b/src/app/WardrobePage/useOutfitState.js index 0ce525e..867b5db 100644 --- a/src/app/WardrobePage/useOutfitState.js +++ b/src/app/WardrobePage/useOutfitState.js @@ -81,11 +81,15 @@ function useOutfitState() { wornItemIds, closetedItemIds ); + const incompatibleItems = items + .filter((i) => i.appearanceOn.layers.length === 0) + .sort((a, b) => a.name.localeCompare(b.name)); const url = buildOutfitUrl(state); const outfitState = { zonesAndItems, + incompatibleItems, name, wornItemIds, closetedItemIds,