Commit 1b86a74e authored by Yuri Mikhin's avatar Yuri Mikhin Committed by Yuri Mikhin

Improve Stats page layout.

parent 7886d41a
...@@ -15,7 +15,7 @@ interface Props { ...@@ -15,7 +15,7 @@ interface Props {
caption?: string; caption?: string;
} }
const CHART_MARGIN = { bottom: 0, left: 10, right: 10, top: 0 }; const CHART_MARGIN = { bottom: 5, left: 10, right: 10, top: 0 };
const ChainIndicatorChart = ({ data }: Props) => { const ChainIndicatorChart = ({ data }: Props) => {
const ref = React.useRef<SVGSVGElement>(null); const ref = React.useRef<SVGSVGElement>(null);
......
...@@ -14,7 +14,7 @@ interface Props extends Omit<React.SVGProps<SVGGElement>, 'scale'> { ...@@ -14,7 +14,7 @@ interface Props extends Omit<React.SVGProps<SVGGElement>, 'scale'> {
const ChartAxis = ({ type, scale, ticks, tickFormat, disableAnimation, anchorEl, ...props }: Props) => { const ChartAxis = ({ type, scale, ticks, tickFormat, disableAnimation, anchorEl, ...props }: Props) => {
const ref = React.useRef<SVGGElement>(null); const ref = React.useRef<SVGGElement>(null);
const textColorToken = useColorModeValue('blackAlpha.500', 'whiteAlpha.500'); const textColorToken = useColorModeValue('blackAlpha.600', 'whiteAlpha.500');
const textColor = useToken('colors', textColorToken); const textColor = useToken('colors', textColorToken);
React.useEffect(() => { React.useEffect(() => {
......
...@@ -13,7 +13,7 @@ interface Props extends Omit<React.SVGProps<SVGGElement>, 'scale'> { ...@@ -13,7 +13,7 @@ interface Props extends Omit<React.SVGProps<SVGGElement>, 'scale'> {
const ChartGridLine = ({ type, scale, ticks, size, disableAnimation, ...props }: Props) => { const ChartGridLine = ({ type, scale, ticks, size, disableAnimation, ...props }: Props) => {
const ref = React.useRef<SVGGElement>(null); const ref = React.useRef<SVGGElement>(null);
const strokeColorToken = useColorModeValue('blackAlpha.300', 'whiteAlpha.300'); const strokeColorToken = useColorModeValue('blackAlpha.200', 'whiteAlpha.200');
const strokeColor = useToken('colors', strokeColorToken); const strokeColor = useToken('colors', strokeColorToken);
React.useEffect(() => { React.useEffect(() => {
......
import { Box, Grid, Heading, Icon, IconButton, Menu, MenuButton, MenuItem, MenuList, Text, useColorModeValue, VisuallyHidden } from '@chakra-ui/react'; import { Box, Grid, Icon, IconButton, Menu, MenuButton, MenuItem, MenuList, Text, Tooltip, useColorModeValue, VisuallyHidden } from '@chakra-ui/react';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import type { TimeChartItem } from './types'; import type { TimeChartItem } from './types';
...@@ -21,7 +21,6 @@ const ChartWidget = ({ items, title, description, isLoading }: Props) => { ...@@ -21,7 +21,6 @@ const ChartWidget = ({ items, title, description, isLoading }: Props) => {
const [ isFullscreen, setIsFullscreen ] = useState(false); const [ isFullscreen, setIsFullscreen ] = useState(false);
const [ isZoomResetInitial, setIsZoomResetInitial ] = React.useState(true); const [ isZoomResetInitial, setIsZoomResetInitial ] = React.useState(true);
const menuButtonColor = useColorModeValue('black', 'white');
const borderColor = useColorModeValue('gray.200', 'gray.600'); const borderColor = useColorModeValue('gray.200', 'gray.600');
const handleZoom = useCallback(() => { const handleZoom = useCallback(() => {
...@@ -56,7 +55,7 @@ const ChartWidget = ({ items, title, description, isLoading }: Props) => { ...@@ -56,7 +55,7 @@ const ChartWidget = ({ items, title, description, isLoading }: Props) => {
return ( return (
<> <>
<Box <Box
padding={{ base: 3, md: 4 }} padding={{ base: 3, lg: 4 }}
borderRadius="md" borderRadius="md"
border="1px" border="1px"
borderColor={ borderColor } borderColor={ borderColor }
...@@ -65,12 +64,15 @@ const ChartWidget = ({ items, title, description, isLoading }: Props) => { ...@@ -65,12 +64,15 @@ const ChartWidget = ({ items, title, description, isLoading }: Props) => {
gridTemplateColumns="auto auto 36px" gridTemplateColumns="auto auto 36px"
gridColumnGap={ 2 } gridColumnGap={ 2 }
> >
<Heading <Text
mb={ 1 } fontWeight={ 600 }
size={{ base: 'xs', md: 'sm' }} fontSize="md"
lineHeight={ 6 }
as="p"
size={{ base: 'xs', lg: 'sm' }}
> >
{ title } { title }
</Heading> </Text>
<Text <Text
mb={ 1 } mb={ 1 }
...@@ -82,22 +84,23 @@ const ChartWidget = ({ items, title, description, isLoading }: Props) => { ...@@ -82,22 +84,23 @@ const ChartWidget = ({ items, title, description, isLoading }: Props) => {
{ description } { description }
</Text> </Text>
<IconButton <Tooltip label="Reset zoom">
hidden={ isZoomResetInitial } <IconButton
aria-label="Reset zoom" hidden={ isZoomResetInitial }
title="Reset zoom" aria-label="Reset zoom"
colorScheme="blue" colorScheme="blue"
w={ 9 } w={ 9 }
h={ 8 } h={ 8 }
gridColumn={ 2 } gridColumn={ 2 }
justifySelf="end" justifySelf="end"
alignSelf="top" alignSelf="top"
gridRow="1/3" gridRow="1/3"
size="sm" size="sm"
variant="ghost" variant="outline"
onClick={ handleZoomResetClick } onClick={ handleZoomResetClick }
icon={ <Icon as={ repeatArrow } w={ 4 } h={ 4 } color="blue.700"/> } icon={ <Icon as={ repeatArrow } w={ 4 } h={ 4 }/> }
/> />
</Tooltip>
<Menu> <Menu>
<MenuButton <MenuButton
...@@ -106,8 +109,9 @@ const ChartWidget = ({ items, title, description, isLoading }: Props) => { ...@@ -106,8 +109,9 @@ const ChartWidget = ({ items, title, description, isLoading }: Props) => {
justifySelf="end" justifySelf="end"
w="36px" w="36px"
h="32px" h="32px"
icon={ <Icon as={ dotsIcon } w={ 4 } h={ 4 } color={ menuButtonColor }/> } icon={ <Icon as={ dotsIcon } w={ 4 } h={ 4 }/> }
colorScheme="transparent" colorScheme="gray"
variant="ghost"
as={ IconButton } as={ IconButton }
> >
<VisuallyHidden> <VisuallyHidden>
...@@ -132,6 +136,7 @@ const ChartWidget = ({ items, title, description, isLoading }: Props) => { ...@@ -132,6 +136,7 @@ const ChartWidget = ({ items, title, description, isLoading }: Props) => {
isOpen={ isFullscreen } isOpen={ isFullscreen }
items={ items } items={ items }
title={ title } title={ title }
description={ description }
onClose={ clearFullscreenChart } onClose={ clearFullscreenChart }
/> />
</> </>
......
...@@ -15,20 +15,21 @@ import useChartSize from 'ui/shared/chart/useChartSize'; ...@@ -15,20 +15,21 @@ import useChartSize from 'ui/shared/chart/useChartSize';
import useTimeChartController from 'ui/shared/chart/useTimeChartController'; import useTimeChartController from 'ui/shared/chart/useTimeChartController';
interface Props { interface Props {
isEnlarged?: boolean;
title: string; title: string;
items: Array<TimeChartItem>; items: Array<TimeChartItem>;
onZoom: () => void; onZoom: () => void;
isZoomResetInitial: boolean; isZoomResetInitial: boolean;
} }
const CHART_MARGIN = { bottom: 20, left: 52, right: 30, top: 10 }; const CHART_MARGIN = { bottom: 20, left: 30, right: 20, top: 10 };
const ChartWidgetGraph = ({ items, onZoom, isZoomResetInitial, title }: Props) => { const ChartWidgetGraph = ({ isEnlarged, items, onZoom, isZoomResetInitial, title }: Props) => {
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const ref = React.useRef<SVGSVGElement>(null); const ref = React.useRef<SVGSVGElement>(null);
const color = useToken('colors', 'blue.200'); const color = useToken('colors', 'blue.200');
const overlayRef = React.useRef<SVGRectElement>(null); const overlayRef = React.useRef<SVGRectElement>(null);
const chartId = useMemo(() => `chart-${ crypto.randomUUID() }`, []); const chartId = useMemo(() => `chart-${ title.split(' ').join('') }`, [ title ]);
const [ range, setRange ] = React.useState<[ number, number ]>([ 0, Infinity ]); const [ range, setRange ] = React.useState<[ number, number ]>([ 0, Infinity ]);
const { innerWidth, innerHeight } = useChartSize(ref.current, CHART_MARGIN); const { innerWidth, innerHeight } = useChartSize(ref.current, CHART_MARGIN);
...@@ -60,7 +61,7 @@ const ChartWidgetGraph = ({ items, onZoom, isZoomResetInitial, title }: Props) = ...@@ -60,7 +61,7 @@ const ChartWidgetGraph = ({ items, onZoom, isZoomResetInitial, title }: Props) =
<ChartGridLine <ChartGridLine
type="horizontal" type="horizontal"
scale={ yScale } scale={ yScale }
ticks={ 3 } ticks={ isEnlarged ? 6 : 3 }
size={ innerWidth } size={ innerWidth }
disableAnimation disableAnimation
/> />
...@@ -79,27 +80,27 @@ const ChartWidgetGraph = ({ items, onZoom, isZoomResetInitial, title }: Props) = ...@@ -79,27 +80,27 @@ const ChartWidgetGraph = ({ items, onZoom, isZoomResetInitial, title }: Props) =
yScale={ yScale } yScale={ yScale }
stroke={ color } stroke={ color }
animation="none" animation="none"
strokeWidth={ 3 } strokeWidth={ isMobile ? 1 : 2 }
/> />
<ChartAxis <ChartAxis
type="left" type="left"
scale={ yScale } scale={ yScale }
ticks={ 5 } ticks={ isEnlarged ? 6 : 3 }
tickFormat={ yTickFormat } tickFormat={ yTickFormat }
disableAnimation disableAnimation
/> />
<ChartOverlay ref={ overlayRef } width={ innerWidth } height={ innerHeight }> <ChartAxis
<ChartAxis type="bottom"
type="bottom" scale={ xScale }
scale={ xScale } transform={ `translate(0, ${ innerHeight })` }
transform={ `translate(0, ${ innerHeight })` } ticks={ isMobile ? 1 : 4 }
ticks={ isMobile ? 1 : 3 } anchorEl={ overlayRef.current }
anchorEl={ overlayRef.current } disableAnimation
disableAnimation />
/>
<ChartOverlay ref={ overlayRef } width={ innerWidth } height={ innerHeight }>
<ChartTooltip <ChartTooltip
chartId={ chartId } chartId={ chartId }
anchorEl={ overlayRef.current } anchorEl={ overlayRef.current }
......
...@@ -5,7 +5,7 @@ const ChartWidgetSkeleton = () => { ...@@ -5,7 +5,7 @@ const ChartWidgetSkeleton = () => {
return ( return (
<Box <Box
height="235px" height="235px"
paddingY={{ base: 3, md: 4 }} paddingY={{ base: 3, lg: 4 }}
> >
<Skeleton w="75%" h="24px" mb={ 1 }/> <Skeleton w="75%" h="24px" mb={ 1 }/>
<Skeleton w="50%" h="18px" mb={ 5 }/> <Skeleton w="50%" h="18px" mb={ 5 }/>
......
import { Button, Flex, Heading, Modal, ModalBody, ModalCloseButton, ModalContent, ModalHeader, ModalOverlay } from '@chakra-ui/react'; import { Box, Button, Grid, Heading, Icon, Modal, ModalBody, ModalCloseButton, ModalContent, ModalOverlay, Text } from '@chakra-ui/react';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import type { TimeChartItem } from './types'; import type { TimeChartItem } from './types';
import repeatArrow from 'icons/repeat_arrow.svg';
import ChartWidgetGraph from './ChartWidgetGraph'; import ChartWidgetGraph from './ChartWidgetGraph';
type Props = { type Props = {
isOpen: boolean; isOpen: boolean;
title: string; title: string;
description: string;
items: Array<TimeChartItem>; items: Array<TimeChartItem>;
onClose: () => void; onClose: () => void;
} }
...@@ -15,6 +18,7 @@ type Props = { ...@@ -15,6 +18,7 @@ type Props = {
const FullscreenChartModal = ({ const FullscreenChartModal = ({
isOpen, isOpen,
title, title,
description,
items, items,
onClose, onClose,
}: Props) => { }: Props) => {
...@@ -39,44 +43,53 @@ const FullscreenChartModal = ({ ...@@ -39,44 +43,53 @@ const FullscreenChartModal = ({
<ModalContent> <ModalContent>
<ModalHeader> <Box
<Flex mb={ 1 }
alignItems="center" >
<Grid
gridColumnGap={ 2 }
> >
<Heading <Heading
as="h2" mb={ 1 }
gridColumn={ 2 } size={{ base: 'xs', sm: 'md' }}
fontSize={{ base: '2xl', sm: '3xl' }}
fontWeight="medium"
lineHeight={ 1 }
color="blue.600"
> >
{ title } { title }
</Heading> </Heading>
<Text
gridColumn={ 1 }
as="p"
variant="secondary"
fontSize="xs"
>
{ description }
</Text>
{ !isZoomResetInitial && ( { !isZoomResetInitial && (
<Button <Button
ml="auto" leftIcon={ <Icon as={ repeatArrow } w={ 4 } h={ 4 }/> }
colorScheme="blue"
gridColumn={ 2 } gridColumn={ 2 }
justifySelf="end" justifySelf="end"
alignSelf="top" alignSelf="top"
gridRow="1/3" gridRow="1/3"
size="md" size="sm"
variant="outline" variant="outline"
onClick={ handleZoomResetClick } onClick={ handleZoomResetClick }
> >
Reset zoom Reset zoom
</Button> </Button>
) } ) }
</Flex> </Grid>
</ModalHeader> </Box>
<ModalCloseButton/> <ModalCloseButton/>
<ModalBody <ModalBody
h="75%" h="100%"
> >
<ChartWidgetGraph <ChartWidgetGraph
isEnlarged
items={ items } items={ items }
onZoom={ handleZoom } onZoom={ handleZoom }
isZoomResetInitial={ isZoomResetInitial } isZoomResetInitial={ isZoomResetInitial }
......
...@@ -37,7 +37,8 @@ export default function useTimeChartController({ data, width, height }: Props) { ...@@ -37,7 +37,8 @@ export default function useTimeChartController({ data, width, height }: Props) {
); );
const yScale = useMemo(() => { const yScale = useMemo(() => {
const indention = (yMax - yMin) * 0.3; const indention = (yMax - yMin) * 0.15;
return d3.scaleLinear() return d3.scaleLinear()
.domain([ yMin >= 0 && yMin - indention <= 0 ? 0 : yMin - indention, yMax + indention ]) .domain([ yMin >= 0 && yMin - indention <= 0 ? 0 : yMin - indention, yMax + indention ])
.range([ height, 0 ]); .range([ height, 0 ]);
......
...@@ -10,7 +10,8 @@ const NumberWidget = ({ label, value }: Props) => { ...@@ -10,7 +10,8 @@ const NumberWidget = ({ label, value }: Props) => {
return ( return (
<Box <Box
bg={ useColorModeValue('blue.50', 'blue.800') } bg={ useColorModeValue('blue.50', 'blue.800') }
p={ 3 } px={ 3 }
py={{ base: 2, lg: 3 }}
borderRadius={ 12 } borderRadius={ 12 }
> >
<Text <Text
......
...@@ -10,7 +10,7 @@ import useFetch from 'lib/hooks/useFetch'; ...@@ -10,7 +10,7 @@ import useFetch from 'lib/hooks/useFetch';
import NumberWidget from './NumberWidget'; import NumberWidget from './NumberWidget';
import NumberWidgetSkeleton from './NumberWidgetSkeleton'; import NumberWidgetSkeleton from './NumberWidgetSkeleton';
const skeletonsCount = 5; const skeletonsCount = 8;
const NumberWidgetsList = () => { const NumberWidgetsList = () => {
const fetch = useFetch(); const fetch = useFetch();
......
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