Compare commits
3 commits
578528f468
...
cd136aa6a5
Author | SHA1 | Date | |
---|---|---|---|
cd136aa6a5 | |||
09846a4516 | |||
fc71f5b5a5 |
7 changed files with 72 additions and 30 deletions
|
@ -77,20 +77,22 @@ function ItemsPanel({ outfitState, outfitSaving, loading, dispatchToOutfit }) {
|
|||
itemCount={outfitState.allItemIds.length}
|
||||
/>
|
||||
) : (
|
||||
<TransitionGroup component={null}>
|
||||
{zonesAndItems.map(({ zoneId, zoneLabel, items }) => (
|
||||
<CSSTransition
|
||||
key={zoneId}
|
||||
{...fadeOutAndRollUpTransition(css)}
|
||||
>
|
||||
<ItemZoneGroup
|
||||
zoneLabel={zoneLabel}
|
||||
items={items}
|
||||
outfitState={outfitState}
|
||||
dispatchToOutfit={dispatchToOutfit}
|
||||
/>
|
||||
</CSSTransition>
|
||||
))}
|
||||
<>
|
||||
<TransitionGroup component={null}>
|
||||
{zonesAndItems.map(({ zoneId, zoneLabel, items }) => (
|
||||
<CSSTransition
|
||||
key={zoneId}
|
||||
{...fadeOutAndRollUpTransition(css)}
|
||||
>
|
||||
<ItemZoneGroup
|
||||
zoneLabel={zoneLabel}
|
||||
items={items}
|
||||
outfitState={outfitState}
|
||||
dispatchToOutfit={dispatchToOutfit}
|
||||
/>
|
||||
</CSSTransition>
|
||||
))}
|
||||
</TransitionGroup>
|
||||
{incompatibleItems.length > 0 && (
|
||||
<ItemZoneGroup
|
||||
zoneLabel="Incompatible"
|
||||
|
@ -109,7 +111,7 @@ function ItemsPanel({ outfitState, outfitSaving, loading, dispatchToOutfit }) {
|
|||
isDisabled
|
||||
/>
|
||||
)}
|
||||
</TransitionGroup>
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
</Box>
|
||||
|
|
|
@ -24,6 +24,7 @@ import {
|
|||
Switch,
|
||||
Tooltip,
|
||||
UnorderedList,
|
||||
useBreakpointValue,
|
||||
useClipboard,
|
||||
useToast,
|
||||
} from "@chakra-ui/react";
|
||||
|
@ -78,6 +79,8 @@ function OutfitControls({
|
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const toast = React.useMemo(() => _toast, []);
|
||||
|
||||
const speciesColorPickerSize = useBreakpointValue({ base: "sm", md: "md" });
|
||||
|
||||
const onSpeciesColorChange = React.useCallback(
|
||||
(species, color, isValid, closestPose) => {
|
||||
if (isValid) {
|
||||
|
@ -208,6 +211,7 @@ function OutfitControls({
|
|||
{outfitState.speciesId && outfitState.colorId && (
|
||||
<Flex
|
||||
gridArea="picker"
|
||||
align="center"
|
||||
justify="center"
|
||||
onClick={maybeUnlockFocus}
|
||||
>
|
||||
|
@ -223,6 +227,7 @@ function OutfitControls({
|
|||
idealPose={outfitState.pose}
|
||||
onChange={onSpeciesColorChange}
|
||||
stateMustAlwaysBeValid
|
||||
size={speciesColorPickerSize}
|
||||
speciesTestId="wardrobe-species-picker"
|
||||
colorTestId="wardrobe-color-picker"
|
||||
/>
|
||||
|
|
|
@ -293,7 +293,7 @@ function PosePickerButton({ pose, altStyle, isOpen, loading, ...props }, ref) {
|
|||
{({ css, cx }) => (
|
||||
<Button
|
||||
variant="unstyled"
|
||||
boxShadow="md"
|
||||
textShadow={`${theme.colors.blackAlpha["700"]} 0 1px 2px`}
|
||||
d="flex"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
|
@ -307,10 +307,11 @@ function PosePickerButton({ pose, altStyle, isOpen, loading, ...props }, ref) {
|
|||
className={cx(
|
||||
css`
|
||||
border: 1px solid transparent !important;
|
||||
color: ${theme.colors.gray["300"]};
|
||||
color: ${theme.colors.gray["100"]};
|
||||
cursor: ${loading ? "wait" : "pointer"} !important;
|
||||
transition:
|
||||
color 0.2s,
|
||||
background: 0.2s,
|
||||
border-color 0.2s !important;
|
||||
padding-left: 0.75em;
|
||||
padding-right: 0.5em;
|
||||
|
@ -319,6 +320,8 @@ function PosePickerButton({ pose, altStyle, isOpen, loading, ...props }, ref) {
|
|||
&.is-open {
|
||||
border-color: ${theme.colors.gray["50"]} !important;
|
||||
color: ${theme.colors.gray["50"]};
|
||||
background: ${theme.colors.blackAlpha["600"]};
|
||||
text-shadow: transparent 0 1px 2px;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
|
|
|
@ -129,6 +129,7 @@ function useOutfitState() {
|
|||
$allItemIds: [ID!]!
|
||||
$speciesId: ID!
|
||||
$colorId: ID!
|
||||
$altStyleId: ID
|
||||
) {
|
||||
items(ids: $allItemIds) {
|
||||
# TODO: De-dupe this from SearchPanel?
|
||||
|
@ -140,7 +141,11 @@ function useOutfitState() {
|
|||
currentUserOwnsThis
|
||||
currentUserWantsThis
|
||||
|
||||
appearanceOn(speciesId: $speciesId, colorId: $colorId) {
|
||||
appearanceOn(
|
||||
speciesId: $speciesId
|
||||
colorId: $colorId
|
||||
altStyleId: $altStyleId
|
||||
) {
|
||||
# This enables us to quickly show the item when the user clicks it!
|
||||
...ItemAppearanceForOutfitPreview
|
||||
|
||||
|
@ -166,7 +171,7 @@ function useOutfitState() {
|
|||
${itemAppearanceFragment}
|
||||
`,
|
||||
{
|
||||
variables: { allItemIds, speciesId, colorId },
|
||||
variables: { allItemIds, speciesId, colorId, altStyleId },
|
||||
context: { sendAuth: true },
|
||||
// Skip if this outfit has no items, as an optimization; or if we don't
|
||||
// have the species/color ID loaded yet because we're waiting on the
|
||||
|
@ -448,7 +453,7 @@ function getOutfitStateFromOutfitData(outfit) {
|
|||
}
|
||||
|
||||
function findItemConflicts(itemIdToAdd, state, apolloClient) {
|
||||
const { wornItemIds, speciesId, colorId } = state;
|
||||
const { wornItemIds, speciesId, colorId, altStyleId } = state;
|
||||
|
||||
const { items } = apolloClient.readQuery({
|
||||
query: gql`
|
||||
|
@ -456,10 +461,15 @@ function findItemConflicts(itemIdToAdd, state, apolloClient) {
|
|||
$itemIds: [ID!]!
|
||||
$speciesId: ID!
|
||||
$colorId: ID!
|
||||
$altStyleId: ID
|
||||
) {
|
||||
items(ids: $itemIds) {
|
||||
id
|
||||
appearanceOn(speciesId: $speciesId, colorId: $colorId) {
|
||||
appearanceOn(
|
||||
speciesId: $speciesId
|
||||
colorId: $colorId
|
||||
altStyleId: $altStyleId
|
||||
) {
|
||||
layers {
|
||||
zone {
|
||||
id
|
||||
|
@ -477,6 +487,7 @@ function findItemConflicts(itemIdToAdd, state, apolloClient) {
|
|||
itemIds: [itemIdToAdd, ...wornItemIds],
|
||||
speciesId,
|
||||
colorId,
|
||||
altStyleId,
|
||||
},
|
||||
});
|
||||
const itemToAdd = items.find((i) => i.id === itemIdToAdd);
|
||||
|
|
|
@ -14,7 +14,7 @@ export function useSearchResults(
|
|||
currentPageNumber,
|
||||
{ skip = false } = {},
|
||||
) {
|
||||
const { speciesId, colorId } = outfitState;
|
||||
const { speciesId, colorId, altStyleId } = outfitState;
|
||||
|
||||
// We debounce the search query, so that we don't resend a new query whenever
|
||||
// the user types anything.
|
||||
|
@ -56,6 +56,7 @@ export function useSearchResults(
|
|||
$zoneIds: [ID!]!
|
||||
$speciesId: ID!
|
||||
$colorId: ID!
|
||||
$altStyleId: ID
|
||||
$offset: Int!
|
||||
$perPage: Int!
|
||||
) {
|
||||
|
@ -78,7 +79,11 @@ export function useSearchResults(
|
|||
currentUserOwnsThis
|
||||
currentUserWantsThis
|
||||
|
||||
appearanceOn(speciesId: $speciesId, colorId: $colorId) {
|
||||
appearanceOn(
|
||||
speciesId: $speciesId
|
||||
colorId: $colorId
|
||||
altStyleId: $altStyleId
|
||||
) {
|
||||
# This enables us to quickly show the item when the user clicks it!
|
||||
...ItemAppearanceForOutfitPreview
|
||||
|
||||
|
@ -104,12 +109,13 @@ export function useSearchResults(
|
|||
{
|
||||
variables: {
|
||||
query: debouncedQuery.value,
|
||||
fitsPet: { speciesId, colorId },
|
||||
fitsPet: { speciesId, colorId, altStyleId },
|
||||
itemKind: debouncedQuery.filterToItemKind,
|
||||
currentUserOwnsOrWants: debouncedQuery.filterToCurrentUserOwnsOrWants,
|
||||
zoneIds: filterToZoneIds,
|
||||
speciesId,
|
||||
colorId,
|
||||
altStyleId,
|
||||
offset,
|
||||
perPage: SEARCH_PER_PAGE,
|
||||
},
|
||||
|
|
|
@ -53,17 +53,26 @@ const typePolicies = {
|
|||
return appearance;
|
||||
}
|
||||
|
||||
// Otherwise, we're going to see if this is a standard color, in which
|
||||
// case we can reuse the standard color appearance if we already have
|
||||
// it! This helps for fast loading when switching between standard
|
||||
// colors.
|
||||
const { speciesId, colorId } = args;
|
||||
const { speciesId, colorId, altStyleId } = args;
|
||||
console.debug(
|
||||
"[appearanceOn] seeking cached appearance",
|
||||
speciesId,
|
||||
colorId,
|
||||
altStyleId,
|
||||
readField("id"),
|
||||
);
|
||||
|
||||
// If this is an alt style, don't try to mess with clever caching.
|
||||
// (Note that, if it's already in the cache, the first condition will
|
||||
// catch that! This won't *always* force a fresh load!)
|
||||
if (altStyleId != null) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Otherwise, we're going to see if this is a standard color, in which
|
||||
// case we can reuse the standard color appearance if we already have
|
||||
// it! This helps for fast loading when switching between standard
|
||||
// colors.
|
||||
const speciesStandardBodyId = readField(
|
||||
"standardBodyId",
|
||||
toReference({ __typename: "Species", id: speciesId }),
|
||||
|
|
|
@ -83,12 +83,17 @@ export default function useOutfitAppearance(outfitState) {
|
|||
query OutfitItemsAppearance(
|
||||
$speciesId: ID!
|
||||
$colorId: ID!
|
||||
$altStyleId: ID
|
||||
$wornItemIds: [ID!]!
|
||||
) {
|
||||
items(ids: $wornItemIds) {
|
||||
id
|
||||
name # HACK: This is for HTML5 detection UI in OutfitControls!
|
||||
appearance: appearanceOn(speciesId: $speciesId, colorId: $colorId) {
|
||||
appearance: appearanceOn(
|
||||
speciesId: $speciesId
|
||||
colorId: $colorId
|
||||
altStyleId: $altStyleId
|
||||
) {
|
||||
...ItemAppearanceForOutfitPreview
|
||||
}
|
||||
}
|
||||
|
@ -99,6 +104,7 @@ export default function useOutfitAppearance(outfitState) {
|
|||
variables: {
|
||||
speciesId,
|
||||
colorId,
|
||||
altStyleId,
|
||||
wornItemIds,
|
||||
},
|
||||
skip: speciesId == null || colorId == null || wornItemIds.length === 0,
|
||||
|
|
Loading…
Reference in a new issue