diff --git a/src/custom/components/Header/MenuTree/index.tsx b/src/custom/components/Header/MenuTree/index.tsx
new file mode 100644
index 0000000000..f6b3d8732f
--- /dev/null
+++ b/src/custom/components/Header/MenuTree/index.tsx
@@ -0,0 +1,165 @@
+import { HeaderLinks as Wrapper, StyledNavLink } from '../styled'
+import MenuDropdown from 'components/MenuDropdown'
+import { MenuTitle, MenuSection } from 'components/MenuDropdown/styled'
+import SVG from 'react-inlinesvg'
+import {
+ MAIN_MENU,
+ MenuTreeItem,
+ MenuItemKind,
+ InternalLink,
+ ExternalLink,
+ DropDownItem,
+ MenuLink,
+} from 'constants/mainMenu'
+import { ExternalLink as ExternalLinkComponent } from 'theme/components'
+
+// Assets
+import IMAGE_MOON from 'assets/cow-swap/moon.svg'
+import IMAGE_SUN from 'assets/cow-swap/sun.svg'
+
+interface MenuImageProps {
+ title: string
+ iconSVG?: string
+ icon?: string
+}
+
+function MenuImage(props: MenuImageProps) {
+ const { title, iconSVG, icon } = props
+
+ if (iconSVG) {
+ return
+ } else if (icon) {
+ return
+ } else {
+ return null
+ }
+}
+
+interface InternalExternalLinkProps {
+ link: InternalLink | ExternalLink
+ handleMobileMenuOnClick: () => void
+}
+
+function InternalExternalLink({ link, handleMobileMenuOnClick }: InternalExternalLinkProps) {
+ const { kind, title, url, iconSVG, icon } = link
+ const menuImage =
+ const isExternal = kind === MenuItemKind.EXTERNAL_LINK
+
+ if (isExternal) {
+ return (
+
+ {menuImage}
+ {title}
+
+ )
+ } else {
+ return (
+
+ {menuImage}
+ {title}
+
+ )
+ }
+}
+
+interface ContextProps {
+ darkMode: boolean
+ toggleDarkMode: () => void
+ handleMobileMenuOnClick: () => void
+}
+
+type DarkModeButtonProps = {
+ context: ContextProps
+}
+
+function DarkModeButton({ context }: DarkModeButtonProps) {
+ const { darkMode, toggleDarkMode, handleMobileMenuOnClick } = context
+ const description = `${darkMode ? 'Sun/light' : 'Moon/dark'} mode icon`
+ const label = (darkMode ? 'Light' : 'Dark') + ' Mode'
+ return (
+
+ )
+}
+
+interface LinkProps {
+ link: MenuLink
+ context: ContextProps
+}
+
+function Link({ link, context }: LinkProps) {
+ switch (link.kind) {
+ case MenuItemKind.DARK_MODE_BUTTON:
+ return
+
+ default:
+ return
+ }
+}
+
+interface DropdownProps {
+ item: DropDownItem
+ context: ContextProps
+}
+
+const DropDown = ({ item, context }: DropdownProps) => {
+ const { title, items } = item
+
+ return (
+
+ {items?.map((item, index) => {
+ const { sectionTitle, links } = item
+ return (
+
+ {sectionTitle && {sectionTitle}}
+ {links.map((link, linkIndex) => (
+
+ ))}
+
+ )
+ })}
+
+ )
+}
+
+interface MenuItemWithDropDownProps {
+ menuItem: MenuTreeItem
+ context: ContextProps
+}
+
+function MenuItemWithDropDown(props: MenuItemWithDropDownProps) {
+ const { menuItem, context } = props
+
+ switch (menuItem.kind) {
+ case MenuItemKind.DROP_DOWN:
+ return
+
+ case undefined: // INTERNAL
+ case MenuItemKind.EXTERNAL_LINK: // EXTERNAL
+ // Render Internal/External links
+ return
+ default:
+ return null
+ }
+}
+
+export interface MenuTreeProps extends ContextProps {
+ isMobileMenuOpen: boolean
+}
+
+export function MenuTree({ isMobileMenuOpen, darkMode, toggleDarkMode, handleMobileMenuOnClick }: MenuTreeProps) {
+ const context = { darkMode, toggleDarkMode, handleMobileMenuOnClick }
+ return (
+
+ {MAIN_MENU.map((menuItem, index) => (
+
+ ))}
+
+ )
+}
diff --git a/src/custom/components/Header/index.tsx b/src/custom/components/Header/index.tsx
index 1720af975a..4d2b7cbdde 100644
--- a/src/custom/components/Header/index.tsx
+++ b/src/custom/components/Header/index.tsx
@@ -1,4 +1,4 @@
-import { useState, useEffect, useCallback, useMemo } from 'react'
+import { useState, useEffect, useCallback } from 'react'
import { SupportedChainId as ChainId } from 'constants/chains'
import { Routes } from 'constants/routes'
import { useHistory } from 'react-router-dom'
@@ -8,40 +8,31 @@ import { useNativeCurrencyBalances } from 'state/wallet/hooks'
import { useDarkModeManager } from 'state/user/hooks'
import { useMediaQuery, upToSmall, upToMedium, upToLarge, LargeAndUp } from 'hooks/useMediaQuery'
import { AMOUNT_PRECISION } from 'constants/index'
-import { MAIN_MENU, MAIN_MENU_TYPE } from 'constants/mainMenu'
+
import { supportedChainId } from 'utils/supportedChainId'
import { formatSmart } from 'utils/format'
import { addBodyClass, removeBodyClass } from 'utils/toggleBodyClass'
-import SVG from 'react-inlinesvg'
// Components
-import { ExternalLink } from 'theme/components'
import { HeaderRow } from './HeaderMod'
import {
Wrapper,
Title,
LogoImage,
- HeaderLinks,
HeaderModWrapper,
UniIcon,
- StyledNavLink,
AccountElement,
BalanceText,
HeaderControls,
HeaderElement,
} from './styled'
+import { MenuTree } from './MenuTree'
import MobileMenuIcon from './MobileMenuIcon'
-import MenuDropdown from 'components/MenuDropdown'
-import { MenuTitle, MenuSection } from 'components/MenuDropdown/styled'
import Web3Status from 'components/Web3Status'
import OrdersPanel from 'components/OrdersPanel'
import NetworkSelector from 'components/Header/NetworkSelector'
import CowBalanceButton from 'components/CowBalanceButton'
-// Assets
-import IMAGE_MOON from 'assets/cow-swap/moon.svg'
-import IMAGE_SUN from 'assets/cow-swap/sun.svg'
-
export const NETWORK_LABELS: { [chainId in ChainId]?: string } = {
[ChainId.RINKEBY]: 'Rinkeby',
// [ChainId.ROPSTEN]: 'Ropsten',
@@ -107,67 +98,6 @@ export default function Header() {
setIsTouch('ontouchstart' in document.documentElement)
}, [isOrdersPanelOpen, isMobileMenuOpen, isUpToLarge, isUpToMedium, isUpToSmall, isLargeAndUp])
- const getMainMenu = useMemo(
- () =>
- MAIN_MENU.map(({ title, url, externalURL, items }: MAIN_MENU_TYPE, index) =>
- !items && !externalURL && url ? (
-
- {title}
-
- ) : !items && externalURL && url ? (
-
- {title}
-
- ) : items ? (
-
- {items.map(({ sectionTitle, links }, index) => {
- return (
-
- {sectionTitle && {sectionTitle}}
- {links.map(({ title, url, externalURL, icon, iconSVG, action }, index) => {
- return action && action === 'setColorMode' ? (
-
- ) : !externalURL && url ? (
-
- {iconSVG ? (
-
- ) : icon ? (
-
- ) : null}{' '}
- {title}
-
- ) : url ? (
-
- {iconSVG ? (
-
- ) : icon ? (
-
- ) : null}{' '}
- {title}
-
- ) : null
- })}
-
- )
- })}
-
- ) : null
- ),
- [darkMode, handleMobileMenuOnClick, toggleDarkMode]
- )
-
return (
@@ -177,7 +107,12 @@ export default function Header() {
- {getMainMenu}
+
diff --git a/src/custom/constants/mainMenu.ts b/src/custom/constants/mainMenu.ts
index ed4288dce7..ceda12f23e 100644
--- a/src/custom/constants/mainMenu.ts
+++ b/src/custom/constants/mainMenu.ts
@@ -11,24 +11,44 @@ import IMAGE_PIE from 'assets/cow-swap/pie.svg'
import IMAGE_SLICER from 'assets/cow-swap/ninja-cow.png'
import IMAGE_GAME from 'assets/cow-swap/game.gif'
-export interface MAIN_MENU_TYPE {
+export enum MenuItemKind {
+ DROP_DOWN = 'DROP_DOWN',
+ EXTERNAL_LINK = 'EXTERNAL_LINK',
+ DARK_MODE_BUTTON = 'DARK_MODE_BUTTON',
+}
+
+export interface BasicMenuLink {
title: string
- url?: string
- externalURL?: boolean
- items?: {
- sectionTitle?: string
- links: {
- title?: string
- url?: string // If URL is an internal route
- externalURL?: boolean // If URL is external
- icon?: string // If icon uses a regular tag
- iconSVG?: string // If icon is a