mango-v4-ui/components/SideNav.tsx

407 lines
12 KiB
TypeScript
Raw Normal View History

2022-07-14 16:36:31 -07:00
import Link from 'next/link'
2022-08-02 19:15:17 -07:00
import TradeIcon from './icons/TradeIcon'
2022-07-14 16:36:31 -07:00
import {
2022-09-06 21:36:35 -07:00
EllipsisHorizontalIcon,
BuildingLibraryIcon,
2022-07-14 16:36:31 -07:00
LightBulbIcon,
2022-09-06 21:36:35 -07:00
ArrowTopRightOnSquareIcon,
2022-07-14 16:36:31 -07:00
ChevronDownIcon,
2022-08-15 18:59:15 -07:00
CurrencyDollarIcon,
2022-08-23 15:33:09 -07:00
ChartBarIcon,
2022-09-07 17:47:59 -07:00
Cog8ToothIcon,
2022-09-11 17:22:37 -07:00
InformationCircleIcon,
2022-09-13 23:24:26 -07:00
ArrowsRightLeftIcon,
2022-09-06 21:36:35 -07:00
} from '@heroicons/react/20/solid'
2022-07-14 16:36:31 -07:00
import { useRouter } from 'next/router'
import { useTranslation } from 'next-i18next'
import { Fragment, ReactNode, useEffect, useState } from 'react'
import { Disclosure, Popover, Transition } from '@headlessui/react'
2022-08-02 19:15:17 -07:00
import MangoAccountSummary from './account/MangoAccountSummary'
import Tooltip from './shared/Tooltip'
2022-09-11 04:48:23 -07:00
import { HealthType } from '@blockworks-foundation/mango-v4'
2022-09-11 17:22:37 -07:00
import { useWallet } from '@solana/wallet-adapter-react'
import useLocalStorageState from '../hooks/useLocalStorageState'
import { ONBOARDING_TOUR_KEY } from '../utils/constants'
2022-09-14 07:52:18 -07:00
import mangoStore from '@store/mangoStore'
import HealthHeart from './account/HealthHeart'
2022-07-14 16:36:31 -07:00
const SideNav = ({ collapsed }: { collapsed: boolean }) => {
2022-09-11 17:22:37 -07:00
const [, setShowOnboardingTour] = useLocalStorageState(ONBOARDING_TOUR_KEY)
2022-07-14 16:36:31 -07:00
const { t } = useTranslation('common')
2022-09-11 17:22:37 -07:00
const { connected } = useWallet()
2022-08-02 19:15:17 -07:00
const mangoAccount = mangoStore((s) => s.mangoAccount.current)
2022-07-14 16:36:31 -07:00
const router = useRouter()
const { pathname } = router
2022-09-11 17:22:37 -07:00
const handleTakeTour = () => {
if (pathname !== '/') {
router.push('/')
}
setShowOnboardingTour(true)
}
2022-07-14 16:36:31 -07:00
return (
<div
2022-09-01 10:53:34 -07:00
className={`flex flex-col justify-between transition-all duration-500 ${
collapsed ? 'w-[64px]' : 'w-44 lg:w-48 xl:w-52'
2022-07-14 16:36:31 -07:00
} min-h-screen border-r border-th-bkg-3 bg-th-bkg-1`}
>
<div className="my-2">
<Link href={'/'} shallow={true} passHref>
2022-07-14 16:36:31 -07:00
<div
className={`h-14 items-center transition-all duration-500 ease-in-out ${
2022-08-11 03:49:16 -07:00
collapsed ? '' : 'justify-start'
} pb-1 pt-2 pl-4`}
2022-07-14 16:36:31 -07:00
>
<div className={`flex flex-shrink-0 cursor-pointer items-center`}>
<img
2022-08-11 03:49:16 -07:00
className={`h-8 w-8 flex-shrink-0`}
2022-07-14 16:36:31 -07:00
src="/logos/logo-mark.svg"
alt="next"
/>
<Transition
show={!collapsed}
as={Fragment}
enter="transition ease-in duration-200"
2022-07-14 16:36:31 -07:00
enterFrom="opacity-50"
enterTo="opacity-100"
leave="transition ease-out duration-200"
2022-07-14 16:36:31 -07:00
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
2022-08-11 03:49:16 -07:00
<span className="ml-3 text-lg font-bold text-th-fgd-1">
2022-07-14 16:36:31 -07:00
Mango
</span>
</Transition>
</div>
</div>
</Link>
2022-09-14 21:51:19 -07:00
<div className="flex flex-col items-start">
2022-07-14 16:36:31 -07:00
<MenuItem
active={pathname === '/'}
collapsed={collapsed}
2022-08-15 18:59:15 -07:00
icon={<CurrencyDollarIcon className="h-5 w-5" />}
2022-08-25 03:47:34 -07:00
title={t('account')}
2022-07-14 16:36:31 -07:00
pagePath="/"
/>
2022-09-12 08:53:57 -07:00
<MenuItem
active={pathname === '/swap'}
collapsed={collapsed}
2022-09-13 23:24:26 -07:00
icon={<ArrowsRightLeftIcon className="h-5 w-5" />}
2022-09-12 08:53:57 -07:00
title={t('swap')}
pagePath="/swap"
/>
2022-07-14 16:36:31 -07:00
<MenuItem
active={pathname === '/trade'}
collapsed={collapsed}
2022-08-08 10:42:18 -07:00
icon={<TradeIcon className="h-5 w-5" />}
2022-07-14 16:36:31 -07:00
title={t('trade')}
pagePath="/trade"
/>
2022-08-23 15:33:09 -07:00
<MenuItem
2022-07-14 16:36:31 -07:00
active={pathname === '/stats'}
collapsed={collapsed}
2022-08-08 10:42:18 -07:00
icon={<ChartBarIcon className="h-5 w-5" />}
2022-07-14 16:36:31 -07:00
title={t('stats')}
pagePath="/stats"
2022-08-23 15:33:09 -07:00
/>
2022-07-18 20:58:21 -07:00
<MenuItem
active={pathname === '/settings'}
collapsed={collapsed}
2022-09-07 17:47:59 -07:00
icon={<Cog8ToothIcon className="h-5 w-5" />}
2022-07-18 20:58:21 -07:00
title={t('settings')}
pagePath="/settings"
/>
2022-07-14 16:36:31 -07:00
<ExpandableMenuItem
collapsed={collapsed}
2022-09-06 21:36:35 -07:00
icon={<EllipsisHorizontalIcon className="h-5 w-5" />}
2022-07-14 16:36:31 -07:00
title={t('more')}
>
2022-08-09 18:21:33 -07:00
{/* <MenuItem
2022-07-14 16:36:31 -07:00
active={pathname === '/fees'}
collapsed={false}
2022-07-17 17:56:05 -07:00
icon={<ReceiptTaxIcon className="h-5 w-5" />}
2022-07-14 16:36:31 -07:00
title={t('fees')}
pagePath="/fees"
hideIconBg
2022-08-09 18:21:33 -07:00
/> */}
2022-07-14 16:36:31 -07:00
<MenuItem
collapsed={false}
2022-07-17 17:56:05 -07:00
icon={<LightBulbIcon className="h-5 w-5" />}
2022-07-14 16:36:31 -07:00
title={t('learn')}
pagePath="https://docs.mango.markets"
hideIconBg
isExternal
showTooltip={false}
2022-07-14 16:36:31 -07:00
/>
<MenuItem
collapsed={false}
2022-09-06 21:36:35 -07:00
icon={<BuildingLibraryIcon className="h-5 w-5" />}
2022-07-14 16:36:31 -07:00
title={t('governance')}
pagePath="https://dao.mango.markets"
hideIconBg
isExternal
showTooltip={false}
2022-07-14 16:36:31 -07:00
/>
2022-09-11 17:22:37 -07:00
{connected ? (
<button
className="default-transition mt-1 flex items-center px-4 text-th-fgd-2 md:hover:text-th-primary"
onClick={handleTakeTour}
>
<InformationCircleIcon className="mr-3 h-5 w-5" />
<span className="text-base">Take UI Tour</span>
</button>
) : null}
2022-07-14 16:36:31 -07:00
</ExpandableMenuItem>
</div>
</div>
2022-09-11 17:22:37 -07:00
<div className="border-t border-th-bkg-3">
<ExpandableMenuItem
collapsed={collapsed}
icon={
<HealthHeart
health={
mangoAccount
? mangoAccount.getHealthRatioUi(HealthType.maint)
: undefined
}
size={32}
/>
}
title={
<div className="text-left">
<p className="mb-0.5 whitespace-nowrap text-xs">Health Check</p>
<p className="whitespace-nowrap text-sm font-bold text-th-fgd-1">
2022-09-13 04:11:52 -07:00
{mangoAccount
? mangoAccount.name
: connected
? 'No Account'
: 'Connect'}
2022-09-11 17:22:37 -07:00
</p>
2022-08-02 19:15:17 -07:00
</div>
2022-09-11 17:22:37 -07:00
}
alignBottom
hideIconBg
>
<div className="px-4 pb-4 pt-2">
2022-09-14 07:52:18 -07:00
<MangoAccountSummary collapsed={collapsed} />
2022-09-11 17:22:37 -07:00
</div>
</ExpandableMenuItem>
</div>
2022-07-14 16:36:31 -07:00
</div>
)
}
export default SideNav
const MenuItem = ({
active,
collapsed,
icon,
title,
pagePath,
hideIconBg,
isExternal,
showTooltip = true,
2022-07-14 16:36:31 -07:00
}: {
active?: boolean
collapsed: boolean
icon: ReactNode
title: string
pagePath: string
hideIconBg?: boolean
isExternal?: boolean
showTooltip?: boolean
2022-07-14 16:36:31 -07:00
}) => {
return (
2022-09-02 03:22:32 -07:00
<Tooltip content={title} placement="right" show={collapsed && showTooltip}>
<Link href={pagePath} shallow={true}>
<a
className={`default-transition flex cursor-pointer px-4 focus:text-th-primary focus:outline-none md:hover:text-th-primary ${
active ? 'text-th-primary' : 'text-th-fgd-1'
} ${hideIconBg ? 'py-1' : 'py-2'}`}
>
<div className="flex w-full items-center justify-between">
<div className="flex items-center">
<div
className={
hideIconBg
? ''
: 'flex h-8 w-8 items-center justify-center rounded-full bg-th-bkg-3'
}
>
{icon}
</div>
<Transition
show={!collapsed}
as={Fragment}
enter="transition ease-in duration-300"
enterFrom="opacity-50"
enterTo="opacity-100"
leave="transition ease-out duration-300"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<span className="ml-3 lg:text-base">{title}</span>
</Transition>
</div>
2022-09-06 21:36:35 -07:00
{isExternal ? (
<ArrowTopRightOnSquareIcon className="h-4 w-4" />
) : null}
2022-07-14 16:36:31 -07:00
</div>
</a>
</Link>
</Tooltip>
2022-07-14 16:36:31 -07:00
)
}
2022-09-12 08:53:57 -07:00
export const ExpandableMenuItem = ({
2022-07-14 16:36:31 -07:00
alignBottom,
children,
collapsed,
hideIconBg,
icon,
title,
}: {
alignBottom?: boolean
children: ReactNode
collapsed: boolean
hideIconBg?: boolean
icon: ReactNode
title: string | ReactNode
}) => {
const [showMenu, setShowMenu] = useState(false)
const onHoverMenu = (open: boolean, action: string) => {
if (
(!open && action === 'onMouseEnter') ||
(open && action === 'onMouseLeave')
) {
setShowMenu(!open)
}
}
useEffect(() => {
if (collapsed) {
setShowMenu(false)
}
}, [collapsed])
2022-07-14 16:36:31 -07:00
const toggleMenu = () => {
setShowMenu(!showMenu)
}
return collapsed ? (
<Popover>
<div
onMouseEnter={
!alignBottom ? () => onHoverMenu(showMenu, 'onMouseEnter') : undefined
}
onMouseLeave={
!alignBottom ? () => onHoverMenu(showMenu, 'onMouseLeave') : undefined
}
2022-07-17 17:56:05 -07:00
className={`relative z-30 ${alignBottom ? '' : 'px-4 py-2'}`}
2022-07-14 16:36:31 -07:00
role="button"
>
<Popover.Button
className="md:hover:text-th-primary"
2022-07-14 16:36:31 -07:00
onClick={() => toggleMenu()}
>
<div
className={` ${
hideIconBg
? ''
2022-08-11 03:49:16 -07:00
: 'flex h-8 w-8 items-center justify-center rounded-full bg-th-bkg-3'
2022-07-14 16:36:31 -07:00
} ${
alignBottom
2022-08-11 03:49:16 -07:00
? 'flex h-[64px] w-[64px] items-center justify-center hover:bg-th-bkg-2'
2022-07-14 16:36:31 -07:00
: ''
}`}
>
{icon}
</div>
</Popover.Button>
<Transition
show={showMenu}
as={Fragment}
enter="transition ease-in duration-300"
enterFrom="opacity-0 scale-90"
enterTo="opacity-100 scale-100"
2022-07-14 16:36:31 -07:00
leave="transition ease-out duration-300"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Popover.Panel
2022-09-07 05:00:21 -07:00
className={`absolute z-20 w-56 rounded-md rounded-l-none border border-th-bkg-3 bg-th-bkg-1 py-2 ${
2022-07-14 16:36:31 -07:00
alignBottom
2022-09-07 05:00:21 -07:00
? 'bottom-0 left-[63px] rounded-b-none border-b-0 p-0'
: 'top-1/2 left-[63px] -translate-y-1/2'
2022-07-14 16:36:31 -07:00
}`}
>
{children}
</Popover.Panel>
</Transition>
</div>
</Popover>
) : (
<Disclosure>
<div
onClick={() => setShowMenu(!showMenu)}
role="button"
2022-07-17 17:56:05 -07:00
className={`w-full px-4 py-2 ${
2022-08-11 03:49:16 -07:00
alignBottom ? 'h-[64px] hover:bg-th-bkg-2' : ''
}`}
2022-07-14 16:36:31 -07:00
>
<Disclosure.Button
className={`flex h-full w-full items-center justify-between rounded-none md:hover:text-th-primary`}
2022-07-14 16:36:31 -07:00
>
<div className="flex items-center">
<div
className={
hideIconBg
? ''
2022-08-11 03:49:16 -07:00
: 'flex h-8 w-8 items-center justify-center rounded-full bg-th-bkg-3'
2022-07-14 16:36:31 -07:00
}
>
{icon}
</div>
<Transition
appear={true}
show={!collapsed}
as={Fragment}
enter="transition ease-in duration-300"
2022-07-14 16:36:31 -07:00
enterFrom="opacity-50"
enterTo="opacity-100"
leave="transition ease-out duration-300"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<span className="ml-3 lg:text-base">{title}</span>
2022-07-14 16:36:31 -07:00
</Transition>
</div>
<ChevronDownIcon
className={`${
showMenu ? 'rotate-180' : 'rotate-360'
2022-07-14 20:38:02 -07:00
} h-5 w-5 flex-shrink-0`}
2022-07-14 16:36:31 -07:00
/>
</Disclosure.Button>
</div>
<Transition
appear={true}
show={showMenu}
as={Fragment}
2022-09-01 09:57:20 -07:00
enter="transition-all ease-in duration-300"
2022-07-14 16:36:31 -07:00
enterFrom="opacity-100 max-h-0"
enterTo="opacity-100 max-h-80"
2022-09-01 09:57:20 -07:00
leave="transition-all ease-out duration-300"
2022-07-14 16:36:31 -07:00
leaveFrom="opacity-100 max-h-80"
leaveTo="opacity-0 max-h-0"
>
<Disclosure.Panel className="w-full overflow-hidden">
2022-08-11 03:49:16 -07:00
<div className={`${!alignBottom ? 'ml-2.5' : ''}`}>{children}</div>
2022-07-14 16:36:31 -07:00
</Disclosure.Panel>
</Transition>
</Disclosure>
)
}