You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

184 lines
4.9 KiB

import {
Box,
BoxProps,
Center,
CloseButton,
Flex,
HStack,
IconButton,
IconButtonProps,
useBreakpointValue,
useColorModeValue,
useUpdateEffect,
} from "@chakra-ui/react"
import { AnimatePresence, motion, useElementScroll } from "framer-motion"
import useRouteChanged from "src/hooks/use-route-changed"
import NextLink from "next/link"
import { useRouter } from "next/router"
import * as React from "react"
import { AiOutlineMenu } from "react-icons/ai"
import { RemoveScroll } from "react-remove-scroll"
import Logo from "src/components/logo"
function NavLink({ href, children }) {
const { pathname } = useRouter()
const [, group] = href.split("/")
const isActive = pathname.includes(group)
return (
<NextLink href={href}>
<Center
flex="1"
minH="40px"
as="button"
rounded="md"
transition="0.2s all"
fontWeight={isActive ? "semibold" : "medium"}
bg={isActive ? "teal.400" : undefined}
borderWidth={isActive ? undefined : "1px"}
color={isActive ? "white" : undefined}
_hover={{
bg: isActive
? "teal.500"
: useColorModeValue("gray.100", "whiteAlpha.100"),
}}
>
{children}
</Center>
</NextLink>
)
}
interface MobileNavContentProps {
isOpen?: boolean
onClose?: () => void
}
export function MobileNavContent(props: MobileNavContentProps) {
const { isOpen, onClose } = props
const closeBtnRef = React.useRef<HTMLButtonElement>()
const { pathname } = useRouter()
useRouteChanged(onClose)
/**
* Scenario: Menu is open on mobile, and user resizes to desktop/tablet viewport.
* Result: We'll close the menu
*/
const showOnBreakpoint = useBreakpointValue({ base: true, lg: false })
React.useEffect(() => {
if (showOnBreakpoint == false) {
onClose()
}
}, [showOnBreakpoint])
useUpdateEffect(() => {
if (isOpen) {
requestAnimationFrame(() => {
closeBtnRef.current?.focus()
})
}
}, [isOpen])
const [shadow, setShadow] = React.useState<string>()
return (
<AnimatePresence>
{isOpen && (
<RemoveScroll forwardProps>
<motion.div
transition={{ duration: 0.08 }}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
<Flex
direction="column"
w="100%"
bg={useColorModeValue("white", "gray.800")}
h="100vh"
overflow="auto"
pos="absolute"
top="0"
left="0"
zIndex={20}
pb="8"
>
<Box>
<Flex justify="space-between" px="6" pt="5" pb="4">
<Logo />
<HStack spacing="5">
<CloseButton ref={closeBtnRef} onClick={onClose} />
</HStack>
</Flex>
<Box px="6" pb="6" pt="2" shadow={shadow}>
<HStack>
<NavLink href="/docs/getting-started">Docs</NavLink>
<NavLink href="/guides/integrations/with-cra">
Guides
</NavLink>
<NavLink href="/team">Team</NavLink>
</HStack>
</Box>
</Box>
<ScrollView
onScroll={(scrolled) => {
setShadow(scrolled ? "md" : undefined)
}}
>
</ScrollView>
</Flex>
</motion.div>
</RemoveScroll>
)}
</AnimatePresence>
)
}
const ScrollView = (props: BoxProps & { onScroll?: any }) => {
const { onScroll, ...rest } = props
const [y, setY] = React.useState(0)
const elRef = React.useRef<any>()
const { scrollY } = useElementScroll(elRef)
React.useEffect(() => {
return scrollY.onChange(() => setY(scrollY.get()))
}, [scrollY])
useUpdateEffect(() => {
onScroll?.(y > 5 ? true : false)
}, [y])
return (
<Box
ref={elRef}
flex="1"
id="routes"
overflow="auto"
px="6"
pb="6"
{...rest}
/>
)
}
export const MobileNavButton = React.forwardRef(
(props: IconButtonProps, ref: React.Ref<any>) => {
return (
<IconButton
ref={ref}
display={{ base: "flex", md: "none" }}
aria-label="Open menu"
fontSize="20px"
color={useColorModeValue("gray.800", "inherit")}
variant="ghost"
icon={<AiOutlineMenu />}
{...props}
/>
)
},
)