mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
125 lines
4.1 KiB
TypeScript
125 lines
4.1 KiB
TypeScript
import { useCallback } from 'react';
|
|
|
|
import type { Address3rdPartyWidget } from 'types/views/address';
|
|
|
|
import config from 'configs/app';
|
|
import * as mixpanel from 'lib/mixpanel/index';
|
|
import { cn } from 'lib/utils/cn';
|
|
import { Image } from '@luxfi/ui/image';
|
|
import { LinkBox, LinkOverlay } from 'toolkit/next/link';
|
|
import { Separator } from '@luxfi/ui/separator';
|
|
import { Skeleton } from '@luxfi/ui/skeleton';
|
|
import { Hint } from 'toolkit/components/Hint/Hint';
|
|
import { ndash } from 'toolkit/utils/htmlEntities';
|
|
import IconSvg from 'ui/shared/IconSvg';
|
|
|
|
import useWidgetData from './useWidgetData';
|
|
|
|
type Props = {
|
|
name: string;
|
|
config: Address3rdPartyWidget | undefined;
|
|
address: string;
|
|
isLoading: boolean;
|
|
};
|
|
|
|
const chainId = config.chain.id || '';
|
|
|
|
function formatUrl(tpl: string, ctx: Record<string, string>) {
|
|
return tpl.replace(/\{\s*(\w+)\s*\}/g, (_, key) => ctx[key] ?? '');
|
|
}
|
|
|
|
const Address3rdPartyWidgetCard = ({ name, config, address, isLoading }: Props) => {
|
|
const { data, isLoading: isDataLoading } = useWidgetData(name, config?.valuePath, address, isLoading);
|
|
|
|
const handleClick = useCallback(() => {
|
|
mixpanel.logEvent(mixpanel.EventTypes.ADDRESS_WIDGET, { Name: name });
|
|
}, [ name ]);
|
|
|
|
if (!config) {
|
|
return null;
|
|
}
|
|
|
|
const url = formatUrl(config.url, {
|
|
address,
|
|
addressLowercase: address.toLowerCase(),
|
|
chainId: config.chainIds?.[chainId] ?? chainId,
|
|
});
|
|
|
|
const [ integer, decimal ] = data?.split('.') || [];
|
|
|
|
const content = isLoading ? (
|
|
<>
|
|
<Skeleton loading w="88px" h="40px" mb={ 1 }/>
|
|
<Skeleton loading w="178px" h="20px"/>
|
|
<Separator className="mt-3 mb-2 border-black/5 dark:border-white/10"/>
|
|
<div className="flex items-center gap-2">
|
|
<Skeleton loading w="20px" h="20px"/>
|
|
<Skeleton loading w="80px" h="20px"/>
|
|
</div>
|
|
</>
|
|
) : (
|
|
<>
|
|
<LinkOverlay href={ url } external onClick={ handleClick } noIcon/>
|
|
<Skeleton loading={ isDataLoading } minW="88px" alignSelf="flex-start">
|
|
{ data ? (
|
|
<span
|
|
className={ cn(
|
|
'text-[32px] leading-[40px] font-medium tracking-[-0.5px] overflow-hidden text-ellipsis whitespace-nowrap block',
|
|
integer === '0' && !decimal ? 'text-[var(--color-text-secondary)]' : 'text-[var(--color-text-primary)]',
|
|
) }
|
|
>
|
|
{ integer }
|
|
{ decimal && (
|
|
<>
|
|
.
|
|
<span className="text-[var(--color-text-secondary)]">
|
|
{ decimal }
|
|
</span>
|
|
</>
|
|
) }
|
|
</span>
|
|
) : (
|
|
<span className="text-[32px] leading-[40px] font-medium tracking-[-0.5px] text-[var(--color-text-secondary)] opacity-20">{ ndash }</span>
|
|
) }
|
|
</Skeleton>
|
|
<div className="flex items-center gap-1 mt-1">
|
|
<span className="text-sm">{ config.title }</span>
|
|
{ config.hint && (
|
|
<Hint
|
|
label={ config.hint }
|
|
tooltipProps={{ positioning: { placement: 'bottom' } }}
|
|
/>
|
|
) }
|
|
</div>
|
|
<Separator className="mt-3 mb-2 border-black/5 dark:border-white/10"/>
|
|
<div className="flex items-center gap-2">
|
|
<Image src={ config.icon } alt={ config.name } boxSize={ 5 }/>
|
|
<div className="flex items-center justify-between flex-1">
|
|
<span className="text-xs text-[var(--color-text-secondary)] group-hover:text-[var(--color-hover)]">
|
|
{ config.name }
|
|
</span>
|
|
<IconSvg
|
|
name="link_external"
|
|
className="w-3 h-3 text-[var(--color-hover)] hidden group-hover:block"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
|
|
return (
|
|
<LinkBox
|
|
className={ cn(
|
|
'group flex flex-col p-3 rounded-md border border-solid transition-[border-color] duration-200',
|
|
isLoading
|
|
? 'cursor-default border-black/5 dark:border-white/10 bg-transparent'
|
|
: 'cursor-pointer border-transparent bg-black/5 dark:bg-white/10 hover:border-black/20 dark:hover:border-white/20',
|
|
) }
|
|
>
|
|
{ content }
|
|
</LinkBox>
|
|
);
|
|
};
|
|
|
|
export default Address3rdPartyWidgetCard;
|