Skip to content

Commit

Permalink
Header component adjustements (#357)
Browse files Browse the repository at this point in the history
Ref: #355 

## Goal:
To adjust `Header` component following latest design changes

## Done:
- Implement generic `Link` and `NavLink` components, a fusion of
Chakra's and Router's `Link` component
- Implement `Navigation` component with animated active item indicator
- Added conditional rendering for `ConnectWallet` component with
presence animation
  • Loading branch information
kkosiorowska authored Apr 30, 2024
2 parents e0a40fd + 689154b commit e1b8d0a
Show file tree
Hide file tree
Showing 13 changed files with 210 additions and 47 deletions.
87 changes: 47 additions & 40 deletions dapp/src/components/Header/ConnectWallet.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
import React from "react"
import { Button, HStack, Icon, Tooltip } from "@chakra-ui/react"
import { useWallet } from "#/hooks"
import { useIsHomeRouteActive, useWallet, useWalletContext } from "#/hooks"
import { CurrencyBalance } from "#/components/shared/CurrencyBalance"
import { TextMd } from "#/components/shared/Typography"
import { BitcoinIcon, EthereumIcon } from "#/assets/icons"
import { BitcoinIcon } from "#/assets/icons"
import { Account } from "@ledgerhq/wallet-api-client"
import { CURRENCY_ID_BITCOIN } from "#/constants"
import {
isSupportedBTCAddressType,
logPromiseFailure,
truncateAddress,
} from "#/utils"
import { AnimatePresence, motion, Variants } from "framer-motion"

const containerVariants: Variants = {
hidden: { opacity: 0, y: -48 },
visible: { opacity: 1, y: 0 },
}

const getCustomDataByAccount = (
account?: Account,
Expand All @@ -28,53 +34,54 @@ const getCustomDataByAccount = (
export default function ConnectWallet() {
const {
bitcoin: { account: btcAccount, requestAccount: requestBitcoinAccount },
ethereum: { account: ethAccount, requestAccount: requestEthereumAccount },
} = useWallet()
// TODO: Move `isConnected` to useWallet hook
const { isConnected } = useWalletContext()

const customDataBtcAccount = getCustomDataByAccount(btcAccount)
const customDataEthAccount = getCustomDataByAccount(ethAccount)

const isHomeRoute = useIsHomeRouteActive()

const handleConnectBitcoinAccount = () => {
logPromiseFailure(requestBitcoinAccount())
}

const handleConnectEthereumAccount = () => {
logPromiseFailure(requestEthereumAccount())
}

return (
<HStack spacing={4}>
<HStack display={{ base: "none", md: "flex" }}>
<TextMd color="grey.500">Balance</TextMd>
<CurrencyBalance
currency="bitcoin"
amount={btcAccount?.balance.toString()}
/>
</HStack>
<Tooltip
label="Currently, we support only Legacy or Native SegWit addresses. Please try connecting another address."
placement="top"
isDisabled={
!(btcAccount && !isSupportedBTCAddressType(btcAccount.address))
}
>
<Button
variant="card"
colorScheme={customDataBtcAccount.colorScheme}
leftIcon={<Icon as={BitcoinIcon} boxSize={6} />}
onClick={handleConnectBitcoinAccount}
<AnimatePresence initial={false}>
{(isConnected || !isHomeRoute) && (
<HStack
as={motion.div}
variants={containerVariants}
initial="hidden"
animate="visible"
exit="hidden"
spacing={4}
>
{customDataBtcAccount.text}
</Button>
</Tooltip>
<Button
variant="card"
colorScheme={customDataEthAccount.colorScheme}
leftIcon={<Icon as={EthereumIcon} boxSize={6} />}
onClick={handleConnectEthereumAccount}
>
{customDataEthAccount.text}
</Button>
</HStack>
<HStack display={{ base: "none", md: "flex" }}>
<TextMd color="grey.500">Balance</TextMd>
<CurrencyBalance
currency="bitcoin"
amount={btcAccount?.balance.toString()}
/>
</HStack>
<Tooltip
label="Currently, we support only Legacy or Native SegWit addresses. Please try connecting another address."
placement="top"
isDisabled={
!(btcAccount && !isSupportedBTCAddressType(btcAccount.address))
}
>
<Button
variant="card"
colorScheme={customDataBtcAccount.colorScheme}
leftIcon={<Icon as={BitcoinIcon} boxSize={6} />}
onClick={handleConnectBitcoinAccount}
>
{customDataBtcAccount.text}
</Button>
</Tooltip>
</HStack>
)}
</AnimatePresence>
)
}
24 changes: 24 additions & 0 deletions dapp/src/components/Header/Navigation/Navigation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from "react"
import { Box, BoxProps, HStack, List } from "@chakra-ui/react"
import { NavigationItemType } from "#/types/navigation"
import NavigationItem from "./NavigationItem"

type NavigationProps = BoxProps & {
items: NavigationItemType[]
}

function Navigation(props: NavigationProps) {
const { items, ...restProps } = props

return (
<Box as="nav" {...restProps}>
<HStack as={List} spacing={5} ml={12}>
{items.map((item) => (
<NavigationItem key={item.href} {...item} />
))}
</HStack>
</Box>
)
}

export default Navigation
38 changes: 38 additions & 0 deletions dapp/src/components/Header/Navigation/NavigationItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from "react"
import {
Box,
ListItem,
ListItemProps,
useMultiStyleConfig,
} from "@chakra-ui/react"
import { motion } from "framer-motion"
import { NavigationItemType } from "#/types/navigation"
import { NavLink } from "../../shared/NavLink"

type NavigationItemProps = ListItemProps & NavigationItemType

function NavigationItem(props: NavigationItemProps) {
const { label, href, ...restProps } = props
const styles = useMultiStyleConfig("Link", { variant: "navigation" })

return (
<ListItem pos="relative" {...restProps}>
<NavLink to={href} sx={styles.container}>
{({ isActive }) => (
<>
{label}
{isActive && (
<Box
as={motion.span}
layoutId="active-route-indicator"
sx={styles.indicator}
/>
)}
</>
)}
</NavLink>
</ListItem>
)
}

export default NavigationItem
1 change: 1 addition & 0 deletions dapp/src/components/Header/Navigation/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Navigation } from "./Navigation"
14 changes: 12 additions & 2 deletions dapp/src/components/Header/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import React from "react"
import { Flex, HStack, Icon } from "@chakra-ui/react"
import { AcreLogo } from "#/assets/icons"
import { routerPath } from "#/router/path"
import { Flex, HStack, Icon } from "@chakra-ui/react"
import { NavigationItemType } from "#/types/navigation"
import ConnectWallet from "./ConnectWallet"
import { Navigation } from "./Navigation"

// TODO: To be adjusted after project pivot/cleanup
const NAVIGATION_ITEMS: NavigationItemType[] = [
{ label: "Season 1", href: routerPath.home },
{ label: "Dashboard", href: routerPath.dashboard },
]

export default function Header() {
return (
<HStack as="header" p={6}>
<HStack as="header" px={10} py={7}>
<Icon as={AcreLogo} w={20} h={12} />
<Navigation items={NAVIGATION_ITEMS} />
<Flex ml="auto">
<ConnectWallet />
</Flex>
Expand Down
16 changes: 16 additions & 0 deletions dapp/src/components/shared/Link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from "react"
import {
Link as ChakraLink,
LinkProps as ChakraLinkProps,
} from "@chakra-ui/react"
import {
Link as RouterLink,
LinkProps as RouterLinkProps,
} from "react-router-dom"

type LinkProps = Omit<ChakraLinkProps, "as" | "href"> &
Pick<RouterLinkProps, "to">

export function Link(props: LinkProps) {
return <ChakraLink as={RouterLink} {...props} />
}
21 changes: 21 additions & 0 deletions dapp/src/components/shared/NavLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from "react"
import {
Link as ChakraLink,
LinkProps as ChakraLinkProps,
} from "@chakra-ui/react"
import {
NavLink as RouterNavLink,
NavLinkProps as RouterNavLinkProps,
} from "react-router-dom"

type NavLinkProps = Omit<ChakraLinkProps, "as" | "href" | "children"> &
Pick<RouterNavLinkProps, "to" | "children">

export function NavLink(props: NavLinkProps) {
const { children, ...restProps } = props
return (
<ChakraLink as={RouterNavLink} {...restProps}>
{children as React.ReactNode}
</ChakraLink>
)
}
1 change: 1 addition & 0 deletions dapp/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ export * from "./useTimeout"
export * from "./useCountdown"
export * from "./useActivities"
export * from "./useSize"
export * from "./router"
1 change: 1 addition & 0 deletions dapp/src/hooks/router/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./useIsActiveRoute"
10 changes: 10 additions & 0 deletions dapp/src/hooks/router/useIsActiveRoute.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { routerPath } from "#/router/path"
import { useLocation } from "react-router-dom"

export const useIsActiveRoute = (route: string) => {
const location = useLocation()

return location.pathname === route
}

export const useIsHomeRouteActive = () => useIsActiveRoute(routerPath.home)
2 changes: 1 addition & 1 deletion dapp/src/router/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from "react"
import { BrowserRouter, Route, Routes } from "react-router-dom"
import LandingPage from "#/pages/LandingPage"
import Layout from "#/components/shared/Layout"
import ActivityPage from "#/pages/ActivityPage"
import DashboardPage from "#/pages/DashboardPage"
import Layout from "#/components/shared/Layout"
import { routerPath } from "./path"

export function Router() {
Expand Down
38 changes: 34 additions & 4 deletions dapp/src/theme/Link.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { defineStyle, defineStyleConfig } from "@chakra-ui/react"
import { createMultiStyleConfigHelpers, defineStyle } from "@chakra-ui/react"

const baseStyle = defineStyle({
const PARTS = ["container", "indicator"]
const multiStyleConfig = createMultiStyleConfigHelpers(PARTS)

const containerBaseStyle = defineStyle({
fontWeight: "semibold",
fontSize: "sm",
lineHeight: "sm",
Expand All @@ -10,6 +13,33 @@ const baseStyle = defineStyle({
},
})

export const linkTheme = defineStyleConfig({
baseStyle,
const navigationContainerStyles = defineStyle({
display: "block",
fontSize: "md",
lineHeight: "md",
fontWeight: "bold",
marginBottom: 2,
color: "grey.500",
_activeLink: { color: "grey.700" },
})

const navigationIndicatorStyles = defineStyle({
pos: "absolute",
bottom: 0.5,
left: 0,
w: "full",
h: 0.5,
bg: "brand.400",
})

export const linkTheme = multiStyleConfig.defineMultiStyleConfig({
baseStyle: {
container: containerBaseStyle,
},
variants: {
navigation: {
container: navigationContainerStyles,
indicator: navigationIndicatorStyles,
},
},
})
4 changes: 4 additions & 0 deletions dapp/src/types/navigation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type NavigationItemType = {
label: string
href: string
}

0 comments on commit e1b8d0a

Please sign in to comment.