-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13 from threshold-network/ui/header-component
UI: Header component Ref: #2 ~Depends on: #12~ This pull request introduces: - `Logo` component: - `Header` component - `SelectWallet` component redesign Additional changes: - `Button` component theme adjustments - `Modal` component theme adjustments Note: Since this PR introduces changes widely used in the project eg. `Modal` or `Button` changes it's recommended to review it and merge primarily.
- Loading branch information
Showing
26 changed files
with
806 additions
and
239 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,54 @@ | ||
import { FC } from "react" | ||
import { | ||
Box, | ||
HStack, | ||
StackProps, | ||
ThemingProps, | ||
useStyleConfig, | ||
} from "@threshold-network/components" | ||
import { Box, StackProps, HStack } from "@threshold-network/components" | ||
import { motion } from "framer-motion" | ||
|
||
type DotsLoadingIndicatorProps = StackProps & Omit<ThemingProps, "orientation"> | ||
const Dot: FC = () => ( | ||
<motion.div | ||
variants={{ | ||
initial: { | ||
y: "50%", | ||
opacity: 0.85, | ||
}, | ||
animate: { | ||
y: "-50%", | ||
opacity: 0, | ||
}, | ||
}} | ||
transition={{ | ||
duration: 0.8, | ||
repeat: Infinity, | ||
repeatType: "reverse", | ||
ease: "easeInOut", | ||
}} | ||
> | ||
<Box w={1} h={1} rounded="full" bg="white" /> | ||
</motion.div> | ||
) | ||
|
||
export const DotsLoadingIndicator: FC<DotsLoadingIndicatorProps> = ({ | ||
colorScheme = "brand", | ||
size = "sm", | ||
...restProps | ||
}) => { | ||
const styles = useStyleConfig("DotsLoadingIndicator", { | ||
colorScheme, | ||
size, | ||
}) | ||
|
||
return ( | ||
<HStack spacing="4" {...restProps}> | ||
<Box __css={styles} /> | ||
<Box __css={styles} /> | ||
<Box __css={styles} /> | ||
</HStack> | ||
) | ||
} | ||
export const DotsLoadingIndicator: FC<StackProps> = (props) => ( | ||
<HStack | ||
spacing={0.5} | ||
w={5} | ||
h={5} | ||
as={motion.div} | ||
variants={{ | ||
initial: { | ||
transition: { | ||
staggerChildren: 0.2, | ||
}, | ||
}, | ||
animate: { | ||
transition: { | ||
staggerChildren: 0.2, | ||
}, | ||
}, | ||
}} | ||
initial="initial" | ||
animate="animate" | ||
{...props} | ||
> | ||
<Dot /> | ||
<Dot /> | ||
<Dot /> | ||
</HStack> | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { Box, BoxProps, Flex } from "@threshold-network/components" | ||
import { useWeb3React } from "@web3-react/core" | ||
import { FC } from "react" | ||
import { ModalType, Token } from "../../enums" | ||
import { useModal } from "../../hooks/useModal" | ||
import { useToken } from "../../hooks/useToken" | ||
import { Logo } from "../Logo" | ||
import { NavigationMenu } from "./NavigationMenu" | ||
import { UserPanel } from "./UserPanel" | ||
|
||
// TODO: Load new fonts | ||
|
||
const Header: FC<BoxProps> = (props) => { | ||
const { | ||
active: isConnected, | ||
deactivate: handleWalletDisconnection, | ||
account: accountAddress, | ||
chainId, | ||
} = useWeb3React() | ||
const { openModal } = useModal() | ||
const handleWalletConnection = () => openModal(ModalType.SelectWallet) | ||
const { balance } = useToken(Token.TBTCV2) | ||
|
||
return ( | ||
<Box | ||
bg={"black"} | ||
color={"white"} | ||
borderBottom={"1px solid"} | ||
borderColor={"whiteAlpha.350"} | ||
{...props} | ||
> | ||
<Flex | ||
maxW={"1920px"} | ||
mx={"auto"} | ||
alignItems={"center"} | ||
px={{ base: 2, lg: 10 }} | ||
h={{ base: 16, lg: 24 }} | ||
> | ||
<Logo zIndex="popover" /> | ||
<NavigationMenu | ||
items={[ | ||
{ label: "Bridge", to: "/tBTC/mint" }, | ||
{ label: "Collect", to: "/collect" }, | ||
{ label: "Earn", to: "/earn" }, | ||
]} | ||
/> | ||
<UserPanel | ||
isConnected={isConnected} | ||
accountAddress={accountAddress} | ||
balance={balance} | ||
chainId={chainId} | ||
onConnectClick={handleWalletConnection} | ||
onDisconnectClick={handleWalletDisconnection} | ||
/> | ||
</Flex> | ||
</Box> | ||
) | ||
} | ||
|
||
export default Header |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
import { spacing } from "@chakra-ui/theme/foundations/spacing" | ||
import { | ||
Button, | ||
Drawer, | ||
DrawerContent, | ||
DrawerOverlay, | ||
HStack, | ||
Icon, | ||
Link, | ||
List, | ||
ListItem, | ||
ListItemProps, | ||
StackDivider, | ||
StackProps, | ||
SystemStyleObject, | ||
useDisclosure, | ||
VisuallyHidden, | ||
VStack, | ||
} from "@threshold-network/components" | ||
import { motion } from "framer-motion" | ||
import { FC, useRef } from "react" | ||
import { NavLink } from "react-router-dom" | ||
import useChakraBreakpoint from "../../hooks/useChakraBreakpoint" | ||
|
||
const NavigationMenuMobileContainer: FC<StackProps> = (props) => ( | ||
<VStack | ||
divider={<StackDivider />} | ||
{...props} | ||
spacing={0} | ||
position="fixed" | ||
inset={0} | ||
h="100vh" | ||
py={16} | ||
bgGradient="radial(circle at bottom right, #0A1616, #090909)" | ||
borderLeft="1px solid" | ||
borderColor="whiteAlpha.250" | ||
alignItems="stretch" | ||
/> | ||
) | ||
|
||
const NavigationMenuDesktopContainer: FC<StackProps> = (props) => ( | ||
<HStack | ||
{...props} | ||
spacing={0} | ||
alignSelf="stretch" | ||
alignItems="stretch" | ||
ml={{ | ||
lg: `calc(${spacing[16]} - ${spacing[5]})`, | ||
xl: `calc(142px - ${spacing[5]})`, | ||
}} | ||
mr="auto" | ||
/> | ||
) | ||
|
||
const HamburgerIcon: FC<{ isToggled: boolean }> = ({ isToggled }) => ( | ||
<Icon | ||
xmlns="http://www.w3.org/2000/svg" | ||
viewBox="0 0 24 24" | ||
w={5} | ||
h={5} | ||
fill="none" | ||
stroke="white" | ||
strokeWidth={1} | ||
strokeLinecap="round" | ||
strokeLinejoin="round" | ||
> | ||
<motion.path | ||
initial={false} | ||
animate={{ | ||
rotate: isToggled ? -45 : 0, | ||
y: isToggled ? "25%" : 0, | ||
}} | ||
d="M3 6h18" | ||
/> | ||
<motion.path | ||
initial={false} | ||
animate={{ | ||
scaleX: isToggled ? 0 : 1, | ||
}} | ||
d="M3 12h18" | ||
/> | ||
<motion.path | ||
initial={false} | ||
animate={{ | ||
rotate: isToggled ? 45 : 0, | ||
y: isToggled ? "-25%" : 0, | ||
}} | ||
d="M3 18h18" | ||
/> | ||
</Icon> | ||
) | ||
|
||
const activeLinkIndicatorStyles: SystemStyleObject = { | ||
position: "relative", | ||
"&.active": { | ||
"&:before": { | ||
content: '""', | ||
position: "absolute", | ||
bottom: 0, | ||
left: { base: 0, lg: 5 }, | ||
width: { base: 0.5, lg: `calc(100% - 2 * ${spacing[5]})` }, // To account for container's padding | ||
height: { base: "full", lg: 0.5 }, | ||
bg: "#53D2FF", | ||
}, | ||
}, | ||
} | ||
|
||
export type NavigationMenuItemType = { | ||
/** The label of the menu item */ | ||
label: string | ||
/** The route to navigate to when the menu item is clicked */ | ||
to: string | ||
} | ||
interface NavigationMenuItemProps | ||
extends ListItemProps, | ||
NavigationMenuItemType {} | ||
|
||
const NavigationMenuItem: FC<NavigationMenuItemProps> = ({ | ||
label, | ||
to, | ||
...restProps | ||
}) => { | ||
return ( | ||
<ListItem {...restProps}> | ||
<Link | ||
as={NavLink} | ||
to={to} | ||
display={"inline-flex"} | ||
alignItems={"center"} | ||
w="full" | ||
h="full" | ||
p={5} | ||
sx={activeLinkIndicatorStyles} | ||
fontWeight={"black"} | ||
textTransform={"uppercase"} | ||
_hover={{ textDecoration: "none" }} | ||
> | ||
{label} | ||
</Link> | ||
</ListItem> | ||
) | ||
} | ||
|
||
const renderNavigationMenuItems = (items: NavigationMenuItemType[]) => | ||
items.map((item) => <NavigationMenuItem {...item} key={item.to} />) | ||
|
||
interface NavigationMenuProps extends StackProps { | ||
/** The menu items to display */ | ||
items: NavigationMenuItemType[] | ||
} | ||
|
||
export const NavigationMenu: FC<NavigationMenuProps> = ({ | ||
items, | ||
...restProps | ||
}) => { | ||
const { isOpen, onOpen, onClose } = useDisclosure() | ||
const isMobile = useChakraBreakpoint("lg") | ||
const buttonRef = useRef<HTMLButtonElement>(null) | ||
|
||
return ( | ||
<> | ||
{isMobile ? ( | ||
<Button | ||
ref={buttonRef} | ||
variant="unstyled" | ||
order={-1} | ||
onClick={isOpen ? onClose : onOpen} | ||
zIndex="popover" | ||
mr={2} | ||
> | ||
<VisuallyHidden> | ||
{isOpen ? "Close" : "Open"} navigation menu | ||
</VisuallyHidden> | ||
<HamburgerIcon isToggled={isOpen} /> | ||
</Button> | ||
) : null} | ||
{isMobile ? ( | ||
<Drawer | ||
isOpen={isOpen} | ||
placement="right" | ||
onClose={onClose} | ||
size="sm" | ||
finalFocusRef={buttonRef} | ||
> | ||
<DrawerOverlay backdropFilter="auto" backdropBlur="lg" /> | ||
<DrawerContent> | ||
<NavigationMenuMobileContainer as={List} {...restProps}> | ||
{renderNavigationMenuItems(items)} | ||
</NavigationMenuMobileContainer> | ||
</DrawerContent> | ||
</Drawer> | ||
) : ( | ||
<NavigationMenuDesktopContainer as={List} {...restProps}> | ||
{renderNavigationMenuItems(items)} | ||
</NavigationMenuDesktopContainer> | ||
)} | ||
</> | ||
) | ||
} |
Oops, something went wrong.