Commit 350147a4 authored by tom's avatar tom

display video

parent 47c7f5d5
...@@ -141,6 +141,9 @@ function makePolicyMap() { ...@@ -141,6 +141,9 @@ function makePolicyMap() {
// walletconnect // walletconnect
'*.walletconnect.com', '*.walletconnect.com',
// token's media
'ipfs.io',
], ],
'font-src': [ 'font-src': [
......
...@@ -4,7 +4,7 @@ import React from 'react'; ...@@ -4,7 +4,7 @@ import React from 'react';
import type { AddressTokenBalance } from 'types/api/address'; import type { AddressTokenBalance } from 'types/api/address';
import link from 'lib/link/link'; import link from 'lib/link/link';
import NftImage from 'ui/shared/NftImage'; import NftImage from 'ui/shared/nft/NftImage';
import TokenLogo from 'ui/shared/TokenLogo'; import TokenLogo from 'ui/shared/TokenLogo';
import TruncatedTextTooltip from 'ui/shared/TruncatedTextTooltip'; import TruncatedTextTooltip from 'ui/shared/TruncatedTextTooltip';
......
import { AspectRatio, chakra, Icon, Image, useColorModeValue } from '@chakra-ui/react'; import type { ResponsiveValue } from '@chakra-ui/react';
import { AspectRatio, chakra, Icon, Image, shouldForwardProp, Skeleton, useColorModeValue } from '@chakra-ui/react';
import type { Property } from 'csstype';
import React from 'react'; import React from 'react';
import nftIcon from 'icons/nft_shield.svg'; import nftIcon from 'icons/nft_shield.svg';
...@@ -7,6 +9,7 @@ interface Props { ...@@ -7,6 +9,7 @@ interface Props {
url: string | null; url: string | null;
className?: string; className?: string;
fallbackPadding?: string; fallbackPadding?: string;
objectFit: ResponsiveValue<Property.ObjectFit>;
} }
interface FallbackProps { interface FallbackProps {
...@@ -25,7 +28,19 @@ const Fallback = ({ className, padding }: FallbackProps) => { ...@@ -25,7 +28,19 @@ const Fallback = ({ className, padding }: FallbackProps) => {
); );
}; };
const NftImage = ({ url, className, fallbackPadding }: Props) => { const NftImage = ({ url, className, fallbackPadding, objectFit }: Props) => {
const [ isLoading, setIsLoading ] = React.useState(true);
const handleLoad = React.useCallback(() => {
setIsLoading(false);
}, []);
const handleLoadError = React.useCallback(() => {
setIsLoading(false);
}, []);
const _objectFit = objectFit || 'contain';
return ( return (
<AspectRatio <AspectRatio
className={ className } className={ className }
...@@ -35,20 +50,34 @@ const NftImage = ({ url, className, fallbackPadding }: Props) => { ...@@ -35,20 +50,34 @@ const NftImage = ({ url, className, fallbackPadding }: Props) => {
borderRadius="md" borderRadius="md"
sx={{ sx={{
'&>img': { '&>img': {
objectFit: 'contain', objectFit: _objectFit,
}, },
}} }}
> >
<Image <Image
w="100%" w="100%"
h="100%" h="100%"
objectFit="contain" objectFit={ _objectFit }
src={ url || undefined } src={ url || undefined }
alt="Token instance image" alt="Token instance image"
fallback={ <Fallback className={ className } padding={ fallbackPadding }/> } fallback={ url && isLoading ? <Skeleton/> : <Fallback className={ className } padding={ fallbackPadding }/> }
onError={ handleLoadError }
onLoad={ handleLoad }
/> />
</AspectRatio> </AspectRatio>
); );
}; };
export default chakra(NftImage); const NftImageChakra = chakra(NftImage, {
shouldForwardProp: (prop) => {
const isChakraProp = !shouldForwardProp(prop);
if (isChakraProp && prop !== 'objectFit') {
return false;
}
return true;
},
});
export default NftImageChakra;
import { AspectRatio, chakra, Skeleton } from '@chakra-ui/react';
import React from 'react';
import NftImage from './NftImage';
import NftVideo from './NftVideo';
interface Props {
imageUrl: string | null;
animationUrl: string | null;
className?: string;
}
const NftMedia = ({ imageUrl, animationUrl, className }: Props) => {
const [ type, setType ] = React.useState<'image' | 'video' | undefined>(!animationUrl ? 'image' : undefined);
React.useEffect(() => {
if (!animationUrl) {
return;
}
const xhr = new XMLHttpRequest();
xhr.open('HEAD', animationUrl, true);
xhr.onload = function() {
const contentType = xhr.getResponseHeader('Content-Type');
setType(contentType?.startsWith('video') ? 'video' : 'image');
};
xhr.send();
return () => {
xhr.abort();
};
}, [ animationUrl ]);
if (!type) {
return (
<AspectRatio
className={ className }
ratio={ 1 / 1 }
overflow="hidden"
borderRadius="md"
>
<Skeleton/>
</AspectRatio>
);
}
if (animationUrl && type === 'video') {
return <NftVideo className={ className } src={ animationUrl }/>;
}
return <NftImage className={ className } url={ animationUrl || imageUrl }/>;
};
export default chakra(NftMedia);
import { AspectRatio, Skeleton, chakra } from '@chakra-ui/react';
import React from 'react';
interface Props {
className?: string;
src: string;
}
const NftVideo = ({ className, src }: Props) => {
const [ isLoading, setIsLoading ] = React.useState(true);
const handleCanPlay = React.useCallback(() => {
setIsLoading(false);
}, []);
return (
<AspectRatio
className={ className }
ratio={ 1 / 1 }
overflow="hidden"
borderRadius="md"
>
<>
<chakra.video
src={ src }
autoPlay
disablePictureInPicture
loop
muted
playsInline
onCanPlayThrough={ handleCanPlay }
borderRadius="md"
/>
{ isLoading && <Skeleton position="absolute" w="100%" h="100%" left={ 0 } top={ 0 }/> }
</>
</AspectRatio>
);
};
export default chakra(NftVideo);
...@@ -9,7 +9,7 @@ import AddressLink from 'ui/shared/address/AddressLink'; ...@@ -9,7 +9,7 @@ import AddressLink from 'ui/shared/address/AddressLink';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import NftImage from 'ui/shared/NftImage'; import NftMedia from 'ui/shared/nft/NftMedia';
import TokenSnippet from 'ui/shared/TokenSnippet/TokenSnippet'; import TokenSnippet from 'ui/shared/TokenSnippet/TokenSnippet';
import TokenInstanceCreatorAddress from './details/TokenInstanceCreatorAddress'; import TokenInstanceCreatorAddress from './details/TokenInstanceCreatorAddress';
...@@ -66,7 +66,13 @@ const TokenInstanceDetails = ({ data, scrollRef }: Props) => { ...@@ -66,7 +66,13 @@ const TokenInstanceDetails = ({ data, scrollRef }: Props) => {
</DetailsInfoItem> </DetailsInfoItem>
<TokenInstanceTransfersCount hash={ data.token.address } id={ data.id } onClick={ handleCounterItemClick }/> <TokenInstanceTransfersCount hash={ data.token.address } id={ data.id } onClick={ handleCounterItemClick }/>
</Grid> </Grid>
<NftImage url={ data.image_url } w="250px" flexShrink={ 0 } alignSelf={{ base: 'center', lg: 'flex-start' }}/> <NftMedia
imageUrl={ data.image_url }
animationUrl={ data.animation_url }
w="250px"
flexShrink={ 0 }
alignSelf={{ base: 'center', lg: 'flex-start' }}
/>
</Flex> </Flex>
); );
}; };
......
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