Add mobile menu

pull/226/head
artemkolodko 2 years ago
parent 69604931e5
commit 35a53cd783
  1. 105
      src/components/appHeader/MenuMobile.tsx
  2. 70
      src/components/appHeader/ResourcesButton.tsx
  3. 24
      src/components/appHeader/ToolsButton.tsx
  4. 94
      src/components/appHeader/index.tsx
  5. 4
      src/pages/TopStatsPage/CommonTopTable.tsx

@ -0,0 +1,105 @@
import {Box, Text} from "grommet";
import {useHistory} from "react-router-dom";
import {useState} from "react";
import {CaretDownFill, CaretUpFill, Sun, Moon, Clock, Calendar} from "grommet-icons";
import {setThemeMode, useThemeMode} from "../../hooks/themeSwitcherHook";
import {DateFormat, setDateFormatMode, useDateFormatMode} from "../../hooks/dateFormatSwitcherHook";
interface MenuRowItem {
title: string
route?: string
content?: any
}
interface MenuRowProps {
title: string
items: MenuRowItem[]
route?: string
onSelect?: (title: string, route?: string) => void
}
const MenuItem = (props: { item: MenuRowItem, onSelect?: (title: string, route?: string) => void }) => {
const { item: { title, route, content }, onSelect } = props
const onClick = (e: any) => {
e.stopPropagation()
if(onSelect) {
onSelect(title, route)
}
}
return <Box pad={'8px 32px'} onClick={onClick}>
<Text size={'small'}>{title}</Text>
{!!content &&
content
}
</Box>
}
const MenuRow = (props: MenuRowProps) => {
const [isItemsVisible, setItemsVisible] = useState(false)
const {title, items, route, onSelect} = props
const onClick = () => {
if(route && onSelect) {
onSelect(title, route)
}
if(items.length > 0) {
setItemsVisible(!isItemsVisible)
}
}
return <Box pad={'4px 16px'} onClick={onClick}>
<Box direction={'row'} justify={'between'} pad={'8px'}>
<Text size={'medium'} color={isItemsVisible ? 'brand' : 'text'}>{title}</Text>
{items.length > 0 && !isItemsVisible && <CaretDownFill size={'14px'} color={'text'} /> }
{items.length > 0 && isItemsVisible && <CaretUpFill size={'14px'} color={'brand'} /> }
</Box>
{isItemsVisible &&
<Box style={{ position: 'relative' }}>
<Box width={'2px'} height={'100%'} margin={{ left: '12px' }} background={'brand'} style={{ position: 'absolute' }} />
{items.map((item, i) => <MenuItem key={item.title + i} item={item} onSelect={onSelect} />)}
</Box>
}
</Box>
}
export const MenuMobile = (props: { isOpened: boolean; onClose: () => void }) => {
const history = useHistory();
const onSelect = (title: string, route?: string) => {
if(route) {
history.push(route);
props.onClose()
}
}
const ThemeSwitch = () => {
const theme = useThemeMode();
return <Box direction={'row'}
gap={'8px'}
align={'center'}
onClick={() => setThemeMode(theme === 'light' ? 'dark' : 'light')}>
<Box>{theme === 'light' ? <Moon /> : <Sun />}</Box>
<Box>{theme === 'light' ? 'Switch to dark mode' : 'Switch to light mode'}</Box>
</Box>
}
const DateFormatSwitch = () => {
const dateFormat = useDateFormatMode();
return <Box direction={'row'}
gap={'8px'}
align={'center'}
onClick={() => setDateFormatMode(dateFormat === DateFormat.EXACT ? DateFormat.RELATIVE : DateFormat.EXACT)}
>
<Box>{dateFormat === DateFormat.EXACT ? <Clock height={'2px'} /> : <Calendar height={'2px'} />}</Box>
<Box>{dateFormat === DateFormat.EXACT ? 'Switch to relative dates' : 'Switch to exact dates'}</Box>
</Box>
}
return <Box pad={'8px 0'} background={'background'} style={{ display: props.isOpened ? 'block' : 'none' }}>
<MenuRow title={'Home'} items={[]} route={'/'} onSelect={onSelect} />
<MenuRow title={'Tokens'} items={[{ title: 'HRC20', route: 'hrc20' }, { title: 'HRC721', route: 'hrc721' }, { title: 'HRC1155', route: 'hrc1155' }]} onSelect={onSelect} />
<MenuRow title={'Tools'} items={[{ title: 'Token Approvals', route: '/tools/approvals' }, { title: 'Check HRC', route: '/tools/checkHrc' }, { title: 'Proxy verification', route: 'proxyContractChecker' }]} onSelect={onSelect} />
<MenuRow title={'Resources'} items={[{ title: 'Charts & Stats', route: 'charts' }, { title: 'Top Statistics', route: 'topstat' }]} onSelect={onSelect} />
<MenuRow title={'Appearence'} items={[{ title: '', content: <ThemeSwitch /> }, { title: '', content: <DateFormatSwitch />}]} />
</Box>
}

@ -0,0 +1,70 @@
import React, { useState } from "react";
import { CaretDownFill } from "grommet-icons";
import { Box, DropButton, Anchor, Text } from "grommet";
import { useHistory } from "react-router-dom";
export function ResourcesButton() {
const history = useHistory();
const [isOpen, setIsOpen] = useState<boolean>(false);
return (
<DropButton
label={
<Box direction={"row"} align="center">
<Text size="small" color="white" weight="bold">
Resources
</Text>
<CaretDownFill color="white" />
</Box>
}
onOpen={() => {
setIsOpen(true);
}}
onClose={() => {
setIsOpen(false);
}}
open={isOpen}
dropProps={{ round: '4px' }}
dropAlign={{ top: "bottom", right: "right" }}
dropContent={
<Box
pad="medium"
background="background"
border={{ size: "xsmall", color: "border" }}
style={{ borderRadius: "0px" }}
gap="small"
>
<Anchor
style={{ textDecoration: "underline" }}
onClick={(e) => {
setIsOpen(false);
history.push("/charts");
}}
>
<Box direction={'row'} align={'center'} gap={'4px'}>
Charts & Stats
<Text size={'xsmall'} color={'successText'}>(new)</Text>
</Box>
</Anchor>
<Anchor
style={{ textDecoration: "underline" }}
onClick={(e) => {
setIsOpen(false);
history.push("/topstat");
}}
>
<Box direction={'row'} align={'center'} gap={'4px'}>
Top Statistics
<Text size={'xsmall'} color={'successText'}>(new)</Text>
</Box>
</Anchor>
</Box>
}
style={{
border: "none",
boxShadow: "none",
paddingRight: "6px"
}}
/>
);
}

@ -61,30 +61,6 @@ export function ToolsButton() {
>
Proxy verification
</Anchor>
<Anchor
style={{ textDecoration: "underline" }}
onClick={(e) => {
setIsOpen(false);
history.push("/charts");
}}
>
<Box direction={'row'} align={'center'} gap={'4px'}>
Charts & Stats
<Text size={'xsmall'} color={'successText'}>(new)</Text>
</Box>
</Anchor>
<Anchor
style={{ textDecoration: "underline" }}
onClick={(e) => {
setIsOpen(false);
history.push("/topstat");
}}
>
<Box direction={'row'} align={'center'} gap={'4px'}>
Top Statistics
<Text size={'xsmall'} color={'successText'}>(new)</Text>
</Box>
</Anchor>
</Box>
}
style={{

@ -1,4 +1,4 @@
import React from "react";
import React, {useState} from "react";
import { Box, Heading, Text } from "grommet";
import { useMediaQuery } from 'react-responsive'
import { FiatPrice, BaseContainer } from "src/components/ui";
@ -9,6 +9,9 @@ import { useThemeMode } from "src/hooks/themeSwitcherHook";
import styled, { CSSProperties } from "styled-components";
import { AddressFormatSwitch } from "./AddressFormatSwitch";
import { ToolsButton } from "./ToolsButton";
import { ResourcesButton } from "./ResourcesButton";
import {MenuMobile} from "./MenuMobile";
import {Menu, Close} from "grommet-icons";
const HeaderLine = (props: any) => {
//@ts-ignore
@ -37,49 +40,64 @@ const ProjectName = styled(Box)`
export function AppHeader(props: { style: CSSProperties }) {
const history = useHistory();
const [isMenuMobileOpened, setMenuMobileOpened] = useState(false)
const isTabletOrMobile = useMediaQuery({ query: '(max-width: 960px)' })
return (
<HeaderLine
{...props}
style={{ boxShadow: "0px 4px 8px rgb(0 0 0 / 12%)" }}
>
<BaseContainer direction="row" align="center" justify="between" flex>
<Heading
level="5"
margin="none"
style={{
cursor: "pointer",
color: "#fff",
}}
onClick={() => history.push("/")}
>
<Box direction={"row"} align={"center"}>
<img src={require("../../assets/Logo.svg").default} />
<Box>
<HeaderLine
{...props}
style={{ boxShadow: "0px 4px 8px rgb(0 0 0 / 12%)" }}
>
<BaseContainer direction="row" align="center" justify="between" flex>
<Heading
level="5"
margin="none"
style={{
cursor: "pointer",
color: "#fff",
}}
onClick={() => history.push("/")}
>
<Box direction={"row"} align={"center"}>
<img src={require("../../assets/Logo.svg").default} />
{!isTabletOrMobile &&
<ProjectName direction={"column"} align={"start"}>
Harmony
<Text size={"small"}>Block Explorer</Text>
</ProjectName>
}
</Box>
</Heading>
<Box direction="row">
<Box direction="row" align={'center'}>
{!isTabletOrMobile &&
<Box alignSelf={'center'} margin={'0 16px 0 0'}>
<Text size={'small'} color="headerText">Address Format</Text>
</Box>
}
<AddressFormatSwitch />
</Box>
{!isTabletOrMobile &&
<ProjectName direction={"column"} align={"start"}>
Harmony
<Text size={"small"}>Block Explorer</Text>
</ProjectName>
<Box direction="row" align={'center'}>
<InfoButton />
<ResourcesButton />
<ToolsButton />
<ConfigureButton />
</Box>
}
</Box>
</Heading>
<Box direction="row">
<Box direction="row" align={'center'}>
{!isTabletOrMobile &&
<Box alignSelf={'center'} margin={'0 16px 0 0'}>
<Text size={'small'} color="headerText">Address Format</Text>
</Box>
{isTabletOrMobile &&
<Box justify={'center'} margin={{ left: 'large' }}>
{isMenuMobileOpened && <Close size={'medium'} color={'white'} onClick={() => setMenuMobileOpened(false)} /> }
{!isMenuMobileOpened && <Menu size={'medium'} color={'white'} onClick={() => setMenuMobileOpened(true)} /> }
</Box>
}
<AddressFormatSwitch />
</Box>
<Box direction="row" align={'center'}>
<InfoButton />
<ToolsButton />
<ConfigureButton />
</Box>
</Box>
</BaseContainer>
</HeaderLine>
</BaseContainer>
</HeaderLine>
{isTabletOrMobile &&
<MenuMobile isOpened={isMenuMobileOpened} onClose={() => setMenuMobileOpened(false)} />
}
</Box>
);
}

@ -42,7 +42,7 @@ const TopTableHeader = (props: { columns: string[] }) => {
direction={'row'}
gap={'8px'}
pad={'8px'}
border={{ size: '2px', side: 'bottom' }}
// border={{ size: '2px', side: 'top' }}
style={{ fontWeight: 'bold' }}
>
<Box width={columnsWidth[0]}>
@ -82,7 +82,7 @@ const TopTableRow = (props: TopTableRowProps) => {
direction={'row'}
gap={'8px'}
pad={'8px'}
border={{ size: '1px', side: 'bottom' }}
border={{ size: '1px', side: 'top' }}
>
<Box width={columnsWidth[0]}>
<Text size={'small'}>{rank}</Text>

Loading…
Cancel
Save