create ItemCard, use it in ItemsPage too

extracted from modeling page!
This commit is contained in:
Emi Matchu 2020-09-11 20:41:39 -07:00
parent 9cb6cc2120
commit 0df57818e3
4 changed files with 102 additions and 68 deletions

View file

@ -1,11 +1,16 @@
import React from "react"; import React from "react";
import { Box, Image, Wrap } from "@chakra-ui/core"; import { Box, Wrap } from "@chakra-ui/core";
import gql from "graphql-tag"; import gql from "graphql-tag";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { useQuery } from "@apollo/client"; import { useQuery } from "@apollo/client";
import HangerSpinner from "./components/HangerSpinner"; import HangerSpinner from "./components/HangerSpinner";
import { Heading1 } from "./util"; import { Heading1 } from "./util";
import ItemCard, {
ItemBadgeList,
NcBadge,
NpBadge,
} from "./components/ItemCard";
import useCurrentUser from "./components/useCurrentUser"; import useCurrentUser from "./components/useCurrentUser";
function ItemsPage() { function ItemsPage() {
@ -21,6 +26,7 @@ function ItemsPage() {
username username
itemsTheyOwn { itemsTheyOwn {
id id
isNc
name name
thumbnailUrl thumbnailUrl
} }
@ -49,17 +55,15 @@ function ItemsPage() {
</Heading1> </Heading1>
<Wrap justify="center"> <Wrap justify="center">
{data.user.itemsTheyOwn.map((item) => ( {data.user.itemsTheyOwn.map((item) => (
<Box key={item.id} width="100px" textAlign="center"> <ItemCard
<Image key={item.id}
src={item.thumbnailUrl} item={item}
alt="" badges={
height="80px" <ItemBadgeList>
width="80px" {item.isNc ? <NcBadge /> : <NpBadge />}
boxShadow="md" </ItemBadgeList>
margin="0 auto" }
/> />
{item.name}
</Box>
))} ))}
</Wrap> </Wrap>
</Box> </Box>

View file

@ -1,5 +1,5 @@
import React from "react"; import React from "react";
import { Badge, Box, SimpleGrid, useColorModeValue } from "@chakra-ui/core"; import { Badge, Box, SimpleGrid } from "@chakra-ui/core";
import { StarIcon } from "@chakra-ui/icons"; import { StarIcon } from "@chakra-ui/icons";
import gql from "graphql-tag"; import gql from "graphql-tag";
import { useQuery } from "@apollo/client"; import { useQuery } from "@apollo/client";
@ -7,7 +7,8 @@ import { useQuery } from "@apollo/client";
import { Delay } from "./util"; import { Delay } from "./util";
import HangerSpinner from "./components/HangerSpinner"; import HangerSpinner from "./components/HangerSpinner";
import { Heading1, Heading2 } from "./util"; import { Heading1, Heading2 } from "./util";
import ItemSummary, { ItemSummaryBadgeList } from "./components/ItemSummary"; import ItemCard from "./components/ItemCard";
import { ItemBadgeList } from "./components/ItemCard";
function ModelingPage() { function ModelingPage() {
return ( return (
@ -83,38 +84,16 @@ function ItemModelsList() {
} }
function ItemModelCard({ item, currentUserOwnsItem, ...props }) { function ItemModelCard({ item, currentUserOwnsItem, ...props }) {
const borderColor = useColorModeValue("gray.100", "green.500"); const badges = (
<ItemModelBadges item={item} currentUserOwnsItem={currentUserOwnsItem} />
return (
<Box
as="a"
href={`https://impress.openneo.net/items/${item.id}`}
p="2"
boxShadow="lg"
borderRadius="lg"
width="400px"
border="1px"
borderColor={borderColor}
className="item-model-card"
{...props}
>
<ItemSummary
item={item}
badges={
<ItemModelBadges
item={item}
currentUserOwnsItem={currentUserOwnsItem}
/>
}
focusSelector=".item-model-card:hover &, .item-model-card:focus &"
/>
</Box>
); );
return <ItemCard item={item} badges={badges} />;
} }
function ItemModelBadges({ item, currentUserOwnsItem }) { function ItemModelBadges({ item, currentUserOwnsItem }) {
return ( return (
<ItemSummaryBadgeList> <ItemBadgeList>
{currentUserOwnsItem && ( {currentUserOwnsItem && (
<Badge colorScheme="yellow" display="flex" alignItems="center"> <Badge colorScheme="yellow" display="flex" alignItems="center">
<StarIcon aria-label="Star" marginRight="1" /> <StarIcon aria-label="Star" marginRight="1" />
@ -124,7 +103,7 @@ function ItemModelBadges({ item, currentUserOwnsItem }) {
{item.speciesThatNeedModels.map((species) => ( {item.speciesThatNeedModels.map((species) => (
<Badge>{species.name}</Badge> <Badge>{species.name}</Badge>
))} ))}
</ItemSummaryBadgeList> </ItemBadgeList>
); );
} }

View file

@ -18,7 +18,13 @@ import {
} from "@chakra-ui/icons"; } from "@chakra-ui/icons";
import loadable from "@loadable/component"; import loadable from "@loadable/component";
import ItemSummary, { ItemSummaryBadgeList } from "../components/ItemSummary"; import {
ItemCardContent,
ItemBadgeList,
ItemBadgeTooltip,
NcBadge,
NpBadge,
} from "../components/ItemCard";
import SupportOnly from "./support/SupportOnly"; import SupportOnly from "./support/SupportOnly";
const LoadableItemSupportDrawer = loadable(() => const LoadableItemSupportDrawer = loadable(() =>
@ -58,7 +64,7 @@ function Item({
<> <>
<ItemContainer isDisabled={isDisabled}> <ItemContainer isDisabled={isDisabled}>
<Box flex="1 1 0" minWidth="0"> <Box flex="1 1 0" minWidth="0">
<ItemSummary <ItemCardContent
item={item} item={item}
badges={<ItemBadges item={item} />} badges={<ItemBadges item={item} />}
itemNameId={itemNameId} itemNameId={itemNameId}
@ -189,11 +195,9 @@ function ItemBadges({ item }) {
); );
return ( return (
<ItemSummaryBadgeList> <ItemBadgeList>
{item.isNc ? ( {item.isNc ? (
<ItemBadgeTooltip label="Neocash"> <NcBadge />
<Badge colorScheme="purple">NC</Badge>
</ItemBadgeTooltip>
) : ( ) : (
// The main purpose of the NP badge is alignment: if there are // The main purpose of the NP badge is alignment: if there are
// zone badges, we want them to start at the same rough position, // zone badges, we want them to start at the same rough position,
@ -201,9 +205,7 @@ function ItemBadges({ item }) {
// generally avoids zone badges, we'd rather have the NC badge be // generally avoids zone badges, we'd rather have the NC badge be
// a little extra that might pop up and hide the NP case, rather // a little extra that might pop up and hide the NP case, rather
// than try to line things up like a table. // than try to line things up like a table.
<ItemBadgeTooltip label="Neopoints"> <NpBadge />
<Badge>NP</Badge>
</ItemBadgeTooltip>
)} )}
{occupiedZoneLabels.map((zoneLabel) => ( {occupiedZoneLabels.map((zoneLabel) => (
<ZoneBadge key={zoneLabel} variant="occupies" zoneLabel={zoneLabel} /> <ZoneBadge key={zoneLabel} variant="occupies" zoneLabel={zoneLabel} />
@ -211,7 +213,7 @@ function ItemBadges({ item }) {
{restrictedZoneLabels.map((zoneLabel) => ( {restrictedZoneLabels.map((zoneLabel) => (
<ZoneBadge key={zoneLabel} variant="restricts" zoneLabel={zoneLabel} /> <ZoneBadge key={zoneLabel} variant="restricts" zoneLabel={zoneLabel} />
))} ))}
</ItemSummaryBadgeList> </ItemBadgeList>
); );
} }
@ -337,18 +339,6 @@ function ZoneBadge({ variant, zoneLabel }) {
return <Badge>{shorthand}</Badge>; return <Badge>{shorthand}</Badge>;
} }
function ItemBadgeTooltip({ label, children }) {
return (
<Tooltip
label={<Box textAlign="center">{label}</Box>}
placement="top"
openDelay={400}
>
{children}
</Tooltip>
);
}
/** /**
* containerHasFocus is a common CSS selector, for the case where our parent * containerHasFocus is a common CSS selector, for the case where our parent
* .item-container is hovered or the adjacent hidden radio/checkbox is * .item-container is hovered or the adjacent hidden radio/checkbox is

View file

@ -1,10 +1,43 @@
import React from "react"; import React from "react";
import { css } from "emotion"; import { css } from "emotion";
import { Box, Image, Wrap, useColorModeValue, useTheme } from "@chakra-ui/core"; import {
Badge,
Box,
Image,
Tooltip,
Wrap,
useColorModeValue,
useTheme,
} from "@chakra-ui/core";
import { safeImageUrl } from "../util"; import { safeImageUrl } from "../util";
function ItemSummary({ function ItemCard({ item, badges, ...props }) {
const borderColor = useColorModeValue("gray.100", "green.500");
return (
<Box
as="a"
href={`https://impress.openneo.net/items/${item.id}`}
p="2"
boxShadow="lg"
borderRadius="lg"
width="400px"
border="1px"
borderColor={borderColor}
className="item-card"
{...props}
>
<ItemCardContent
item={item}
badges={badges}
focusSelector=".item-card:hover &, .item-card:focus &"
/>
</Box>
);
}
export function ItemCardContent({
item, item,
badges, badges,
isWorn, isWorn,
@ -140,7 +173,7 @@ function ItemName({ children, isDisabled, focusSelector, ...props }) {
); );
} }
export function ItemSummaryBadgeList({ children }) { export function ItemBadgeList({ children }) {
return ( return (
<Wrap spacing="2" marginTop="1" opacity="0.7"> <Wrap spacing="2" marginTop="1" opacity="0.7">
{children} {children}
@ -148,4 +181,32 @@ export function ItemSummaryBadgeList({ children }) {
); );
} }
export default ItemSummary; export function ItemBadgeTooltip({ label, children }) {
return (
<Tooltip
label={<Box textAlign="center">{label}</Box>}
placement="top"
openDelay={400}
>
{children}
</Tooltip>
);
}
export function NcBadge() {
return (
<ItemBadgeTooltip label="Neocash">
<Badge colorScheme="purple">NC</Badge>
</ItemBadgeTooltip>
);
}
export function NpBadge() {
return (
<ItemBadgeTooltip label="Neopoints">
<Badge>NP</Badge>
</ItemBadgeTooltip>
);
}
export default ItemCard;