Commit 3d0f21f8 authored by tom's avatar tom

navigation refactoring

parent 90d38a52
...@@ -11,30 +11,32 @@ import publicTagIcon from 'icons/publictags.svg'; ...@@ -11,30 +11,32 @@ import publicTagIcon from 'icons/publictags.svg';
import tokensIcon from 'icons/token.svg'; import tokensIcon from 'icons/token.svg';
import transactionsIcon from 'icons/transactions.svg'; import transactionsIcon from 'icons/transactions.svg';
import watchlistIcon from 'icons/watchlist.svg'; import watchlistIcon from 'icons/watchlist.svg';
import useBasePath from 'lib/hooks/useBasePath'; import useCurrentRoute from 'lib/link/useCurrentRoute';
import useLink from 'lib/link/useLink';
export default function useNavItems() { export default function useNavItems() {
const basePath = useBasePath(); const link = useLink();
const currentRoute = useCurrentRoute()();
return React.useMemo(() => { return React.useMemo(() => {
const mainNavItems = [ const mainNavItems = [
{ text: 'Blocks', pathname: basePath + '/blocks', icon: blocksIcon }, { text: 'Blocks', url: link('blocks'), icon: blocksIcon, isActive: [ 'block', 'blocks' ].includes(currentRoute) },
{ text: 'Transactions', pathname: basePath + '/tx', icon: transactionsIcon }, { text: 'Transactions', url: link('txs'), icon: transactionsIcon, isActive: [ 'tx', 'txs' ].includes(currentRoute) },
{ text: 'Tokens', pathname: basePath + '/tokens', icon: tokensIcon }, { text: 'Tokens', url: link('tokens'), icon: tokensIcon, isActive: [ 'token', 'tokens' ].includes(currentRoute) },
{ text: 'Apps', pathname: basePath + '/apps', icon: appsIcon }, { text: 'Apps', url: link('apps'), icon: appsIcon, isActive: currentRoute === 'apps' },
{ text: 'Other', pathname: basePath + '/other', icon: gearIcon }, { text: 'Other', url: link('other'), icon: gearIcon, isActive: currentRoute === 'other' },
]; ];
const accountNavItems = [ const accountNavItems = [
{ text: 'Watchlist', pathname: basePath + '/account/watchlist', icon: watchlistIcon }, { text: 'Watchlist', url: link('watchlist'), icon: watchlistIcon, isActive: currentRoute === 'watchlist' },
{ text: 'Private tags', pathname: basePath + '/account/tag_address', icon: privateTagIcon }, { text: 'Private tags', url: link('private_tags', { tab: 'address' }), icon: privateTagIcon, isActive: currentRoute === 'private_tags' },
{ text: 'Public tags', pathname: basePath + '/account/public_tags_request', icon: publicTagIcon }, { text: 'Public tags', url: link('public_tags'), icon: publicTagIcon, isActive: currentRoute === 'public_tags' },
{ text: 'API keys', pathname: basePath + '/account/api_key', icon: apiKeysIcon }, { text: 'API keys', url: link('api_keys'), icon: apiKeysIcon, isActive: currentRoute === 'api_keys' },
{ text: 'Custom ABI', pathname: basePath + '/account/custom_abi', icon: abiIcon }, { text: 'Custom ABI', url: link('custom_abi'), icon: abiIcon, isActive: currentRoute === 'custom_abi' },
]; ];
const profileItem = { text: 'My profile', pathname: basePath + '/auth/profile', icon: profileIcon }; const profileItem = { text: 'My profile', url: link('profile'), icon: profileIcon, isActive: currentRoute === 'profile' };
return { mainNavItems, accountNavItems, profileItem }; return { mainNavItems, accountNavItems, profileItem };
}, [ basePath ]); }, [ link, currentRoute ]);
} }
...@@ -10,6 +10,7 @@ export function link(routeName: RouteName, urlParams?: Record<string, string | u ...@@ -10,6 +10,7 @@ export function link(routeName: RouteName, urlParams?: Record<string, string | u
} }
const toPath = compile(route.pattern, { encode: encodeURIComponent, validate: false }); const toPath = compile(route.pattern, { encode: encodeURIComponent, validate: false });
const path = toPath(urlParams); const path = toPath(urlParams);
const url = new URL(path, window.location.origin); const url = new URL(path, window.location.origin);
......
...@@ -3,9 +3,45 @@ export interface Route { ...@@ -3,9 +3,45 @@ export interface Route {
} }
export type RouteName = keyof typeof ROUTES; export type RouteName = keyof typeof ROUTES;
const BASE_PATH = '/:network_type/:network_sub_type';
export const ROUTES = { export const ROUTES = {
tx: { tx: {
pattern: '/:network_type/:network_sub_type/tx/:id/:tab?', pattern: `${ BASE_PATH }/tx/:id/:tab?`,
},
txs: {
pattern: `${ BASE_PATH }/txs`,
},
blocks: {
pattern: `${ BASE_PATH }/blocks`,
},
tokens: {
pattern: `${ BASE_PATH }/tokens`,
},
apps: {
pattern: `${ BASE_PATH }/apps`,
},
// ??? what URL will be here
other: {
pattern: `${ BASE_PATH }/other`,
},
watchlist: {
pattern: `${ BASE_PATH }/account/watchlist`,
},
private_tags: {
pattern: `${ BASE_PATH }/account/tag_{:tab}`,
},
public_tags: {
pattern: `${ BASE_PATH }/account/public_tags_request`,
},
api_keys: {
pattern: `${ BASE_PATH }/account/api_key`,
},
custom_abi: {
pattern: `${ BASE_PATH }/account/custom_abi`,
},
profile: {
pattern: `${ BASE_PATH }/auth/profile`,
}, },
}; };
......
import { useRouter } from 'next/router';
import { match } from 'path-to-regexp';
import React from 'react';
import type { RouteName } from 'lib/link/routes';
import { ROUTES } from 'lib/link/routes';
export default function useCurrentRoute() {
const { asPath } = useRouter();
return React.useCallback(() => {
for (const routeName in ROUTES) {
const route = ROUTES[routeName as RouteName];
const isMatch = Boolean(match(route.pattern)(asPath));
if (isMatch) {
return routeName as RouteName;
}
}
return '';
}, [ asPath ]);
}
...@@ -10,13 +10,13 @@ import useColors from './useColors'; ...@@ -10,13 +10,13 @@ import useColors from './useColors';
interface Props { interface Props {
isCollapsed?: boolean; isCollapsed?: boolean;
isActive?: boolean; isActive?: boolean;
pathname: string; url: string;
text: string; text: string;
icon: React.FunctionComponent<React.SVGAttributes<SVGElement>>; icon: React.FunctionComponent<React.SVGAttributes<SVGElement>>;
px?: string | number; px?: string | number;
} }
const NavLink = ({ text, pathname, icon, isCollapsed, isActive, px }: Props) => { const NavLink = ({ text, url, icon, isCollapsed, isActive, px }: Props) => {
const colors = useColors(); const colors = useColors();
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const width = (() => { const width = (() => {
...@@ -28,7 +28,7 @@ const NavLink = ({ text, pathname, icon, isCollapsed, isActive, px }: Props) => ...@@ -28,7 +28,7 @@ const NavLink = ({ text, pathname, icon, isCollapsed, isActive, px }: Props) =>
})(); })();
return ( return (
<NextLink href={ pathname } passHref> <NextLink href={ url } passHref>
<Link <Link
as="li" as="li"
listStyleType="none" listStyleType="none"
......
import { ChevronLeftIcon } from '@chakra-ui/icons'; import { ChevronLeftIcon } from '@chakra-ui/icons';
import { Flex, Box, VStack, useColorModeValue, useBreakpointValue } from '@chakra-ui/react'; import { Flex, Box, VStack, useColorModeValue, useBreakpointValue } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import * as cookies from 'lib/cookies'; import * as cookies from 'lib/cookies';
...@@ -13,8 +12,6 @@ import NavFooter from './NavFooter'; ...@@ -13,8 +12,6 @@ import NavFooter from './NavFooter';
import NavLink from './NavLink'; import NavLink from './NavLink';
const NavigationDesktop = () => { const NavigationDesktop = () => {
const router = useRouter();
const { mainNavItems, accountNavItems } = useNavItems(); const { mainNavItems, accountNavItems } = useNavItems();
const isLargeScreen = useBreakpointValue({ base: false, xl: true }); const isLargeScreen = useBreakpointValue({ base: false, xl: true });
const cookieValue = cookies.get(cookies.NAMES.NAV_BAR_COLLAPSED); const cookieValue = cookies.get(cookies.NAMES.NAV_BAR_COLLAPSED);
...@@ -66,14 +63,12 @@ const NavigationDesktop = () => { ...@@ -66,14 +63,12 @@ const NavigationDesktop = () => {
</Box> </Box>
<Box as="nav" mt={ 14 }> <Box as="nav" mt={ 14 }>
<VStack as="ul" spacing="2" alignItems="flex-start" overflow="hidden"> <VStack as="ul" spacing="2" alignItems="flex-start" overflow="hidden">
{ mainNavItems.map((item) => { mainNavItems.map((item) => <NavLink key={ item.text } { ...item } isCollapsed={ isCollapsed }/>) }
<NavLink key={ item.text } { ...item } isCollapsed={ isCollapsed } isActive={ router.asPath.startsWith(item.pathname) }/>) }
</VStack> </VStack>
</Box> </Box>
<Box as="nav" mt={ 12 }> <Box as="nav" mt={ 12 }>
<VStack as="ul" spacing="2" alignItems="flex-start" overflow="hidden"> <VStack as="ul" spacing="2" alignItems="flex-start" overflow="hidden">
{ accountNavItems.map((item) => { accountNavItems.map((item) => <NavLink key={ item.text } { ...item } isCollapsed={ isCollapsed }/>) }
<NavLink key={ item.text } { ...item } isCollapsed={ isCollapsed } isActive={ router.asPath.startsWith(item.pathname) }/>) }
</VStack> </VStack>
</Box> </Box>
<NavFooter isCollapsed={ isCollapsed }/> <NavFooter isCollapsed={ isCollapsed }/>
......
import { Box, VStack } from '@chakra-ui/react'; import { Box, VStack } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import useNavItems from 'lib/hooks/useNavItems'; import useNavItems from 'lib/hooks/useNavItems';
...@@ -8,18 +7,17 @@ import NavLink from 'ui/blocks/navigation/NavLink'; ...@@ -8,18 +7,17 @@ import NavLink from 'ui/blocks/navigation/NavLink';
const NavigationMobile = () => { const NavigationMobile = () => {
const { mainNavItems, accountNavItems } = useNavItems(); const { mainNavItems, accountNavItems } = useNavItems();
const router = useRouter();
return ( return (
<> <>
<Box as="nav" mt={ 6 }> <Box as="nav" mt={ 6 }>
<VStack as="ul" spacing="2" alignItems="flex-start" overflow="hidden"> <VStack as="ul" spacing="2" alignItems="flex-start" overflow="hidden">
{ mainNavItems.map((item) => <NavLink key={ item.text } { ...item } isActive={ router.asPath.startsWith(item.pathname) }/>) } { mainNavItems.map((item) => <NavLink key={ item.text } { ...item }/>) }
</VStack> </VStack>
</Box> </Box>
<Box as="nav" mt={ 6 }> <Box as="nav" mt={ 6 }>
<VStack as="ul" spacing="2" alignItems="flex-start" overflow="hidden"> <VStack as="ul" spacing="2" alignItems="flex-start" overflow="hidden">
{ accountNavItems.map((item) => <NavLink key={ item.text } { ...item } isActive={ router.asPath.startsWith(item.pathname) }/>) } { accountNavItems.map((item) => <NavLink key={ item.text } { ...item }/>) }
</VStack> </VStack>
</Box> </Box>
<NavFooter/> <NavFooter/>
......
...@@ -33,10 +33,10 @@ const ProfileMenuContent = ({ name, nickname, email }: Props) => { ...@@ -33,10 +33,10 @@ const ProfileMenuContent = ({ name, nickname, email }: Props) => {
> >
{ email } { email }
</Text> </Text>
<NavLink { ...profileItem } px="0px"/> <NavLink { ...profileItem } isActive={ undefined } px="0px"/>
<Box as="nav" mt={ 2 } pt={ 2 } borderTopColor={ borderColor } borderTopWidth="1px" { ...getDefaultTransitionProps() }> <Box as="nav" mt={ 2 } pt={ 2 } borderTopColor={ borderColor } borderTopWidth="1px" { ...getDefaultTransitionProps() }>
<VStack as="ul" spacing="0" alignItems="flex-start" overflow="hidden"> <VStack as="ul" spacing="0" alignItems="flex-start" overflow="hidden">
{ accountNavItems.map((item) => <NavLink key={ item.text } { ...item } px="0px"/>) } { accountNavItems.map((item) => <NavLink key={ item.text } { ...item } isActive={ undefined } px="0px"/>) }
</VStack> </VStack>
</Box> </Box>
<Box mt={ 2 } pt={ 3 } borderTopColor={ borderColor } borderTopWidth="1px" { ...getDefaultTransitionProps() }> <Box mt={ 2 } pt={ 3 } borderTopColor={ borderColor } borderTopWidth="1px" { ...getDefaultTransitionProps() }>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment