Commit 34f281d3 authored by tom's avatar tom

remove LinkInternal and LinkExternal components

parent 2b22bfc2
......@@ -26,12 +26,10 @@ const RESTRICTED_MODULES = {
{ name: '@metamask/post-message-stream', message: 'Please lazy-load @metamask/post-message-stream or use useProvider hook instead' },
{ name: 'playwright/TestApp', message: 'Please use render() fixture from test() function of playwright/lib module' },
{ name: 'ui/shared/chakra/Skeleton', message: 'Please use Skeleton component from toolkit/chakra instead' },
{ name: 'ui/shared/links/LinkInternal', message: 'Please use Link component from toolkit/chakra instead' },
{ name: 'ui/shared/links/LinkExternal', message: 'Please use Link component from toolkit/chakra instead' },
{
name: '@chakra-ui/react',
importNames: [
'Menu', 'useToast', 'useDisclosure', 'useClipboard', 'Tooltip', 'Skeleton', 'IconButton', 'Button',
'Menu', 'useToast', 'useDisclosure', 'useClipboard', 'Tooltip', 'Skeleton', 'IconButton', 'Button', 'Link',
'Image', 'Popover', 'PopoverTrigger', 'PopoverContent', 'PopoverBody', 'PopoverFooter',
'DrawerRoot', 'DrawerBody', 'DrawerContent', 'DrawerOverlay', 'DrawerBackdrop', 'DrawerTrigger', 'Drawer',
'Alert', 'AlertIcon', 'AlertTitle', 'AlertDescription',
......
......@@ -77,7 +77,8 @@ export const PopoverTrigger = React.forwardRef<
HTMLButtonElement,
ChakraPopover.TriggerProps
>(function PopoverTrigger(props, ref) {
return <ChakraPopover.Trigger asChild ref={ ref } { ...props }/>;
const { asChild = true, ...rest } = props;
return <ChakraPopover.Trigger asChild={ asChild } ref={ ref } { ...rest }/>;
});
export const PopoverTitle = ChakraPopover.Title;
......
......@@ -112,6 +112,9 @@ const semanticTokens: ThemingConfig['semanticTokens'] = {
selected: { value: { _light: '{colors.blue.50}', _dark: '{colors.gray.800}' } },
},
},
menu: {
DEFAULT: { value: { _light: '{colors.blackAlpha.800}', _dark: '{colors.whiteAlpha.800}' } },
},
},
tooltip: {
DEFAULT: {
......
......@@ -45,6 +45,13 @@ export const recipe = defineRecipe({
bgColor: 'transparent',
},
},
menu: {
color: 'link.menu',
_hover: {
color: 'link.primary.hover',
textDecoration: 'none',
},
},
navigation: {
color: 'link.navigation.fg',
bg: 'link.navigation.bg',
......
......@@ -11,12 +11,12 @@ import { getResourceKey } from 'lib/api/useApiQuery';
import useIsMobile from 'lib/hooks/useIsMobile';
import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage';
import { Link } from 'toolkit/chakra/link';
import BlocksList from 'ui/blocks/BlocksList';
import BlocksTable from 'ui/blocks/BlocksTable';
import ActionBar from 'ui/shared/ActionBar';
import DataListDisplay from 'ui/shared/DataListDisplay';
import IconSvg from 'ui/shared/IconSvg';
import LinkInternal from 'ui/shared/links/LinkInternal';
import Pagination from 'ui/shared/pagination/Pagination';
import type { QueryWithPagesResult } from 'ui/shared/pagination/useQueryWithPages';
import * as SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice';
......@@ -115,10 +115,10 @@ const BlocksContent = ({ type, query, enableSocket = true, top }: Props) => {
const actionBar = isMobile ? (
<ActionBar mt={ -6 }>
<LinkInternal display="inline-flex" alignItems="center" href={ route({ pathname: '/block/countdown' }) }>
<Link href={ route({ pathname: '/block/countdown' }) }>
<IconSvg name="hourglass" boxSize={ 5 } mr={ 2 }/>
<span>Block countdown</span>
</LinkInternal>
</Link>
<Pagination ml="auto" { ...query.pagination }/>
</ActionBar>
) : null;
......
......@@ -12,13 +12,13 @@ import getBlockTotalReward from 'lib/block/getBlockTotalReward';
import { WEI } from 'lib/consts';
import getNetworkValidatorTitle from 'lib/networks/getNetworkValidatorTitle';
import { currencyUnits } from 'lib/units';
import { Link } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton';
import { Tooltip } from 'toolkit/chakra/tooltip';
import BlockGasUsed from 'ui/shared/block/BlockGasUsed';
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import IconSvg from 'ui/shared/IconSvg';
import LinkInternal from 'ui/shared/links/LinkInternal';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import TimeAgoWithTooltip from 'ui/shared/TimeAgoWithTooltip';
import Utilization from 'ui/shared/Utilization/Utilization';
......@@ -86,9 +86,9 @@ const BlocksListItem = ({ data, isLoading, enableTimeIncrement, animation }: Pro
<Text fontWeight={ 500 }>Txn</Text>
{ data.transaction_count > 0 ? (
<Skeleton loading={ isLoading } display="inline-block">
<LinkInternal href={ route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: String(data.height), tab: 'txs' } }) }>
<Link href={ route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: String(data.height), tab: 'txs' } }) }>
{ data.transaction_count }
</LinkInternal>
</Link>
</Skeleton>
) :
<Text color="text.secondary">{ data.transaction_count }</Text>
......
......@@ -8,9 +8,9 @@ import { route } from 'nextjs-routes';
import useApiQuery from 'lib/api/useApiQuery';
import { nbsp } from 'lib/html-entities';
import { HOMEPAGE_STATS } from 'stubs/stats';
import { Link } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton';
import IconSvg from 'ui/shared/IconSvg';
import LinkInternal from 'ui/shared/links/LinkInternal';
import Pagination from 'ui/shared/pagination/Pagination';
interface Props {
......@@ -36,10 +36,10 @@ const BlocksTabSlot = ({ pagination }: Props) => {
</Skeleton>
</Box>
) }
<LinkInternal display="inline-flex" alignItems="center" href={ route({ pathname: '/block/countdown' }) }>
<Link href={ route({ pathname: '/block/countdown' }) }>
<IconSvg name="hourglass" boxSize={ 5 } mr={ 2 }/>
<span>Block countdown</span>
</LinkInternal>
</Link>
<Pagination my={ 1 } { ...pagination }/>
</Flex>
);
......
......@@ -9,6 +9,7 @@ import { route } from 'nextjs-routes';
import config from 'configs/app';
import getBlockTotalReward from 'lib/block/getBlockTotalReward';
import { WEI } from 'lib/consts';
import { Link } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton';
import { TableCell, TableRow } from 'toolkit/chakra/table';
import { Tooltip } from 'toolkit/chakra/tooltip';
......@@ -16,7 +17,6 @@ import BlockGasUsed from 'ui/shared/block/BlockGasUsed';
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import IconSvg from 'ui/shared/IconSvg';
import LinkInternal from 'ui/shared/links/LinkInternal';
import TimeAgoWithTooltip from 'ui/shared/TimeAgoWithTooltip';
import Utilization from 'ui/shared/Utilization/Utilization';
......@@ -46,15 +46,16 @@ const BlocksTableItem = ({ data, isLoading, enableTimeIncrement, animation }: Pr
<IconSvg name="checkered_flag" boxSize={ 5 } p="1px" isLoading={ isLoading } flexShrink={ 0 }/>
</Tooltip>
) }
{ /* TODO @tom2drum fix tooltip */ }
<Tooltip disabled={ data.type !== 'reorg' } content="Chain reorganizations">
<BlockEntity
isLoading={ isLoading }
number={ data.height }
hash={ data.type !== 'block' ? data.hash : undefined }
noIcon
fontWeight={ 600 }
/>
<span>
<BlockEntity
isLoading={ isLoading }
number={ data.height }
hash={ data.type !== 'block' ? data.hash : undefined }
noIcon
fontWeight={ 600 }
/>
</span>
</Tooltip>
</Flex>
<TimeAgoWithTooltip
......@@ -84,12 +85,12 @@ const BlocksTableItem = ({ data, isLoading, enableTimeIncrement, animation }: Pr
<TableCell isNumeric >
{ data.transaction_count > 0 ? (
<Skeleton loading={ isLoading } display="inline-block">
<LinkInternal href={ route({
<Link href={ route({
pathname: '/block/[height_or_hash]',
query: { height_or_hash: String(data.height), tab: 'txs' },
}) }>
{ data.transaction_count }
</LinkInternal>
</Link>
</Skeleton>
) : data.transaction_count }
</TableCell>
......
......@@ -17,8 +17,8 @@ import useSocketMessage from 'lib/socket/useSocketMessage';
import { BLOCK } from 'stubs/block';
import { HOMEPAGE_STATS } from 'stubs/stats';
import { Heading } from 'toolkit/chakra/heading';
import { Link } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton';
import LinkInternal from 'ui/shared/links/LinkInternal';
import LatestBlocksItem from './LatestBlocksItem';
......@@ -95,7 +95,7 @@ const LatestBlocks = () => {
))) }
</VStack>
<Flex justifyContent="center">
<LinkInternal fontSize="sm" href={ route({ pathname: '/blocks' }) }>View all blocks</LinkInternal>
<Link textStyle="sm" href={ route({ pathname: '/blocks' }) }>View all blocks</Link>
</Flex>
</>
);
......
......@@ -8,7 +8,7 @@ import { AddressHighlightProvider } from 'lib/contexts/addressHighlight';
import useIsMobile from 'lib/hooks/useIsMobile';
import useNewTxsSocket from 'lib/hooks/useNewTxsSocket';
import { TX } from 'stubs/tx';
import LinkInternal from 'ui/shared/links/LinkInternal';
import { Link } from 'toolkit/chakra/link';
import SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice';
import LatestTxsItem from './LatestTxsItem';
......@@ -55,7 +55,7 @@ const LatestTransactions = () => {
</Box>
</AddressHighlightProvider>
<Flex justifyContent="center">
<LinkInternal fontSize="sm" href={ txsUrl }>View all transactions</LinkInternal>
<Link textStyle="sm" href={ txsUrl }>View all transactions</Link>
</Flex>
</>
);
......
......@@ -6,7 +6,7 @@ import { route } from 'nextjs-routes';
import useApiQuery from 'lib/api/useApiQuery';
import useIsMobile from 'lib/hooks/useIsMobile';
import { TX } from 'stubs/tx';
import LinkInternal from 'ui/shared/links/LinkInternal';
import { Link } from 'toolkit/chakra/link';
import useRedirectForInvalidAuthToken from 'ui/snippets/auth/useRedirectForInvalidAuthToken';
import LatestTxsItem from './LatestTxsItem';
......@@ -53,7 +53,7 @@ const LatestWatchlistTxs = () => {
))) }
</Box>
<Flex justifyContent="center">
<LinkInternal fontSize="sm" href={ txsUrl }>View all watch list transactions</LinkInternal>
<Link textStyle="sm" href={ txsUrl }>View all watch list transactions</Link>
</Flex>
</>
);
......
......@@ -15,7 +15,7 @@ import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage';
import { ARBITRUM_L2_TXN_BATCHES_ITEM } from 'stubs/arbitrumL2';
import { Heading } from 'toolkit/chakra/heading';
import LinkInternal from 'ui/shared/links/LinkInternal';
import { Link } from 'toolkit/chakra/link';
import LatestBatchItem from './LatestBatchItem';
......@@ -82,7 +82,7 @@ const LatestArbitrumL2Batches = () => {
))) }
</VStack>
<Flex justifyContent="center">
<LinkInternal fontSize="sm" href={ route({ pathname: '/batches' }) }>View all batches</LinkInternal>
<Link textStyle="sm" href={ route({ pathname: '/batches' }) }>View all batches</Link>
</Flex>
</>
);
......
......@@ -3,9 +3,9 @@ import React from 'react';
import { route } from 'nextjs-routes';
import { Link } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton';
import BatchEntityL2 from 'ui/shared/entities/block/BatchEntityL2';
import LinkInternal from 'ui/shared/links/LinkInternal';
import TimeAgoWithTooltip from 'ui/shared/TimeAgoWithTooltip';
type Props = {
......@@ -49,14 +49,12 @@ const LatestBatchItem = ({ number, timestamp, txCount, status, isLoading, animat
<Flex alignItems="center" justifyContent="space-between" w="100%" flexWrap="wrap">
<Flex alignItems="center">
<Skeleton loading={ isLoading } mr={ 2 }>Txn</Skeleton>
<LinkInternal
<Link
href={ route({ pathname: '/batches/[number]', query: { number: number.toString(), tab: 'txs' } }) }
isLoading={ isLoading }
loading={ isLoading }
>
<Skeleton loading={ isLoading }>
{ txCount }
</Skeleton>
</LinkInternal>
{ txCount }
</Link>
</Flex>
{ status }
</Flex>
......
......@@ -14,7 +14,7 @@ import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage';
import { ZKEVM_L2_TXN_BATCHES_ITEM } from 'stubs/zkEvmL2';
import { Heading } from 'toolkit/chakra/heading';
import LinkInternal from 'ui/shared/links/LinkInternal';
import { Link } from 'toolkit/chakra/link';
import ZkEvmL2TxnBatchStatus from 'ui/shared/statusTag/ZkEvmL2TxnBatchStatus';
import LatestBatchItem from './LatestBatchItem';
......@@ -86,7 +86,7 @@ const LatestZkEvmL2Batches = () => {
})) }
</VStack>
<Flex justifyContent="center">
<LinkInternal fontSize="sm" href={ route({ pathname: '/batches' }) }>View all batches</LinkInternal>
<Link textStyle="sm" href={ route({ pathname: '/batches' }) }>View all batches</Link>
</Flex>
</>
);
......
......@@ -9,11 +9,11 @@ import React from 'react';
import { route } from 'nextjs-routes';
import useIsMobile from 'lib/hooks/useIsMobile';
import { Link } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton';
import BlockEntityL1 from 'ui/shared/entities/block/BlockEntityL1';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import TxEntityL1 from 'ui/shared/entities/tx/TxEntityL1';
import LinkInternal from 'ui/shared/links/LinkInternal';
import SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice';
import TimeAgoWithTooltip from 'ui/shared/TimeAgoWithTooltip';
......@@ -165,7 +165,7 @@ const LatestDeposits = ({ isLoading, items, socketAlert, socketItemsNum }: Props
))) }
</Box>
<Flex justifyContent="center">
<LinkInternal textStyle="sm" href={ depositsUrl }>View all deposits</LinkInternal>
<Link textStyle="sm" href={ depositsUrl }>View all deposits</Link>
</Flex>
</>
);
......
/* eslint-disable max-len */
/* eslint-disable react/jsx-no-bind */
import { createListCollection, HStack, Link, Spinner, VStack } from '@chakra-ui/react';
import { createListCollection, HStack, Spinner, VStack } from '@chakra-ui/react';
import React from 'react';
import { Button } from 'toolkit/chakra/button';
......@@ -153,17 +153,6 @@ const ChakraShowcases = () => {
</HStack>
</section>
<section>
<Heading textStyle="heading.md" mb={ 2 }>Links</Heading>
<HStack gap={ 4 } flexWrap="wrap">
<Link>Primary</Link>
<Link visual="secondary">Secondary</Link>
<Link visual="subtle">Subtle</Link>
<Link visual="navigation">Navigation</Link>
<Link visual="navigation" data-selected p={ 3 } borderRadius="base">Navigation selected</Link>
</HStack>
</section>
<section>
<Heading textStyle="heading.md" mb={ 2 }>Tooltips</Heading>
<HStack gap={ 4 }>
......
......@@ -9,7 +9,6 @@ import type { ButtonProps } from 'toolkit/chakra/button';
import { Button } from 'toolkit/chakra/button';
import { Tooltip } from 'toolkit/chakra/tooltip';
import IconSvg from 'ui/shared/IconSvg';
import LinkInternal from 'ui/shared/links/LinkInternal';
type Props = {
size?: ButtonProps['size'];
......@@ -35,7 +34,7 @@ const RewardsButton = ({ variant = 'header', size }: Props) => {
variant={ variant }
selected={ !isLoading && Boolean(apiToken) }
flexShrink={ 0 }
as={ apiToken ? LinkInternal : 'button' }
as={ apiToken ? 'a' : 'button' }
{ ...(apiToken ? { href: route({ pathname: '/account/rewards' }) } : {}) }
onClick={ apiToken ? undefined : openLoginModal }
onFocus={ handleFocus }
......
......@@ -12,9 +12,9 @@ import { Button } from 'toolkit/chakra/button';
import { Field } from 'toolkit/chakra/field';
import { Image } from 'toolkit/chakra/image';
import { Input } from 'toolkit/chakra/input';
import { Link } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton';
import { Switch } from 'toolkit/chakra/switch';
import LinkExternal from 'ui/shared/links/LinkExternal';
import useProfileQuery from 'ui/snippets/auth/useProfileQuery';
type Props = {
......@@ -111,9 +111,9 @@ const LoginStepContent = ({ goNext, closeModal, openAuthModal }: Props) => {
/>
<Box mb={ 6 }>
Merits are awarded for a variety of different Blockscout activities. Connect a wallet to get started.
<LinkExternal href="https://docs.blockscout.com/using-blockscout/merits" ml={ 1 } fontWeight="500">
<Link external href="https://docs.blockscout.com/using-blockscout/merits" ml={ 1 } fontWeight="500">
More about Blockscout Merits
</LinkExternal>
</Link>
</Box>
{ isSignUp && isLoggedIntoAccountWithWallet && (
<Box mb={ 6 }>
......
import { Flex, Link, chakra } from '@chakra-ui/react';
import { Flex, chakra } from '@chakra-ui/react';
import { debounce } from 'es-toolkit';
import React from 'react';
import useIsMobile from 'lib/hooks/useIsMobile';
import { Heading } from 'toolkit/chakra/heading';
import { Link } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton';
import { Tooltip } from 'toolkit/chakra/tooltip';
import { useDisclosure } from 'toolkit/hooks/useDisclosure';
import TextAd from 'ui/shared/ad/TextAd';
import IconSvg from 'ui/shared/IconSvg';
import LinkInternal from 'ui/shared/links/LinkInternal';
type BackLinkProp = { label: string; url: string } | { label: string; onClick: () => void };
......@@ -49,19 +49,9 @@ const BackLink = (props: BackLinkProp & { isLoading?: boolean }) => {
const icon = <IconSvg name="arrows/east" boxSize={ 6 } transform="rotate(180deg)" margin="auto" color="gray.400" flexShrink={ 0 }/>;
if ('url' in props) {
return (
<Tooltip content={ props.label }>
<LinkInternal display="inline-flex" href={ props.url } h="40px" mr={ 3 }>
{ icon }
</LinkInternal>
</Tooltip>
);
}
return (
<Tooltip content={ props.label }>
<Link display="inline-flex" onClick={ props.onClick } h="40px" mr={ 3 }>
<Link display="inline-flex" href={ 'url' in props ? props.url : undefined } onClick={ 'onClick' in props ? props.onClick : undefined } h="40px" mr={ 3 }>
{ icon }
</Link>
</Tooltip>
......
......@@ -2,6 +2,7 @@ import { chakra, Flex } from '@chakra-ui/react';
import type { IconProps } from '@chakra-ui/react';
import React from 'react';
import { Link as LinkToolkit } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton';
import type { Props as CopyToClipboardProps } from 'ui/shared/CopyToClipboard';
import CopyToClipboard from 'ui/shared/CopyToClipboard';
......@@ -9,8 +10,6 @@ import HashStringShorten from 'ui/shared/HashStringShorten';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import type { IconName } from 'ui/shared/IconSvg';
import IconSvg from 'ui/shared/IconSvg';
import LinkExternal from 'ui/shared/links/LinkExternal';
import LinkInternal from 'ui/shared/links/LinkInternal';
import { getIconProps, type IconSize } from './utils';
......@@ -40,10 +39,9 @@ export interface ContainerBaseProps extends Pick<EntityBaseProps, 'className'> {
onMouseLeave?: (event: React.MouseEvent) => void;
}
const Container = chakra(React.forwardRef(({ className, children, ...props }: ContainerBaseProps, ref: React.Ref<HTMLDivElement>) => {
const Container = chakra(({ className, children, ...props }: ContainerBaseProps) => {
return (
<Flex
ref={ ref }
className={ className }
alignItems="center"
minWidth={ 0 } // for content truncation - https://css-tricks.com/flexbox-truncated-text/
......@@ -52,7 +50,7 @@ const Container = chakra(React.forwardRef(({ className, children, ...props }: Co
{ children }
</Flex>
);
}));
});
export interface LinkBaseProps extends Pick<EntityBaseProps, 'className' | 'onClick' | 'isLoading' | 'isExternal' | 'href' | 'noLink' | 'query'> {
children: React.ReactNode;
......@@ -69,17 +67,16 @@ const Link = chakra(({ isLoading, children, isExternal, onClick, href, noLink }:
return null;
}
const Component = isExternal ? LinkExternal : LinkInternal;
return (
<Component
<LinkToolkit
{ ...styles }
href={ href }
isLoading={ isLoading }
loading={ isLoading }
external={ isExternal }
onClick={ onClick }
>
{ children }
</Component>
</LinkToolkit>
);
});
......
......@@ -51,20 +51,20 @@ export interface EntityProps extends EntityBase.EntityBaseProps {
hash?: string;
}
const BlockEntity = (props: EntityProps, ref: React.Ref<HTMLDivElement>) => {
const BlockEntity = (props: EntityProps) => {
const partsProps = distributeEntityProps(props);
const content = <Content { ...partsProps.content }/>;
return (
<Container { ...partsProps.container } ref={ ref }>
<Container { ...partsProps.container }>
<Icon { ...partsProps.icon }/>
{ props.noLink ? content : <Link { ...partsProps.link }>{ content }</Link> }
</Container>
);
};
export default React.memo(chakra(React.forwardRef(BlockEntity)));
export default React.memo(chakra(BlockEntity));
export {
Container,
......
......@@ -12,9 +12,9 @@ import { route } from 'nextjs-routes';
import config from 'configs/app';
import dayjs from 'lib/date/dayjs';
import { Link } from 'toolkit/chakra/link';
import type { TooltipProps } from 'toolkit/chakra/tooltip';
import { Tooltip } from 'toolkit/chakra/tooltip';
import LinkInternal from 'ui/shared/links/LinkInternal';
import GasInfoTooltipRow from './GasInfoTooltipRow';
import GasInfoUpdateTimer from './GasInfoUpdateTimer';
......@@ -57,9 +57,9 @@ const GasInfoTooltip = ({ children, data, dataUpdatedAt, isOpen, placement }: Pr
<GasInfoTooltipRow name="Normal" info={ data.gas_prices.average }/>
<GasInfoTooltipRow name="Slow" info={ data.gas_prices.slow }/>
</Grid>
<LinkInternal href={ route({ pathname: '/gas-tracker' }) } className="dark">
<Link href={ route({ pathname: '/gas-tracker' }) } className="dark">
Gas tracker overview
</LinkInternal>
</Link>
</Flex>
);
......
import type { LinkProps } from '@chakra-ui/react';
import { Link, chakra, Box } from '@chakra-ui/react';
import React from 'react';
import { Skeleton } from 'toolkit/chakra/skeleton';
import IconSvg from 'ui/shared/IconSvg';
import type { Variants } from './useLinkStyles';
import { useLinkStyles } from './useLinkStyles';
interface Props {
href: string | undefined;
className?: string;
children: React.ReactNode;
isLoading?: boolean;
variant?: Variants;
iconColor?: LinkProps['color'];
onClick?: LinkProps['onClick'];
}
const LinkExternal = ({ href, children, className, isLoading, variant, iconColor, onClick }: Props) => {
const commonProps = {
display: 'inline-block',
alignItems: 'center',
};
const styleProps = useLinkStyles(commonProps, variant);
if (isLoading) {
if (variant === 'subtle') {
return (
<Skeleton className={ className } { ...styleProps } bgColor="inherit">
{ children }
<Box boxSize={ 3 } display="inline-block"/>
</Skeleton>
);
}
return (
<Box className={ className } { ...styleProps }>
{ children }
<Skeleton boxSize={ 3 } verticalAlign="middle" display="inline-block"/>
</Box>
);
}
return (
<Link className={ className } { ...styleProps } target="_blank" href={ href } onClick={ onClick } variant={ variant }>
{ children }
<IconSvg name="link_external" boxSize={ 3 } verticalAlign="middle" color={ iconColor ?? 'icon_link_external' } flexShrink={ 0 }/>
</Link>
);
};
export default React.memo(chakra(LinkExternal));
import type { LinkProps, FlexProps } from '@chakra-ui/react';
import { Flex, Link } from '@chakra-ui/react';
import type { LinkProps as NextLinkProps } from 'next/link';
import NextLink from 'next/link';
import type { LegacyRef } from 'react';
import React from 'react';
import type { Variants } from './useLinkStyles';
import { useLinkStyles } from './useLinkStyles';
type Props = LinkProps & {
variant?: Variants;
isLoading?: boolean;
scroll?: boolean;
};
const LinkInternal = ({ isLoading, variant, scroll = true, ...props }: Props, ref: LegacyRef<HTMLAnchorElement>) => {
const styleProps = useLinkStyles({}, variant);
if (isLoading) {
return <Flex alignItems="center" { ...props as FlexProps } { ...styleProps }>{ props.children }</Flex>;
}
if (!props.href) {
return <Link { ...props } ref={ ref } { ...styleProps }/>;
}
return (
<NextLink href={ props.href as NextLinkProps['href'] } passHref target={ props.target } legacyBehavior scroll={ scroll }>
<Link { ...props } ref={ ref } { ...styleProps }/>
</NextLink>
);
};
export default React.memo(React.forwardRef(LinkInternal));
import type { ChakraProps } from '@chakra-ui/react';
import { useColorModeValue } from 'toolkit/chakra/color-mode';
export type Variants = 'subtle';
// TODO @tom2drum remove this
export function useLinkStyles(commonProps: ChakraProps, variant?: Variants) {
const subtleLinkBg = useColorModeValue('gray.100', 'gray.700');
switch (variant) {
case 'subtle': {
return {
...commonProps,
px: '10px',
py: '6px',
bgColor: subtleLinkBg,
borderRadius: 'base',
};
}
default:{
return commonProps;
}
}
}
......@@ -67,9 +67,16 @@ const LinksShowcase = () => {
<Link href="/" variant="underlaid" external>Default</Link>
<Link href="/" variant="underlaid" external data-hover>Hover</Link>
</Sample>
<Sample label="variant: menu">
<Link href="/" variant="menu">Default</Link>
<Link href="/" variant="menu" data-hover>Hover</Link>
</Sample>
</SamplesStack>
</Section>
{ /* TODO @tom2drum links with icons */ }
<span>??? links with icons</span>
<Section>
<SectionHeader>Loading</SectionHeader>
<SamplesStack>
......
......@@ -6,8 +6,7 @@ import type { NavItem } from 'types/client/navigation';
import { route } from 'nextjs-routes';
import { isInternalItem } from 'lib/hooks/useNavItems';
import LinkExternal from 'ui/shared/links/LinkExternal';
import LinkInternal from 'ui/shared/links/LinkInternal';
import { Link } from 'toolkit/chakra/link';
import LightningLabel from '../LightningLabel';
import NavLinkIcon from '../NavLinkIcon';
......@@ -23,8 +22,6 @@ const NavLink = ({ className, item, noIcon }: Props) => {
const isInternalLink = isInternalItem(item);
const isActive = 'isActive' in item && item.isActive;
const Link = isInternalLink ? LinkInternal : LinkExternal;
const href = isInternalLink ? route(item.nextRoute) : item.url;
const isHighlighted = checkRouteHighlight(item);
......@@ -34,7 +31,8 @@ const NavLink = ({ className, item, noIcon }: Props) => {
>
<Link
className={ className }
href={ href }
href={ isInternalLink ? route(item.nextRoute) : item.url }
external={ !isInternalLink }
display="flex"
alignItems="center"
variant="navigation"
......
import { HStack, chakra, Separator, Link } from '@chakra-ui/react';
import { HStack, chakra, Separator } from '@chakra-ui/react';
import React from 'react';
import type { NavGroupItem } from 'types/client/navigation';
import { Link } from 'toolkit/chakra/link';
import { Tooltip } from 'toolkit/chakra/tooltip';
import { useDisclosure } from 'toolkit/hooks/useDisclosure';
import IconSvg from 'ui/shared/IconSvg';
......
......@@ -9,7 +9,7 @@ type Props = {
export default function useNavLinkStyleProps({ isExpanded, isCollapsed, isActive }: Props) {
return {
itemProps: {
visual: 'navigation' as const,
variant: 'navigation' as const,
py: '9px',
display: 'flex',
...(isActive ? { 'data-selected': true } : {}),
......
import { Link, HStack, Box, useBreakpointValue, chakra } from '@chakra-ui/react';
import NextLink from 'next/link';
import { HStack, Box, useBreakpointValue, chakra } from '@chakra-ui/react';
import React from 'react';
import type { NavItem } from 'types/client/navigation';
......@@ -8,6 +7,7 @@ import { route } from 'nextjs-routes';
import useIsMobile from 'lib/hooks/useIsMobile';
import { isInternalItem } from 'lib/hooks/useNavItems';
import { Link } from 'toolkit/chakra/link';
import { Tooltip } from 'toolkit/chakra/tooltip';
import IconSvg from 'ui/shared/IconSvg';
......@@ -27,7 +27,6 @@ const NavLink = ({ item, onClick, isCollapsed, isDisabled }: Props) => {
const isMobile = useIsMobile();
const isInternalLink = isInternalItem(item);
const href = isInternalLink ? route(item.nextRoute) : item.url;
const isExpanded = isCollapsed === false;
......@@ -36,63 +35,55 @@ const NavLink = ({ item, onClick, isCollapsed, isDisabled }: Props) => {
const isHighlighted = checkRouteHighlight(item);
const content = (
<Link
href={ href }
target={ isInternalLink ? '_self' : '_blank' }
{ ...styleProps.itemProps }
w={{ base: '100%', lg: isExpanded ? '100%' : '60px', xl: isCollapsed ? '60px' : '100%' }}
display="flex"
position="relative"
px={{ base: 2, lg: isExpanded ? 2 : '15px', xl: isCollapsed ? '15px' : 2 }}
aria-label={ `${ item.text } link` }
whiteSpace="nowrap"
onClick={ onClick }
_hover={{
[`& *:not(.${ LIGHTNING_LABEL_CLASS_NAME }, .${ LIGHTNING_LABEL_CLASS_NAME } *)`]: {
color: isDisabled ? 'inherit' : 'link.primary.hover',
},
}}
>
<Tooltip
content={ item.text }
showArrow={ false }
disabled={ isMobile || isCollapsed === false || (isCollapsed === undefined && isXLScreen) }
positioning={{ placement: 'right', offset: { crossAxis: 0, mainAxis: 20 } }}
visual="navigation"
contentProps={{
color: isInternalLink && item.isActive ? 'link.navigation.fg.selected' : 'link.navigation.fg.hover',
}}
interactive
>
<HStack gap={ 0 } overflow="hidden">
<NavLinkIcon item={ item }/>
<chakra.span
{ ...styleProps.textProps }
ml={ 3 }
display={{ base: 'inline', lg: isExpanded ? 'inline' : 'none', xl: isCollapsed ? 'none' : 'inline' }}
>
<span>{ item.text }</span>
{ !isInternalLink && <IconSvg name="link_external" boxSize={ 3 } color="icon_link_external" verticalAlign="middle"/> }
</chakra.span>
{ isHighlighted && (
<LightningLabel
iconColor={ isInternalLink && item.isActive ? 'link.navigation.bg.selected' : 'link.navigation.bg' }
isCollapsed={ isCollapsed }
/>
) }
</HStack>
</Tooltip>
</Link>
);
return (
<Box as="li" listStyleType="none" w="100%">
{ isInternalLink ? (
<NextLink href={ item.nextRoute } passHref legacyBehavior>
{ content }
</NextLink>
) : content }
<Link
href={ isInternalLink ? route(item.nextRoute) : item.url }
external={ !isInternalLink }
{ ...styleProps.itemProps }
w={{ base: '100%', lg: isExpanded ? '100%' : '60px', xl: isCollapsed ? '60px' : '100%' }}
display="flex"
position="relative"
px={{ base: 2, lg: isExpanded ? 2 : '15px', xl: isCollapsed ? '15px' : 2 }}
aria-label={ `${ item.text } link` }
whiteSpace="nowrap"
onClick={ onClick }
_hover={{
[`& *:not(.${ LIGHTNING_LABEL_CLASS_NAME }, .${ LIGHTNING_LABEL_CLASS_NAME } *)`]: {
color: isDisabled ? 'inherit' : 'link.primary.hover',
},
}}
>
<Tooltip
content={ item.text }
showArrow={ false }
disabled={ isMobile || isCollapsed === false || (isCollapsed === undefined && isXLScreen) }
positioning={{ placement: 'right', offset: { crossAxis: 0, mainAxis: 20 } }}
visual="navigation"
contentProps={{
color: isInternalLink && item.isActive ? 'link.navigation.fg.selected' : 'link.navigation.fg.hover',
}}
interactive
>
<HStack gap={ 0 } overflow="hidden">
<NavLinkIcon item={ item }/>
<chakra.span
{ ...styleProps.textProps }
ml={ 3 }
display={{ base: 'inline', lg: isExpanded ? 'inline' : 'none', xl: isCollapsed ? 'none' : 'inline' }}
>
<span>{ item.text }</span>
{ !isInternalLink && <IconSvg name="link_external" boxSize={ 3 } color="icon_link_external" verticalAlign="middle"/> }
</chakra.span>
{ isHighlighted && (
<LightningLabel
iconColor={ isInternalLink && item.isActive ? 'link.navigation.bg.selected' : 'link.navigation.bg' }
isCollapsed={ isCollapsed }
/>
) }
</HStack>
</Tooltip>
</Link>
</Box>
);
};
......
......@@ -12,9 +12,9 @@ import { route } from 'nextjs-routes';
import useIsMobile from 'lib/hooks/useIsMobile';
import * as mixpanel from 'lib/mixpanel/index';
import { getRecentSearchKeywords, saveToRecentKeywords } from 'lib/recentSearchKeywords';
import { Link } from 'toolkit/chakra/link';
import { PopoverBody, PopoverContent, PopoverFooter, PopoverRoot, PopoverTrigger } from 'toolkit/chakra/popover';
import { useDisclosure } from 'toolkit/hooks/useDisclosure';
import LinkInternal from 'ui/shared/links/LinkInternal';
import SearchBarBackdrop from './SearchBarBackdrop';
import SearchBarInput from './SearchBarInput';
......@@ -130,7 +130,7 @@ const SearchBar = ({ isHomepage }: Props) => {
lazyMount
closeOnInteractOutside={ false }
>
<PopoverTrigger>
<PopoverTrigger asChild={ false } w="100%">
<SearchBarInput
ref={ inputRef }
onChange={ handleSearchTermChange }
......@@ -174,13 +174,13 @@ const SearchBar = ({ isHomepage }: Props) => {
</Box>
</PopoverBody>
{ searchTerm.trim().length > 0 && query.data && query.data.length >= 50 && (
<PopoverFooter>
<LinkInternal
<PopoverFooter pt={ 2 } borderTopWidth={ 1 } borderColor="border.divider">
<Link
href={ route({ pathname: '/search-results', query: { q: searchTerm } }) }
fontSize="sm"
textStyle="sm"
>
View all results
</LinkInternal>
</Link>
</PopoverFooter>
) }
</PopoverContent>
......
......@@ -3,7 +3,7 @@ import React from 'react';
import { route } from 'nextjs-routes';
import LinkInternal from 'ui/shared/links/LinkInternal';
import { Link } from 'toolkit/chakra/link';
interface Props {
blockHeight: string;
......@@ -15,9 +15,9 @@ const SearchBarSuggestBlockCountdown = ({ blockHeight, onClick, className }: Pro
return (
<Box className={ className }>
<span>Learn </span>
<LinkInternal href={ route({ pathname: '/block/countdown/[height]', query: { height: blockHeight } }) } onClick={ onClick }>
<Link href={ route({ pathname: '/block/countdown/[height]', query: { height: blockHeight } }) } onClick={ onClick }>
estimated time for this block
</LinkInternal>
</Link>
<span> to be created.</span>
</Box>
);
......
......@@ -5,57 +5,26 @@ import type { DeFiDropdownItem as TDeFiDropdownItem } from 'types/client/deFiDro
import { route } from 'nextjs-routes';
import { Link } from 'toolkit/chakra/link';
import IconSvg from 'ui/shared/IconSvg';
import LinkExternal from 'ui/shared/links/LinkExternal';
import LinkInternal from 'ui/shared/links/LinkInternal';
type Props = {
item: TDeFiDropdownItem & { onClick: () => void };
};
const DeFiDropdownItem = ({ item }: Props) => {
const styles = {
width: '100%',
height: '34px',
display: 'inline-flex',
alignItems: 'center',
color: { base: 'blackAlpha.800', _dark: 'gray.400' },
_hover: {
textDecoration: 'none',
'& *': {
color: 'link.primary.hover',
},
},
};
const content = (
<>
return (
<Link
href={ item.dappId ? route({ pathname: '/apps/[id]', query: { id: item.dappId, action: 'connect' } }) : item.url }
external={ !item.dappId }
w="100%"
h="34px"
variant="menu"
>
<IconSvg name={ item.icon } boxSize={ 5 } mr={ 2 }/>
<Text as="span" fontSize="sm">{ item.text }</Text>
</>
</Link>
);
if (item.dappId) {
return (
<LinkInternal
href={ route({ pathname: '/apps/[id]', query: { id: item.dappId, action: 'connect' } }) }
target="_self"
{ ...styles }
>
{ content }
</LinkInternal>
);
}
if (item.url) {
return (
<LinkExternal href={ item.url } { ...styles }>
{ content }
</LinkExternal>
);
}
return null;
};
export default React.memo(DeFiDropdownItem);
import { Image, Box } from '@chakra-ui/react';
import { Box } from '@chakra-ui/react';
import React from 'react';
import { route } from 'nextjs-routes';
......@@ -6,9 +6,8 @@ import { route } from 'nextjs-routes';
import config from 'configs/app';
import useIsMobile from 'lib/hooks/useIsMobile';
import * as mixpanel from 'lib/mixpanel/index';
import LinkExternal from 'ui/shared/links/LinkExternal';
import LinkInternal from 'ui/shared/links/LinkInternal';
import { Image } from 'toolkit/chakra/image';
import { Link } from 'toolkit/chakra/link';
const getGasFeature = config.features.getGasButton;
const GetGasButton = () => {
......@@ -29,14 +28,12 @@ const GetGasButton = () => {
const url = urlObj.toString();
const isInternal = typeof dappId === 'string';
const Link = isInternal ? LinkInternal : LinkExternal;
const href = isInternal ? route({ pathname: '/apps/[id]', query: { id: dappId, url } }) : url;
return (
<>
<Box h="1px" w="8px" bg="border.divider" mx={ 1 }/>
<Link
href={ href }
href={ isInternal ? route({ pathname: '/apps/[id]', query: { id: dappId, url } }) : url }
external={ !isInternal }
display="flex"
alignItems="center"
textStyle="xs"
......
......@@ -75,22 +75,24 @@ const UserProfileButton = ({ profileQuery, size, variant, onClick, isPending, ..
disabled={ isMobile || isLoading || Boolean(data) }
openDelay={ 500 }
>
<Button
ref={ ref }
size={ size }
variant={ variant }
onClick={ onClick }
onFocus={ handleFocus }
selected={ dataExists }
highlighted={ isAutoConnectDisabled }
textStyle="sm"
px={ dataExists ? 2.5 : 4 }
fontWeight={ dataExists ? 700 : 600 }
loading={ isButtonLoading }
{ ...rest }
>
{ content }
</Button>
<span>
<Button
ref={ ref }
size={ size }
variant={ variant }
onClick={ onClick }
onFocus={ handleFocus }
selected={ dataExists }
highlighted={ isAutoConnectDisabled }
textStyle="sm"
px={ dataExists ? 2.5 : 4 }
fontWeight={ dataExists ? 700 : 600 }
loading={ isButtonLoading }
{ ...rest }
>
{ content }
</Button>
</span>
</Tooltip>
);
};
......
......@@ -3,25 +3,23 @@ import React from 'react';
import type { NavLink } from './types';
import { Link } from 'toolkit/chakra/link';
import IconSvg from 'ui/shared/IconSvg';
import LinkInternal from 'ui/shared/links/LinkInternal';
const UserProfileContentNavLink = ({ href, icon, text, onClick }: NavLink) => {
return (
<LinkInternal
<Link
href={ href }
display="flex"
alignItems="center"
columnGap={ 3 }
py="14px"
color="inherit"
_hover={{ textDecoration: 'none', color: 'link.primary.hover' }}
onClick={ onClick }
variant="menu"
>
<IconSvg name={ icon } boxSize={ 5 } flexShrink={ 0 }/>
<Box textStyle="sm" fontWeight="500">{ text }</Box>
</LinkInternal>
</Link>
);
};
......
......@@ -9,8 +9,8 @@ import { route } from 'nextjs-routes';
import config from 'configs/app';
import getValueWithUnit from 'lib/getValueWithUnit';
import { currencyUnits } from 'lib/units';
import { Link } from 'toolkit/chakra/link';
import BlobEntity from 'ui/shared/entities/blob/BlobEntity';
import LinkInternal from 'ui/shared/links/LinkInternal';
import TextSeparator from 'ui/shared/TextSeparator';
import TxFee from 'ui/shared/tx/TxFee';
import Utilization from 'ui/shared/Utilization/Utilization';
......@@ -35,12 +35,12 @@ const TxAdditionalInfoContent = ({ tx }: { tx: Transaction }) => {
<Flex alignItems="center" justifyContent="space-between">
<Text { ...sectionTitleProps }>Blobs: { tx.blob_versioned_hashes.length }</Text>
{ tx.blob_versioned_hashes.length > 3 && (
<LinkInternal
<Link
href={ route({ pathname: '/tx/[hash]', query: { hash: tx.hash, tab: 'blobs' } }) }
mb={ 3 }
>
view all
</LinkInternal>
</Link>
) }
</Flex>
<Flex flexDir="column" rowGap={ 3 }>
......@@ -116,7 +116,7 @@ const TxAdditionalInfoContent = ({ tx }: { tx: Transaction }) => {
</Box>
</Box>
) }
<LinkInternal href={ route({ pathname: '/tx/[hash]', query: { hash: tx.hash } }) }>More details</LinkInternal>
<Link href={ route({ pathname: '/tx/[hash]', query: { hash: tx.hash } }) }>More details</Link>
</>
);
};
......
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