2021-01-18 06:31:27 -08:00
|
|
|
import React from "react";
|
2021-04-01 20:08:35 -07:00
|
|
|
import {
|
|
|
|
|
Skeleton,
|
|
|
|
|
useColorModeValue,
|
|
|
|
|
useTheme,
|
|
|
|
|
useToken,
|
|
|
|
|
} from "@chakra-ui/react";
|
2021-01-18 06:31:27 -08:00
|
|
|
import { ClassNames } from "@emotion/react";
|
|
|
|
|
import { Link } from "react-router-dom";
|
|
|
|
|
|
|
|
|
|
import { safeImageUrl, useCommonStyles } from "../util";
|
|
|
|
|
|
|
|
|
|
function SquareItemCard({ item, ...props }) {
|
2021-04-01 20:08:35 -07:00
|
|
|
const outlineShadowValue = useToken("shadows", "outline");
|
2021-01-18 06:31:27 -08:00
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<ClassNames>
|
|
|
|
|
{({ css }) => (
|
|
|
|
|
// SquareItemCard renders in large lists of 1k+ items, so we get a big
|
|
|
|
|
// perf win by using Emotion directly instead of Chakra's styled-system
|
|
|
|
|
// Box.
|
|
|
|
|
<Link
|
|
|
|
|
to={`/items/${item.id}`}
|
|
|
|
|
className={css`
|
|
|
|
|
transition: all 0.2s;
|
|
|
|
|
&:hover,
|
|
|
|
|
&:focus {
|
|
|
|
|
transform: scale(1.05);
|
|
|
|
|
}
|
|
|
|
|
&:focus {
|
2021-04-01 20:08:35 -07:00
|
|
|
box-shadow: ${outlineShadowValue};
|
2021-01-18 06:31:27 -08:00
|
|
|
outline: none;
|
|
|
|
|
}
|
|
|
|
|
`}
|
|
|
|
|
{...props}
|
|
|
|
|
>
|
|
|
|
|
<SquareItemCardLayout
|
|
|
|
|
name={item.name}
|
2021-04-01 20:08:35 -07:00
|
|
|
thumbnailImage={<ItemThumbnail item={item} />}
|
2021-01-18 06:31:27 -08:00
|
|
|
/>
|
|
|
|
|
</Link>
|
|
|
|
|
)}
|
|
|
|
|
</ClassNames>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function SquareItemCardLayout({ name, thumbnailImage, minHeightNumLines = 2 }) {
|
|
|
|
|
const { brightBackground } = useCommonStyles();
|
|
|
|
|
const brightBackgroundValue = useToken("colors", brightBackground);
|
|
|
|
|
const theme = useTheme();
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
// SquareItemCard renders in large lists of 1k+ items, so we get a big perf
|
|
|
|
|
// win by using Emotion directly instead of Chakra's styled-system Box.
|
|
|
|
|
<ClassNames>
|
|
|
|
|
{({ css }) => (
|
|
|
|
|
<div
|
|
|
|
|
className={css`
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
align-items: center;
|
|
|
|
|
text-align: center;
|
|
|
|
|
box-shadow: ${theme.shadows.md};
|
|
|
|
|
border-radius: ${theme.radii.md};
|
|
|
|
|
padding: ${theme.space["3"]};
|
|
|
|
|
width: calc(80px + 2em);
|
|
|
|
|
background: ${brightBackgroundValue};
|
|
|
|
|
`}
|
|
|
|
|
>
|
|
|
|
|
{thumbnailImage}
|
|
|
|
|
<div
|
|
|
|
|
className={css`
|
|
|
|
|
margin-top: ${theme.space["1"]};
|
|
|
|
|
font-size: ${theme.fontSizes.sm};
|
|
|
|
|
/* Set min height to match a 2-line item name, so the cards
|
|
|
|
|
* in a row aren't toooo differently sized... */
|
|
|
|
|
min-height: ${minHeightNumLines * 1.5 + "em"};
|
|
|
|
|
-webkit-line-clamp: 3;
|
|
|
|
|
-webkit-box-orient: vertical;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
width: 100%;
|
|
|
|
|
`}
|
|
|
|
|
// HACK: Emotion turns this into -webkit-display: -webkit-box?
|
|
|
|
|
style={{ display: "-webkit-box" }}
|
|
|
|
|
>
|
|
|
|
|
{name}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</ClassNames>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-01 20:08:35 -07:00
|
|
|
function ItemThumbnail({ item }) {
|
|
|
|
|
const mdRadiusValue = useToken("radii", "md");
|
|
|
|
|
|
2021-05-13 16:24:24 -07:00
|
|
|
const colorScheme = item.isNc ? "purple" : item.isPb ? "orange" : "gray";
|
|
|
|
|
|
2021-04-01 20:08:35 -07:00
|
|
|
const badgeBackground = useColorModeValue(
|
2021-05-13 16:24:24 -07:00
|
|
|
`${colorScheme}.100`,
|
|
|
|
|
`${colorScheme}.500`
|
2021-04-01 20:08:35 -07:00
|
|
|
);
|
|
|
|
|
const badgeColor = useColorModeValue(
|
2021-05-13 16:24:24 -07:00
|
|
|
`${colorScheme}.500`,
|
|
|
|
|
`${colorScheme}.100`
|
2021-04-01 20:08:35 -07:00
|
|
|
);
|
|
|
|
|
const thumbnailShadowColor = useColorModeValue(
|
2021-05-13 16:24:24 -07:00
|
|
|
`${colorScheme}.200`,
|
|
|
|
|
`${colorScheme}.600`
|
2021-04-01 20:08:35 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const [
|
|
|
|
|
badgeBackgroundValue,
|
|
|
|
|
badgeColorValue,
|
|
|
|
|
thumbnailShadowColorValue,
|
|
|
|
|
] = useToken("colors", [badgeBackground, badgeColor, thumbnailShadowColor]);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<ClassNames>
|
|
|
|
|
{({ css }) => (
|
|
|
|
|
<div
|
|
|
|
|
className={css`
|
|
|
|
|
position: relative;
|
|
|
|
|
`}
|
|
|
|
|
>
|
|
|
|
|
<img
|
|
|
|
|
src={safeImageUrl(item.thumbnailUrl)}
|
|
|
|
|
alt={`Thumbnail art for ${item.name}`}
|
|
|
|
|
width={80}
|
|
|
|
|
height={80}
|
|
|
|
|
className={css`
|
|
|
|
|
border-radius: ${mdRadiusValue};
|
|
|
|
|
box-shadow: 0 0 4px ${thumbnailShadowColorValue};
|
|
|
|
|
|
|
|
|
|
/* Don't let alt text flash in while loading */
|
|
|
|
|
&:-moz-loading {
|
|
|
|
|
visibility: hidden;
|
|
|
|
|
}
|
|
|
|
|
`}
|
|
|
|
|
loading="lazy"
|
|
|
|
|
/>
|
|
|
|
|
{item.isNc != null && (
|
|
|
|
|
<div
|
|
|
|
|
className={css`
|
|
|
|
|
position: absolute;
|
|
|
|
|
bottom: -6px;
|
|
|
|
|
right: -3px;
|
|
|
|
|
/* Copied from Chakra <Badge> */
|
|
|
|
|
display: inline-block;
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
vertical-align: middle;
|
|
|
|
|
padding-left: 0.25rem;
|
|
|
|
|
padding-right: 0.25rem;
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
font-size: 0.65rem;
|
|
|
|
|
border-radius: 0.125rem;
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
background: ${badgeBackgroundValue};
|
|
|
|
|
color: ${badgeColorValue};
|
|
|
|
|
`}
|
|
|
|
|
>
|
2021-05-13 16:24:24 -07:00
|
|
|
{item.isNc ? "NC" : item.isPb ? "PB" : "NP"}
|
2021-04-01 20:08:35 -07:00
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</ClassNames>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-18 06:31:27 -08:00
|
|
|
export function SquareItemCardSkeleton({ minHeightNumLines }) {
|
|
|
|
|
return (
|
|
|
|
|
<SquareItemCardLayout
|
|
|
|
|
name={
|
|
|
|
|
<>
|
|
|
|
|
<Skeleton width="100%" height="1em" marginTop="2" />
|
|
|
|
|
{minHeightNumLines >= 3 && (
|
|
|
|
|
<Skeleton width="100%" height="1em" marginTop="2" />
|
|
|
|
|
)}
|
|
|
|
|
</>
|
|
|
|
|
}
|
|
|
|
|
thumbnailImage={<Skeleton width="80px" height="80px" />}
|
|
|
|
|
minHeightNumLines={minHeightNumLines}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default SquareItemCard;
|