Commit 4221b04b authored by tom goriunov's avatar tom goriunov Committed by GitHub

Limit page content width (#2197)

* limit content width for horizontal menu layout

* limit content width for vertical menu layout

* limit amout of tabs in routed tabs skeleton

* fix width of error screen

* add NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL L2 review envs

* add tests

* fixes

* fix tests

* move content wrapper to render fixture

* update screenshots and fix tests
parent fb6b1b1b
...@@ -67,6 +67,7 @@ frontend: ...@@ -67,6 +67,7 @@ frontend:
NEXT_PUBLIC_METADATA_SERVICE_API_HOST: https://metadata.services.blockscout.com NEXT_PUBLIC_METADATA_SERVICE_API_HOST: https://metadata.services.blockscout.com
NEXT_PUBLIC_ROLLUP_TYPE: optimistic NEXT_PUBLIC_ROLLUP_TYPE: optimistic
NEXT_PUBLIC_ROLLUP_L1_BASE_URL: https://eth.blockscout.com NEXT_PUBLIC_ROLLUP_L1_BASE_URL: https://eth.blockscout.com
NEXT_PUBLIC_ROLLUP_L2_WITHDRAWAL_URL: https://app.optimism.io/bridge/withdraw
NEXT_PUBLIC_GRAPHIQL_TRANSACTION: 0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62 NEXT_PUBLIC_GRAPHIQL_TRANSACTION: 0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62
NEXT_PUBLIC_USE_NEXT_JS_PROXY: true NEXT_PUBLIC_USE_NEXT_JS_PROXY: true
NEXT_PUBLIC_NAVIGATION_LAYOUT: horizontal NEXT_PUBLIC_NAVIGATION_LAYOUT: horizontal
......
import type { ChakraProps } from '@chakra-ui/react'; import { type ChakraProps } from '@chakra-ui/react';
import { GrowthBookProvider } from '@growthbook/growthbook-react'; import { GrowthBookProvider } from '@growthbook/growthbook-react';
import * as Sentry from '@sentry/react'; import * as Sentry from '@sentry/react';
import { QueryClientProvider } from '@tanstack/react-query'; import { QueryClientProvider } from '@tanstack/react-query';
...@@ -19,6 +19,7 @@ import useLoadFeatures from 'lib/growthbook/useLoadFeatures'; ...@@ -19,6 +19,7 @@ import useLoadFeatures from 'lib/growthbook/useLoadFeatures';
import useNotifyOnNavigation from 'lib/hooks/useNotifyOnNavigation'; import useNotifyOnNavigation from 'lib/hooks/useNotifyOnNavigation';
import { SocketProvider } from 'lib/socket/context'; import { SocketProvider } from 'lib/socket/context';
import AppErrorBoundary from 'ui/shared/AppError/AppErrorBoundary'; import AppErrorBoundary from 'ui/shared/AppError/AppErrorBoundary';
import AppErrorGlobalContainer from 'ui/shared/AppError/AppErrorGlobalContainer';
import GoogleAnalytics from 'ui/shared/GoogleAnalytics'; import GoogleAnalytics from 'ui/shared/GoogleAnalytics';
import Layout from 'ui/shared/layout/Layout'; import Layout from 'ui/shared/layout/Layout';
import Web3ModalProvider from 'ui/shared/Web3ModalProvider'; import Web3ModalProvider from 'ui/shared/Web3ModalProvider';
...@@ -38,7 +39,7 @@ const ERROR_SCREEN_STYLES: ChakraProps = { ...@@ -38,7 +39,7 @@ const ERROR_SCREEN_STYLES: ChakraProps = {
justifyContent: 'center', justifyContent: 'center',
width: 'fit-content', width: 'fit-content',
maxW: '800px', maxW: '800px',
margin: '0 auto', margin: { base: '0 auto', lg: '0 auto' },
p: { base: 4, lg: 0 }, p: { base: 4, lg: 0 },
}; };
...@@ -60,6 +61,7 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) { ...@@ -60,6 +61,7 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) {
<AppErrorBoundary <AppErrorBoundary
{ ...ERROR_SCREEN_STYLES } { ...ERROR_SCREEN_STYLES }
onError={ handleError } onError={ handleError }
Container={ AppErrorGlobalContainer }
> >
<Web3ModalProvider> <Web3ModalProvider>
<AppContextProvider pageProps={ pageProps }> <AppContextProvider pageProps={ pageProps }>
......
import { Box, useColorModeValue } from '@chakra-ui/react';
import React from 'react';
interface Props {
children?: React.ReactNode;
}
const ContentWrapper = ({ children }: Props) => {
const bgColor = useColorModeValue('white', 'black');
return <Box bgColor={ bgColor }>{ children }</Box>;
};
export default React.memo(ContentWrapper);
...@@ -6,6 +6,7 @@ import React from 'react'; ...@@ -6,6 +6,7 @@ import React from 'react';
import type { JsonObject } from '@playwright/experimental-ct-core/types/component'; import type { JsonObject } from '@playwright/experimental-ct-core/types/component';
import ContentWrapper from 'playwright/ContentWrapper';
import type { Props as TestAppProps } from 'playwright/TestApp'; import type { Props as TestAppProps } from 'playwright/TestApp';
import TestApp from 'playwright/TestApp'; import TestApp from 'playwright/TestApp';
...@@ -27,7 +28,7 @@ export type RenderFixture = (component: JSX.Element, options?: Options, props?: ...@@ -27,7 +28,7 @@ export type RenderFixture = (component: JSX.Element, options?: Options, props?:
const fixture: TestFixture<RenderFixture, { mount: Mount }> = async({ mount }, use) => { const fixture: TestFixture<RenderFixture, { mount: Mount }> = async({ mount }, use) => {
await use((component, options, props) => { await use((component, options, props) => {
return mount( return mount(
<TestApp { ...props }>{ component }</TestApp>, <TestApp { ...props }><ContentWrapper>{ component }</ContentWrapper></TestApp>,
options, options,
); );
}); });
......
...@@ -7,7 +7,7 @@ import getDefaultTransitionProps from './utils/getDefaultTransitionProps'; ...@@ -7,7 +7,7 @@ import getDefaultTransitionProps from './utils/getDefaultTransitionProps';
const global = (props: StyleFunctionProps) => ({ const global = (props: StyleFunctionProps) => ({
body: { body: {
bg: mode('white', 'black')(props), bg: mode('gray.100', '#3A4957')(props),
...getDefaultTransitionProps(), ...getDefaultTransitionProps(),
'-webkit-tap-highlight-color': 'transparent', '-webkit-tap-highlight-color': 'transparent',
'font-variant-ligatures': 'no-contextual', 'font-variant-ligatures': 'no-contextual',
......
...@@ -7,11 +7,13 @@ import { test, expect } from 'playwright/lib'; ...@@ -7,11 +7,13 @@ import { test, expect } from 'playwright/lib';
import NameDomain from './NameDomain'; import NameDomain from './NameDomain';
test('details tab', async({ render, mockTextAd, mockApiResponse }) => { test('details tab', async({ render, mockTextAd, mockApiResponse, mockAssetResponse }) => {
await mockTextAd(); await mockTextAd();
await mockApiResponse('domain_info', ensDomainMock.ensDomainA, { await mockApiResponse('domain_info', ensDomainMock.ensDomainA, {
pathParams: { chainId: config.chain.id, name: ensDomainMock.ensDomainA.name }, pathParams: { chainId: config.chain.id, name: ensDomainMock.ensDomainA.name },
}); });
await mockAssetResponse(ensDomainMock.ensDomainA.protocol?.icon_url as string, './playwright/mocks/image_s.jpg');
const component = await render( const component = await render(
<NameDomain/>, <NameDomain/>,
{ hooksConfig: { { hooksConfig: {
...@@ -24,7 +26,7 @@ test('details tab', async({ render, mockTextAd, mockApiResponse }) => { ...@@ -24,7 +26,7 @@ test('details tab', async({ render, mockTextAd, mockApiResponse }) => {
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
}); });
test('history tab +@mobile', async({ render, mockTextAd, mockApiResponse }) => { test('history tab +@mobile', async({ render, mockTextAd, mockApiResponse, mockAssetResponse }) => {
await mockTextAd(); await mockTextAd();
await mockApiResponse('domain_info', ensDomainMock.ensDomainA, { await mockApiResponse('domain_info', ensDomainMock.ensDomainA, {
pathParams: { chainId: config.chain.id, name: ensDomainMock.ensDomainA.name }, pathParams: { chainId: config.chain.id, name: ensDomainMock.ensDomainA.name },
...@@ -37,6 +39,7 @@ test('history tab +@mobile', async({ render, mockTextAd, mockApiResponse }) => { ...@@ -37,6 +39,7 @@ test('history tab +@mobile', async({ render, mockTextAd, mockApiResponse }) => {
}, { }, {
pathParams: { chainId: config.chain.id, name: ensDomainMock.ensDomainA.name }, pathParams: { chainId: config.chain.id, name: ensDomainMock.ensDomainA.name },
}); });
await mockAssetResponse(ensDomainMock.ensDomainA.protocol?.icon_url as string, './playwright/mocks/image_s.jpg');
const component = await render( const component = await render(
<NameDomain/>, <NameDomain/>,
{ hooksConfig: { { hooksConfig: {
......
...@@ -9,13 +9,18 @@ interface Props { ...@@ -9,13 +9,18 @@ interface Props {
className?: string; className?: string;
children: React.ReactNode; children: React.ReactNode;
onError?: (error: Error) => void; onError?: (error: Error) => void;
Container?: React.FC<{ children: React.ReactNode }>;
} }
const AppErrorBoundary = ({ className, children, onError }: Props) => { const AppErrorBoundary = ({ className, children, onError, Container }: Props) => {
const renderErrorScreen = React.useCallback((error?: Error) => { const renderErrorScreen = React.useCallback((error?: Error) => {
return <AppError error={ error } className={ className }/>; const content = <AppError error={ error } className={ className }/>;
}, [ className ]); if (Container) {
return <Container>{ content }</Container>;
}
return content;
}, [ className, Container ]);
return ( return (
<ErrorBoundary renderErrorScreen={ renderErrorScreen } onError={ onError }> <ErrorBoundary renderErrorScreen={ renderErrorScreen } onError={ onError }>
......
import { Box, useColorModeValue } from '@chakra-ui/react';
import React from 'react';
interface Props {
children: React.ReactNode;
}
const AppErrorGlobalContainer = ({ children }: Props) => {
const bgColor = useColorModeValue('white', 'black');
return <Box bgColor={ bgColor }>{ children }</Box>;
};
export default React.memo(AppErrorGlobalContainer);
...@@ -80,7 +80,7 @@ const AdaptiveTabsList = (props: Props) => { ...@@ -80,7 +80,7 @@ const AdaptiveTabsList = (props: Props) => {
props.tabListProps) props.tabListProps)
} }
> >
{ tabsList.map((tab, index) => { { tabsList.slice(0, props.isLoading ? 5 : Infinity).map((tab, index) => {
if (!tab.id) { if (!tab.id) {
if (props.isLoading) { if (props.isLoading) {
return null; return null;
......
...@@ -99,7 +99,7 @@ const TabsWithScroll = ({ ...@@ -99,7 +99,7 @@ const TabsWithScroll = ({
// - tabs list is changed when API data is loaded // - tabs list is changed when API data is loaded
// is to do full re-render of the tabs list // is to do full re-render of the tabs list
// so we use screenWidth + tabIds as a key for the TabsList component // so we use screenWidth + tabIds as a key for the TabsList component
key={ screenWidth + '_' + tabsList.map((tab) => tab.id).join(':') } key={ isLoading + '_' + screenWidth + '_' + tabsList.map((tab) => tab.id).join(':') }
tabs={ tabs } tabs={ tabs }
tabListProps={ tabListProps } tabListProps={ tabListProps }
rightSlot={ rightSlot } rightSlot={ rightSlot }
......
...@@ -160,6 +160,7 @@ const AddressEntry = (props: EntityProps) => { ...@@ -160,6 +160,7 @@ const AddressEntry = (props: EntityProps) => {
onMouseEnter={ context?.onMouseEnter } onMouseEnter={ context?.onMouseEnter }
onMouseLeave={ context?.onMouseLeave } onMouseLeave={ context?.onMouseLeave }
position="relative" position="relative"
zIndex={ 0 }
> >
<Icon { ...partsProps } color={ props.iconColor }/> <Icon { ...partsProps } color={ props.iconColor }/>
<Link { ...linkProps }> <Link { ...linkProps }>
......
...@@ -2,6 +2,7 @@ import React from 'react'; ...@@ -2,6 +2,7 @@ import React from 'react';
import { indexingStatus } from 'mocks/stats/index'; import { indexingStatus } from 'mocks/stats/index';
import { test, expect } from 'playwright/lib'; import { test, expect } from 'playwright/lib';
import * as pwConfig from 'playwright/utils/config';
import Layout from './Layout'; import Layout from './Layout';
...@@ -16,3 +17,20 @@ test('base view +@mobile', async({ render, mockEnvs, mockApiResponse }) => { ...@@ -16,3 +17,20 @@ test('base view +@mobile', async({ render, mockEnvs, mockApiResponse }) => {
const component = await render(<Layout>Page Content</Layout>); const component = await render(<Layout>Page Content</Layout>);
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
}); });
test.describe('xl screen', () => {
test.use({ viewport: pwConfig.viewport.xl });
test('vertical navigation', async({ render }) => {
const component = await render(<Layout>Page Content</Layout>);
await expect(component).toHaveScreenshot();
});
test('horizontal navigation', async({ render, mockEnvs }) => {
await mockEnvs([
[ 'NEXT_PUBLIC_NAVIGATION_LAYOUT', 'horizontal' ],
]);
const component = await render(<Layout>Page Content</Layout>);
await expect(component).toHaveScreenshot();
});
});
import { Box, chakra } from '@chakra-ui/react'; import { Box, chakra, useColorModeValue } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import config from 'configs/app';
import { CONTENT_MAX_WIDTH } from '../utils';
interface Props { interface Props {
children: React.ReactNode; children: React.ReactNode;
className?: string; className?: string;
} }
const Container = ({ children, className }: Props) => { const Container = ({ children, className }: Props) => {
const bgColor = useColorModeValue('white', 'black');
return ( return (
<Box className={ className } minWidth={{ base: '100vw', lg: 'fit-content' }}> <Box
className={ className }
minWidth={{ base: '100vw', lg: 'fit-content' }}
maxW={ config.UI.navigation.layout === 'horizontal' ? undefined : `${ CONTENT_MAX_WIDTH }px` }
m="0 auto"
bgColor={ bgColor }
>
{ children } { children }
</Box> </Box>
); );
......
...@@ -3,6 +3,8 @@ import React from 'react'; ...@@ -3,6 +3,8 @@ import React from 'react';
import config from 'configs/app'; import config from 'configs/app';
import { CONTENT_MAX_WIDTH } from '../utils';
interface Props { interface Props {
children: React.ReactNode; children: React.ReactNode;
className?: string; className?: string;
...@@ -16,6 +18,8 @@ const MainArea = ({ children, className }: Props) => { ...@@ -16,6 +18,8 @@ const MainArea = ({ children, className }: Props) => {
<Flex <Flex
className={ className } className={ className }
w="100%" w="100%"
maxW={ `${ CONTENT_MAX_WIDTH }px` }
m="0 auto"
minH={{ minH={{
base: `calc(100vh - ${ TOP_BAR_HEIGHT }px)`, base: `calc(100vh - ${ TOP_BAR_HEIGHT }px)`,
lg: `calc(100vh - ${ TOP_BAR_HEIGHT + HORIZONTAL_NAV_BAR_HEIGHT }px)`, lg: `calc(100vh - ${ TOP_BAR_HEIGHT + HORIZONTAL_NAV_BAR_HEIGHT }px)`,
......
...@@ -14,7 +14,7 @@ const MainColumn = ({ children, className }: Props) => { ...@@ -14,7 +14,7 @@ const MainColumn = ({ children, className }: Props) => {
className={ className } className={ className }
flexDir="column" flexDir="column"
flexGrow={ 1 } flexGrow={ 1 }
w={{ base: '100%', lg: 'auto' }} w={{ base: '100%', lg: config.UI.navigation.layout === 'horizontal' ? '100%' : 'auto' }}
paddingX={{ base: 3, lg: config.UI.navigation.layout === 'horizontal' ? 6 : 12 }} paddingX={{ base: 3, lg: config.UI.navigation.layout === 'horizontal' ? 6 : 12 }}
paddingTop={{ base: `${ 12 + 52 }px`, lg: 6 }} // 12px is top padding of content area, 52px is search bar height paddingTop={{ base: `${ 12 + 52 }px`, lg: 6 }} // 12px is top padding of content area, 52px is search bar height
paddingBottom={ 8 } paddingBottom={ 8 }
......
import config from 'configs/app';
export const CONTENT_MAX_WIDTH = config.UI.navigation.layout === 'horizontal' ? 1440 : 1512;
import type { GridProps } from '@chakra-ui/react'; import type { GridProps, HTMLChakraProps } from '@chakra-ui/react';
import { Box, Grid, Flex, Text, Link, VStack, Skeleton, useColorModeValue } from '@chakra-ui/react'; import { Box, Grid, Flex, Text, Link, VStack, Skeleton, useColorModeValue } from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
...@@ -12,6 +12,7 @@ import useFetch from 'lib/hooks/useFetch'; ...@@ -12,6 +12,7 @@ import useFetch from 'lib/hooks/useFetch';
import useIssueUrl from 'lib/hooks/useIssueUrl'; import useIssueUrl from 'lib/hooks/useIssueUrl';
import { copy } from 'lib/html-entities'; import { copy } from 'lib/html-entities';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
import { CONTENT_MAX_WIDTH } from 'ui/shared/layout/utils';
import NetworkAddToWallet from 'ui/shared/NetworkAddToWallet'; import NetworkAddToWallet from 'ui/shared/NetworkAddToWallet';
import FooterLinkItem from './FooterLinkItem'; import FooterLinkItem from './FooterLinkItem';
...@@ -154,89 +155,98 @@ const Footer = () => { ...@@ -154,89 +155,98 @@ const Footer = () => {
); );
}, [ apiVersionUrl, backendVersionData?.backend_version, frontendLink, logoColor ]); }, [ apiVersionUrl, backendVersionData?.backend_version, frontendLink, logoColor ]);
const containerProps: GridProps = { const containerProps: HTMLChakraProps<'div'> = {
as: 'footer', as: 'footer',
borderTopWidth: '1px',
borderTopColor: 'solid',
};
const contentProps: GridProps = {
px: { base: 4, lg: config.UI.navigation.layout === 'horizontal' ? 6 : 12 }, px: { base: 4, lg: config.UI.navigation.layout === 'horizontal' ? 6 : 12 },
py: { base: 4, lg: 8 }, py: { base: 4, lg: 8 },
borderTop: '1px solid',
borderColor: 'divider',
gridTemplateColumns: { base: '1fr', lg: 'minmax(auto, 470px) 1fr' }, gridTemplateColumns: { base: '1fr', lg: 'minmax(auto, 470px) 1fr' },
columnGap: { lg: '32px', xl: '100px' }, columnGap: { lg: '32px', xl: '100px' },
maxW: `${ CONTENT_MAX_WIDTH }px`,
m: '0 auto',
}; };
if (config.UI.footer.links) { if (config.UI.footer.links) {
return ( return (
<Grid { ...containerProps }> <Box { ...containerProps }>
<div> <Grid { ...contentProps }>
{ renderNetworkInfo() } <div>
{ renderProjectInfo() } { renderNetworkInfo() }
</div> { renderProjectInfo() }
</div>
<Grid
gap={{ base: 6, lg: colNum === MAX_LINKS_COLUMNS + 1 ? 2 : 8, xl: 12 }} <Grid
gridTemplateColumns={{ gap={{ base: 6, lg: colNum === MAX_LINKS_COLUMNS + 1 ? 2 : 8, xl: 12 }}
base: 'repeat(auto-fill, 160px)', gridTemplateColumns={{
lg: `repeat(${ colNum }, 135px)`, base: 'repeat(auto-fill, 160px)',
xl: `repeat(${ colNum }, 160px)`, lg: `repeat(${ colNum }, 135px)`,
}} xl: `repeat(${ colNum }, 160px)`,
justifyContent={{ lg: 'flex-end' }} }}
mt={{ base: 8, lg: 0 }} justifyContent={{ lg: 'flex-end' }}
> mt={{ base: 8, lg: 0 }}
{ >
([ {
{ title: 'Blockscout', links: BLOCKSCOUT_LINKS }, ([
...(linksData || []), { title: 'Blockscout', links: BLOCKSCOUT_LINKS },
]) ...(linksData || []),
.slice(0, colNum) ])
.map(linkGroup => ( .slice(0, colNum)
<Box key={ linkGroup.title }> .map(linkGroup => (
<Skeleton fontWeight={ 500 } mb={ 3 } display="inline-block" isLoaded={ !isPlaceholderData }>{ linkGroup.title }</Skeleton> <Box key={ linkGroup.title }>
<VStack spacing={ 1 } alignItems="start"> <Skeleton fontWeight={ 500 } mb={ 3 } display="inline-block" isLoaded={ !isPlaceholderData }>{ linkGroup.title }</Skeleton>
{ linkGroup.links.map(link => <FooterLinkItem { ...link } key={ link.text } isLoading={ isPlaceholderData }/>) } <VStack spacing={ 1 } alignItems="start">
</VStack> { linkGroup.links.map(link => <FooterLinkItem { ...link } key={ link.text } isLoading={ isPlaceholderData }/>) }
</Box> </VStack>
)) </Box>
} ))
}
</Grid>
</Grid> </Grid>
</Grid> </Box>
); );
} }
return ( return (
<Grid <Box { ...containerProps }>
{ ...containerProps } <Grid
gridTemplateAreas={{ { ...contentProps }
lg: ` gridTemplateAreas={{
lg: `
"network links-top" "network links-top"
"info links-bottom" "info links-bottom"
`, `,
}}
>
{ renderNetworkInfo({ lg: 'network' }) }
{ renderProjectInfo({ lg: 'info' }) }
<Grid
gridArea={{ lg: 'links-bottom' }}
gap={ 1 }
gridTemplateColumns={{
base: 'repeat(auto-fill, 160px)',
lg: 'repeat(3, 160px)',
xl: 'repeat(4, 160px)',
}} }}
gridTemplateRows={{
base: 'auto',
lg: 'repeat(3, auto)',
xl: 'repeat(2, auto)',
}}
gridAutoFlow={{ base: 'row', lg: 'column' }}
alignContent="start"
justifyContent={{ lg: 'flex-end' }}
mt={{ base: 8, lg: 0 }}
> >
{ BLOCKSCOUT_LINKS.map(link => <FooterLinkItem { ...link } key={ link.text }/>) }
{ renderNetworkInfo({ lg: 'network' }) }
{ renderProjectInfo({ lg: 'info' }) }
<Grid
gridArea={{ lg: 'links-bottom' }}
gap={ 1 }
gridTemplateColumns={{
base: 'repeat(auto-fill, 160px)',
lg: 'repeat(3, 160px)',
xl: 'repeat(4, 160px)',
}}
gridTemplateRows={{
base: 'auto',
lg: 'repeat(3, auto)',
xl: 'repeat(2, auto)',
}}
gridAutoFlow={{ base: 'row', lg: 'column' }}
alignContent="start"
justifyContent={{ lg: 'flex-end' }}
mt={{ base: 8, lg: 0 }}
>
{ BLOCKSCOUT_LINKS.map(link => <FooterLinkItem { ...link } key={ link.text }/>) }
</Grid>
</Grid> </Grid>
</Grid> </Box>
); );
}; };
......
import { chakra, Flex } from '@chakra-ui/react'; import { Box, chakra, Flex } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import config from 'configs/app'; import config from 'configs/app';
import useNavItems, { isGroupItem } from 'lib/hooks/useNavItems'; import useNavItems, { isGroupItem } from 'lib/hooks/useNavItems';
import { CONTENT_MAX_WIDTH } from 'ui/shared/layout/utils';
import NetworkLogo from 'ui/snippets/networkMenu/NetworkLogo'; import NetworkLogo from 'ui/snippets/networkMenu/NetworkLogo';
import ProfileMenuDesktop from 'ui/snippets/profileMenu/ProfileMenuDesktop'; import ProfileMenuDesktop from 'ui/snippets/profileMenu/ProfileMenuDesktop';
import WalletMenuDesktop from 'ui/snippets/walletMenu/WalletMenuDesktop'; import WalletMenuDesktop from 'ui/snippets/walletMenu/WalletMenuDesktop';
...@@ -15,30 +16,32 @@ const NavigationDesktop = () => { ...@@ -15,30 +16,32 @@ const NavigationDesktop = () => {
const { mainNavItems } = useNavItems(); const { mainNavItems } = useNavItems();
return ( return (
<Flex <Box borderColor="divider" borderBottomWidth="1px">
display={{ base: 'none', lg: 'flex' }} <Flex
alignItems="center" display={{ base: 'none', lg: 'flex' }}
px={ 6 } alignItems="center"
py={ 2 } px={ 6 }
borderBottomWidth="1px" py={ 2 }
borderColor="divider" maxW={ `${ CONTENT_MAX_WIDTH }px` }
> m="0 auto"
<NetworkLogo isCollapsed={ false } w={{ lg: 'auto' }} maxW="120px"/> >
<TestnetBadge ml={ 3 }/> <NetworkLogo isCollapsed={ false } w={{ lg: 'auto' }} maxW="120px"/>
<chakra.nav ml="auto" mr={ config.features.account.isEnabled || config.features.blockchainInteraction.isEnabled ? 8 : 0 }> <TestnetBadge ml={ 3 }/>
<Flex as="ul" columnGap={ 3 }> <chakra.nav ml="auto" mr={ config.features.account.isEnabled || config.features.blockchainInteraction.isEnabled ? 8 : 0 }>
{ mainNavItems.map((item) => { <Flex as="ul" columnGap={ 3 }>
if (isGroupItem(item)) { { mainNavItems.map((item) => {
return <NavLinkGroup key={ item.text } item={ item }/>; if (isGroupItem(item)) {
} else { return <NavLinkGroup key={ item.text } item={ item }/>;
return <NavLink key={ item.text } item={ item } noIcon py={ 1.5 } w="fit-content"/>; } else {
} return <NavLink key={ item.text } item={ item } noIcon py={ 1.5 } w="fit-content"/>;
}) } }
</Flex> }) }
</chakra.nav> </Flex>
{ config.features.account.isEnabled && <ProfileMenuDesktop buttonBoxSize="32px"/> } </chakra.nav>
{ config.features.blockchainInteraction.isEnabled && <WalletMenuDesktop size="sm"/> } { config.features.account.isEnabled && <ProfileMenuDesktop buttonBoxSize="32px"/> }
</Flex> { config.features.blockchainInteraction.isEnabled && <WalletMenuDesktop size="sm"/> }
</Flex>
</Box>
); );
}; };
......
...@@ -2,6 +2,7 @@ import { Flex, Divider, useColorModeValue, Box } from '@chakra-ui/react'; ...@@ -2,6 +2,7 @@ import { Flex, Divider, useColorModeValue, Box } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import config from 'configs/app'; import config from 'configs/app';
import { CONTENT_MAX_WIDTH } from 'ui/shared/layout/utils';
import DeFiDropdown from './DeFiDropdown'; import DeFiDropdown from './DeFiDropdown';
import NetworkMenu from './NetworkMenu'; import NetworkMenu from './NetworkMenu';
...@@ -12,30 +13,33 @@ const TopBar = () => { ...@@ -12,30 +13,33 @@ const TopBar = () => {
const bgColor = useColorModeValue('gray.50', 'whiteAlpha.100'); const bgColor = useColorModeValue('gray.50', 'whiteAlpha.100');
return ( return (
<Flex <Box bgColor={ bgColor }>
py={ 2 } <Flex
px={{ base: 3, lg: 6 }} py={ 2 }
bgColor={ bgColor } px={{ base: 3, lg: 6 }}
justifyContent="space-between" maxW={ `${ CONTENT_MAX_WIDTH }px` }
alignItems="center" m="0 auto"
> justifyContent="space-between"
<TopBarStats/> alignItems="center"
<Flex alignItems="center"> >
{ config.features.deFiDropdown.isEnabled && ( <TopBarStats/>
<> <Flex alignItems="center">
<DeFiDropdown/> { config.features.deFiDropdown.isEnabled && (
<Divider mr={ 3 } ml={{ base: 2, sm: 3 }} height={ 4 } orientation="vertical"/> <>
</> <DeFiDropdown/>
) } <Divider mr={ 3 } ml={{ base: 2, sm: 3 }} height={ 4 } orientation="vertical"/>
<Settings/> </>
{ config.UI.navigation.layout === 'horizontal' && Boolean(config.UI.navigation.featuredNetworks) && ( ) }
<Box display={{ base: 'none', lg: 'flex' }}> <Settings/>
<Divider mx={ 3 } height={ 4 } orientation="vertical"/> { config.UI.navigation.layout === 'horizontal' && Boolean(config.UI.navigation.featuredNetworks) && (
<NetworkMenu/> <Box display={{ base: 'none', lg: 'flex' }}>
</Box> <Divider mx={ 3 } height={ 4 } orientation="vertical"/>
) } <NetworkMenu/>
</Box>
) }
</Flex>
</Flex> </Flex>
</Flex> </Box>
); );
}; };
......
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