TokenInstanceMetadataInfo.tsx 3.28 KB
Newer Older
贾浩@五瓣科技's avatar
贾浩@五瓣科技 committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
import { Grid, GridItem, Skeleton, useColorModeValue } from '@chakra-ui/react';
import React from 'react';

import type { TokenInstance } from 'types/api/token';
import type { MetadataAttributes } from 'types/client/token';

import parseMetadata from 'lib/token/parseMetadata';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider';
import LinkExternal from 'ui/shared/LinkExternal';
import TruncatedValue from 'ui/shared/TruncatedValue';

interface Props {
  data?: TokenInstance;
  isLoading?: boolean;
}

interface ItemProps {
  data: MetadataAttributes;
  isLoading?: boolean;
}

const Item = ({ data, isLoading }: ItemProps) => {
  const attributeBgColor = useColorModeValue('blackAlpha.50', 'whiteAlpha.50');

  const value = (() => {
    if (data.value_type === 'URL') {
      return (
        <LinkExternal
          whiteSpace="nowrap"
          display="inline-flex"
          alignItems="center"
          w="100%"
          overflow="hidden"
          href={ data.value }
          fontSize="sm"
          lineHeight={ 5 }
        >
          <TruncatedValue value={ data.value } w="calc(100% - 16px)"/>
        </LinkExternal>
      );
    }

    return <TruncatedValue value={ data.value } fontSize="sm" w="100%" isLoading={ isLoading }/>;
  })();

  return (
    <GridItem
      bgColor={ attributeBgColor }
      borderRadius="md"
      px={ 4 }
      py={ 2 }
      display="flex"
      flexDir="column"
      alignItems="flex-start"
    >
      <Skeleton isLoaded={ !isLoading } fontSize="xs" lineHeight={ 4 } color="text_secondary" fontWeight={ 500 } mb={ 1 }>
        <span>{ data.trait_type }</span>
      </Skeleton>
      { value }
    </GridItem>
  );
};

const TokenInstanceMetadataInfo = ({ data, isLoading }: Props) => {
  const metadata = React.useMemo(() => parseMetadata(data?.metadata), [ data ]);
  const hasMetadata = metadata && Boolean((metadata.name || metadata.description || metadata.attributes));

  if (!hasMetadata) {
    return null;
  }

  return (
    <>
      <DetailsInfoItemDivider/>
      { metadata?.name && (
        <DetailsInfoItem
          title="Name"
          hint="NFT name"
          whiteSpace="normal"
          wordBreak="break-word"
          isLoading={ isLoading }
        >
          <Skeleton isLoaded={ !isLoading }>
            { metadata.name }
          </Skeleton>
        </DetailsInfoItem>
      ) }
      { metadata?.description && (
        <DetailsInfoItem
          title="Description"
          hint="NFT description"
          whiteSpace="normal"
          wordBreak="break-word"
          isLoading={ isLoading }
        >
          <Skeleton isLoaded={ !isLoading }>
            { metadata.description }
          </Skeleton>
        </DetailsInfoItem>
      ) }
      { metadata?.attributes && (
        <DetailsInfoItem
          title="Attributes"
          hint="NFT attributes"
          whiteSpace="normal"
          isLoading={ isLoading }
        >
          <Grid gap={ 2 } templateColumns="repeat(auto-fill,minmax(160px, 1fr))" w="100%">
            { metadata.attributes.map((attribute, index) => <Item key={ index } data={ attribute } isLoading={ isLoading }/>) }
          </Grid>
        </DetailsInfoItem>
      ) }
    </>
  );
};

export default React.memo(TokenInstanceMetadataInfo);