code-split nav bar out
This commit is contained in:
parent
0fa378ec6c
commit
0975a94511
2 changed files with 197 additions and 185 deletions
193
src/app/GlobalNavBar.js
Normal file
193
src/app/GlobalNavBar.js
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
import React from "react";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
HStack,
|
||||||
|
IconButton,
|
||||||
|
Menu,
|
||||||
|
MenuButton,
|
||||||
|
MenuItem,
|
||||||
|
MenuList,
|
||||||
|
useBreakpointValue,
|
||||||
|
useColorMode,
|
||||||
|
} from "@chakra-ui/core";
|
||||||
|
import { Link, useLocation } from "react-router-dom";
|
||||||
|
import { useAuth0 } from "@auth0/auth0-react";
|
||||||
|
import {
|
||||||
|
ChevronLeftIcon,
|
||||||
|
HamburgerIcon,
|
||||||
|
MoonIcon,
|
||||||
|
SunIcon,
|
||||||
|
} from "@chakra-ui/icons";
|
||||||
|
|
||||||
|
import useCurrentUser from "./components/useCurrentUser";
|
||||||
|
|
||||||
|
import HomeLinkIcon from "../images/home-link-icon.png";
|
||||||
|
import HomeLinkIcon2x from "../images/home-link-icon@2x.png";
|
||||||
|
|
||||||
|
function GlobalNavBar() {
|
||||||
|
const navStyle = useBreakpointValue({ base: "menu", md: "buttons" });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box display="flex" alignItems="center" flexWrap="wrap">
|
||||||
|
<HStack alignItems="center" spacing="2" marginRight="4">
|
||||||
|
<HomeLink />
|
||||||
|
{navStyle === "menu" && <NavMenu />}
|
||||||
|
{navStyle === "buttons" && <NavButtons />}
|
||||||
|
</HStack>
|
||||||
|
<Box marginLeft="auto">
|
||||||
|
<UserNavBarSection />
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function HomeLink() {
|
||||||
|
const { pathname } = useLocation();
|
||||||
|
const isHomePage = pathname === "/";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
as={Link}
|
||||||
|
to="/"
|
||||||
|
display="flex"
|
||||||
|
alignItems="center"
|
||||||
|
position="relative"
|
||||||
|
role="group"
|
||||||
|
transition="all 0.2s"
|
||||||
|
opacity="0.8"
|
||||||
|
_hover={{ transform: "scale(1.1)", opacity: "1" }}
|
||||||
|
_focus={{ transform: "scale(1.1)", opacity: "1" }}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
position="absolute"
|
||||||
|
right="100%"
|
||||||
|
opacity={isHomePage ? "0" : "1"}
|
||||||
|
transform={isHomePage ? "translateX(3px)" : "none"}
|
||||||
|
transition="all 0.2s"
|
||||||
|
>
|
||||||
|
<ChevronLeftIcon />
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
as="img"
|
||||||
|
src={HomeLinkIcon}
|
||||||
|
srcSet={`${HomeLinkIcon} 1x, ${HomeLinkIcon2x} 2x`}
|
||||||
|
alt=""
|
||||||
|
height="2em"
|
||||||
|
width="2em"
|
||||||
|
borderRadius="lg"
|
||||||
|
boxShadow="md"
|
||||||
|
/>
|
||||||
|
<Box
|
||||||
|
height="2em"
|
||||||
|
width="2em"
|
||||||
|
position="absolute"
|
||||||
|
top="0"
|
||||||
|
left="0"
|
||||||
|
right="0"
|
||||||
|
bottom="0"
|
||||||
|
borderRadius="lg"
|
||||||
|
transition="border 0.2s"
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function UserNavBarSection() {
|
||||||
|
const { isLoading, isAuthenticated, loginWithRedirect, logout } = useAuth0();
|
||||||
|
const { id, username } = useCurrentUser();
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAuthenticated) {
|
||||||
|
return (
|
||||||
|
<HStack align="center" spacing="2">
|
||||||
|
{username && (
|
||||||
|
<Box fontSize="sm" textAlign="right">
|
||||||
|
Hi, {username}!
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
{id && (
|
||||||
|
<NavButton
|
||||||
|
as={Link}
|
||||||
|
to={`/user/${id}/items`}
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
|
Items
|
||||||
|
</NavButton>
|
||||||
|
)}
|
||||||
|
<NavButton onClick={() => logout({ returnTo: window.location.origin })}>
|
||||||
|
Log out
|
||||||
|
</NavButton>
|
||||||
|
</HStack>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return <NavButton onClick={() => loginWithRedirect()}>Log in</NavButton>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavMenu() {
|
||||||
|
const { colorMode, toggleColorMode } = useColorMode();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Menu>
|
||||||
|
<MenuButton as={NavButton} icon={<HamburgerIcon />} />
|
||||||
|
<MenuList fontSize="sm">
|
||||||
|
<MenuItem as={Link} to="/modeling">
|
||||||
|
Modeling
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem onClick={toggleColorMode}>
|
||||||
|
{colorMode === "light" ? (
|
||||||
|
<Box display="flex" alignItems="center">
|
||||||
|
<Box>Dark mode</Box>
|
||||||
|
<MoonIcon marginLeft="2" />
|
||||||
|
</Box>
|
||||||
|
) : (
|
||||||
|
<Box display="flex" alignItems="center">
|
||||||
|
<Box>Light mode</Box>
|
||||||
|
<SunIcon marginLeft="2" />
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</MenuItem>
|
||||||
|
</MenuList>
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavButtons() {
|
||||||
|
const { colorMode, toggleColorMode } = useColorMode();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<NavButton as={Link} to="/modeling">
|
||||||
|
Modeling
|
||||||
|
</NavButton>
|
||||||
|
<NavButton
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
aria-label={
|
||||||
|
colorMode === "light" ? "Switch to dark mode" : "Switch to light mode"
|
||||||
|
}
|
||||||
|
icon={colorMode === "light" ? <MoonIcon /> : <SunIcon />}
|
||||||
|
onClick={toggleColorMode}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const NavButton = React.forwardRef(({ icon, ...props }, ref) => {
|
||||||
|
const Component = icon ? IconButton : Button;
|
||||||
|
|
||||||
|
// Opacity is in a separate Box, to avoid overriding the built-in Button
|
||||||
|
// hover/focus states.
|
||||||
|
return (
|
||||||
|
<Box opacity="0.8" _hover={{ opacity: "1" }} _focus={{ opacity: "1" }}>
|
||||||
|
<Component size="sm" variant="outline" icon={icon} ref={ref} {...props} />
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default GlobalNavBar;
|
|
@ -1,204 +1,23 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {
|
import { Box } from "@chakra-ui/core";
|
||||||
Box,
|
import loadable from "@loadable/component";
|
||||||
Button,
|
|
||||||
HStack,
|
|
||||||
IconButton,
|
|
||||||
Menu,
|
|
||||||
MenuButton,
|
|
||||||
MenuItem,
|
|
||||||
MenuList,
|
|
||||||
useBreakpointValue,
|
|
||||||
useColorMode,
|
|
||||||
} from "@chakra-ui/core";
|
|
||||||
import { Link, useLocation } from "react-router-dom";
|
|
||||||
import { useAuth0 } from "@auth0/auth0-react";
|
|
||||||
import {
|
|
||||||
ChevronLeftIcon,
|
|
||||||
HamburgerIcon,
|
|
||||||
MoonIcon,
|
|
||||||
SunIcon,
|
|
||||||
} from "@chakra-ui/icons";
|
|
||||||
|
|
||||||
import useCurrentUser from "./components/useCurrentUser";
|
const GlobalNavBar = loadable(() => import("./GlobalNavBar"));
|
||||||
|
|
||||||
import HomeLinkIcon from "../images/home-link-icon.png";
|
|
||||||
import HomeLinkIcon2x from "../images/home-link-icon@2x.png";
|
|
||||||
|
|
||||||
function PageLayout({ children }) {
|
function PageLayout({ children }) {
|
||||||
const navStyle = useBreakpointValue({ base: "menu", md: "buttons" });
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box padding="6" paddingTop="3" maxWidth="1024px" margin="0 auto">
|
<Box padding="6" paddingTop="3" maxWidth="1024px" margin="0 auto">
|
||||||
<Box
|
<Box
|
||||||
width="100%"
|
width="100%"
|
||||||
display="flex"
|
|
||||||
alignItems="center"
|
|
||||||
flexWrap="wrap"
|
|
||||||
marginBottom="6"
|
marginBottom="6"
|
||||||
// Leave space while content is still loading
|
// Leave space while content is still loading
|
||||||
minHeight="2rem"
|
minHeight="2rem"
|
||||||
>
|
>
|
||||||
<HStack alignItems="center" spacing="2" marginRight="4">
|
<GlobalNavBar />
|
||||||
<HomeLink />
|
|
||||||
{navStyle === "menu" && <NavMenu />}
|
|
||||||
{navStyle === "buttons" && <NavButtons />}
|
|
||||||
</HStack>
|
|
||||||
<Box marginLeft="auto">
|
|
||||||
<UserNavBarSection />
|
|
||||||
</Box>
|
|
||||||
</Box>
|
</Box>
|
||||||
{children}
|
{children}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function HomeLink() {
|
|
||||||
const { pathname } = useLocation();
|
|
||||||
const isHomePage = pathname === "/";
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box
|
|
||||||
as={Link}
|
|
||||||
to="/"
|
|
||||||
display="flex"
|
|
||||||
alignItems="center"
|
|
||||||
position="relative"
|
|
||||||
role="group"
|
|
||||||
transition="all 0.2s"
|
|
||||||
opacity="0.8"
|
|
||||||
_hover={{ transform: "scale(1.1)", opacity: "1" }}
|
|
||||||
_focus={{ transform: "scale(1.1)", opacity: "1" }}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
position="absolute"
|
|
||||||
right="100%"
|
|
||||||
opacity={isHomePage ? "0" : "1"}
|
|
||||||
transform={isHomePage ? "translateX(3px)" : "none"}
|
|
||||||
transition="all 0.2s"
|
|
||||||
>
|
|
||||||
<ChevronLeftIcon />
|
|
||||||
</Box>
|
|
||||||
<Box
|
|
||||||
as="img"
|
|
||||||
src={HomeLinkIcon}
|
|
||||||
srcSet={`${HomeLinkIcon} 1x, ${HomeLinkIcon2x} 2x`}
|
|
||||||
alt=""
|
|
||||||
height="2em"
|
|
||||||
width="2em"
|
|
||||||
borderRadius="lg"
|
|
||||||
boxShadow="md"
|
|
||||||
/>
|
|
||||||
<Box
|
|
||||||
height="2em"
|
|
||||||
width="2em"
|
|
||||||
position="absolute"
|
|
||||||
top="0"
|
|
||||||
left="0"
|
|
||||||
right="0"
|
|
||||||
bottom="0"
|
|
||||||
borderRadius="lg"
|
|
||||||
transition="border 0.2s"
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function UserNavBarSection() {
|
|
||||||
const { isLoading, isAuthenticated, loginWithRedirect, logout } = useAuth0();
|
|
||||||
const { id, username } = useCurrentUser();
|
|
||||||
|
|
||||||
if (isLoading) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isAuthenticated) {
|
|
||||||
return (
|
|
||||||
<HStack align="center" spacing="2">
|
|
||||||
{username && (
|
|
||||||
<Box fontSize="sm" textAlign="right">
|
|
||||||
Hi, {username}!
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
{id && (
|
|
||||||
<NavButton
|
|
||||||
as={Link}
|
|
||||||
to={`/user/${id}/items`}
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
>
|
|
||||||
Items
|
|
||||||
</NavButton>
|
|
||||||
)}
|
|
||||||
<NavButton onClick={() => logout({ returnTo: window.location.origin })}>
|
|
||||||
Log out
|
|
||||||
</NavButton>
|
|
||||||
</HStack>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return <NavButton onClick={() => loginWithRedirect()}>Log in</NavButton>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function NavMenu() {
|
|
||||||
const { colorMode, toggleColorMode } = useColorMode();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Menu>
|
|
||||||
<MenuButton as={NavButton} icon={<HamburgerIcon />} />
|
|
||||||
<MenuList fontSize="sm">
|
|
||||||
<MenuItem as={Link} to="/modeling">
|
|
||||||
Modeling
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem onClick={toggleColorMode}>
|
|
||||||
{colorMode === "light" ? (
|
|
||||||
<Box display="flex" alignItems="center">
|
|
||||||
<Box>Dark mode</Box>
|
|
||||||
<MoonIcon marginLeft="2" />
|
|
||||||
</Box>
|
|
||||||
) : (
|
|
||||||
<Box display="flex" alignItems="center">
|
|
||||||
<Box>Light mode</Box>
|
|
||||||
<SunIcon marginLeft="2" />
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</MenuItem>
|
|
||||||
</MenuList>
|
|
||||||
</Menu>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function NavButtons() {
|
|
||||||
const { colorMode, toggleColorMode } = useColorMode();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<NavButton as={Link} to="/modeling">
|
|
||||||
Modeling
|
|
||||||
</NavButton>
|
|
||||||
<NavButton
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
aria-label={
|
|
||||||
colorMode === "light" ? "Switch to dark mode" : "Switch to light mode"
|
|
||||||
}
|
|
||||||
icon={colorMode === "light" ? <MoonIcon /> : <SunIcon />}
|
|
||||||
onClick={toggleColorMode}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const NavButton = React.forwardRef(({ icon, ...props }, ref) => {
|
|
||||||
const Component = icon ? IconButton : Button;
|
|
||||||
|
|
||||||
// Opacity is in a separate Box, to avoid overriding the built-in Button
|
|
||||||
// hover/focus states.
|
|
||||||
return (
|
|
||||||
<Box opacity="0.8" _hover={{ opacity: "1" }} _focus={{ opacity: "1" }}>
|
|
||||||
<Component size="sm" variant="outline" icon={icon} ref={ref} {...props} />
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
export default PageLayout;
|
export default PageLayout;
|
||||||
|
|
Loading…
Reference in a new issue