embed item page in wardrobe page drawer

This commit is contained in:
Emi Matchu 2020-09-12 19:29:20 -07:00
parent 056b238462
commit dcf2ec6a26
5 changed files with 77 additions and 27 deletions

View file

@ -23,16 +23,24 @@ import OutfitPreview from "./components/OutfitPreview";
function ItemPage() { function ItemPage() {
const { itemId } = useParams(); const { itemId } = useParams();
return <ItemPageContent itemId={itemId} />;
}
/**
* ItemPageContent is the content of ItemPage, but we also use it as the
* entry point for ItemPageDrawer! When embedded in ItemPageDrawer, the
* `isEmbedded` prop is true, so we know not to e.g. set the page title.
*/
export function ItemPageContent({ itemId, isEmbedded }) {
return ( return (
<VStack spacing="6"> <VStack spacing="6">
<ItemPageHeader itemId={itemId} /> <ItemPageHeader itemId={itemId} isEmbedded={isEmbedded} />
<ItemPageOutfitPreview itemId={itemId} /> <ItemPageOutfitPreview itemId={itemId} />
</VStack> </VStack>
); );
} }
function ItemPageHeader({ itemId }) { function ItemPageHeader({ itemId, isEmbedded }) {
const { error, data } = useQuery( const { error, data } = useQuery(
gql` gql`
query ItemPage($itemId: ID!) { query ItemPage($itemId: ID!) {
@ -47,7 +55,7 @@ function ItemPageHeader({ itemId }) {
{ variables: { itemId }, returnPartialData: true } { variables: { itemId }, returnPartialData: true }
); );
usePageTitle(data?.item?.name); usePageTitle(data?.item?.name, { skip: isEmbedded });
if (error) { if (error) {
return <Box color="red.400">{error.message}</Box>; return <Box color="red.400">{error.message}</Box>;
@ -67,7 +75,14 @@ function ItemPageHeader({ itemId }) {
</Skeleton> </Skeleton>
<Box> <Box>
<Skeleton isLoaded={item?.name}> <Skeleton isLoaded={item?.name}>
<Heading1 lineHeight="1.1">{item?.name || "Item name here"}</Heading1> <Heading1
lineHeight="1.1"
// Nudge down the size a bit in the embed case, to better fit the
// tighter layout!
size={isEmbedded ? "xl" : "2xl"}
>
{item?.name || "Item name here"}
</Heading1>
</Skeleton> </Skeleton>
<ItemPageBadges item={item} /> <ItemPageBadges item={item} />
</Box> </Box>
@ -131,7 +146,7 @@ function ItemPageBadges({ item }) {
encodeURIComponent(item.name) encodeURIComponent(item.name)
} }
> >
Trades Trade Post
</LinkBadge> </LinkBadge>
)} )}
</Skeleton> </Skeleton>

30
src/app/ItemPageDrawer.js Normal file
View file

@ -0,0 +1,30 @@
import React from "react";
import {
Drawer,
DrawerBody,
DrawerContent,
DrawerCloseButton,
DrawerOverlay,
useBreakpointValue,
} from "@chakra-ui/core";
import { ItemPageContent } from "./ItemPage";
function ItemPageDrawer({ item, isOpen, onClose }) {
const placement = useBreakpointValue({ base: "bottom", lg: "right" });
return (
<Drawer placement={placement} size="md" isOpen={isOpen} onClose={onClose}>
<DrawerOverlay>
<DrawerContent>
<DrawerCloseButton />
<DrawerBody>
<ItemPageContent itemId={item.id} isEmbedded />
</DrawerBody>
</DrawerContent>
</DrawerOverlay>
</Drawer>
);
}
export default ItemPageDrawer;

View file

@ -16,6 +16,7 @@ import {
InfoIcon, InfoIcon,
NotAllowedIcon, NotAllowedIcon,
} from "@chakra-ui/icons"; } from "@chakra-ui/icons";
import { Link } from "react-router-dom";
import loadable from "@loadable/component"; import loadable from "@loadable/component";
import { import {
@ -27,6 +28,7 @@ import {
} from "../components/ItemCard"; } from "../components/ItemCard";
import SupportOnly from "./support/SupportOnly"; import SupportOnly from "./support/SupportOnly";
const LoadableItemPageDrawer = loadable(() => import("../ItemPageDrawer"));
const LoadableItemSupportDrawer = loadable(() => const LoadableItemSupportDrawer = loadable(() =>
import("./support/ItemSupportDrawer") import("./support/ItemSupportDrawer")
); );
@ -58,6 +60,7 @@ function Item({
onRemove, onRemove,
isDisabled = false, isDisabled = false,
}) { }) {
const [infoDrawerIsOpen, setInfoDrawerIsOpen] = React.useState(false);
const [supportDrawerIsOpen, setSupportDrawerIsOpen] = React.useState(false); const [supportDrawerIsOpen, setSupportDrawerIsOpen] = React.useState(false);
return ( return (
@ -97,13 +100,25 @@ function Item({
<ItemActionButton <ItemActionButton
icon={<InfoIcon />} icon={<InfoIcon />}
label="More info" label="More info"
href={`https://impress.openneo.net/items/${ to={`/items/${item.id}`}
item.id onClick={(e) => {
}-${item.name.replace(/ /g, "-")}`} const willProbablyOpenInNewTab =
onClick={(e) => e.stopPropagation()} e.metaKey || e.shiftKey || e.altKey || e.ctrlKey;
if (willProbablyOpenInNewTab) {
return;
}
setInfoDrawerIsOpen(true);
e.preventDefault();
}}
/> />
</Box> </Box>
</ItemContainer> </ItemContainer>
<LoadableItemPageDrawer
item={item}
isOpen={infoDrawerIsOpen}
onClose={() => setInfoDrawerIsOpen(false)}
/>
<SupportOnly> <SupportOnly>
<LoadableItemSupportDrawer <LoadableItemSupportDrawer
item={item} item={item}
@ -220,7 +235,7 @@ function ItemBadges({ item }) {
/** /**
* ItemActionButton is one of a list of actions a user can take for this item. * ItemActionButton is one of a list of actions a user can take for this item.
*/ */
function ItemActionButton({ icon, label, href, onClick }) { function ItemActionButton({ icon, label, to, onClick }) {
const theme = useTheme(); const theme = useTheme();
const focusBackgroundColor = useColorModeValue( const focusBackgroundColor = useColorModeValue(
@ -235,13 +250,12 @@ function ItemActionButton({ icon, label, href, onClick }) {
return ( return (
<Tooltip label={label} placement="top"> <Tooltip label={label} placement="top">
<IconButton <IconButton
as={href ? "a" : "button"} as={to ? Link : "button"}
icon={icon} icon={icon}
aria-label={label} aria-label={label}
variant="ghost" variant="ghost"
color="gray.400" color="gray.400"
href={href} to={to}
target={href ? "_blank" : null}
onClick={onClick} onClick={onClick}
className={css` className={css`
opacity: 0; opacity: 0;

View file

@ -41,22 +41,12 @@ import useSupport from "./useSupport";
* from another lazy-loaded component! * from another lazy-loaded component!
*/ */
function ItemSupportDrawer({ item, isOpen, onClose }) { function ItemSupportDrawer({ item, isOpen, onClose }) {
const placement = useBreakpointValue({ const placement = useBreakpointValue({ base: "bottom", lg: "right" });
base: "bottom",
lg: "right",
// TODO: There's a bug in the Chakra RC that doesn't read the breakpoint
// specification correctly - we need these extra keys until it's fixed!
// https://github.com/chakra-ui/chakra-ui/issues/1444
0: "bottom",
1: "bottom",
2: "right",
3: "right",
});
return ( return (
<Drawer <Drawer
placement={placement} placement={placement}
size="md"
isOpen={isOpen} isOpen={isOpen}
onClose={onClose} onClose={onClose}
// blockScrollOnMount doesn't matter on our fullscreen UI, but the // blockScrollOnMount doesn't matter on our fullscreen UI, but the

View file

@ -111,10 +111,11 @@ export function useDebounce(
/** /**
* usePageTitle sets the page title! * usePageTitle sets the page title!
*/ */
export function usePageTitle(title) { export function usePageTitle(title, { skip = false } = {}) {
React.useEffect(() => { React.useEffect(() => {
if (skip) return;
document.title = title ? `${title} | Dress to Impress` : "Dress to Impress"; document.title = title ? `${title} | Dress to Impress` : "Dress to Impress";
}, [title]); }, [title, skip]);
} }
/** /**