Commit 3148fc64 authored by tom's avatar tom

public tags styles

parent a86ee441
import { ChakraProvider } from '@chakra-ui/react';
import { GrowthBookProvider } from '@growthbook/growthbook-react'; import { GrowthBookProvider } from '@growthbook/growthbook-react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
...@@ -15,7 +14,7 @@ import { RewardsContextProvider } from 'lib/contexts/rewards'; ...@@ -15,7 +14,7 @@ import { RewardsContextProvider } from 'lib/contexts/rewards';
import { SettingsContextProvider } from 'lib/contexts/settings'; import { SettingsContextProvider } from 'lib/contexts/settings';
import { SocketProvider } from 'lib/socket/context'; import { SocketProvider } from 'lib/socket/context';
import currentChain from 'lib/web3/currentChain'; import currentChain from 'lib/web3/currentChain';
import theme from 'theme/theme'; import { Provider as ChakraProvider } from 'toolkit/chakra/provider';
import { port as socketPort } from './utils/socket'; import { port as socketPort } from './utils/socket';
...@@ -72,7 +71,7 @@ const TestApp = ({ children, withSocket, appContext = defaultAppContext, marketp ...@@ -72,7 +71,7 @@ const TestApp = ({ children, withSocket, appContext = defaultAppContext, marketp
})); }));
return ( return (
<ChakraProvider theme={ theme }> <ChakraProvider>
<QueryClientProvider client={ queryClient }> <QueryClientProvider client={ queryClient }>
<SocketProvider url={ withSocket ? `ws://${ config.app.host }:${ socketPort }` : undefined }> <SocketProvider url={ withSocket ? `ws://${ config.app.host }:${ socketPort }` : undefined }>
<AppContextProvider { ...appContext }> <AppContextProvider { ...appContext }>
......
...@@ -8,16 +8,30 @@ import IconSvg from 'ui/shared/IconSvg'; ...@@ -8,16 +8,30 @@ import IconSvg from 'ui/shared/IconSvg';
import { Skeleton } from './skeleton'; import { Skeleton } from './skeleton';
export const LinkExternalIcon = ({ color }: { color?: ChakraLinkProps['color'] }) => (
<IconSvg
name="link_external"
boxSize={ 3 }
verticalAlign="middle"
color={ color ?? 'icon.externalLink' }
_groupHover={{
color: 'inherit',
}}
flexShrink={ 0 }
/>
);
export interface LinkProps extends ChakraLinkProps { export interface LinkProps extends ChakraLinkProps {
loading?: boolean; loading?: boolean;
external?: boolean; external?: boolean;
scroll?: boolean; scroll?: boolean;
iconColor?: ChakraLinkProps['color']; iconColor?: ChakraLinkProps['color'];
noIcon?: boolean;
} }
export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>( export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
function Link(props, ref) { function Link(props, ref) {
const { external, loading, href, children, scroll = true, iconColor, ...rest } = props; const { external, loading, href, children, scroll = true, iconColor, noIcon, ...rest } = props;
if (external) { if (external) {
return ( return (
...@@ -27,19 +41,12 @@ export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>( ...@@ -27,19 +41,12 @@ export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
href={ href } href={ href }
className="group" className="group"
target="_blank" target="_blank"
rel="noopener noreferrer" { ...rest } rel="noopener noreferrer"
cursor={ href ? 'pointer' : 'default' }
{ ...rest }
> >
{ children } { children }
<IconSvg { !noIcon && <LinkExternalIcon color={ iconColor }/> }
name="link_external"
boxSize={ 3 }
verticalAlign="middle"
color={ iconColor ?? 'icon.externalLink' }
_groupHover={{
color: 'inherit',
}}
flexShrink={ 0 }
/>
</ChakraLink> </ChakraLink>
</Skeleton> </Skeleton>
); );
...@@ -47,7 +54,7 @@ export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>( ...@@ -47,7 +54,7 @@ export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
return ( return (
<Skeleton loading={ loading } asChild> <Skeleton loading={ loading } asChild>
<ChakraLink asChild ref={ ref } { ...rest }> <ChakraLink asChild ref={ ref } cursor={ href ? 'pointer' : 'default' } { ...rest }>
{ href ? <NextLink href={ href as NextLinkProps['href'] } scroll={ scroll }>{ children }</NextLink> : <span>{ children }</span> } { href ? <NextLink href={ href as NextLinkProps['href'] } scroll={ scroll }>{ children }</NextLink> : <span>{ children }</span> }
</ChakraLink> </ChakraLink>
</Skeleton> </Skeleton>
......
...@@ -8,6 +8,7 @@ import { Skeleton } from './skeleton'; ...@@ -8,6 +8,7 @@ import { Skeleton } from './skeleton';
export interface TagProps extends ChakraTag.RootProps { export interface TagProps extends ChakraTag.RootProps {
startElement?: React.ReactNode; startElement?: React.ReactNode;
endElement?: React.ReactNode; endElement?: React.ReactNode;
endElementProps?: ChakraTag.EndElementProps;
onClose?: VoidFunction; onClose?: VoidFunction;
closable?: boolean; closable?: boolean;
truncated?: boolean; truncated?: boolean;
...@@ -19,6 +20,7 @@ export const Tag = React.forwardRef<HTMLSpanElement, TagProps>( ...@@ -19,6 +20,7 @@ export const Tag = React.forwardRef<HTMLSpanElement, TagProps>(
const { const {
startElement, startElement,
endElement, endElement,
endElementProps,
onClose, onClose,
closable = Boolean(onClose), closable = Boolean(onClose),
children, children,
...@@ -41,7 +43,7 @@ export const Tag = React.forwardRef<HTMLSpanElement, TagProps>( ...@@ -41,7 +43,7 @@ export const Tag = React.forwardRef<HTMLSpanElement, TagProps>(
) } ) }
{ labelElement } { labelElement }
{ endElement && ( { endElement && (
<ChakraTag.EndElement>{ endElement }</ChakraTag.EndElement> <ChakraTag.EndElement { ...endElementProps }>{ endElement }</ChakraTag.EndElement>
) } ) }
{ closable && ( { closable && (
<ChakraTag.EndElement> <ChakraTag.EndElement>
......
...@@ -4,10 +4,16 @@ import type { ExcludeUndefined } from 'types/utils'; ...@@ -4,10 +4,16 @@ import type { ExcludeUndefined } from 'types/utils';
const colors: ExcludeUndefined<ThemingConfig['tokens']>['colors'] = { const colors: ExcludeUndefined<ThemingConfig['tokens']>['colors'] = {
green: { green: {
'50': { value: '#F0FFF4' },
'100': { value: '#C6F6D5' }, '100': { value: '#C6F6D5' },
'200': { value: '#9AE6B4' },
'300': { value: '#68D391' },
'400': { value: '#48BB78' }, '400': { value: '#48BB78' },
'500': { value: '#38A169' }, '500': { value: '#38A169' },
'600': { value: '#25855A' }, '600': { value: '#25855A' },
'700': { value: '#276749' },
'800': { value: '#22543D' },
'900': { value: '#1C4532' },
}, },
blue: { blue: {
'50': { value: '#EBF8FF' }, '50': { value: '#EBF8FF' },
...@@ -22,11 +28,40 @@ const colors: ExcludeUndefined<ThemingConfig['tokens']>['colors'] = { ...@@ -22,11 +28,40 @@ const colors: ExcludeUndefined<ThemingConfig['tokens']>['colors'] = {
'900': { value: '#1A365D' }, '900': { value: '#1A365D' },
}, },
red: { red: {
'500': { value: '#E53E3E' }, '50': { value: '#FFF5F5' },
'100': { value: '#FED7D7' }, '100': { value: '#FED7D7' },
'200': { value: '#FEB2B2' },
'300': { value: '#FC8181' },
'400': { value: '#F56565' },
'500': { value: '#E53E3E' },
'600': { value: '#C53030' },
'700': { value: '#9B2C2C' },
'800': { value: '#822727' },
'900': { value: '#63171B' },
}, },
orange: { orange: {
'50': { value: '#FFFAF0' },
'100': { value: '#FEEBCB' }, '100': { value: '#FEEBCB' },
'200': { value: '#FBD38D' },
'300': { value: '#F6AD55' },
'400': { value: '#ED8936' },
'500': { value: '#DD6B20' },
'600': { value: '#C05621' },
'700': { value: '#9C4221' },
'800': { value: '#7B341E' },
'900': { value: '#652B19' },
},
yellow: {
'50': { value: '#FFFFF0' },
'100': { value: '#FEFCBF' },
'200': { value: '#FAF089' },
'300': { value: '#F6E05E' },
'400': { value: '#ECC94B' },
'500': { value: '#D69E2E' },
'600': { value: '#B7791F' },
'700': { value: '#975A16' },
'800': { value: '#744210' },
'900': { value: '#5F370E' },
}, },
gray: { gray: {
'50': { value: '#F7FAFC' }, '50': { value: '#F7FAFC' },
...@@ -40,8 +75,68 @@ const colors: ExcludeUndefined<ThemingConfig['tokens']>['colors'] = { ...@@ -40,8 +75,68 @@ const colors: ExcludeUndefined<ThemingConfig['tokens']>['colors'] = {
'800': { value: '#1A202C' }, '800': { value: '#1A202C' },
'900': { value: '#171923' }, '900': { value: '#171923' },
}, },
teal: {
'50': { value: '#E6FFFA' },
'100': { value: '#B2F5EA' },
'200': { value: '#81E6D9' },
'300': { value: '#4FD1C5' },
'400': { value: '#38B2AC' },
'500': { value: '#319795' },
'600': { value: '#2C7A7B' },
'700': { value: '#285E61' },
'800': { value: '#234E52' },
'900': { value: '#1D4044' },
},
cyan: {
'50': { value: '#EDFDFD' },
'100': { value: '#C4F1F9' },
'200': { value: '#9DECF9' },
'300': { value: '#76E4F7' },
'400': { value: '#0BC5EA' },
'500': { value: '#00B5D8' },
'600': { value: '#00A3C4' },
'700': { value: '#0987A0' },
'800': { value: '#086F83' },
'900': { value: '#065666' },
},
purple: {
'50': { value: '#FAF5FF' },
'100': { value: '#E9D8FD' },
'200': { value: '#D6BCFA' },
'300': { value: '#B794F4' },
'400': { value: '#9F7AEA' },
'500': { value: '#805AD5' },
'600': { value: '#6B46C1' },
'700': { value: '#553C9A' },
'800': { value: '#44337A' },
'900': { value: '#322659' },
},
pink: {
'50': { value: '#FFF5F7' },
'100': { value: '#FED7E2' },
'200': { value: '#FBB6CE' },
'300': { value: '#F687B3' },
'400': { value: '#ED64A6' },
'500': { value: '#D53F8C' },
'600': { value: '#B83280' },
'700': { value: '#97266D' },
'800': { value: '#702459' },
'900': { value: '#521B41' },
},
black: { value: '#101112' }, black: { value: '#101112' },
white: { value: '#ffffff' }, white: { value: '#ffffff' },
whiteAlpha: {
'50': { value: 'RGBA(16, 17, 18, 0.04)' },
'100': { value: 'RGBA(16, 17, 18, 0.06)' },
'200': { value: 'RGBA(16, 17, 18, 0.08)' },
'300': { value: 'RGBA(16, 17, 18, 0.16)' },
'400': { value: 'RGBA(16, 17, 18, 0.24)' },
'500': { value: 'RGBA(16, 17, 18, 0.36)' },
'600': { value: 'RGBA(16, 17, 18, 0.48)' },
'700': { value: 'RGBA(16, 17, 18, 0.64)' },
'800': { value: 'RGBA(16, 17, 18, 0.80)' },
'900': { value: 'RGBA(16, 17, 18, 0.92)' },
},
blackAlpha: { blackAlpha: {
'50': { value: 'RGBA(16, 17, 18, 0.04)' }, '50': { value: 'RGBA(16, 17, 18, 0.04)' },
'100': { value: 'RGBA(16, 17, 18, 0.06)' }, '100': { value: 'RGBA(16, 17, 18, 0.06)' },
...@@ -54,6 +149,7 @@ const colors: ExcludeUndefined<ThemingConfig['tokens']>['colors'] = { ...@@ -54,6 +149,7 @@ const colors: ExcludeUndefined<ThemingConfig['tokens']>['colors'] = {
'800': { value: 'RGBA(16, 17, 18, 0.80)' }, '800': { value: 'RGBA(16, 17, 18, 0.80)' },
'900': { value: 'RGBA(16, 17, 18, 0.92)' }, '900': { value: 'RGBA(16, 17, 18, 0.92)' },
}, },
// BRAND COLORS
github: { value: '#171923' }, github: { value: '#171923' },
telegram: { value: '#2775CA' }, telegram: { value: '#2775CA' },
linkedin: { value: '#1564BA' }, linkedin: { value: '#1564BA' },
......
...@@ -321,6 +321,10 @@ const semanticTokens: ThemingConfig['semanticTokens'] = { ...@@ -321,6 +321,10 @@ const semanticTokens: ThemingConfig['semanticTokens'] = {
tag: { tag: {
root: { root: {
subtle: { subtle: {
bg: { value: { _light: '{colors.blackAlpha.50}', _dark: '{colors.whiteAlpha.100}' } },
fg: { value: { _light: '{colors.blackAlpha.800}', _dark: '{colors.whiteAlpha.800}' } },
},
clickable: {
bg: { value: { _light: '{colors.gray.100}', _dark: '{colors.gray.800}' } }, bg: { value: { _light: '{colors.gray.100}', _dark: '{colors.gray.800}' } },
fg: { value: { _light: '{colors.blackAlpha.800}', _dark: '{colors.whiteAlpha.800}' } }, fg: { value: { _light: '{colors.blackAlpha.800}', _dark: '{colors.whiteAlpha.800}' } },
}, },
......
...@@ -38,6 +38,9 @@ export const recipe = defineSlotRecipe({ ...@@ -38,6 +38,9 @@ export const recipe = defineSlotRecipe({
}, },
startElement: { startElement: {
flexShrink: 0, flexShrink: 0,
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
boxSize: 'var(--tag-element-size)', boxSize: 'var(--tag-element-size)',
ms: 'var(--tag-element-offset)', ms: 'var(--tag-element-offset)',
'&:has([data-scope=avatar])': { '&:has([data-scope=avatar])': {
...@@ -48,6 +51,9 @@ export const recipe = defineSlotRecipe({ ...@@ -48,6 +51,9 @@ export const recipe = defineSlotRecipe({
}, },
endElement: { endElement: {
flexShrink: 0, flexShrink: 0,
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
boxSize: 'var(--tag-element-size)', boxSize: 'var(--tag-element-size)',
me: 'var(--tag-element-offset)', me: 'var(--tag-element-offset)',
_icon: { boxSize: '100%' }, _icon: { boxSize: '100%' },
...@@ -66,8 +72,8 @@ export const recipe = defineSlotRecipe({ ...@@ -66,8 +72,8 @@ export const recipe = defineSlotRecipe({
minH: '6', minH: '6',
gap: '1', gap: '1',
'--tag-avatar-size': 'spacing.4', '--tag-avatar-size': 'spacing.4',
'--tag-element-size': 'spacing.4', '--tag-element-size': 'spacing.3',
'--tag-element-offset': '-2px', '--tag-element-offset': '0px',
}, },
label: { label: {
textStyle: 'sm', textStyle: 'sm',
...@@ -85,6 +91,19 @@ export const recipe = defineSlotRecipe({ ...@@ -85,6 +91,19 @@ export const recipe = defineSlotRecipe({
}, },
}, },
}, },
clickable: {
root: {
cursor: 'pointer',
bgColor: 'tag.root.clickable.bg',
color: 'tag.root.clickable.fg',
'&:not([data-loading], [aria-busy=true])': {
bgColor: 'tag.root.clickable.bg',
},
_hover: {
opacity: 0.76,
},
},
},
}, },
}, },
......
...@@ -3,7 +3,6 @@ import React from 'react'; ...@@ -3,7 +3,6 @@ import React from 'react';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import { Badge } from 'toolkit/chakra/badge';
import { Link } from 'toolkit/chakra/link'; import { Link } from 'toolkit/chakra/link';
import { Tag } from 'toolkit/chakra/tag'; import { Tag } from 'toolkit/chakra/tag';
import { Tooltip } from 'toolkit/chakra/tooltip'; import { Tooltip } from 'toolkit/chakra/tooltip';
...@@ -26,9 +25,9 @@ const BlockCeloEpochTag = ({ blockQuery }: Props) => { ...@@ -26,9 +25,9 @@ const BlockCeloEpochTag = ({ blockQuery }: Props) => {
undefined; undefined;
const content = epochBlockNumber ? ( const content = epochBlockNumber ? (
<Link href={ route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: String(epochBlockNumber) } }) }> <Link href={ route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: String(epochBlockNumber) } }) }>
<Tag>Epoch #{ blockQuery.data.celo.epoch_number }</Tag> <Tag variant="clickable">Epoch #{ blockQuery.data.celo.epoch_number }</Tag>
</Link> </Link>
) : <Badge>Epoch #{ blockQuery.data.celo.epoch_number }</Badge>; ) : <Tag>Epoch #{ blockQuery.data.celo.epoch_number }</Tag>;
return ( return (
<Tooltip <Tooltip
......
import { Button, Image, Text, useColorModeValue, chakra } from '@chakra-ui/react'; import { Text, chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { AddressMetadataTagFormatted } from 'types/client/addressMetadata'; import type { AddressMetadataTagFormatted } from 'types/client/addressMetadata';
...@@ -7,8 +7,8 @@ import { route } from 'nextjs-routes'; ...@@ -7,8 +7,8 @@ import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
import { Image } from 'toolkit/chakra/image';
import LinkExternal from '../links/LinkExternal'; import { Link } from 'toolkit/chakra/link';
type Props = { type Props = {
data: NonNullable<AddressMetadataTagFormatted['meta']>; data: NonNullable<AddressMetadataTagFormatted['meta']>;
...@@ -18,9 +18,6 @@ type Props = { ...@@ -18,9 +18,6 @@ type Props = {
}; };
const AppActionButton = ({ data, className, txHash, source }: Props) => { const AppActionButton = ({ data, className, txHash, source }: Props) => {
const defaultTextColor = useColorModeValue('blue.600', 'blue.300');
const defaultBg = useColorModeValue('gray.100', 'gray.700');
const { appID, textColor, bgColor, appActionButtonText, appLogoURL, appMarketplaceURL } = data; const { appID, textColor, bgColor, appActionButtonText, appLogoURL, appMarketplaceURL } = data;
const actionURL = appMarketplaceURL?.replace('{chainId}', config.chain.id || '').replace('{txHash}', txHash || ''); const actionURL = appMarketplaceURL?.replace('{chainId}', config.chain.id || '').replace('{txHash}', txHash || '');
...@@ -47,44 +44,29 @@ const AppActionButton = ({ data, className, txHash, source }: Props) => { ...@@ -47,44 +44,29 @@ const AppActionButton = ({ data, className, txHash, source }: Props) => {
mr={ 2 } mr={ 2 }
/> />
) } ) }
<Text fontSize="sm" fontWeight="500" color="currentColor"> <Text textStyle="sm" fontWeight="500" color="currentColor">
{ appActionButtonText } { appActionButtonText }
</Text> </Text>
</> </>
); );
return appID ? ( const isExternal = !appID;
<Button
className={ className } return (
as="a" <Link
href={ route({ pathname: '/apps/[id]', query: { id: appID, action: 'connect', ...(actionURL ? { url: actionURL } : {}) } }) }
onClick={ handleClick }
display="flex"
size="sm"
px={ 2 }
color={ textColor || defaultTextColor }
bg={ bgColor || defaultBg }
_hover={{ bg: bgColor, opacity: 0.9 }}
_active={{ bg: bgColor, opacity: 0.9 }}
>
{ content }
</Button>
) : (
<LinkExternal
className={ className } className={ className }
href={ actionURL } href={ isExternal ? actionURL : route({ pathname: '/apps/[id]', query: { id: appID, action: 'connect', ...(actionURL ? { url: actionURL } : {}) } }) }
external={ isExternal }
onClick={ handleClick } onClick={ handleClick }
variant="subtle" variant="underlaid"
display="flex"
px={ 2 }
iconColor={ textColor } iconColor={ textColor }
color={ textColor } color={ textColor }
bg={ bgColor } bg={ bgColor }
_hover={{ color: textColor }} _hover={{ color: textColor, opacity: textColor || bgColor ? 0.9 : 1 }}
_active={{ color: textColor }} _active={{ color: textColor, opacity: textColor || bgColor ? 0.9 : 1 }}
> >
{ content } { content }
</LinkExternal> </Link>
); );
}; };
......
import type { ResponsiveValue } from '@chakra-ui/react'; import type { HTMLChakraProps } from '@chakra-ui/react';
import { chakra, Image, Tag } from '@chakra-ui/react'; import { chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { EntityTag as TEntityTag } from './types'; import type { EntityTag as TEntityTag } from './types';
import Skeleton from 'ui/shared/chakra/Skeleton'; import * as mixpanel from 'lib/mixpanel/index';
import { Image } from 'toolkit/chakra/image';
import { Link, LinkExternalIcon } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton';
import { Tag } from 'toolkit/chakra/tag';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
import TruncatedValue from 'ui/shared/TruncatedValue';
import EntityTagLink from './EntityTagLink'; import EntityTagTooltip from './EntityTagTooltip';
import EntityTagPopover from './EntityTagPopover';
import { getTagLinkParams } from './utils'; import { getTagLinkParams } from './utils';
interface Props { interface Props extends HTMLChakraProps<'span'> {
data: TEntityTag; data: TEntityTag;
isLoading?: boolean; isLoading?: boolean;
maxW?: ResponsiveValue<string>;
noLink?: boolean; noLink?: boolean;
} }
const EntityTag = ({ data, isLoading, maxW, noLink }: Props) => { const EntityTag = ({ data, isLoading, noLink, ...rest }: Props) => {
if (isLoading) { const linkParams = !noLink ? getTagLinkParams(data) : undefined;
return <Skeleton borderRadius="sm" w="100px" h="24px"/>; const hasLink = Boolean(linkParams);
const iconColor = data.meta?.textColor ?? 'gray.400';
const handleLinkClick = React.useCallback(() => {
if (!linkParams?.href) {
return;
} }
const hasLink = !noLink && Boolean(getTagLinkParams(data)); mixpanel.logEvent(mixpanel.EventTypes.PAGE_WIDGET, {
const iconColor = data.meta?.textColor ?? 'gray.400'; Type: 'Address tag',
Info: data.slug,
URL: linkParams.href,
});
}, [ linkParams?.href, data.slug ]);
if (isLoading) {
return <Skeleton loading borderRadius="sm" w="100px" h="24px"/>;
}
const name = (() => { const name = (() => {
if (data.meta?.warpcastHandle) { if (data.meta?.warpcastHandle) {
...@@ -38,11 +52,19 @@ const EntityTag = ({ data, isLoading, maxW, noLink }: Props) => { ...@@ -38,11 +52,19 @@ const EntityTag = ({ data, isLoading, maxW, noLink }: Props) => {
const icon = (() => { const icon = (() => {
if (data.meta?.tagIcon) { if (data.meta?.tagIcon) {
return <Image boxSize={ 3 } mr={ 1 } flexShrink={ 0 } src={ data.meta.tagIcon } alt={ `${ data.name } icon` }/>; return <Image boxSize={ 3 } src={ data.meta.tagIcon } alt={ `${ data.name } icon` }/>;
} }
if (data.tagType === 'name') { if (data.tagType === 'name') {
return <IconSvg name="publictags_slim" boxSize={ 3 } mr={ 1 } flexShrink={ 0 } color={ iconColor }/>; return <IconSvg name="publictags_slim" boxSize={ 3 } color={ iconColor }/>;
}
return null;
})();
const prefix = (() => {
if (data.meta?.tagIcon) {
return null;
} }
if (data.tagType === 'protocol' || data.tagType === 'generic') { if (data.tagType === 'protocol' || data.tagType === 'generic') {
...@@ -53,24 +75,23 @@ const EntityTag = ({ data, isLoading, maxW, noLink }: Props) => { ...@@ -53,24 +75,23 @@ const EntityTag = ({ data, isLoading, maxW, noLink }: Props) => {
})(); })();
return ( return (
<EntityTagPopover data={ data }> <EntityTagTooltip data={ data }>
<Link external={ linkParams?.type === 'external' } href={ linkParams?.href } onClick={ handleLinkClick } noIcon>
<Tag <Tag
display="flex"
alignItems="center"
minW={ 0 }
w="fit-content"
maxW={ maxW }
bg={ data.meta?.bgColor } bg={ data.meta?.bgColor }
color={ data.meta?.textColor } color={ data.meta?.textColor }
colorScheme={ hasLink ? 'gray-blue' : 'gray' } startElement={ icon }
truncated
endElement={ linkParams?.type === 'external' ? <LinkExternalIcon color={ iconColor }/> : null }
endElementProps={ linkParams?.type === 'external' ? { ml: -1 } : undefined }
_hover={ hasLink ? { opacity: 0.76 } : undefined } _hover={ hasLink ? { opacity: 0.76 } : undefined }
variant={ hasLink ? 'clickable' : 'subtle' }
{ ...rest }
> >
<EntityTagLink data={ data } noLink={ noLink }> { prefix }{ name }
{ icon }
<TruncatedValue value={ name } tooltipPlacement="top"/>
</EntityTagLink>
</Tag> </Tag>
</EntityTagPopover> </Link>
</EntityTagTooltip>
); );
}; };
......
import React from 'react';
import type { EntityTag } from './types';
import * as mixpanel from 'lib/mixpanel/index';
import LinkExternal from 'ui/shared/links/LinkExternal';
import LinkInternal from 'ui/shared/links/LinkInternal';
import { getTagLinkParams } from './utils';
interface Props {
data: EntityTag;
children: React.ReactNode;
noLink?: boolean;
}
const EntityTagLink = ({ data, children, noLink }: Props) => {
const linkParams = !noLink ? getTagLinkParams(data) : undefined;
const handleLinkClick = React.useCallback(() => {
if (!linkParams?.href) {
return;
}
mixpanel.logEvent(mixpanel.EventTypes.PAGE_WIDGET, {
Type: 'Address tag',
Info: data.slug,
URL: linkParams.href,
});
}, [ linkParams?.href, data.slug ]);
const linkProps = {
color: 'inherit',
display: 'inline-flex',
overflow: 'hidden',
_hover: { textDecor: 'none', color: 'inherit' },
onClick: handleLinkClick,
};
if (linkParams?.type === 'internal') {
return (
<LinkInternal
{ ...linkProps }
href={ linkParams.href }
>
{ children }
</LinkInternal>
);
}
if (linkParams?.type === 'external') {
return (
<LinkExternal
{ ...linkProps }
href={ linkParams.href }
iconColor={ data.meta?.textColor }
>
{ children }
</LinkExternal>
);
}
// eslint-disable-next-line react/jsx-no-useless-fragment
return <>{ children }</>;
};
export default React.memo(EntityTagLink);
import { chakra, Image, Flex, PopoverArrow, PopoverBody, PopoverContent, PopoverTrigger, useColorModeValue, DarkMode } from '@chakra-ui/react'; import { chakra, Flex } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { EntityTag } from './types'; import type { EntityTag } from './types';
import makePrettyLink from 'lib/makePrettyLink'; import makePrettyLink from 'lib/makePrettyLink';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
import Popover from 'ui/shared/chakra/Popover'; import { Image } from 'toolkit/chakra/image';
import LinkExternal from 'ui/shared/links/LinkExternal'; import { Link } from 'toolkit/chakra/link';
import { Tooltip } from 'toolkit/chakra/tooltip';
interface Props { interface Props {
data: EntityTag; data: EntityTag;
children: React.ReactNode; children: React.ReactNode;
} }
const EntityTagPopover = ({ data, children }: Props) => { const EntityTagTooltip = ({ data, children }: Props) => {
const bgColor = useColorModeValue('gray.700', 'gray.900');
const link = makePrettyLink(data.meta?.tooltipUrl); const link = makePrettyLink(data.meta?.tooltipUrl);
const hasPopover = Boolean(data.meta?.tooltipIcon || data.meta?.tooltipTitle || data.meta?.tooltipDescription || data.meta?.tooltipUrl); const hasPopover = Boolean(data.meta?.tooltipIcon || data.meta?.tooltipTitle || data.meta?.tooltipDescription || data.meta?.tooltipUrl);
...@@ -35,15 +35,8 @@ const EntityTagPopover = ({ data, children }: Props) => { ...@@ -35,15 +35,8 @@ const EntityTagPopover = ({ data, children }: Props) => {
return <>{ children }</>; return <>{ children }</>;
} }
return ( const content = (
<Popover trigger="hover" isLazy gutter={ 8 }> <Flex textStyle="sm" flexDir="column" rowGap={ 2 } textAlign="left" className="dark">
<PopoverTrigger>
{ children }
</PopoverTrigger>
<PopoverContent bgColor={ bgColor } borderRadius="sm" maxW="280px" w="fit-content">
<PopoverArrow bgColor={ bgColor }/>
<DarkMode>
<PopoverBody color="white" p={ 2 } fontSize="sm" display="flex" flexDir="column" rowGap={ 2 }>
{ (data.meta?.tooltipIcon || data.meta?.tooltipTitle) && ( { (data.meta?.tooltipIcon || data.meta?.tooltipTitle) && (
<Flex columnGap={ 3 } alignItems="center"> <Flex columnGap={ 3 } alignItems="center">
{ data.meta?.tooltipIcon && <Image src={ data.meta.tooltipIcon } boxSize="30px" alt={ `${ data.name } tag logo` }/> } { data.meta?.tooltipIcon && <Image src={ data.meta.tooltipIcon } boxSize="30px" alt={ `${ data.name } tag logo` }/> }
...@@ -51,12 +44,15 @@ const EntityTagPopover = ({ data, children }: Props) => { ...@@ -51,12 +44,15 @@ const EntityTagPopover = ({ data, children }: Props) => {
</Flex> </Flex>
) } ) }
{ data.meta?.tooltipDescription && <chakra.span>{ data.meta.tooltipDescription }</chakra.span> } { data.meta?.tooltipDescription && <chakra.span>{ data.meta.tooltipDescription }</chakra.span> }
{ link && <LinkExternal href={ link.url } onClick={ handleLinkClick }>{ link.domain }</LinkExternal> } { link && <Link external href={ link.url } onClick={ handleLinkClick }>{ link.domain }</Link> }
</PopoverBody> </Flex>
</DarkMode> );
</PopoverContent>
</Popover> return (
<Tooltip content={ content } interactive>
{ children }
</Tooltip>
); );
}; };
export default React.memo(EntityTagPopover); export default React.memo(EntityTagTooltip);
import { Box, Flex, PopoverBody, PopoverContent, PopoverTrigger, chakra } from '@chakra-ui/react'; import { Box, Flex, chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { EntityTag as TEntityTag } from './types'; import type { EntityTag as TEntityTag } from './types';
import config from 'configs/app'; import config from 'configs/app';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import Popover from 'ui/shared/chakra/Popover'; import { Badge } from 'toolkit/chakra/badge';
import Tag from 'ui/shared/chakra/Tag'; import { PopoverBody, PopoverContent, PopoverRoot, PopoverTrigger } from 'toolkit/chakra/popover';
import EntityTag from './EntityTag'; import EntityTag from './EntityTag';
...@@ -39,20 +39,20 @@ const EntityTags = ({ tags, className, isLoading }: Props) => { ...@@ -39,20 +39,20 @@ const EntityTags = ({ tags, className, isLoading }: Props) => {
<> <>
{ tags.slice(0, visibleNum).map((tag) => <EntityTag key={ tag.slug } data={ tag } isLoading={ isLoading } maxW={ tagMaxW }/>) } { tags.slice(0, visibleNum).map((tag) => <EntityTag key={ tag.slug } data={ tag } isLoading={ isLoading } maxW={ tagMaxW }/>) }
{ metaSuitesPlaceholder } { metaSuitesPlaceholder }
<Popover trigger="click" placement="bottom-start" isLazy> <PopoverRoot>
<PopoverTrigger> <PopoverTrigger>
<Tag isLoading={ isLoading } cursor="pointer" as="button" _hover={{ color: 'link_hovered' }}> <Badge loading={ isLoading } cursor="pointer" as="button" _hover={{ color: 'link.primary.hover' }}>
+{ tags.length - visibleNum } +{ tags.length - visibleNum }
</Tag> </Badge>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent maxW="300px" w="auto"> <PopoverContent maxW="300px">
<PopoverBody > <PopoverBody>
<Flex columnGap={ 2 } rowGap={ 2 } flexWrap="wrap"> <Flex columnGap={ 2 } rowGap={ 2 } flexWrap="wrap">
{ tags.slice(visibleNum).map((tag) => <EntityTag key={ tag.slug } data={ tag }/>) } { tags.slice(visibleNum).map((tag) => <EntityTag key={ tag.slug } data={ tag }/>) }
</Flex> </Flex>
</PopoverBody> </PopoverBody>
</PopoverContent> </PopoverContent>
</Popover> </PopoverRoot>
</> </>
); );
} }
......
import React from 'react'; import React from 'react';
import * as addressMetadataMock from 'mocks/metadata/address';
import { Tag } from 'toolkit/chakra/tag'; import { Tag } from 'toolkit/chakra/tag';
import EntityTag from 'ui/shared/EntityTags/EntityTag';
import { Section, Container, SectionHeader, SamplesStack, Sample } from './parts'; import { Section, Container, SectionHeader, SamplesStack, Sample, SectionSubHeader } from './parts';
const TagsShowcase = () => { const TagsShowcase = () => {
// TODO @tom2drum CELO tags, public tags, filtered tags // TODO @tom2drum filtered tags
return ( return (
<Container value="tags"> <Container value="tags">
<Section> <Section>
<SectionHeader>Variant</SectionHeader> <SectionHeader>Variant</SectionHeader>
<SamplesStack> <SamplesStack>
<Sample label="variant: ???"> <Sample label="variant: subtle">
<Tag>My tag</Tag> <Tag>My tag</Tag>
</Sample>
<Sample label="variant: clickable">
<Tag variant="clickable">My tag</Tag>
</Sample>
</SamplesStack>
</Section>
<Section>
<SectionHeader>Truncated</SectionHeader>
<SamplesStack>
<Sample label="truncated: true">
<Tag maxW="150px" truncated>Very very very very very looooooonggggg text</Tag> <Tag maxW="150px" truncated>Very very very very very looooooonggggg text</Tag>
</Sample>
</SamplesStack>
</Section>
<Section>
<SectionHeader>Loading</SectionHeader>
<SamplesStack>
<Sample label="loading: true">
<Tag loading>My tag</Tag> <Tag loading>My tag</Tag>
<Tag maxW="150px" truncated loading>Very very very very very looooooonggggg text</Tag> <Tag maxW="150px" truncated loading>Very very very very very looooooonggggg text</Tag>
</Sample> </Sample>
<Sample label="loading: false">
<Tag>My tag</Tag>
<Tag maxW="150px" truncated>Very very very very very looooooonggggg text</Tag>
</Sample>
</SamplesStack> </SamplesStack>
</Section> </Section>
<Section>
<SectionHeader>Examples</SectionHeader>
<SectionSubHeader>Public tags</SectionSubHeader>
<SamplesStack>
<Sample>
<EntityTag data={ addressMetadataMock.nameTag }/>
<EntityTag data={ addressMetadataMock.customNameTag }/>
<EntityTag data={ addressMetadataMock.warpcastTag }/>
<EntityTag data={ addressMetadataMock.genericTag }/>
<EntityTag data={ addressMetadataMock.protocolTag }/>
<EntityTag data={ addressMetadataMock.infoTagWithLink } maxW="150px"/>
<EntityTag data={ addressMetadataMock.tagWithTooltip }/>
<EntityTag data={ addressMetadataMock.nameTag } isLoading/>
</Sample>
</SamplesStack>
<SectionSubHeader>Filter tags</SectionSubHeader>
<span>TODO</span>
</Section>
</Container> </Container>
); );
}; };
......
...@@ -9,7 +9,6 @@ import { NOVES_TRANSLATE } from 'stubs/noves/NovesTranslate'; ...@@ -9,7 +9,6 @@ import { NOVES_TRANSLATE } from 'stubs/noves/NovesTranslate';
import { TX_INTERPRETATION } from 'stubs/txInterpretation'; import { TX_INTERPRETATION } from 'stubs/txInterpretation';
import { Link } from 'toolkit/chakra/link'; import { Link } from 'toolkit/chakra/link';
import AccountActionsMenu from 'ui/shared/AccountActionsMenu/AccountActionsMenu'; import AccountActionsMenu from 'ui/shared/AccountActionsMenu/AccountActionsMenu';
// TODO @tom2drum fix app action button
import AppActionButton from 'ui/shared/AppActionButton/AppActionButton'; import AppActionButton from 'ui/shared/AppActionButton/AppActionButton';
import useAppActionData from 'ui/shared/AppActionButton/useAppActionData'; import useAppActionData from 'ui/shared/AppActionButton/useAppActionData';
import { TX_ACTIONS_BLOCK_ID } from 'ui/shared/DetailsActionsWrapper'; import { TX_ACTIONS_BLOCK_ID } from 'ui/shared/DetailsActionsWrapper';
...@@ -138,9 +137,9 @@ const TxSubHeading = ({ hash, hasTag, txQuery }: Props) => { ...@@ -138,9 +137,9 @@ const TxSubHeading = ({ hash, hasTag, txQuery }: Props) => {
mt={{ base: 3, lg: 0 }} mt={{ base: 3, lg: 0 }}
> >
{ !hasTag && <AccountActionsMenu isLoading={ isLoading }/> } { !hasTag && <AccountActionsMenu isLoading={ isLoading }/> }
{ /* { appActionData && ( { appActionData && (
<AppActionButton data={ appActionData } txHash={ hash } source="Txn"/> <AppActionButton data={ appActionData } txHash={ hash } source="Txn"/>
) } */ } ) }
<NetworkExplorers type="tx" pathParam={ hash } ml={{ base: 0, lg: 'auto' }}/> <NetworkExplorers type="tx" pathParam={ hash } ml={{ base: 0, lg: 'auto' }}/>
</Flex> </Flex>
</Box> </Box>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment