Commit 083fd33f authored by tom's avatar tom

home page refactoring: first part

parent 62423eec
...@@ -32,6 +32,8 @@ const RESTRICTED_MODULES = { ...@@ -32,6 +32,8 @@ const RESTRICTED_MODULES = {
'Menu', 'useToast', 'useDisclosure', 'useClipboard', 'Tooltip', 'Skeleton', 'IconButton', 'Button', 'Menu', 'useToast', 'useDisclosure', 'useClipboard', 'Tooltip', 'Skeleton', 'IconButton', 'Button',
'Image', 'Popover', 'PopoverTrigger', 'PopoverContent', 'PopoverBody', 'PopoverFooter', 'Image', 'Popover', 'PopoverTrigger', 'PopoverContent', 'PopoverBody', 'PopoverFooter',
'DrawerRoot', 'DrawerBody', 'DrawerContent', 'DrawerOverlay', 'DrawerBackdrop', 'DrawerTrigger', 'Drawer', 'DrawerRoot', 'DrawerBody', 'DrawerContent', 'DrawerOverlay', 'DrawerBackdrop', 'DrawerTrigger', 'Drawer',
'Alert', 'AlertIcon', 'AlertTitle', 'AlertDescription',
'Heading', 'Badge',
], ],
message: 'Please use corresponding component or hook from ui/shared/chakra component instead', message: 'Please use corresponding component or hook from ui/shared/chakra component instead',
}, },
...@@ -441,4 +443,13 @@ export default tseslint.config( ...@@ -441,4 +443,13 @@ export default tseslint.config(
'no-restricted-properties': 'off', 'no-restricted-properties': 'off',
}, },
}, },
{
files: [
'toolkit/chakra/**',
],
rules: {
// for toolkit components allow to import @chakra-ui/react directly
'no-restricted-imports': 'off',
},
},
); );
...@@ -35,7 +35,7 @@ export const Alert = React.forwardRef<HTMLDivElement, AlertProps>( ...@@ -35,7 +35,7 @@ export const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
{ children ? ( { children ? (
<ChakraAlert.Content> <ChakraAlert.Content>
{ title && <ChakraAlert.Title>{ title }</ChakraAlert.Title> } { title && <ChakraAlert.Title>{ title }</ChakraAlert.Title> }
<ChakraAlert.Description>{ children }</ChakraAlert.Description> <ChakraAlert.Description display="inline-flex">{ children }</ChakraAlert.Description>
</ChakraAlert.Content> </ChakraAlert.Content>
) : ( ) : (
<ChakraAlert.Title flex="1">{ title }</ChakraAlert.Title> <ChakraAlert.Title flex="1">{ title }</ChakraAlert.Title>
......
import type { BadgeProps as ChakraBadgeProps } from '@chakra-ui/react';
import { Badge as ChakraBadge } from '@chakra-ui/react';
import React from 'react';
import { Skeleton } from './skeleton';
export interface BadgeProps extends ChakraBadgeProps {
loading?: boolean;
}
export const Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(
function Badge(props, ref) {
const { loading, ...rest } = props;
return (
<Skeleton loading={ loading }>
<ChakraBadge ref={ ref } { ...rest }/>
</Skeleton>
);
});
/* eslint-disable no-restricted-imports */
import { Drawer as ChakraDrawer, Portal } from '@chakra-ui/react'; import { Drawer as ChakraDrawer, Portal } from '@chakra-ui/react';
import * as React from 'react'; import * as React from 'react';
...@@ -50,7 +49,11 @@ export const DrawerRoot = (props: ChakraDrawer.RootProps) => { ...@@ -50,7 +49,11 @@ export const DrawerRoot = (props: ChakraDrawer.RootProps) => {
return <ChakraDrawer.Root { ...rest } initialFocusEl={ initialFocusEl }/>; return <ChakraDrawer.Root { ...rest } initialFocusEl={ initialFocusEl }/>;
}; };
export const DrawerTrigger = ChakraDrawer.Trigger; export const DrawerTrigger = (props: ChakraDrawer.TriggerProps) => {
const { asChild = true, ...rest } = props;
return <ChakraDrawer.Trigger asChild={ asChild } { ...rest }/>;
};
export const DrawerFooter = ChakraDrawer.Footer; export const DrawerFooter = ChakraDrawer.Footer;
export const DrawerHeader = ChakraDrawer.Header; export const DrawerHeader = ChakraDrawer.Header;
export const DrawerBody = ChakraDrawer.Body; export const DrawerBody = ChakraDrawer.Body;
......
import type { HeadingProps as ChakraHeadingProps } from '@chakra-ui/react';
import { Heading as ChakraHeading } from '@chakra-ui/react';
import React from 'react';
export interface HeadingProps extends ChakraHeadingProps {
level?: '1' | '2' | '3';
}
export const Heading = React.forwardRef<HTMLHeadingElement, HeadingProps>(
function Heading(props, ref) {
const { level, ...rest } = props;
const textStyle = (() => {
if (level === '1') {
return { base: 'heading.md', lg: 'heading.xl' };
}
if (level === '2') {
return { base: 'heading.sm', lg: 'heading.lg' };
}
return { base: 'heading.xs', lg: 'heading.md' };
})();
const as = (() => {
if (level === '1') {
return 'h1';
}
if (level === '2') {
return 'h2';
}
return 'h3';
})();
return <ChakraHeading ref={ ref } color="heading" textStyle={ textStyle } as={ as } { ...rest }/>;
});
import { forwardRef } from 'react'; import React from 'react';
import { Button, type ButtonProps } from './button'; import { Button, type ButtonProps } from './button';
import { Skeleton } from './skeleton';
export interface IconButtonProps extends ButtonProps {} export interface IconButtonProps extends ButtonProps {}
export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>( export const IconButton = React.forwardRef<HTMLDivElement, IconButtonProps>(
function IconButton(props, ref) { function IconButton(props, ref) {
const { loading, ...rest } = props;
return ( return (
<Button <Skeleton loading={ loading } asChild ref={ ref }>
display="inline-flex" <Button
px="0" display="inline-flex"
py="0" px="0"
height="auto" py="0"
minW="auto" height="auto"
flexShrink="0" minW="auto"
ref={ ref } flexShrink="0"
{ ...props } { ...rest }
visual={ props.visual ?? 'plain' } visual={ props.visual ?? 'plain' }
/> />
</Skeleton>
); );
}, },
); );
/* eslint-disable no-restricted-imports */
import { Popover as ChakraPopover, Portal } from '@chakra-ui/react'; import { Popover as ChakraPopover, Portal } from '@chakra-ui/react';
import * as React from 'react'; import * as React from 'react';
...@@ -61,11 +60,14 @@ export const PopoverRoot = (props: ChakraPopover.RootProps) => { ...@@ -61,11 +60,14 @@ export const PopoverRoot = (props: ChakraPopover.RootProps) => {
...props.positioning?.offset, ...props.positioning?.offset,
}, },
}; };
const { lazyMount = true, unmountOnExit = true, ...rest } = props;
return ( return (
<ChakraPopover.Root <ChakraPopover.Root
autoFocus={ false } autoFocus={ false }
{ ...props } lazyMount={ lazyMount }
unmountOnExit={ unmountOnExit }
{ ...rest }
positioning={ positioning } positioning={ positioning }
/> />
); );
...@@ -75,7 +77,7 @@ export const PopoverTrigger = React.forwardRef< ...@@ -75,7 +77,7 @@ export const PopoverTrigger = React.forwardRef<
HTMLButtonElement, HTMLButtonElement,
ChakraPopover.TriggerProps ChakraPopover.TriggerProps
>(function PopoverTrigger(props, ref) { >(function PopoverTrigger(props, ref) {
return <ChakraPopover.Trigger as="div" display="flex" asChild ref={ ref } { ...props }/>; return <ChakraPopover.Trigger asChild ref={ ref } { ...props }/>;
}); });
export const PopoverTitle = ChakraPopover.Title; export const PopoverTitle = ChakraPopover.Title;
......
/* eslint-disable no-restricted-imports */
import { Tooltip as ChakraTooltip, Portal } from '@chakra-ui/react'; import { Tooltip as ChakraTooltip, Portal } from '@chakra-ui/react';
import { useClickAway } from '@uidotdev/usehooks'; import { useClickAway } from '@uidotdev/usehooks';
import * as React from 'react'; import * as React from 'react';
...@@ -24,14 +23,17 @@ export const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>( ...@@ -24,14 +23,17 @@ export const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>(
selected, selected,
children, children,
disabled, disabled,
portalled, portalled = true,
content, content,
contentProps, contentProps,
portalRef, portalRef,
defaultOpen = false,
lazyMount = true,
unmountOnExit = true,
...rest ...rest
} = props; } = props;
const [ open, setOpen ] = React.useState(false); const [ open, setOpen ] = React.useState(defaultOpen);
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const triggerRef = useClickAway<HTMLButtonElement>(() => setOpen(false)); const triggerRef = useClickAway<HTMLButtonElement>(() => setOpen(false));
...@@ -66,12 +68,13 @@ export const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>( ...@@ -66,12 +68,13 @@ export const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>(
onOpenChange={ isMobile ? undefined : handleOpenChange } onOpenChange={ isMobile ? undefined : handleOpenChange }
closeOnClick={ false } closeOnClick={ false }
visual={ visual } visual={ visual }
lazyMount={ lazyMount }
unmountOnExit={ unmountOnExit }
{ ...rest } { ...rest }
positioning={ positioning } positioning={ positioning }
> >
<ChakraTooltip.Trigger <ChakraTooltip.Trigger
ref={ triggerRef } ref={ triggerRef }
as="div"
asChild asChild
onClick={ isMobile ? handleTriggerClick : undefined } onClick={ isMobile ? handleTriggerClick : undefined }
> >
......
...@@ -179,6 +179,7 @@ const semanticTokens: ThemingConfig['semanticTokens'] = { ...@@ -179,6 +179,7 @@ const semanticTokens: ThemingConfig['semanticTokens'] = {
bg: { bg: {
info: { value: { _light: '{colors.blue.100}', _dark: '{colors.blue.900}' } }, info: { value: { _light: '{colors.blue.100}', _dark: '{colors.blue.900}' } },
warning: { value: { _light: '{colors.orange.100}', _dark: '{colors.orange.800/60}' } }, warning: { value: { _light: '{colors.orange.100}', _dark: '{colors.orange.800/60}' } },
warning_table: { value: { _light: '{colors.orange.50}', _dark: '{colors.orange.800/60}' } },
success: { value: { _light: '{colors.green.100}', _dark: '{colors.green.900}' } }, success: { value: { _light: '{colors.green.100}', _dark: '{colors.green.900}' } },
error: { value: { _light: '{colors.red.100}', _dark: '{colors.red.900}' } }, error: { value: { _light: '{colors.red.100}', _dark: '{colors.red.900}' } },
neutral: { value: { _light: '{colors.blackAlpha.50}', _dark: '{colors.whiteAlpha.100}' } }, neutral: { value: { _light: '{colors.blackAlpha.50}', _dark: '{colors.whiteAlpha.100}' } },
...@@ -239,6 +240,43 @@ const semanticTokens: ThemingConfig['semanticTokens'] = { ...@@ -239,6 +240,43 @@ const semanticTokens: ThemingConfig['semanticTokens'] = {
DEFAULT: { value: { _light: '{colors.blackAlpha.200}', _dark: '{colors.whiteAlpha.200}' } }, DEFAULT: { value: { _light: '{colors.blackAlpha.200}', _dark: '{colors.whiteAlpha.200}' } },
}, },
}, },
badge: {
gray: {
bg: { value: { _light: '{colors.blackAlpha.50}', _dark: '{colors.whiteAlpha.100}' } },
fg: { value: { _light: '{colors.blackAlpha.800}', _dark: '{colors.whiteAlpha.800}' } },
},
green: {
bg: { value: { _light: '{colors.green.50}', _dark: '{colors.green.800}' } },
fg: { value: { _light: '{colors.green.500}', _dark: '{colors.green.200}' } },
},
red: {
bg: { value: { _light: '{colors.red.50}', _dark: '{colors.red.800}' } },
fg: { value: { _light: '{colors.red.500}', _dark: '{colors.red.200}' } },
},
purple: {
bg: { value: { _light: '{colors.purple.50}', _dark: '{colors.purple.800}' } },
fg: { value: { _light: '{colors.purple.500}', _dark: '{colors.purple.100}' } },
},
orange: {
bg: { value: { _light: '{colors.orange.50}', _dark: '{colors.orange.800}' } },
fg: { value: { _light: '{colors.orange.500}', _dark: '{colors.orange.100}' } },
},
blue: {
bg: { value: { _light: '{colors.blue.50}', _dark: '{colors.blue.800}' } },
fg: { value: { _light: '{colors.blue.500}', _dark: '{colors.blue.100}' } },
},
yellow: {
bg: { value: { _light: '{colors.yellow.50}', _dark: '{colors.yellow.800}' } },
fg: { value: { _light: '{colors.yellow.500}', _dark: '{colors.yellow.100}' } },
},
teal: {
bg: { value: { _light: '{colors.teal.50}', _dark: '{colors.teal.800}' } },
fg: { value: { _light: '{colors.teal.500}', _dark: '{colors.teal.100}' } },
},
},
heading: {
DEFAULT: { value: { _light: '{colors.blackAlpha.800}', _dark: '{colors.whiteAlpha.800}' } },
},
text: { text: {
primary: { value: { _light: '{colors.blackAlpha.800}', _dark: '{colors.whiteAlpha.800}' } }, primary: { value: { _light: '{colors.blackAlpha.800}', _dark: '{colors.whiteAlpha.800}' } },
secondary: { value: { _light: '{colors.gray.500}', _dark: '{colors.gray.400}' } }, secondary: { value: { _light: '{colors.gray.500}', _dark: '{colors.gray.400}' } },
......
...@@ -16,38 +16,45 @@ export const textStyles: ThemingConfig['textStyles'] = { ...@@ -16,38 +16,45 @@ export const textStyles: ThemingConfig['textStyles'] = {
heading: { heading: {
xl: { xl: {
value: { value: {
fontSize: '40px', fontSize: '32px',
lineHeight: '48px', lineHeight: '40px',
fontWeight: '500', fontWeight: '500',
letterSpacing: '-1px', letterSpacing: '-0.5px',
fontFamily: 'heading', fontFamily: 'heading',
}, },
}, },
lg: { lg: {
value: { value: {
fontSize: '32px', fontSize: '24px',
lineHeight: '40px', lineHeight: '32px',
fontWeight: '500', fontWeight: '500',
letterSpacing: '-0.5px',
fontFamily: 'heading', fontFamily: 'heading',
}, },
}, },
md: { md: {
value: { value: {
fontSize: '24px', fontSize: '18px',
lineHeight: '32px', lineHeight: '24px',
fontWeight: '500', fontWeight: '500',
fontFamily: 'heading', fontFamily: 'heading',
}, },
}, },
sm: { sm: {
value: { value: {
fontSize: '18px', fontSize: '16px',
lineHeight: '24px', lineHeight: '24px',
fontWeight: '500', fontWeight: '500',
fontFamily: 'heading', fontFamily: 'heading',
}, },
}, },
xs: {
value: {
fontSize: '14px',
lineHeight: '20px',
fontWeight: '600',
fontFamily: 'heading',
},
},
}, },
text: { text: {
md: { md: {
......
...@@ -14,6 +14,7 @@ export const zIndex: TokenDefinition['zIndex'] = { ...@@ -14,6 +14,7 @@ export const zIndex: TokenDefinition['zIndex'] = {
modal: { value: 1400 }, modal: { value: 1400 },
popover: { value: 1500 }, popover: { value: 1500 },
tooltip: { value: 1550 }, // otherwise tooltips will not be visible in modals tooltip: { value: 1550 }, // otherwise tooltips will not be visible in modals
tooltip2: { value: 1551 }, // for tooltips in tooltips
skipLink: { value: 1600 }, skipLink: { value: 1600 },
toast: { value: 1700 }, toast: { value: 1700 },
}; };
......
...@@ -42,6 +42,9 @@ export const recipe = defineSlotRecipe({ ...@@ -42,6 +42,9 @@ export const recipe = defineSlotRecipe({
warning: { warning: {
root: { bg: 'alert.bg.warning', color: 'alert.fg' }, root: { bg: 'alert.bg.warning', color: 'alert.fg' },
}, },
warning_table: {
root: { bg: 'alert.bg.warning_table', color: 'alert.fg' },
},
success: { success: {
root: { bg: 'alert.bg.success', color: 'alert.fg' }, root: { bg: 'alert.bg.success', color: 'alert.fg' },
}, },
...@@ -82,7 +85,7 @@ export const recipe = defineSlotRecipe({ ...@@ -82,7 +85,7 @@ export const recipe = defineSlotRecipe({
}, },
indicator: { indicator: {
boxSize: '5', boxSize: '5',
mt: '2px', my: '2px',
}, },
}, },
}, },
......
import { defineRecipe } from '@chakra-ui/react';
export const recipe = defineRecipe({
base: {
display: 'inline-flex',
alignItems: 'center',
borderRadius: 'sm',
gap: '1',
fontWeight: '500',
whiteSpace: 'nowrap',
userSelect: 'none',
},
variants: {
variant: {
subtle: {},
},
colorPalette: {
gray: {
bg: 'badge.gray.bg',
color: 'badge.gray.fg',
},
green: {
bg: 'badge.green.bg',
color: 'badge.green.fg',
},
red: {
bg: 'badge.red.bg',
color: 'badge.red.fg',
},
purple: {
bg: 'badge.purple.bg',
color: 'badge.purple.fg',
},
orange: {
bg: 'badge.orange.bg',
color: 'badge.orange.fg',
},
blue: {
bg: 'badge.blue.bg',
color: 'badge.blue.fg',
},
yellow: {
bg: 'badge.yellow.bg',
color: 'badge.yellow.fg',
},
teal: {
bg: 'badge.teal.bg',
color: 'badge.teal.fg',
},
},
size: {
md: {
textStyle: 'sm',
px: '1',
py: '0.5',
minH: '6',
},
},
},
defaultVariants: {
variant: 'subtle',
colorPalette: 'gray',
size: 'md',
},
});
...@@ -124,7 +124,6 @@ export const recipe = defineSlotRecipe({ ...@@ -124,7 +124,6 @@ export const recipe = defineSlotRecipe({
// anyway it will override the minH from the "full" size variant // anyway it will override the minH from the "full" size variant
// minH: 'auto', // minH: 'auto',
maxH: 'calc(100% - 7.5rem)', maxH: 'calc(100% - 7.5rem)',
borderRadius: 'xl',
}, },
body: { body: {
overflow: 'auto', overflow: 'auto',
......
import { recipe as alert } from './alert.recipe'; import { recipe as alert } from './alert.recipe';
import { recipe as badge } from './badge.recipe';
import { recipe as button } from './button.recipe'; import { recipe as button } from './button.recipe';
import { recipe as closeButton } from './close-button.recipe'; import { recipe as closeButton } from './close-button.recipe';
import { recipe as dialog } from './dialog.recipe'; import { recipe as dialog } from './dialog.recipe';
...@@ -20,6 +21,7 @@ import { recipe as toast } from './toast.recipe'; ...@@ -20,6 +21,7 @@ import { recipe as toast } from './toast.recipe';
import { recipe as tooltip } from './tooltip.recipe'; import { recipe as tooltip } from './tooltip.recipe';
export const recipes = { export const recipes = {
badge,
button, button,
closeButton, closeButton,
input, input,
......
// we use custom heading size for hero banner
// eslint-disable-next-line no-restricted-imports
import { Box, Flex, Heading } from '@chakra-ui/react'; import { Box, Flex, Heading } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
......
...@@ -12,8 +12,8 @@ import type { Transaction } from 'types/api/transaction'; ...@@ -12,8 +12,8 @@ import type { Transaction } from 'types/api/transaction';
import config from 'configs/app'; import config from 'configs/app';
import getValueWithUnit from 'lib/getValueWithUnit'; import getValueWithUnit from 'lib/getValueWithUnit';
import { currencyUnits } from 'lib/units'; import { currencyUnits } from 'lib/units';
import { Skeleton } from 'toolkit/chakra/skeleton';
import AddressFromTo from 'ui/shared/address/AddressFromTo'; import AddressFromTo from 'ui/shared/address/AddressFromTo';
import Skeleton from 'ui/shared/chakra/Skeleton';
import TxEntity from 'ui/shared/entities/tx/TxEntity'; import TxEntity from 'ui/shared/entities/tx/TxEntity';
import TxStatus from 'ui/shared/statusTag/TxStatus'; import TxStatus from 'ui/shared/statusTag/TxStatus';
import TimeAgoWithTooltip from 'ui/shared/TimeAgoWithTooltip'; import TimeAgoWithTooltip from 'ui/shared/TimeAgoWithTooltip';
...@@ -68,9 +68,8 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => { ...@@ -68,9 +68,8 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => {
timestamp={ tx.timestamp } timestamp={ tx.timestamp }
enableIncrement enableIncrement
isLoading={ isLoading } isLoading={ isLoading }
color="text_secondary" color="text.secondary"
fontWeight="400" textStyle="sm"
fontSize="sm"
flexShrink={ 0 } flexShrink={ 0 }
ml={ 2 } ml={ 2 }
/> />
...@@ -83,17 +82,17 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => { ...@@ -83,17 +82,17 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => {
isLoading={ isLoading } isLoading={ isLoading }
mode="compact" mode="compact"
/> />
<Flex flexDir="column"> <Flex flexDir="column" rowGap={ 3 }>
{ !config.UI.views.tx.hiddenFields?.value && ( { !config.UI.views.tx.hiddenFields?.value && (
<Skeleton isLoaded={ !isLoading } my="3px"> <Skeleton loading={ isLoading } textStyle="md">
<Text as="span" whiteSpace="pre">Value </Text> <Text as="span" whiteSpace="pre">Value </Text>
<Text as="span" variant="secondary">{ getValueWithUnit(tx.value).dp(5).toFormat() } { currencyUnits.ether }</Text> <Text as="span" color="text.secondary">{ getValueWithUnit(tx.value).dp(5).toFormat() } { currencyUnits.ether }</Text>
</Skeleton> </Skeleton>
) } ) }
{ !config.UI.views.tx.hiddenFields?.tx_fee && ( { !config.UI.views.tx.hiddenFields?.tx_fee && (
<Skeleton isLoaded={ !isLoading } display="flex" whiteSpace="pre" my="3px"> <Skeleton loading={ isLoading } display="flex" whiteSpace="pre" textStyle="md">
<Text as="span">Fee </Text> <Text as="span">Fee </Text>
<TxFee tx={ tx } accuracy={ 5 } color="text_secondary"/> <TxFee tx={ tx } accuracy={ 5 } color="text.secondary"/>
</Skeleton> </Skeleton>
) } ) }
</Flex> </Flex>
......
...@@ -11,8 +11,8 @@ import type { Transaction } from 'types/api/transaction'; ...@@ -11,8 +11,8 @@ import type { Transaction } from 'types/api/transaction';
import config from 'configs/app'; import config from 'configs/app';
import getValueWithUnit from 'lib/getValueWithUnit'; import getValueWithUnit from 'lib/getValueWithUnit';
import { currencyUnits } from 'lib/units'; import { currencyUnits } from 'lib/units';
import { Skeleton } from 'toolkit/chakra/skeleton';
import AddressFromTo from 'ui/shared/address/AddressFromTo'; import AddressFromTo from 'ui/shared/address/AddressFromTo';
import Skeleton from 'ui/shared/chakra/Skeleton';
import TxEntity from 'ui/shared/entities/tx/TxEntity'; import TxEntity from 'ui/shared/entities/tx/TxEntity';
import TxStatus from 'ui/shared/statusTag/TxStatus'; import TxStatus from 'ui/shared/statusTag/TxStatus';
import TimeAgoWithTooltip from 'ui/shared/TimeAgoWithTooltip'; import TimeAgoWithTooltip from 'ui/shared/TimeAgoWithTooltip';
...@@ -78,15 +78,15 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => { ...@@ -78,15 +78,15 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => {
mb={ 3 } mb={ 3 }
/> />
{ !config.UI.views.tx.hiddenFields?.value && ( { !config.UI.views.tx.hiddenFields?.value && (
<Skeleton isLoaded={ !isLoading } mb={ 2 } fontSize="sm" w="fit-content"> <Skeleton loading={ isLoading } mb={ 2 } fontSize="sm" w="fit-content">
<Text as="span">Value </Text> <Text as="span">Value </Text>
<Text as="span" variant="secondary">{ getValueWithUnit(tx.value).dp(5).toFormat() } { currencyUnits.ether }</Text> <Text as="span" color="text.secondary">{ getValueWithUnit(tx.value).dp(5).toFormat() } { currencyUnits.ether }</Text>
</Skeleton> </Skeleton>
) } ) }
{ !config.UI.views.tx.hiddenFields?.tx_fee && ( { !config.UI.views.tx.hiddenFields?.tx_fee && (
<Skeleton isLoaded={ !isLoading } fontSize="sm" w="fit-content" display="flex" whiteSpace="pre"> <Skeleton loading={ isLoading } fontSize="sm" w="fit-content" display="flex" whiteSpace="pre">
<Text as="span">Fee </Text> <Text as="span">Fee </Text>
<TxFee tx={ tx } accuracy={ 5 } color="text_secondary"/> <TxFee tx={ tx } accuracy={ 5 } color="text.secondary"/>
</Skeleton> </Skeleton>
) } ) }
</Box> </Box>
......
import { Heading } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import config from 'configs/app'; import config from 'configs/app';
import { Heading } from 'toolkit/chakra/heading';
import LatestOptimisticDeposits from 'ui/home/latestDeposits/LatestOptimisticDeposits'; import LatestOptimisticDeposits from 'ui/home/latestDeposits/LatestOptimisticDeposits';
import LatestTxs from 'ui/home/LatestTxs'; import LatestTxs from 'ui/home/LatestTxs';
import LatestWatchlistTxs from 'ui/home/LatestWatchlistTxs'; import LatestWatchlistTxs from 'ui/home/LatestWatchlistTxs';
...@@ -29,7 +29,7 @@ const TransactionsHome = () => { ...@@ -29,7 +29,7 @@ const TransactionsHome = () => {
].filter(Boolean); ].filter(Boolean);
return ( return (
<> <>
<Heading as="h4" size="sm" mb={ 3 }>Transactions</Heading> <Heading level="3" mb={ 3 }>Transactions</Heading>
<TabsWithScroll tabs={ tabs } lazyBehavior="keepMounted" tabListProps={ TAB_LIST_PROPS }/> <TabsWithScroll tabs={ tabs } lazyBehavior="keepMounted" tabListProps={ TAB_LIST_PROPS }/>
</> </>
); );
...@@ -37,7 +37,7 @@ const TransactionsHome = () => { ...@@ -37,7 +37,7 @@ const TransactionsHome = () => {
return ( return (
<> <>
<Heading as="h4" size="sm" mb={ 3 }>Latest transactions</Heading> <Heading level="3" mb={ 3 }>Latest transactions</Heading>
<LatestTxs/> <LatestTxs/>
</> </>
); );
......
...@@ -45,7 +45,7 @@ const ChainIndicatorChart = ({ data }: Props) => { ...@@ -45,7 +45,7 @@ const ChainIndicatorChart = ({ data }: Props) => {
data={ data[0].items } data={ data[0].items }
xScale={ axes.x.scale } xScale={ axes.x.scale }
yScale={ axes.y.scale } yScale={ axes.y.scale }
stroke={ lineColor } stroke={ lineColor[0] }
animation="left" animation="left"
strokeWidth={ 3 } strokeWidth={ 3 }
/> />
......
import { Text, Flex, Box, useColorModeValue } from '@chakra-ui/react'; import { Text, Flex, Box } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query'; import type { UseQueryResult } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
...@@ -6,7 +6,7 @@ import type { HomeStats } from 'types/api/stats'; ...@@ -6,7 +6,7 @@ import type { HomeStats } from 'types/api/stats';
import type { ChainIndicatorId } from 'types/homepage'; import type { ChainIndicatorId } from 'types/homepage';
import type { ResourceError } from 'lib/api/resources'; import type { ResourceError } from 'lib/api/resources';
import Skeleton from 'ui/shared/chakra/Skeleton'; import { Skeleton } from 'toolkit/chakra/skeleton';
interface Props { interface Props {
id: ChainIndicatorId; id: ChainIndicatorId;
...@@ -20,20 +20,17 @@ interface Props { ...@@ -20,20 +20,17 @@ interface Props {
} }
const ChainIndicatorItem = ({ id, title, value, valueDiff, icon, isSelected, onClick, stats }: Props) => { const ChainIndicatorItem = ({ id, title, value, valueDiff, icon, isSelected, onClick, stats }: Props) => {
const activeColor = useColorModeValue('gray.500', 'gray.400');
const activeBgColor = useColorModeValue('white', 'black');
const handleClick = React.useCallback(() => { const handleClick = React.useCallback(() => {
onClick(id); onClick(id);
}, [ id, onClick ]); }, [ id, onClick ]);
const valueContent = (() => { const valueContent = (() => {
if (!stats.data) { if (!stats.data) {
return <Text variant="secondary" fontWeight={ 400 }>no data</Text>; return <Text color="text.secondary" fontWeight={ 400 }>no data</Text>;
} }
return ( return (
<Skeleton isLoaded={ !stats.isPlaceholderData } variant="secondary" fontWeight={ 600 } minW="30px"> <Skeleton loading={ stats.isPlaceholderData } fontWeight={ 600 } minW="30px">
{ value(stats.data) } { value(stats.data) }
</Skeleton> </Skeleton>
); );
...@@ -51,7 +48,7 @@ const ChainIndicatorItem = ({ id, title, value, valueDiff, icon, isSelected, onC ...@@ -51,7 +48,7 @@ const ChainIndicatorItem = ({ id, title, value, valueDiff, icon, isSelected, onC
const diffColor = diff >= 0 ? 'green.500' : 'red.500'; const diffColor = diff >= 0 ? 'green.500' : 'red.500';
return ( return (
<Skeleton isLoaded={ !stats.isPlaceholderData } ml={ 1 } display="flex" alignItems="center" color={ diffColor }> <Skeleton loading={ stats.isPlaceholderData } ml={ 1 } display="flex" alignItems="center" color={ diffColor }>
<span>{ diff >= 0 ? '+' : '-' }</span> <span>{ diff >= 0 ? '+' : '-' }</span>
<Text color={ diffColor } fontWeight={ 600 }>{ Math.abs(diff) }%</Text> <Text color={ diffColor } fontWeight={ 600 }>{ Math.abs(diff) }%</Text>
</Skeleton> </Skeleton>
...@@ -68,14 +65,14 @@ const ChainIndicatorItem = ({ id, title, value, valueDiff, icon, isSelected, onC ...@@ -68,14 +65,14 @@ const ChainIndicatorItem = ({ id, title, value, valueDiff, icon, isSelected, onC
as="li" as="li"
borderRadius="base" borderRadius="base"
cursor="pointer" cursor="pointer"
color={ isSelected ? activeColor : 'link' } color={ isSelected ? { _light: 'gray.500', _dark: 'gray.400' } : 'link' }
bgColor={ isSelected ? activeBgColor : undefined } bgColor={ isSelected ? { _light: 'white', _dark: 'black' } : undefined }
onClick={ handleClick } onClick={ handleClick }
fontSize="xs" fontSize="xs"
fontWeight={ 500 } fontWeight={ 500 }
_hover={{ _hover={{
bgColor: activeBgColor, bgColor: { _light: 'white', _dark: 'black' },
color: isSelected ? activeColor : 'link_hovered', color: isSelected ? { _light: 'gray.500', _dark: 'gray.400' } : 'link.primary.hover',
zIndex: 1, zIndex: 1,
}} }}
> >
......
import { Flex, Text, useColorModeValue } from '@chakra-ui/react'; import { Flex, Text } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import config from 'configs/app'; import config from 'configs/app';
import useApiQuery from 'lib/api/useApiQuery'; import useApiQuery from 'lib/api/useApiQuery';
import { HOMEPAGE_STATS } from 'stubs/stats'; import { HOMEPAGE_STATS } from 'stubs/stats';
import Skeleton from 'ui/shared/chakra/Skeleton'; import { Skeleton } from 'toolkit/chakra/skeleton';
import Hint from 'ui/shared/Hint'; import Hint from 'ui/shared/Hint';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
...@@ -39,8 +39,6 @@ const ChainIndicators = () => { ...@@ -39,8 +39,6 @@ const ChainIndicators = () => {
}, },
}); });
const bgColor = useColorModeValue('gray.50', 'whiteAlpha.100');
if (indicators.length === 0) { if (indicators.length === 0) {
return null; return null;
} }
...@@ -74,7 +72,7 @@ const ChainIndicators = () => { ...@@ -74,7 +72,7 @@ const ChainIndicators = () => {
const diffColor = diff >= 0 ? 'green.500' : 'red.500'; const diffColor = diff >= 0 ? 'green.500' : 'red.500';
return ( return (
<Skeleton isLoaded={ !statsQueryResult.isPlaceholderData } display="flex" alignItems="center" color={ diffColor } ml={ 2 }> <Skeleton loading={ statsQueryResult.isPlaceholderData } display="flex" alignItems="center" color={ diffColor } ml={ 2 }>
<IconSvg name="arrows/up-head" boxSize={ 5 } mr={ 1 } transform={ diff < 0 ? 'rotate(180deg)' : 'rotate(0)' }/> <IconSvg name="arrows/up-head" boxSize={ 5 } mr={ 1 } transform={ diff < 0 ? 'rotate(180deg)' : 'rotate(0)' }/>
<Text color={ diffColor } fontWeight={ 600 }>{ diff }%</Text> <Text color={ diffColor } fontWeight={ 600 }>{ diff }%</Text>
</Skeleton> </Skeleton>
...@@ -86,7 +84,7 @@ const ChainIndicators = () => { ...@@ -86,7 +84,7 @@ const ChainIndicators = () => {
px={{ base: 3, lg: 4 }} px={{ base: 3, lg: 4 }}
py={ 3 } py={ 3 }
borderRadius="base" borderRadius="base"
bgColor={ bgColor } bgColor={{ _light: 'gray.50', _dark: 'whiteAlpha.100' }}
columnGap={{ base: 3, lg: 4 }} columnGap={{ base: 3, lg: 4 }}
rowGap={ 0 } rowGap={ 0 }
flexBasis="50%" flexBasis="50%"
......
/* eslint-disable max-len */ /* eslint-disable max-len */
/* eslint-disable react/jsx-no-bind */ /* eslint-disable react/jsx-no-bind */
import { createListCollection, Heading, HStack, Link, Spinner, Tabs, VStack } from '@chakra-ui/react'; import { createListCollection, HStack, Link, Spinner, Tabs, VStack } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import { Alert } from 'toolkit/chakra/alert'; import { Alert } from 'toolkit/chakra/alert';
import { Badge } from 'toolkit/chakra/badge';
import { Button } from 'toolkit/chakra/button'; import { Button } from 'toolkit/chakra/button';
import { useColorMode } from 'toolkit/chakra/color-mode'; import { useColorMode } from 'toolkit/chakra/color-mode';
import { Field } from 'toolkit/chakra/field'; import { Field } from 'toolkit/chakra/field';
import { Heading } from 'toolkit/chakra/heading';
import { Input } from 'toolkit/chakra/input'; import { Input } from 'toolkit/chakra/input';
import { InputGroup } from 'toolkit/chakra/input-group'; import { InputGroup } from 'toolkit/chakra/input-group';
import { NativeSelectField, NativeSelectRoot } from 'toolkit/chakra/native-select'; import { NativeSelectField, NativeSelectRoot } from 'toolkit/chakra/native-select';
...@@ -224,6 +226,20 @@ const ChakraShowcases = () => { ...@@ -224,6 +226,20 @@ const ChakraShowcases = () => {
</HStack> </HStack>
</section> </section>
<section>
<Heading textStyle="heading.md" mb={ 2 }>Badges</Heading>
<HStack gap={ 4 } whiteSpace="nowrap" flexWrap="wrap">
<Badge colorPalette="gray">Gray</Badge>
<Badge colorPalette="green">Green</Badge>
<Badge colorPalette="red">Red</Badge>
<Badge colorPalette="purple">Purple</Badge>
<Badge colorPalette="orange">Orange</Badge>
<Badge colorPalette="blue">Blue</Badge>
<Badge colorPalette="yellow">Yellow</Badge>
<Badge colorPalette="teal">Teal</Badge>
</HStack>
</section>
<section> <section>
<Heading textStyle="heading.md" mb={ 2 }>Toasts</Heading> <Heading textStyle="heading.md" mb={ 2 }>Toasts</Heading>
<HStack gap={ 4 } whiteSpace="nowrap"> <HStack gap={ 4 } whiteSpace="nowrap">
......
...@@ -31,17 +31,17 @@ const Home = () => { ...@@ -31,17 +31,17 @@ const Home = () => {
return ( return (
<Box as="main"> <Box as="main">
<HeroBanner/> <HeroBanner/>
{ /* <Flex flexDir={{ base: 'column', lg: 'row' }} columnGap={ 2 } rowGap={ 1 } mt={ 3 } _empty={{ mt: 0 }}> <Flex flexDir={{ base: 'column', lg: 'row' }} columnGap={ 2 } rowGap={ 1 } mt={ 3 } _empty={{ mt: 0 }}>
<Stats/> <Stats/>
<ChainIndicators/> <ChainIndicators/>
</Flex> </Flex>
<AdBanner mt={ 6 } mx="auto" display={{ base: 'flex', lg: 'none' }} justifyContent="center"/> <AdBanner mt={ 6 } mx="auto" display={{ base: 'flex', lg: 'none' }} justifyContent="center"/>
<Flex mt={ 8 } direction={{ base: 'column', lg: 'row' }} columnGap={ 12 } rowGap={ 6 }> <Flex mt={ 8 } direction={{ base: 'column', lg: 'row' }} columnGap={ 12 } rowGap={ 6 }>
{ leftWidget } { /* { leftWidget } */ }
<Box flexGrow={ 1 }> <Box flexGrow={ 1 }>
<Transactions/> <Transactions/>
</Box> </Box>
</Flex> */ } </Flex>
</Box> </Box>
); );
}; };
......
import { import { chakra } from '@chakra-ui/react';
useColorModeValue,
chakra,
Button,
} from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import Skeleton from 'ui/shared/chakra/Skeleton'; import { IconButton } from 'toolkit/chakra/icon-button';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
interface Props { interface Props {
isOpen?: boolean; loading?: boolean;
isLoading?: boolean;
className?: string; className?: string;
onClick?: () => void;
} }
const AdditionalInfoButton = ({ isOpen, onClick, className, isLoading }: Props, ref: React.ForwardedRef<HTMLButtonElement>) => { const AdditionalInfoButton = (props: Props, ref: React.ForwardedRef<HTMLButtonElement>) => {
const infoBgColor = useColorModeValue('blue.50', 'gray.600');
if (isLoading) {
return <Skeleton boxSize={ 6 } borderRadius="sm" flexShrink={ 0 }/>;
}
return ( return (
<Button <IconButton
variant="unstyled"
display="inline-flex"
alignItems="center"
className={ className }
ref={ ref } ref={ ref }
background={ isOpen ? infoBgColor : 'unset' } color="icon_info"
borderRadius="8px" _hover={{ color: 'link.primary.hover' }}
w="24px" _open={{
h="24px" bgColor: { _light: 'blue.50', _dark: 'gray.600' },
onClick={ onClick } color: 'link.primary.hover',
cursor="pointer" }}
flexShrink={ 0 } borderRadius="base"
aria-label="Transaction info" aria-label="Transaction info"
boxSize={ 6 }
{ ...props }
> >
<IconSvg <IconSvg name="info" boxSize={ 5 }/>
name="info" </IconButton>
boxSize={ 5 }
color={ isOpen ? 'link_hovered' : 'icon_info' }
_hover={{ color: 'link_hovered' }}
/>
</Button>
); );
}; };
......
...@@ -54,6 +54,9 @@ const CopyToClipboard = ({ text, className, isLoading, onClick, size = 5, type, ...@@ -54,6 +54,9 @@ const CopyToClipboard = ({ text, className, isLoading, onClick, size = 5, type,
return ( return (
<Tooltip <Tooltip
content={ hasCopied ? 'Copied' : `Copy${ type === 'link' ? ' link ' : ' ' }to clipboard` } content={ hasCopied ? 'Copied' : `Copy${ type === 'link' ? ' link ' : ' ' }to clipboard` }
contentProps={{
zIndex: 'tooltip2',
}}
// open={ hasCopied } // open={ hasCopied }
> >
<IconButton <IconButton
......
...@@ -2,10 +2,10 @@ import { chakra } from '@chakra-ui/react'; ...@@ -2,10 +2,10 @@ import { chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import getCurrencyValue from 'lib/getCurrencyValue'; import getCurrencyValue from 'lib/getCurrencyValue';
import Skeleton from 'ui/shared/chakra/Skeleton'; import { Skeleton } from 'toolkit/chakra/skeleton';
interface Props { interface Props {
value: string; value: string | null;
currency?: string; currency?: string;
exchangeRate?: string | null; exchangeRate?: string | null;
className?: string; className?: string;
......
import { Alert, AlertDescription, chakra } from '@chakra-ui/react'; import { chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import { Alert } from 'toolkit/chakra/alert';
const DataFetchAlert = ({ className }: { className?: string }) => { const DataFetchAlert = ({ className }: { className?: string }) => {
return ( return (
<Alert status="warning" width="fit-content" className={ className }> <Alert status="warning" width="fit-content" className={ className }>
<AlertDescription> Something went wrong. Try refreshing the page or come back later.
Something went wrong. Try refreshing the page or come back later.
</AlertDescription>
</Alert> </Alert>
); );
}; };
......
...@@ -37,7 +37,6 @@ const Hint = ({ label, className, tooltipProps, isLoading }: Props) => { ...@@ -37,7 +37,6 @@ const Hint = ({ label, className, tooltipProps, isLoading }: Props) => {
<IconButton <IconButton
aria-label="hint" aria-label="hint"
boxSize={ 5 } boxSize={ 5 }
display="inline-block"
className={ className } className={ className }
// onMouseEnter={ onOpen } // onMouseEnter={ onOpen }
// onMouseLeave={ onClose } // onMouseLeave={ onClose }
......
import { Heading, Flex, Link, chakra } from '@chakra-ui/react'; import { Flex, Link, chakra } from '@chakra-ui/react';
import { debounce } from 'es-toolkit'; import { debounce } from 'es-toolkit';
import React from 'react'; import React from 'react';
import { useDisclosure } from 'toolkit/hooks/useDisclosure';
import { Tooltip } from 'toolkit/chakra/tooltip';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import { Heading } from 'toolkit/chakra/heading';
import { Tooltip } from 'toolkit/chakra/tooltip';
import { useDisclosure } from 'toolkit/hooks/useDisclosure';
import TextAd from 'ui/shared/ad/TextAd'; import TextAd from 'ui/shared/ad/TextAd';
import Skeleton from 'ui/shared/chakra/Skeleton'; import Skeleton from 'ui/shared/chakra/Skeleton';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
...@@ -139,7 +140,7 @@ const PageTitle = ({ title, contentAfter, withTextAd, backLink, className, isLoa ...@@ -139,7 +140,7 @@ const PageTitle = ({ title, contentAfter, withTextAd, backLink, className, isLoa
<Heading <Heading
ref={ headingRef } ref={ headingRef }
as="h1" as="h1"
textStyle="heading.lg" level="1"
whiteSpace="normal" whiteSpace="normal"
wordBreak="break-all" wordBreak="break-all"
style={{ style={{
......
import { Alert, Link, Text, chakra, useTheme, useColorModeValue, Tr, Td } from '@chakra-ui/react'; import { Link, Text, chakra, Table } from '@chakra-ui/react';
import { transparentize } from '@chakra-ui/theme-tools';
import React from 'react'; import React from 'react';
import Skeleton from 'ui/shared/chakra/Skeleton'; import { Alert } from 'toolkit/chakra/alert';
import { Skeleton } from 'toolkit/chakra/skeleton';
interface InjectedProps { interface InjectedProps {
content: React.ReactNode; content: React.ReactNode;
...@@ -19,8 +19,6 @@ interface Props { ...@@ -19,8 +19,6 @@ interface Props {
} }
const SocketNewItemsNotice = chakra(({ children, className, url, num, alert, type = 'transaction', isLoading }: Props) => { const SocketNewItemsNotice = chakra(({ children, className, url, num, alert, type = 'transaction', isLoading }: Props) => {
const theme = useTheme();
const alertContent = (() => { const alertContent = (() => {
if (alert) { if (alert) {
return alert; return alert;
...@@ -55,24 +53,18 @@ const SocketNewItemsNotice = chakra(({ children, className, url, num, alert, typ ...@@ -55,24 +53,18 @@ const SocketNewItemsNotice = chakra(({ children, className, url, num, alert, typ
); );
})(); })();
const color = useColorModeValue('blackAlpha.800', 'whiteAlpha.800');
const bgColor = useColorModeValue('orange.50', transparentize('orange.200', 0.16)(theme));
const content = !isLoading ? ( const content = !isLoading ? (
<Alert <Alert
className={ className } className={ className }
status="warning" visual="warning_table"
px={ 4 } px={ 4 }
py="6px" py="6px"
fontWeight={ 400 }
fontSize="sm" fontSize="sm"
lineHeight={ 5 } startElement={ null }
bgColor={ bgColor }
color={ color }
> >
{ alertContent } { alertContent }
</Alert> </Alert>
) : <Skeleton className={ className } h="33px"/>; ) : <Skeleton className={ className } h="36px" loading/>;
return children ? children({ content }) : content; return children ? children({ content }) : content;
}); });
...@@ -90,7 +82,7 @@ export const Desktop = ({ ...props }: Props) => { ...@@ -90,7 +82,7 @@ export const Desktop = ({ ...props }: Props) => {
my={ props.isLoading ? '6px' : 0 } my={ props.isLoading ? '6px' : 0 }
{ ...props } { ...props }
> >
{ ({ content }) => <Tr><Td colSpan={ 100 } p={ 0 } _first={{ p: 0 }} _last={{ p: 0 }}>{ content }</Td></Tr> } { ({ content }) => <Table.Row><Table.Cell colSpan={ 100 } p={ 0 } _first={{ p: 0 }} _last={{ p: 0 }}>{ content }</Table.Cell></Table.Row> }
</SocketNewItemsNotice> </SocketNewItemsNotice>
); );
}; };
......
import { Tooltip, chakra } from '@chakra-ui/react'; import { chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import Skeleton from 'ui/shared/chakra/Skeleton'; import { Skeleton } from 'toolkit/chakra/skeleton';
import { Tooltip } from 'toolkit/chakra/tooltip';
type Props = { type Props = {
timestamp?: string | number | null; timestamp?: string | number | null;
...@@ -20,11 +21,11 @@ const TimeAgoWithTooltip = ({ timestamp, fallbackText, isLoading, enableIncremen ...@@ -20,11 +21,11 @@ const TimeAgoWithTooltip = ({ timestamp, fallbackText, isLoading, enableIncremen
} }
const content = timestamp ? const content = timestamp ?
<Tooltip label={ dayjs(timestamp).format('llll') }><span>{ timeAgo }</span></Tooltip> : <Tooltip content={ dayjs(timestamp).format('llll') }><span>{ timeAgo }</span></Tooltip> :
<span>{ fallbackText }</span>; <span>{ fallbackText }</span>;
return ( return (
<Skeleton isLoaded={ !isLoading } className={ className }> <Skeleton loading={ isLoading } className={ className }>
{ content } { content }
</Skeleton> </Skeleton>
); );
......
import { Box, Flex, chakra, useColorModeValue } from '@chakra-ui/react'; import { Box, Flex, chakra } from '@chakra-ui/react';
import { clamp } from 'es-toolkit'; import { clamp } from 'es-toolkit';
import React from 'react'; import React from 'react';
import Skeleton from 'ui/shared/chakra/Skeleton'; import { Skeleton } from 'toolkit/chakra/skeleton';
interface Props { interface Props {
className?: string; className?: string;
value: number; value: number;
...@@ -14,17 +15,17 @@ const WIDTH = 50; ...@@ -14,17 +15,17 @@ const WIDTH = 50;
const Utilization = ({ className, value, colorScheme = 'green', isLoading }: Props) => { const Utilization = ({ className, value, colorScheme = 'green', isLoading }: Props) => {
const valueString = (clamp(value * 100 || 0, 0, 100)).toLocaleString(undefined, { maximumFractionDigits: 2 }) + '%'; const valueString = (clamp(value * 100 || 0, 0, 100)).toLocaleString(undefined, { maximumFractionDigits: 2 }) + '%';
const colorGrayScheme = useColorModeValue('gray.500', 'gray.400'); const colorGrayScheme = { _light: 'gray.500', _dark: 'gray.400' };
const color = colorScheme === 'gray' ? colorGrayScheme : 'green.500'; const color = colorScheme === 'gray' ? colorGrayScheme : 'green.500';
return ( return (
<Flex className={ className } alignItems="center" columnGap={ 2 }> <Flex className={ className } alignItems="center" columnGap={ 2 }>
<Skeleton isLoaded={ !isLoading } w={ `${ WIDTH }px` } h="4px" borderRadius="full" overflow="hidden"> <Skeleton loading={ isLoading } w={ `${ WIDTH }px` } h="4px" borderRadius="full" overflow="hidden">
<Box bg={ useColorModeValue('blackAlpha.200', 'whiteAlpha.200') } h="100%"> <Box bg={{ _light: 'blackAlpha.200', _dark: 'whiteAlpha.200' }} h="100%">
<Box bg={ color } w={ valueString } h="100%"/> <Box bg={ color } w={ valueString } h="100%"/>
</Box> </Box>
</Skeleton> </Skeleton>
<Skeleton isLoaded={ !isLoading } color={ color } fontWeight="bold"> <Skeleton loading={ isLoading } color={ color } fontWeight="bold">
<span> <span>
{ valueString } { valueString }
</span> </span>
......
import type { ThemeTypings } from '@chakra-ui/react'; import type { ConditionalValue } from '@chakra-ui/react';
import { Flex, Grid, chakra, useBreakpointValue } from '@chakra-ui/react'; import { Flex, Grid, chakra, useBreakpointValue } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
...@@ -17,7 +17,7 @@ interface Props { ...@@ -17,7 +17,7 @@ interface Props {
from: AddressParam; from: AddressParam;
to: AddressParam | null; to: AddressParam | null;
current?: string; current?: string;
mode?: Mode | Partial<Record<ThemeTypings['breakpoints'], Mode>>; mode?: Mode | ConditionalValue<Mode>;
className?: string; className?: string;
isLoading?: boolean; isLoading?: boolean;
tokenHash?: string; tokenHash?: string;
...@@ -28,9 +28,9 @@ interface Props { ...@@ -28,9 +28,9 @@ interface Props {
const AddressFromTo = ({ from, to, current, mode: modeProp, className, isLoading, tokenHash = '', noIcon }: Props) => { const AddressFromTo = ({ from, to, current, mode: modeProp, className, isLoading, tokenHash = '', noIcon }: Props) => {
const mode = useBreakpointValue( const mode = useBreakpointValue(
{ {
base: (typeof modeProp === 'object' ? modeProp.base : modeProp), base: (typeof modeProp === 'object' && 'base' in modeProp ? modeProp.base : modeProp),
lg: (typeof modeProp === 'object' ? modeProp.lg : modeProp), lg: (typeof modeProp === 'object' && 'lg' in modeProp ? modeProp.lg : modeProp),
xl: (typeof modeProp === 'object' ? modeProp.xl : modeProp), xl: (typeof modeProp === 'object' && 'xl' in modeProp ? modeProp.xl : modeProp),
}, },
) ?? 'long'; ) ?? 'long';
......
import { Tooltip, chakra, useColorModeValue } from '@chakra-ui/react'; import { chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import { Tooltip } from 'toolkit/chakra/tooltip';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
import type { TxCourseType } from './utils'; import type { TxCourseType } from './utils';
...@@ -14,19 +15,19 @@ interface Props { ...@@ -14,19 +15,19 @@ interface Props {
const AddressFromToIcon = ({ isLoading, type, className }: Props) => { const AddressFromToIcon = ({ isLoading, type, className }: Props) => {
const styles = { const styles = {
'in': { 'in': {
color: useColorModeValue('green.500', 'green.200'), color: { _light: 'green.500', _dark: 'green.200' },
bgColor: useColorModeValue('green.50', 'green.800'), bgColor: { _light: 'green.50', _dark: 'green.800' },
}, },
out: { out: {
color: useColorModeValue('yellow.600', 'yellow.500'), color: { _light: 'yellow.600', _dark: 'yellow.500' },
bgColor: useColorModeValue('orange.50', 'yellow.900'), bgColor: { _light: 'orange.50', _dark: 'yellow.900' },
}, },
self: { self: {
color: useColorModeValue('blackAlpha.400', 'whiteAlpha.400'), color: { _light: 'blackAlpha.400', _dark: 'whiteAlpha.400' },
bgColor: useColorModeValue('blackAlpha.50', 'whiteAlpha.50'), bgColor: { _light: 'blackAlpha.50', _dark: 'whiteAlpha.50' },
}, },
unspecified: { unspecified: {
color: useColorModeValue('gray.500', 'gray.300'), color: { _light: 'gray.500', _dark: 'gray.300' },
bgColor: 'transparent', bgColor: 'transparent',
}, },
}; };
...@@ -53,7 +54,7 @@ const AddressFromToIcon = ({ isLoading, type, className }: Props) => { ...@@ -53,7 +54,7 @@ const AddressFromToIcon = ({ isLoading, type, className }: Props) => {
} }
return ( return (
<Tooltip label={ labels[type] }> <Tooltip content={ labels[type] }>
{ icon } { icon }
</Tooltip> </Tooltip>
); );
......
import { useColorModeValue, useToken, useTheme } from '@chakra-ui/react'; import { useToken } from '@chakra-ui/react';
import { transparentize } from '@chakra-ui/theme-tools';
import * as d3 from 'd3'; import * as d3 from 'd3';
import React from 'react'; import React from 'react';
import type { TimeChartItem } from 'ui/shared/chart/types'; import type { TimeChartItem } from 'ui/shared/chart/types';
import { useColorModeValue } from 'toolkit/chakra/color-mode';
interface Props extends React.SVGProps<SVGPathElement> { interface Props extends React.SVGProps<SVGPathElement> {
id?: string; id?: string;
xScale: d3.ScaleTime<number, number> | d3.ScaleLinear<number, number>; xScale: d3.ScaleTime<number, number> | d3.ScaleLinear<number, number>;
...@@ -16,13 +17,12 @@ interface Props extends React.SVGProps<SVGPathElement> { ...@@ -16,13 +17,12 @@ interface Props extends React.SVGProps<SVGPathElement> {
const ChartArea = ({ id, xScale, yScale, color, data, noAnimation, ...props }: Props) => { const ChartArea = ({ id, xScale, yScale, color, data, noAnimation, ...props }: Props) => {
const ref = React.useRef(null); const ref = React.useRef(null);
const theme = useTheme();
const gradientColorId = `${ id || 'gradient' }-${ color }-color`; const gradientColorId = `${ id || 'gradient' }-${ color }-color`;
const gradientStopColor = useToken('colors', useColorModeValue('whiteAlpha.200', 'blackAlpha.100')); const gradientStopColor = useToken('colors', useColorModeValue('whiteAlpha.200', 'blackAlpha.100'));
const defaultGradient = { const defaultGradient = {
startColor: useToken('colors', useColorModeValue('blue.100', 'blue.400')), startColor: useToken('colors', useColorModeValue('blue.100', 'blue.400')),
stopColor: useToken('colors', transparentize(useColorModeValue('blue.100', 'blue.400'), 0)(theme)), stopColor: useToken('colors', useColorModeValue('rgba(190, 227, 248, 0)', 'rgba(66, 153, 225, 0)')), // blue.100 - blue.400 with 0 opacity
}; };
React.useEffect(() => { React.useEffect(() => {
...@@ -60,14 +60,14 @@ const ChartArea = ({ id, xScale, yScale, color, data, noAnimation, ...props }: P ...@@ -60,14 +60,14 @@ const ChartArea = ({ id, xScale, yScale, color, data, noAnimation, ...props }: P
<defs> <defs>
<linearGradient id={ `${ gradientColorId }` } x1="0%" x2="0%" y1="0%" y2="100%"> <linearGradient id={ `${ gradientColorId }` } x1="0%" x2="0%" y1="0%" y2="100%">
<stop offset="0%" stopColor={ color }/> <stop offset="0%" stopColor={ color }/>
<stop offset="100%" stopColor={ gradientStopColor }/> <stop offset="100%" stopColor={ gradientStopColor[0] }/>
</linearGradient> </linearGradient>
</defs> </defs>
) : ( ) : (
<defs> <defs>
<linearGradient id="gradient-chart-area-default" x1="0%" x2="0%" y1="0%" y2="100%"> <linearGradient id="gradient-chart-area-default" x1="0%" x2="0%" y1="0%" y2="100%">
<stop offset="0%" stopColor={ defaultGradient.startColor }/> <stop offset="0%" stopColor={ defaultGradient.startColor[0] }/>
<stop offset="100%" stopColor={ defaultGradient.stopColor }/> <stop offset="100%" stopColor={ defaultGradient.stopColor[0] }/>
</linearGradient> </linearGradient>
</defs> </defs>
) } ) }
......
...@@ -155,8 +155,10 @@ const ChartTooltip = ({ ...@@ -155,8 +155,10 @@ const ChartTooltip = ({
<g <g
ref={ ref } ref={ ref }
opacity={ 0 } opacity={ 0 }
fontSize="12px" style={{
fontWeight="500" fontWeight: '500',
fontSize: '12px',
}}
{ ...props } { ...props }
> >
<ChartTooltipLine/> <ChartTooltipLine/>
......
...@@ -12,7 +12,7 @@ const ChartTooltipBackdrop = () => { ...@@ -12,7 +12,7 @@ const ChartTooltipBackdrop = () => {
className="ChartTooltip__backdrop" className="ChartTooltip__backdrop"
rx={ 12 } rx={ 12 }
ry={ 12 } ry={ 12 }
fill={ bgColor } fill={ bgColor[0] }
/> />
); );
}; };
......
...@@ -4,7 +4,7 @@ import React from 'react'; ...@@ -4,7 +4,7 @@ import React from 'react';
const ChartTooltipLine = () => { const ChartTooltipLine = () => {
const lineColor = useToken('colors', 'gray.400'); const lineColor = useToken('colors', 'gray.400');
return <line className="ChartTooltip__line" stroke={ lineColor } strokeDasharray="3"/>; return <line className="ChartTooltip__line" stroke={ lineColor[0] } strokeDasharray="3"/>;
}; };
export default React.memo(ChartTooltipLine); export default React.memo(ChartTooltipLine);
......
import { useColorModeValue, useToken } from '@chakra-ui/react'; import { useToken } from '@chakra-ui/react';
import * as d3 from 'd3'; import * as d3 from 'd3';
import React from 'react'; import React from 'react';
import type { TimeChartData, TimeChartItem } from 'ui/shared/chart/types'; import type { TimeChartData, TimeChartItem } from 'ui/shared/chart/types';
import { useColorModeValue } from 'toolkit/chakra/color-mode';
import { POINT_SIZE } from './utils'; import { POINT_SIZE } from './utils';
const ChartTooltipPoint = () => { const ChartTooltipPoint = () => {
...@@ -15,8 +17,8 @@ const ChartTooltipPoint = () => { ...@@ -15,8 +17,8 @@ const ChartTooltipPoint = () => {
className="ChartTooltip__point" className="ChartTooltip__point"
r={ POINT_SIZE / 2 } r={ POINT_SIZE / 2 }
opacity={ 1 } opacity={ 1 }
fill={ bgColor } fill={ bgColor[0] }
stroke={ borderColor } stroke={ borderColor[0] }
strokeWidth={ 4 } strokeWidth={ 4 }
/> />
); );
......
...@@ -23,7 +23,7 @@ const ChartTooltipRow = ({ label, lineNum, children }: Props) => { ...@@ -23,7 +23,7 @@ const ChartTooltipRow = ({ label, lineNum, children }: Props) => {
className="ChartTooltip__label" className="ChartTooltip__label"
transform="translate(0,0)" transform="translate(0,0)"
dominantBaseline="hanging" dominantBaseline="hanging"
fill={ labelColor } fill={ labelColor[0] }
> >
{ label } { label }
</text> </text>
...@@ -31,7 +31,7 @@ const ChartTooltipRow = ({ label, lineNum, children }: Props) => { ...@@ -31,7 +31,7 @@ const ChartTooltipRow = ({ label, lineNum, children }: Props) => {
className="ChartTooltip__value" className="ChartTooltip__value"
transform={ `translate(${ LABEL_WIDTH },0)` } transform={ `translate(${ LABEL_WIDTH },0)` }
dominantBaseline="hanging" dominantBaseline="hanging"
fill={ textColor } fill={ textColor[0] }
/> />
</> </>
) } ) }
......
...@@ -17,7 +17,7 @@ const ChartTooltipTitle = ({ resolution = Resolution.DAY }: { resolution?: Resol ...@@ -17,7 +17,7 @@ const ChartTooltipTitle = ({ resolution = Resolution.DAY }: { resolution?: Resol
<text <text
className="ChartTooltip__title" className="ChartTooltip__title"
transform="translate(0,0)" transform="translate(0,0)"
fill={ titleColor } fill={ titleColor[0] }
opacity={ 0 } opacity={ 0 }
dominantBaseline="hanging" dominantBaseline="hanging"
> >
......
...@@ -115,7 +115,7 @@ const Content = chakra((props: ContentProps) => { ...@@ -115,7 +115,7 @@ const Content = chakra((props: ContentProps) => {
return ( return (
<Tooltip content={ label } contentProps={{ maxW: { base: 'calc(100vw - 8px)', lg: '400px' } }}> <Tooltip content={ label } contentProps={{ maxW: { base: 'calc(100vw - 8px)', lg: '400px' } }}>
<Skeleton loading={ props.isLoading } overflow="hidden" textOverflow="ellipsis" whiteSpace="nowrap" as="span"> <Skeleton loading={ props.isLoading } overflow="hidden" textOverflow="ellipsis" whiteSpace="nowrap">
{ nameText } { nameText }
</Skeleton> </Skeleton>
</Tooltip> </Tooltip>
...@@ -160,6 +160,8 @@ const AddressEntry = (props: EntityProps) => { ...@@ -160,6 +160,8 @@ const AddressEntry = (props: EntityProps) => {
const settingsContext = useSettingsContext(); const settingsContext = useSettingsContext();
const altHash = !props.noAltHash && settingsContext?.addressFormat === 'bech32' ? toBech32Address(props.address.hash) : undefined; const altHash = !props.noAltHash && settingsContext?.addressFormat === 'bech32' ? toBech32Address(props.address.hash) : undefined;
const content = <Content { ...partsProps.content } altHash={ altHash }/>;
return ( return (
<Container <Container
// we have to use the global classnames here, see theme/global.ts // we have to use the global classnames here, see theme/global.ts
...@@ -172,9 +174,7 @@ const AddressEntry = (props: EntityProps) => { ...@@ -172,9 +174,7 @@ const AddressEntry = (props: EntityProps) => {
zIndex={ 0 } zIndex={ 0 }
> >
<Icon { ...partsProps.icon }/> <Icon { ...partsProps.icon }/>
<Link { ...partsProps.link }> { props.noLink ? content : (<Link { ...partsProps.link }> { content } </Link>) }
<Content { ...partsProps.content } altHash={ altHash }/>
</Link>
<Copy { ...partsProps.copy } altHash={ altHash }/> <Copy { ...partsProps.copy } altHash={ altHash }/>
</Container> </Container>
); );
......
import { Box, DarkMode, PopoverBody, PopoverContent, PopoverTrigger, Portal, useColorModeValue, Flex, PopoverArrow } from '@chakra-ui/react'; import { Box, Flex } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import Popover from 'ui/shared/chakra/Popover'; import { Tooltip } from 'toolkit/chakra/tooltip';
import * as EntityBase from 'ui/shared/entities/base/components'; import * as EntityBase from 'ui/shared/entities/base/components';
import type { ContentProps } from './AddressEntity'; import type { ContentProps } from './AddressEntity';
import AddressEntity from './AddressEntity'; import AddressEntity from './AddressEntity';
const AddressEntityContentProxy = (props: ContentProps) => { const AddressEntityContentProxy = (props: ContentProps) => {
const bgColor = useColorModeValue('gray.700', 'gray.900');
const implementations = props.address.implementations; const implementations = props.address.implementations;
const handleClick = React.useCallback((event: React.MouseEvent) => {
event.stopPropagation();
}, []);
if (!implementations || implementations.length === 0) { if (!implementations || implementations.length === 0) {
return null; return null;
} }
...@@ -25,51 +19,46 @@ const AddressEntityContentProxy = (props: ContentProps) => { ...@@ -25,51 +19,46 @@ const AddressEntityContentProxy = (props: ContentProps) => {
const implementationName = implementations.length === 1 && implementations[0].name ? implementations[0].name : undefined; const implementationName = implementations.length === 1 && implementations[0].name ? implementations[0].name : undefined;
return ( const content = (
<Popover trigger="hover" isLazy gutter={ 8 }> <>
<PopoverTrigger> <Box fontWeight={ 600 }>
<Box display="inline-flex" w="100%"> Proxy contract
<EntityBase.Content { props.address.name ? ` (${ props.address.name })` : '' }
{ ...props } </Box>
truncation={ nameTag || implementationName || props.address.name ? 'tail' : props.truncation } <AddressEntity address={{ hash: props.address.hash, filecoin: props.address.filecoin }} noLink noIcon noHighlight justifyContent="center"/>
text={ nameTag || implementationName || props.address.name || props.altHash || props.address.hash } <Box fontWeight={ 600 } mt={ 2 }>
Implementation{ implementations.length > 1 ? 's' : '' }
{ implementationName ? ` (${ implementationName })` : '' }
</Box>
<Flex flexWrap="wrap" columnGap={ 3 }>
{ implementations.map((item) => (
<AddressEntity
key={ item.address }
address={{ hash: item.address, filecoin: { robust: item.filecoin_robust_address } }}
noLink
noIcon
noHighlight
minW={ `calc((100% - ${ colNum - 1 } * 12px) / ${ colNum })` }
flex={ 1 }
justifyContent={ colNum === 1 ? 'center' : undefined }
isTooltipDisabled isTooltipDisabled
/> />
</Box> )) }
</PopoverTrigger> </Flex>
<Portal> </>
<DarkMode> );
<PopoverContent bgColor={ bgColor } w="fit-content" borderRadius="sm" maxW={{ base: '100vw', lg: '410px' }} onClick={ handleClick }>
<PopoverArrow bgColor={ bgColor }/> return (
<PopoverBody color="white" p={ 2 } fontSize="sm" lineHeight={ 5 } textAlign="center"> <Tooltip content={ content } interactive contentProps={{ maxW: { base: '100vw', lg: '410px' } }}>
<Box fontWeight={ 600 }> <Box display="inline-flex" w="100%">
Proxy contract <EntityBase.Content
{ props.address.name ? ` (${ props.address.name })` : '' } { ...props }
</Box> truncation={ nameTag || implementationName || props.address.name ? 'tail' : props.truncation }
<AddressEntity address={{ hash: props.address.hash, filecoin: props.address.filecoin }} noLink noIcon noHighlight justifyContent="center"/> text={ nameTag || implementationName || props.address.name || props.altHash || props.address.hash }
<Box fontWeight={ 600 } mt={ 2 }> isTooltipDisabled
Implementation{ implementations.length > 1 ? 's' : '' } />
{ implementationName ? ` (${ implementationName })` : '' } </Box>
</Box> </Tooltip>
<Flex flexWrap="wrap" columnGap={ 3 }>
{ implementations.map((item) => (
<AddressEntity
key={ item.address }
address={{ hash: item.address, filecoin: { robust: item.filecoin_robust_address } }}
noLink
noIcon
noHighlight
minW={ `calc((100% - ${ colNum - 1 } * 12px) / ${ colNum })` }
flex={ 1 }
justifyContent={ colNum === 1 ? 'center' : undefined }
/>
)) }
</Flex>
</PopoverBody>
</PopoverContent>
</DarkMode>
</Portal>
</Popover>
); );
}; };
......
...@@ -64,7 +64,7 @@ const Link = chakra(({ isLoading, children, isExternal, onClick, href, noLink }: ...@@ -64,7 +64,7 @@ const Link = chakra(({ isLoading, children, isExternal, onClick, href, noLink }:
}; };
if (noLink) { if (noLink) {
return <Skeleton loading={ isLoading } { ...styles }>{ children }</Skeleton>; return null;
} }
const Component = isExternal ? LinkExternal : LinkInternal; const Component = isExternal ? LinkExternal : LinkInternal;
...@@ -109,7 +109,7 @@ const Icon = ({ isLoading, noIcon, size, name, color, borderRadius, marginRight, ...@@ -109,7 +109,7 @@ const Icon = ({ isLoading, noIcon, size, name, color, borderRadius, marginRight,
); );
}; };
export interface ContentBaseProps extends Pick<EntityBaseProps, 'className' | 'isLoading' | 'truncation' | 'tailLength'> { export interface ContentBaseProps extends Pick<EntityBaseProps, 'className' | 'isLoading' | 'truncation' | 'tailLength' | 'isTooltipDisabled'> {
asProp?: React.ElementType; asProp?: React.ElementType;
text: string; text: string;
} }
...@@ -157,6 +157,7 @@ const Content = chakra(({ className, isLoading, asProp, text, truncation = 'dyna ...@@ -157,6 +157,7 @@ const Content = chakra(({ className, isLoading, asProp, text, truncation = 'dyna
overflow="hidden" overflow="hidden"
whiteSpace="nowrap" whiteSpace="nowrap"
textOverflow={ truncation === 'tail' ? 'ellipsis' : undefined } textOverflow={ truncation === 'tail' ? 'ellipsis' : undefined }
w="100%"
> >
{ children } { children }
</Skeleton> </Skeleton>
......
import type { As } from '@chakra-ui/react';
import { chakra } from '@chakra-ui/react'; import { chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
...@@ -77,7 +76,7 @@ const TxEntity = (props: EntityProps) => { ...@@ -77,7 +76,7 @@ const TxEntity = (props: EntityProps) => {
); );
}; };
export default React.memo(chakra<As, EntityProps>(TxEntity)); export default React.memo(chakra(TxEntity));
export { export {
Container, Container,
......
import { Box, Flex, Text, useColorModeValue, chakra } from '@chakra-ui/react'; import { Box, Flex, Text, chakra } from '@chakra-ui/react';
import NextLink from 'next/link'; import NextLink from 'next/link';
import React from 'react'; import React from 'react';
import type { Route } from 'nextjs-routes'; import type { Route } from 'nextjs-routes';
import Skeleton from 'ui/shared/chakra/Skeleton'; import { Skeleton } from 'toolkit/chakra/skeleton';
import Hint from 'ui/shared/Hint'; import Hint from 'ui/shared/Hint';
import IconSvg, { type IconName } from 'ui/shared/IconSvg'; import IconSvg, { type IconName } from 'ui/shared/IconSvg';
import TruncatedValue from 'ui/shared/TruncatedValue'; import TruncatedValue from 'ui/shared/TruncatedValue';
...@@ -52,16 +52,12 @@ const StatsWidget = ({ ...@@ -52,16 +52,12 @@ const StatsWidget = ({
period, period,
href, href,
}: Props) => { }: Props) => {
const bgColor = useColorModeValue('gray.50', 'whiteAlpha.100');
const skeletonBgColor = useColorModeValue('blackAlpha.50', 'whiteAlpha.50');
const hintColor = useColorModeValue('gray.600', 'gray.400');
return ( return (
<Container href={ !isLoading ? href : undefined }> <Container href={ !isLoading ? href : undefined }>
<Flex <Flex
className={ className } className={ className }
alignItems="center" alignItems="center"
bgColor={ isLoading ? skeletonBgColor : bgColor } bgColor={ isLoading ? { _light: 'blackAlpha.50', _dark: 'whiteAlpha.50' } : { _light: 'gray.50', _dark: 'whiteAlpha.100' } }
p={ 3 } p={ 3 }
borderRadius="base" borderRadius="base"
justifyContent="space-between" justifyContent="space-between"
...@@ -84,21 +80,19 @@ const StatsWidget = ({ ...@@ -84,21 +80,19 @@ const StatsWidget = ({
) } ) }
<Box w={{ base: '100%', lg: icon ? 'calc(100% - 48px)' : '100%' }}> <Box w={{ base: '100%', lg: icon ? 'calc(100% - 48px)' : '100%' }}>
<Skeleton <Skeleton
isLoaded={ !isLoading } loading={ isLoading }
color="text_secondary" color="text_secondary"
fontSize="xs" textStyle="xs"
lineHeight="16px"
w="fit-content" w="fit-content"
> >
<h2>{ label }</h2> <h2>{ label }</h2>
</Skeleton> </Skeleton>
<Skeleton <Skeleton
isLoaded={ !isLoading } loading={ isLoading }
display="flex" display="flex"
alignItems="baseline" alignItems="baseline"
fontWeight={ 500 } fontWeight={ 500 }
fontSize="lg" textStyle="lg"
lineHeight={ 6 }
> >
{ valuePrefix && <chakra.span whiteSpace="pre">{ valuePrefix }</chakra.span> } { valuePrefix && <chakra.span whiteSpace="pre">{ valuePrefix }</chakra.span> }
{ typeof value === 'string' ? ( { typeof value === 'string' ? (
...@@ -112,15 +106,15 @@ const StatsWidget = ({ ...@@ -112,15 +106,15 @@ const StatsWidget = ({
<Text ml={ 2 } mr={ 1 } color="green.500"> <Text ml={ 2 } mr={ 1 } color="green.500">
+{ diffFormatted || Number(diff).toLocaleString() } +{ diffFormatted || Number(diff).toLocaleString() }
</Text> </Text>
<Text variant="secondary" fontSize="sm">({ diffPeriod })</Text> <Text color="text.secondary" textStyle="sm">({ diffPeriod })</Text>
</> </>
) } ) }
{ period && <Text variant="secondary" fontSize="xs" fontWeight={ 400 } ml={ 1 }>({ period })</Text> } { period && <Text color="text.secondary" textStyle="xs" fontWeight={ 400 } ml={ 1 }>({ period })</Text> }
</Skeleton> </Skeleton>
</Box> </Box>
{ typeof hint === 'string' ? ( { typeof hint === 'string' ? (
<Skeleton isLoaded={ !isLoading } alignSelf="center" borderRadius="base"> <Skeleton loading={ isLoading } alignSelf="center" borderRadius="base">
<Hint label={ hint } boxSize={ 6 } color={ hintColor }/> <Hint label={ hint } boxSize={ 6 } color={{ _light: 'gray.600', _dark: 'gray.400' }}/>
</Skeleton> </Skeleton>
) : hint } ) : hint }
</Flex> </Flex>
......
import { TagLabel, Tooltip, chakra } from '@chakra-ui/react'; import { chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import capitalizeFirstLetter from 'lib/capitalizeFirstLetter'; import capitalizeFirstLetter from 'lib/capitalizeFirstLetter';
import Tag from 'ui/shared/chakra/Tag'; import type { BadgeProps } from 'toolkit/chakra/badge';
import { Badge } from 'toolkit/chakra/badge';
import { Tooltip } from 'toolkit/chakra/tooltip';
import type { IconName } from 'ui/shared/IconSvg'; import type { IconName } from 'ui/shared/IconSvg';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
...@@ -18,31 +20,31 @@ export interface Props { ...@@ -18,31 +20,31 @@ export interface Props {
const StatusTag = ({ type, text, errorText, isLoading, className }: Props) => { const StatusTag = ({ type, text, errorText, isLoading, className }: Props) => {
let icon: IconName; let icon: IconName;
let colorScheme; let colorPalette: BadgeProps['colorPalette'];
const capitalizedText = capitalizeFirstLetter(text); const capitalizedText = capitalizeFirstLetter(text);
switch (type) { switch (type) {
case 'ok': case 'ok':
icon = 'status/success'; icon = 'status/success';
colorScheme = 'green'; colorPalette = 'green';
break; break;
case 'error': case 'error':
icon = 'status/error'; icon = 'status/error';
colorScheme = 'red'; colorPalette = 'red';
break; break;
case 'pending': case 'pending':
icon = 'status/pending'; icon = 'status/pending';
colorScheme = 'gray'; colorPalette = 'gray';
break; break;
} }
return ( return (
<Tooltip label={ errorText }> <Tooltip content={ errorText } disabled={ !errorText }>
<Tag colorScheme={ colorScheme } display="flex" isLoading={ isLoading } className={ className }> <Badge colorPalette={ colorPalette } loading={ isLoading } className={ className }>
<IconSvg boxSize={ 2.5 } name={ icon } mr={ 1 } flexShrink={ 0 }/> <IconSvg boxSize={ 2.5 } name={ icon } mr={ 1 } flexShrink={ 0 }/>
<TagLabel display="block">{ capitalizedText }</TagLabel> <span>{ capitalizedText }</span>
</Tag> </Badge>
</Tooltip> </Tooltip>
); );
}; };
......
...@@ -6,7 +6,7 @@ import type { Transaction } from 'types/api/transaction'; ...@@ -6,7 +6,7 @@ import type { Transaction } from 'types/api/transaction';
import config from 'configs/app'; import config from 'configs/app';
import getCurrencyValue from 'lib/getCurrencyValue'; import getCurrencyValue from 'lib/getCurrencyValue';
import { currencyUnits } from 'lib/units'; import { currencyUnits } from 'lib/units';
import Skeleton from 'ui/shared/chakra/Skeleton'; import { Skeleton } from 'toolkit/chakra/skeleton';
import CurrencyValue from 'ui/shared/CurrencyValue'; import CurrencyValue from 'ui/shared/CurrencyValue';
import TokenEntity from 'ui/shared/entities/token/TokenEntity'; import TokenEntity from 'ui/shared/entities/token/TokenEntity';
...@@ -32,7 +32,7 @@ const TxFee = ({ className, tx, accuracy, accuracyUsd, isLoading, withCurrency = ...@@ -32,7 +32,7 @@ const TxFee = ({ className, tx, accuracy, accuracyUsd, isLoading, withCurrency =
accuracyUsd, accuracyUsd,
}); });
return ( return (
<Skeleton whiteSpace="pre-wrap" wordBreak="break-word" isLoaded={ !isLoading } display="flex" flexWrap="wrap" className={ className }> <Skeleton whiteSpace="pre-wrap" wordBreak="break-word" loading={ isLoading } display="flex" flexWrap="wrap" className={ className }>
<span>{ valueStr } </span> <span>{ valueStr } </span>
<TokenEntity token={ token } noCopy onlySymbol w="auto" ml={ 1 }/> <TokenEntity token={ token } noCopy onlySymbol w="auto" ml={ 1 }/>
{ usd && withUsd && <chakra.span color="text_secondary"> (${ usd })</chakra.span> } { usd && withUsd && <chakra.span color="text_secondary"> (${ usd })</chakra.span> }
...@@ -51,7 +51,7 @@ const TxFee = ({ className, tx, accuracy, accuracyUsd, isLoading, withCurrency = ...@@ -51,7 +51,7 @@ const TxFee = ({ className, tx, accuracy, accuracyUsd, isLoading, withCurrency =
}); });
return ( return (
<Skeleton whiteSpace="pre" isLoaded={ !isLoading } display="flex" className={ className }> <Skeleton whiteSpace="pre" loading={ isLoading } display="flex" className={ className }>
<span>{ valueStr } </span> <span>{ valueStr } </span>
{ valueStr !== '0' && <TokenEntity token={ token } noCopy onlySymbol w="auto" ml={ 1 }/> } { valueStr !== '0' && <TokenEntity token={ token } noCopy onlySymbol w="auto" ml={ 1 }/> }
{ usd && withUsd && <chakra.span color="text_secondary"> (${ usd })</chakra.span> } { usd && withUsd && <chakra.span color="text_secondary"> (${ usd })</chakra.span> }
......
...@@ -3,7 +3,7 @@ import React from 'react'; ...@@ -3,7 +3,7 @@ import React from 'react';
import type { Transaction } from 'types/api/transaction'; import type { Transaction } from 'types/api/transaction';
import Tag from 'ui/shared/chakra/Tag'; import { Badge } from 'toolkit/chakra/badge';
interface Props { interface Props {
tx: Transaction; tx: Transaction;
...@@ -23,16 +23,16 @@ const TxWatchListTags = ({ tx, isLoading }: Props) => { ...@@ -23,16 +23,16 @@ const TxWatchListTags = ({ tx, isLoading }: Props) => {
return ( return (
<Flex columnGap={ 2 } rowGap={ 2 } flexWrap="wrap" overflow="hidden" maxW="100%"> <Flex columnGap={ 2 } rowGap={ 2 } flexWrap="wrap" overflow="hidden" maxW="100%">
{ tags.map((tag) => ( { tags.map((tag) => (
<Tag <Badge
key={ tag.label } key={ tag.label }
isLoading={ isLoading } loading={ isLoading }
isTruncated truncate
// TODO @tom2drum check these styles
// maxW={{ base: '115px', lg: 'initial' }} // maxW={{ base: '115px', lg: 'initial' }}
colorScheme="gray" colorPalette="gray"
variant="subtle"
> >
{ tag.display_name } { tag.display_name }
</Tag> </Badge>
)) } )) }
</Flex> </Flex>
); );
......
...@@ -10,7 +10,7 @@ interface Props { ...@@ -10,7 +10,7 @@ interface Props {
className?: string; className?: string;
} }
const NetworkMenuButton = ({ isActive, onClick, className }: Props, ref: React.ForwardedRef<HTMLButtonElement>) => { const NetworkMenuButton = ({ isActive, onClick, className, ...rest }: Props, ref: React.ForwardedRef<HTMLDivElement>) => {
return ( return (
<IconButton <IconButton
className={ className } className={ className }
...@@ -24,6 +24,7 @@ const NetworkMenuButton = ({ isActive, onClick, className }: Props, ref: React.F ...@@ -24,6 +24,7 @@ const NetworkMenuButton = ({ isActive, onClick, className }: Props, ref: React.F
onClick={ onClick } onClick={ onClick }
aria-label="Network menu" aria-label="Network menu"
aria-roledescription="menu" aria-roledescription="menu"
{ ...rest }
> >
<IconSvg <IconSvg
name="networks" name="networks"
......
import { import { chakra, DialogBody } from '@chakra-ui/react';
chakra,
Modal,
ModalContent,
ModalCloseButton,
PopoverTrigger,
PopoverContent,
PopoverBody,
useDisclosure,
} from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { Transaction } from 'types/api/transaction'; import type { Transaction } from 'types/api/transaction';
import { DialogContent, DialogHeader, DialogRoot, DialogTrigger } from 'toolkit/chakra/dialog';
import { Heading } from 'toolkit/chakra/heading';
import { PopoverBody, PopoverContent, PopoverRoot, PopoverTrigger } from 'toolkit/chakra/popover';
import AdditionalInfoButton from 'ui/shared/AdditionalInfoButton'; import AdditionalInfoButton from 'ui/shared/AdditionalInfoButton';
import Popover from 'ui/shared/chakra/Popover';
import TxAdditionalInfoContainer from './TxAdditionalInfoContainer'; import TxAdditionalInfoContainer from './TxAdditionalInfoContainer';
import TxAdditionalInfoContent from './TxAdditionalInfoContent'; import TxAdditionalInfoContent from './TxAdditionalInfoContent';
...@@ -32,39 +25,39 @@ type Props = ...@@ -32,39 +25,39 @@ type Props =
className?: string; className?: string;
}; };
// TODO @tom2drum fix other popovers
const TxAdditionalInfo = ({ hash, tx, isMobile, isLoading, className }: Props) => { const TxAdditionalInfo = ({ hash, tx, isMobile, isLoading, className }: Props) => {
const { isOpen, onOpen, onClose } = useDisclosure();
const content = hash !== undefined ? <TxAdditionalInfoContainer hash={ hash }/> : <TxAdditionalInfoContent tx={ tx }/>; const content = hash !== undefined ? <TxAdditionalInfoContainer hash={ hash }/> : <TxAdditionalInfoContent tx={ tx }/>;
if (isMobile) { if (isMobile) {
return ( return (
<> <DialogRoot size="full">
<AdditionalInfoButton onClick={ onOpen } isLoading={ isLoading } className={ className }/> <DialogTrigger>
<Modal isOpen={ isOpen } onClose={ onClose } size="full"> <AdditionalInfoButton loading={ isLoading } className={ className }/>
<ModalContent paddingTop={ 4 }> </DialogTrigger>
<ModalCloseButton/> <DialogContent>
<DialogHeader>
Additional info
</DialogHeader>
<DialogBody>
{ content } { content }
</ModalContent> </DialogBody>
</Modal> </DialogContent>
</> </DialogRoot>
); );
} }
return ( return (
<Popover placement="right-start" openDelay={ 300 } isLazy> <PopoverRoot positioning={{ placement: 'right-start' }}>
{ ({ isOpen }) => ( <PopoverTrigger>
<> <AdditionalInfoButton loading={ isLoading } className={ className }/>
<PopoverTrigger> </PopoverTrigger>
<AdditionalInfoButton isOpen={ isOpen } isLoading={ isLoading } className={ className }/> <PopoverContent w="330px">
</PopoverTrigger> <PopoverBody textStyle="sm">
<PopoverContent border="1px solid" borderColor="border.divider"> <Heading level="3" mb={ 6 }>Additional info </Heading>
<PopoverBody fontWeight={ 400 } fontSize="sm"> { content }
{ content } </PopoverBody>
</PopoverBody> </PopoverContent>
</PopoverContent> </PopoverRoot>
</>
) }
</Popover>
); );
}; };
......
import { Box, Divider } from '@chakra-ui/react'; import { Box, Separator } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import useApiQuery from 'lib/api/useApiQuery'; import useApiQuery from 'lib/api/useApiQuery';
import Skeleton from 'ui/shared/chakra/Skeleton'; import { Skeleton } from 'toolkit/chakra/skeleton';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataFetchAlert from 'ui/shared/DataFetchAlert';
import TxAdditionalInfoContent from './TxAdditionalInfoContent'; import TxAdditionalInfoContent from './TxAdditionalInfoContent';
...@@ -22,30 +22,29 @@ const TxAdditionalInfoContainer = ({ hash }: Props) => { ...@@ -22,30 +22,29 @@ const TxAdditionalInfoContainer = ({ hash }: Props) => {
if (isPending) { if (isPending) {
return ( return (
<Box> <Box>
<Skeleton w="130px" h="24px" borderRadius="full" mb={ 6 }/>
<Box> <Box>
<Skeleton w="110px" h="16px" borderRadius="full" mb={ 3 }/> <Skeleton loading w="110px" h="16px" borderRadius="full" mb={ 3 }/>
<Skeleton w="100%" h="16px" borderRadius="full"/> <Skeleton loading w="100%" h="16px" borderRadius="full"/>
</Box> </Box>
<Divider my={ 4 }/> <Separator my={ 4 }/>
<Box> <Box>
<Skeleton w="110px" h="16px" borderRadius="full" mb={ 3 }/> <Skeleton loading w="110px" h="16px" borderRadius="full" mb={ 3 }/>
<Skeleton w="100%" h="16px" borderRadius="full"/> <Skeleton loading w="100%" h="16px" borderRadius="full"/>
</Box> </Box>
<Divider my={ 4 }/> <Separator my={ 4 }/>
<Box> <Box>
<Skeleton w="110px" h="16px" borderRadius="full" mb={ 3 }/> <Skeleton loading w="110px" h="16px" borderRadius="full" mb={ 3 }/>
<Skeleton w="100%" h="16px" borderRadius="full"/> <Skeleton loading w="100%" h="16px" borderRadius="full"/>
</Box> </Box>
<Divider my={ 4 }/> <Separator my={ 4 }/>
<Box> <Box>
<Skeleton w="110px" h="16px" borderRadius="full" mb={ 3 }/> <Skeleton loading w="110px" h="16px" borderRadius="full" mb={ 3 }/>
<Skeleton w="75%" h="16px" borderRadius="full"/> <Skeleton loading w="75%" h="16px" borderRadius="full"/>
<Skeleton w="75%" h="16px" borderRadius="full" mt={ 1 }/> <Skeleton loading w="75%" h="16px" borderRadius="full" mt={ 1 }/>
<Skeleton w="75%" h="16px" borderRadius="full" mt={ 1 }/> <Skeleton loading w="75%" h="16px" borderRadius="full" mt={ 1 }/>
</Box> </Box>
<Divider my={ 4 }/> <Separator my={ 4 }/>
<Skeleton w="80px" h="16px" borderRadius="full"/> <Skeleton loading w="80px" h="16px" borderRadius="full"/>
</Box> </Box>
); );
} }
......
import { Box, Heading, Text, Flex } from '@chakra-ui/react'; import { Box, Text, Flex } from '@chakra-ui/react';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import React from 'react'; import React from 'react';
...@@ -30,7 +30,6 @@ const TxAdditionalInfoContent = ({ tx }: { tx: Transaction }) => { ...@@ -30,7 +30,6 @@ const TxAdditionalInfoContent = ({ tx }: { tx: Transaction }) => {
return ( return (
<> <>
<Heading as="h4" size="sm" mb={ 6 }>Additional info </Heading>
{ tx.blob_versioned_hashes && tx.blob_versioned_hashes.length > 0 && ( { tx.blob_versioned_hashes && tx.blob_versioned_hashes.length > 0 && (
<Box { ...sectionProps } mb={ 4 }> <Box { ...sectionProps } mb={ 4 }>
<Flex alignItems="center" justifyContent="space-between"> <Flex alignItems="center" justifyContent="space-between">
......
...@@ -2,7 +2,8 @@ import React from 'react'; ...@@ -2,7 +2,8 @@ import React from 'react';
import type { TransactionType } from 'types/api/transaction'; import type { TransactionType } from 'types/api/transaction';
import Tag from 'ui/shared/chakra/Tag'; import type { BadgeProps } from 'toolkit/chakra/badge';
import { Badge } from 'toolkit/chakra/badge';
export interface Props { export interface Props {
types: Array<TransactionType>; types: Array<TransactionType>;
...@@ -24,51 +25,51 @@ const TxType = ({ types, isLoading }: Props) => { ...@@ -24,51 +25,51 @@ const TxType = ({ types, isLoading }: Props) => {
const typeToShow = types.sort((t1, t2) => TYPES_ORDER.indexOf(t1) - TYPES_ORDER.indexOf(t2))[0]; const typeToShow = types.sort((t1, t2) => TYPES_ORDER.indexOf(t1) - TYPES_ORDER.indexOf(t2))[0];
let label; let label;
let colorScheme; let colorPalette: BadgeProps['colorPalette'];
switch (typeToShow) { switch (typeToShow) {
case 'contract_call': case 'contract_call':
label = 'Contract call'; label = 'Contract call';
colorScheme = 'blue'; colorPalette = 'blue';
break; break;
case 'blob_transaction': case 'blob_transaction':
label = 'Blob txn'; label = 'Blob txn';
colorScheme = 'yellow'; colorPalette = 'yellow';
break; break;
case 'contract_creation': case 'contract_creation':
label = 'Contract creation'; label = 'Contract creation';
colorScheme = 'blue'; colorPalette = 'blue';
break; break;
case 'token_transfer': case 'token_transfer':
label = 'Token transfer'; label = 'Token transfer';
colorScheme = 'orange'; colorPalette = 'orange';
break; break;
case 'token_creation': case 'token_creation':
label = 'Token creation'; label = 'Token creation';
colorScheme = 'orange'; colorPalette = 'orange';
break; break;
case 'coin_transfer': case 'coin_transfer':
label = 'Coin transfer'; label = 'Coin transfer';
colorScheme = 'orange'; colorPalette = 'orange';
break; break;
case 'rootstock_remasc': case 'rootstock_remasc':
label = 'REMASC'; label = 'REMASC';
colorScheme = 'blue'; colorPalette = 'blue';
break; break;
case 'rootstock_bridge': case 'rootstock_bridge':
label = 'Bridge'; label = 'Bridge';
colorScheme = 'blue'; colorPalette = 'blue';
break; break;
default: default:
label = 'Transaction'; label = 'Transaction';
colorScheme = 'purple'; colorPalette = 'purple';
} }
return ( return (
<Tag colorScheme={ colorScheme } isLoading={ isLoading }> <Badge colorPalette={ colorPalette } loading={ isLoading }>
{ label } { label }
</Tag> </Badge>
); );
}; };
......
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