MP-3564: added navigation dropdown and Governance NavLink (#639)
This commit is contained in:
parent
9c1d4dfbee
commit
74f4206668
@ -28,6 +28,7 @@
|
|||||||
"@sentry/nextjs": "^7.77.0",
|
"@sentry/nextjs": "^7.77.0",
|
||||||
"@splinetool/react-spline": "^2.2.6",
|
"@splinetool/react-spline": "^2.2.6",
|
||||||
"@splinetool/runtime": "^0.9.482",
|
"@splinetool/runtime": "^0.9.482",
|
||||||
|
"@tailwindcss/container-queries": "^0.1.1",
|
||||||
"@tanstack/react-table": "^8.10.6",
|
"@tanstack/react-table": "^8.10.6",
|
||||||
"@tippyjs/react": "^4.2.6",
|
"@tippyjs/react": "^4.2.6",
|
||||||
"bignumber.js": "^9.1.2",
|
"bignumber.js": "^9.1.2",
|
||||||
|
@ -10,14 +10,17 @@ import Settings from 'components/Settings'
|
|||||||
import Wallet from 'components/Wallet'
|
import Wallet from 'components/Wallet'
|
||||||
import useAccountId from 'hooks/useAccountId'
|
import useAccountId from 'hooks/useAccountId'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
|
import { WalletID } from 'types/enums/wallet'
|
||||||
import { ENABLE_HLS } from 'utils/constants'
|
import { ENABLE_HLS } from 'utils/constants'
|
||||||
|
import { getGovernanceUrl } from 'utils/helpers'
|
||||||
|
|
||||||
export const menuTree: { pages: Page[]; label: string }[] = [
|
export const menuTree = (walletId: WalletID): MenuTreeEntry[] => [
|
||||||
{ pages: ['trade'], label: 'Trade' },
|
{ pages: ['trade'], label: 'Trade' },
|
||||||
{ pages: ['lend', 'farm'], label: 'Earn' },
|
{ pages: ['lend', 'farm'], label: 'Earn' },
|
||||||
{ pages: ['borrow'], label: 'Borrow' },
|
{ pages: ['borrow'], label: 'Borrow' },
|
||||||
...(ENABLE_HLS ? [{ pages: ['hls-staking'] as Page[], label: 'High Leverage' }] : []),
|
...(ENABLE_HLS ? [{ pages: ['hls-staking'] as Page[], label: 'High Leverage' }] : []),
|
||||||
{ pages: ['portfolio'], label: 'Portfolio' },
|
{ pages: ['portfolio'], label: 'Portfolio' },
|
||||||
|
{ pages: ['governance'], label: 'Governance', externalUrl: getGovernanceUrl(walletId) },
|
||||||
]
|
]
|
||||||
|
|
||||||
export default function DesktopHeader() {
|
export default function DesktopHeader() {
|
||||||
@ -37,9 +40,8 @@ export default function DesktopHeader() {
|
|||||||
return (
|
return (
|
||||||
<header
|
<header
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'fixed left-0 top-0 z-50 hidden w-full',
|
'fixed left-0 top-0 z-50 w-full',
|
||||||
'before:content-[" "] before:absolute before:inset-0 before:-z-1 before:h-full before:w-full before:rounded-sm before:backdrop-blur-sticky',
|
'before:content-[" "] before:absolute before:inset-0 before:-z-1 before:h-full before:w-full before:rounded-sm before:backdrop-blur-sticky',
|
||||||
'lg:block',
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
@ -1,18 +1,28 @@
|
|||||||
|
import { useShuttle } from '@delphi-labs/shuttle-react'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
|
import Button from 'components/Button'
|
||||||
import { menuTree } from 'components/Header/DesktopHeader'
|
import { menuTree } from 'components/Header/DesktopHeader'
|
||||||
import { Logo } from 'components/Icons'
|
import { ChevronDown, Logo } from 'components/Icons'
|
||||||
import { NavLink } from 'components/Navigation/NavLink'
|
import { NavLink } from 'components/Navigation/NavLink'
|
||||||
import useAccountId from 'hooks/useAccountId'
|
import useAccountId from 'hooks/useAccountId'
|
||||||
|
import useToggle from 'hooks/useToggle'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
|
import { WalletID } from 'types/enums/wallet'
|
||||||
import { getRoute } from 'utils/route'
|
import { getRoute } from 'utils/route'
|
||||||
|
|
||||||
export default function DesktopNavigation() {
|
export default function DesktopNavigation() {
|
||||||
|
const [showMenu, setShowMenu] = useToggle()
|
||||||
|
const { recentWallet } = useShuttle()
|
||||||
|
const walletId = (recentWallet?.providerId as WalletID) ?? WalletID.Keplr
|
||||||
const address = useStore((s) => s.address)
|
const address = useStore((s) => s.address)
|
||||||
const accountId = useAccountId()
|
const accountId = useAccountId()
|
||||||
|
|
||||||
const focusComponent = useStore((s) => s.focusComponent)
|
const focusComponent = useStore((s) => s.focusComponent)
|
||||||
|
|
||||||
|
const menu = useMemo(() => menuTree(walletId), [walletId])
|
||||||
|
|
||||||
function getIsActive(pages: string[]) {
|
function getIsActive(pages: string[]) {
|
||||||
const segments = location.pathname.split('/')
|
const segments = location.pathname.split('/')
|
||||||
return pages.some((page) => segments.includes(page))
|
return pages.some((page) => segments.includes(page))
|
||||||
@ -30,16 +40,62 @@ export default function DesktopNavigation() {
|
|||||||
</span>
|
</span>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
{!focusComponent && (
|
{!focusComponent && (
|
||||||
<div className='flex gap-8 px-6'>
|
<div className='flex gap-8 px-6 @container/navigation relative flex-1'>
|
||||||
{menuTree.map((item, index) => (
|
{menu.map((item, index) => (
|
||||||
<NavLink
|
<NavLink
|
||||||
key={index}
|
key={index}
|
||||||
href={getRoute(item.pages[0], address, accountId)}
|
href={
|
||||||
|
item.externalUrl ? item.externalUrl : getRoute(item.pages[0], address, accountId)
|
||||||
|
}
|
||||||
isActive={getIsActive(item.pages)}
|
isActive={getIsActive(item.pages)}
|
||||||
|
className={`@nav-${index}/navigation:inline-block hidden whitespace-nowrap`}
|
||||||
|
target={item.externalUrl ? '_blank' : undefined}
|
||||||
>
|
>
|
||||||
{item.label}
|
{item.label}
|
||||||
</NavLink>
|
</NavLink>
|
||||||
))}
|
))}
|
||||||
|
<div className={`@nav-${menu.length - 1}/navigation:hidden flex items-center relative`}>
|
||||||
|
<Button
|
||||||
|
leftIcon={<ChevronDown />}
|
||||||
|
color='quaternary'
|
||||||
|
variant='transparent'
|
||||||
|
onClick={() => setShowMenu(!showMenu)}
|
||||||
|
text='More'
|
||||||
|
className='!text-base !p-0 !min-h-0'
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
showMenu ? 'flex' : 'hidden',
|
||||||
|
'absolute left-0 top-[calc(100%+4px)]',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<ul
|
||||||
|
className={classNames(
|
||||||
|
'py-4 list-none flex flex-wrap gap-2 bg-white/10 backdrop-blur-lg',
|
||||||
|
'relative isolate max-w-full overflow-hidden rounded-sm',
|
||||||
|
'before:content-[" "] before:absolute before:inset-0 before:-z-1 before:rounded-sm before:p-[1px] before:border-glas',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{menu.map((item, index) => (
|
||||||
|
<li className={`@nav-${index}/navigation:hidden block w-full m-0`} key={index}>
|
||||||
|
<NavLink
|
||||||
|
href={
|
||||||
|
item.externalUrl
|
||||||
|
? item.externalUrl
|
||||||
|
: getRoute(item.pages[0], address, accountId)
|
||||||
|
}
|
||||||
|
onClick={() => setShowMenu(false)}
|
||||||
|
isActive={getIsActive(item.pages)}
|
||||||
|
className='w-full px-4 whitespace-nowrap'
|
||||||
|
target={item.externalUrl ? '_blank' : undefined}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</NavLink>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,16 +6,22 @@ interface Props {
|
|||||||
href: string
|
href: string
|
||||||
children: string | ReactNode
|
children: string | ReactNode
|
||||||
isActive?: boolean
|
isActive?: boolean
|
||||||
|
className?: string
|
||||||
|
onClick?: () => void
|
||||||
|
target?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NavLink = (props: Props) => {
|
export const NavLink = (props: Props) => {
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
to={props.href}
|
to={props.href}
|
||||||
|
onClick={props.onClick ? props.onClick : undefined}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'text-sm font-semibold hover:text-white active:text-white',
|
props.className,
|
||||||
|
'font-semibold hover:text-white active:text-white',
|
||||||
props.isActive ? 'pointer-events-none text-white' : 'text-white/60',
|
props.isActive ? 'pointer-events-none text-white' : 'text-white/60',
|
||||||
)}
|
)}
|
||||||
|
target={props.target}
|
||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -3,6 +3,9 @@ export enum DocURL {
|
|||||||
BORROW_LENDING_URL = 'https://docs.marsprotocol.io/docs/learn/mars-v2/borrow',
|
BORROW_LENDING_URL = 'https://docs.marsprotocol.io/docs/learn/mars-v2/borrow',
|
||||||
CHANGE_LOG_URL = 'https://docs.marsprotocol.io/docs/overview/changelog',
|
CHANGE_LOG_URL = 'https://docs.marsprotocol.io/docs/overview/changelog',
|
||||||
COOKIE_POLICY_URL = 'https://docs.marsprotocol.io/docs/overview/legal/cookie-policy',
|
COOKIE_POLICY_URL = 'https://docs.marsprotocol.io/docs/overview/legal/cookie-policy',
|
||||||
|
COUNCIL_LEAP = 'https://cosmos.leapwallet.io/chains/mars/governance',
|
||||||
|
COUNCIL_STATION = 'https://station.terra.money/gov#PROPOSAL_STATUS_VOTING_PERIOD',
|
||||||
|
COUNCIL_KEPLR = 'https://wallet.keplr.app/chains/mars-hub?tab=governance',
|
||||||
DOCS_URL = 'https://docs.marsprotocol.io/',
|
DOCS_URL = 'https://docs.marsprotocol.io/',
|
||||||
FARM_INTRO_URL = 'https://docs.marsprotocol.io/docs/learn/tutorials/farming/farming-intro',
|
FARM_INTRO_URL = 'https://docs.marsprotocol.io/docs/learn/tutorials/farming/farming-intro',
|
||||||
MANAGE_ACCOUNT_URL = 'https://docs.marsprotocol.io/docs/learn/tutorials/credit-accounts/credit-accounts-intro',
|
MANAGE_ACCOUNT_URL = 'https://docs.marsprotocol.io/docs/learn/tutorials/credit-accounts/credit-accounts-intro',
|
||||||
|
5
src/types/interfaces/components/Navigation.d.ts
vendored
Normal file
5
src/types/interfaces/components/Navigation.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
interface MenuTreeEntry {
|
||||||
|
pages: Page[]
|
||||||
|
label: string
|
||||||
|
externalUrl?: string
|
||||||
|
}
|
1
src/types/interfaces/route.d.ts
vendored
1
src/types/interfaces/route.d.ts
vendored
@ -7,3 +7,4 @@ type Page =
|
|||||||
| 'portfolio/{accountId}'
|
| 'portfolio/{accountId}'
|
||||||
| 'hls-farm'
|
| 'hls-farm'
|
||||||
| 'hls-staking'
|
| 'hls-staking'
|
||||||
|
| 'governance'
|
||||||
|
@ -3,6 +3,8 @@ import throttle from 'lodash.throttle'
|
|||||||
|
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
import { DocURL } from 'types/enums/docURL'
|
||||||
|
import { WalletID } from 'types/enums/wallet'
|
||||||
import { getCoinValue } from 'utils/formatters'
|
import { getCoinValue } from 'utils/formatters'
|
||||||
|
|
||||||
BigNumber.config({ EXPONENTIAL_AT: 1e9 })
|
BigNumber.config({ EXPONENTIAL_AT: 1e9 })
|
||||||
@ -60,3 +62,14 @@ export function getValueFromBNCoins(coins: BNCoin[], prices: BNCoin[]): BigNumbe
|
|||||||
export function getLeverageFromLTV(ltv: number) {
|
export function getLeverageFromLTV(ltv: number) {
|
||||||
return +(1 / (1 - ltv)).toPrecision(2)
|
return +(1 / (1 - ltv)).toPrecision(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getGovernanceUrl(walletId: WalletID) {
|
||||||
|
switch (walletId) {
|
||||||
|
case WalletID.Station:
|
||||||
|
return DocURL.COUNCIL_STATION
|
||||||
|
case WalletID.Leap:
|
||||||
|
return DocURL.COUNCIL_LEAP
|
||||||
|
default:
|
||||||
|
return DocURL.COUNCIL_KEPLR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -35,6 +35,18 @@ module.exports = {
|
|||||||
'fill-martian-red',
|
'fill-martian-red',
|
||||||
'fill-grey-light',
|
'fill-grey-light',
|
||||||
'w-2',
|
'w-2',
|
||||||
|
'@nav-0/navigation:inline-block',
|
||||||
|
'@nav-1/navigation:inline-block',
|
||||||
|
'@nav-2/navigation:inline-block',
|
||||||
|
'@nav-3/navigation:inline-block',
|
||||||
|
'@nav-4/navigation:inline-block',
|
||||||
|
'@nav-5/navigation:inline-block',
|
||||||
|
'@nav-0/navigation:hidden',
|
||||||
|
'@nav-1/navigation:hidden',
|
||||||
|
'@nav-2/navigation:hidden',
|
||||||
|
'@nav-3/navigation:hidden',
|
||||||
|
'@nav-4/navigation:hidden',
|
||||||
|
'@nav-5/navigation:hidden',
|
||||||
],
|
],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
@ -122,6 +134,14 @@ module.exports = {
|
|||||||
white: '#FFF',
|
white: '#FFF',
|
||||||
pink: '#de587f',
|
pink: '#de587f',
|
||||||
},
|
},
|
||||||
|
containers: {
|
||||||
|
'nav-0': '100px',
|
||||||
|
'nav-1': '160px',
|
||||||
|
'nav-2': '250px',
|
||||||
|
'nav-3': '400px',
|
||||||
|
'nav-4': '500px',
|
||||||
|
'nav-5': '600px',
|
||||||
|
},
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
sans: ['Inter', 'sans-serif'],
|
sans: ['Inter', 'sans-serif'],
|
||||||
},
|
},
|
||||||
@ -278,6 +298,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
require('tailwind-scrollbar-hide'),
|
require('tailwind-scrollbar-hide'),
|
||||||
|
require('@tailwindcss/container-queries'),
|
||||||
plugin(function ({ addBase, addUtilities, theme }) {
|
plugin(function ({ addBase, addUtilities, theme }) {
|
||||||
addBase({
|
addBase({
|
||||||
h1: { fontSize: '61px', lineHeight: '80px', fontWeight: theme('fontWeight.light') },
|
h1: { fontSize: '61px', lineHeight: '80px', fontWeight: theme('fontWeight.light') },
|
||||||
|
@ -3252,6 +3252,11 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
tslib "^2.4.0"
|
tslib "^2.4.0"
|
||||||
|
|
||||||
|
"@tailwindcss/container-queries@^0.1.1":
|
||||||
|
version "0.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tailwindcss/container-queries/-/container-queries-0.1.1.tgz#9a759ce2cb8736a4c6a0cb93aeb740573a731974"
|
||||||
|
integrity sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA==
|
||||||
|
|
||||||
"@tanstack/react-table@^8.10.6":
|
"@tanstack/react-table@^8.10.6":
|
||||||
version "8.10.6"
|
version "8.10.6"
|
||||||
resolved "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.10.6.tgz"
|
resolved "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.10.6.tgz"
|
||||||
|
Loading…
Reference in New Issue
Block a user