mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
114 lines
3.1 KiB
TypeScript
114 lines
3.1 KiB
TypeScript
import { chakra } from '@chakra-ui/react';
|
|
import React from 'react';
|
|
|
|
import type { TokenInstance } from 'types/api/token';
|
|
|
|
import useLoadImageViaIpfs from './useLoadImageViaIpfs';
|
|
import useNftMediaInfo from './useNftMediaInfo';
|
|
import type { MediaElementProps, Size } from './utils';
|
|
import { videoPlayProps } from './utils';
|
|
|
|
interface Props extends MediaElementProps<'video'> {
|
|
instance: TokenInstance;
|
|
autoPlay?: boolean;
|
|
size?: Size;
|
|
}
|
|
|
|
const POSTER_ALLOWED_TYPES = [ 'image' as const ];
|
|
|
|
const NftVideo = ({ src, transport, instance, autoPlay = true, onLoad, size = 'original', onError, onClick, ...rest }: Props) => {
|
|
const ref = React.useRef<HTMLVideoElement>(null);
|
|
|
|
const mediaInfoQuery = useNftMediaInfo({ data: instance, size, field: 'image_url', isEnabled: true, allowedTypes: POSTER_ALLOWED_TYPES });
|
|
const loadImageViaIpfs = useLoadImageViaIpfs();
|
|
|
|
const handleMouseEnter = React.useCallback(() => {
|
|
!autoPlay && ref.current?.play();
|
|
}, [ autoPlay ]);
|
|
|
|
const handleMouseLeave = React.useCallback(() => {
|
|
!autoPlay && ref.current?.pause();
|
|
}, [ autoPlay ]);
|
|
|
|
const loadViaHttp = React.useCallback(async() => {
|
|
if (!ref.current) {
|
|
return;
|
|
}
|
|
|
|
ref.current.src = src;
|
|
onLoad && (ref.current.oncanplaythrough = onLoad);
|
|
onError && (ref.current.onerror = onError);
|
|
}, [ src, onLoad, onError ]);
|
|
|
|
React.useEffect(() => {
|
|
switch (transport) {
|
|
case 'ipfs': {
|
|
// Currently we don't support IPFS video loading
|
|
onError?.();
|
|
break;
|
|
}
|
|
case 'http':
|
|
loadViaHttp();
|
|
break;
|
|
}
|
|
}, [ loadViaHttp, onError, transport ]);
|
|
|
|
const loadPosterViaHttp = React.useCallback(async(src: string) => {
|
|
if (!ref.current || !ref.current.poster) {
|
|
return;
|
|
}
|
|
|
|
const poster = new Image();
|
|
poster.src = src;
|
|
// we want to call onLoad right after the poster is loaded
|
|
// otherwise, the skeleton will be shown underneath the element until the video is loaded
|
|
onLoad && (poster.onload = onLoad);
|
|
|
|
ref.current.poster = poster.src;
|
|
}, [ onLoad ]);
|
|
|
|
const loadPosterViaIpfs = React.useCallback((url: string) => {
|
|
loadImageViaIpfs(url)
|
|
.then((src) => {
|
|
if (src && ref.current) {
|
|
ref.current.poster = src;
|
|
onLoad?.();
|
|
}
|
|
})
|
|
.catch(onError);
|
|
}, [ loadImageViaIpfs, onError, onLoad ]);
|
|
|
|
React.useEffect(() => {
|
|
if (autoPlay) {
|
|
return;
|
|
}
|
|
|
|
if (!mediaInfoQuery.isPending && mediaInfoQuery.data) {
|
|
const mediaInfo = mediaInfoQuery.data[0];
|
|
switch (mediaInfo.transport) {
|
|
case 'ipfs':
|
|
loadPosterViaIpfs(mediaInfo.src);
|
|
break;
|
|
case 'http':
|
|
loadPosterViaHttp(mediaInfo.src);
|
|
break;
|
|
}
|
|
}
|
|
|
|
}, [ autoPlay, loadPosterViaHttp, loadPosterViaIpfs, mediaInfoQuery.data, mediaInfoQuery.isPending ]);
|
|
|
|
return (
|
|
<chakra.video
|
|
ref={ ref }
|
|
{ ...videoPlayProps }
|
|
autoPlay={ autoPlay }
|
|
onClick={ onClick }
|
|
onMouseEnter={ handleMouseEnter }
|
|
onMouseLeave={ handleMouseLeave }
|
|
{ ...rest }
|
|
/>
|
|
);
|
|
};
|
|
|
|
export default React.memo(NftVideo);
|