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.
 
 

250 lines
6.5 KiB

import React from 'react';
import {
Box,
BoxProps,
ChevronIcon,
color,
Fade,
Flex,
FlexProps,
space,
Stack,
StxInline,
IconButton,
} from '@stacks/ui';
import { Link, LinkProps, Text } from '@components/typography';
import MenuIcon from 'mdi-react/MenuIcon';
import CloseIcon from 'mdi-react/CloseIcon';
import { useMobileMenuState } from '@common/hooks/use-mobile-menu';
import { ForwardRefExoticComponentWithAs, forwardRefWithAs } from '@stacks/ui-core';
import NextLink from 'next/link';
import { StacksDocsLogo } from '@components/stacks-docs-logo';
import { ColorModeButton } from '@components/color-mode-button';
import { SearchButton } from '@components/search-button';
import { border, transition } from '@common/utils';
import { getCapsizeStyles } from '@components/mdx/typography';
import { useTouchable } from '@common/hooks/use-touchable';
import { useRouter } from 'next/router';
const MenuButton = ({ ...rest }: any) => {
const { isOpen, handleOpen, handleClose } = useMobileMenuState();
const Icon = isOpen ? CloseIcon : MenuIcon;
const handleClick = isOpen ? handleClose : handleOpen;
return (
<IconButton
color="var(--colors-invert)"
display={['grid', 'grid', 'none']}
onClick={handleClick}
icon={Icon}
/>
);
};
const HeaderWrapper: React.FC<BoxProps> = React.forwardRef((props, ref: any) => (
<Box as="header" ref={ref} width="100%" position="relative" zIndex={9999} {...props} />
));
interface NavChildren {
label: string;
href?: string;
target?: string;
}
interface NavItem {
label: string;
href: string;
target?: string;
children?: NavItem[];
}
const nav: NavItem[] = [
{
label: 'Start building',
href: '',
children: [
{
label: 'Documentation',
href: 'https://docs.stacks.co/',
target: '_self',
},
{
label: 'GitHub',
href: 'https://github.com/stacks-network',
},
{
label: 'Resources',
href: 'https://www.stacks.co/learn/learning-resources',
},
{
label: 'Discord',
href: 'https://discord.gg/5DJaBrf',
},
{
label: 'Forum',
href: 'https://forum.stacks.org',
},
],
},
{ label: 'Discover apps', href: 'https://www.stacks.co/explore/discover-apps' },
];
const HeaderTextItem: ForwardRefExoticComponentWithAs<BoxProps & LinkProps, 'a'> = forwardRefWithAs<
BoxProps & LinkProps,
'a'
>(({ children, href, as = 'a', ...rest }, ref) => (
<Text
color={color('invert')}
{...{
...getCapsizeStyles(16, 26),
fontWeight: '400',
color: 'currentColor',
_hover: {
cursor: href ? 'pointer' : 'unset',
textDecoration: href ? 'underline' : 'none',
color: href ? color('accent') : 'currentColor',
},
...rest,
}}
as={as}
href={href}
ref={ref}
>
{children}
</Text>
));
const NavItem: React.FC<FlexProps & { item: NavItem }> = ({ item, ...props }) => {
const { hover, active, bind } = useTouchable({
behavior: 'link',
});
return (
<Flex justifyContent="center" position="relative" {...props} {...bind}>
<HeaderTextItem
as={item.href ? 'a' : 'span'}
href={item.href}
rel="nofollow noopener noreferrer"
target="_blank"
>
{item.label}
</HeaderTextItem>
{item.children ? (
<Box color={color('text-caption')} ml={space('extra-tight')}>
<ChevronIcon direction="down" />
</Box>
) : null}
{item.children ? (
<Fade in={hover || active}>
{styles => (
<Box
pt={space('base-loose')}
top="100%"
position="absolute"
transform="translateX(-5px)"
zIndex={99999999}
minWidth="200px"
style={{ ...styles }}
>
<Box
borderRadius="12px"
border={border()}
bg={color('bg')}
overflow="hidden"
boxShadow="0 0 8px 0 rgba(15,17,23,.03), 0 16px 40px 0 rgba(15,17,23,.06)"
>
{item.children.map((child, _key) => (
<Box
_hover={{
bg: color('accent'),
color: color('bg'),
cursor: 'pointer',
}}
transition={transition()}
color={color('text-title')}
borderBottom={_key < item.children.length - 1 && border()}
px={space('base')}
py={space('base-loose')}
as="a"
display="block"
// @ts-ignore
href={child.href}
target={child.target || '_blank'}
>
<HeaderTextItem color="currentColor">{child.label}</HeaderTextItem>
</Box>
))}
</Box>
</Box>
)}
</Fade>
) : null}
</Flex>
);
};
const Navigation: React.FC<BoxProps> = props => {
return (
<Box
as="nav"
position="relative"
zIndex={99999999}
display={['none', 'none', 'block']}
transform="translateY(2px)"
{...props}
>
<Stack mr={space('base')} isInline spacing={space('extra-loose')}>
{nav.map((item, key) => (
<NavItem item={item} key={key} />
))}
</Stack>
</Box>
);
};
const LogoLink = React.memo(() => {
return (
<NextLink href="/" passHref>
<Link _hover={{ textDecoration: 'none' }} as="a" display="flex">
<Flex as="span" alignItems="center">
<StacksDocsLogo color={color('text-title')} />
</Flex>
</Link>
</NextLink>
);
});
const Header = ({ hideSubBar, ...rest }: any) => {
return (
<>
<HeaderWrapper>
<Box mx="auto" px="extra-loose">
<Flex
justifyContent="space-between"
alignItems="center"
bg={color('bg')}
style={{
backdropFilter: 'blur(5px)',
}}
height="72px"
mx="auto"
color={color('text-title')}
{...rest}
>
<LogoLink />
<Flex alignItems="center">
<Navigation />
<Stack isInline spacing="tight">
<SearchButton />
<ColorModeButton />
<MenuButton />
</Stack>
</Flex>
</Flex>
</Box>
</HeaderWrapper>
</>
);
};
export { Header };