diff --git a/explorer/src/components/account/MetaplexNFTHeader.tsx b/explorer/src/components/account/MetaplexNFTHeader.tsx index 868ac89b94..3e5cbab9eb 100644 --- a/explorer/src/components/account/MetaplexNFTHeader.tsx +++ b/explorer/src/components/account/MetaplexNFTHeader.tsx @@ -18,7 +18,7 @@ export function NFTHeader({ return (
- +
diff --git a/explorer/src/img/logos-solana/dark-solana-logo.svg b/explorer/src/img/logos-solana/dark-solana-logo.svg new file mode 100644 index 0000000000..4ae077d11a --- /dev/null +++ b/explorer/src/img/logos-solana/dark-solana-logo.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/explorer/src/metaplex/Art/Art.tsx b/explorer/src/metaplex/Art/Art.tsx index 367a5a0c39..a9d2351a77 100644 --- a/explorer/src/metaplex/Art/Art.tsx +++ b/explorer/src/metaplex/Art/Art.tsx @@ -1,4 +1,4 @@ -import React, { Ref, useCallback, useEffect, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { MetadataCategory, MetadataFile } from "../types"; import { pubkeyToString } from "../utils"; import { useCachedImage, useExtendedArt } from "./useArt"; @@ -7,8 +7,11 @@ import { PublicKey } from "@solana/web3.js"; import { getLast } from "../utils"; import { Metadata } from "metaplex/classes"; import ContentLoader from "react-content-loader"; +import ErrorLogo from "img/logos-solana/dark-solana-logo.svg"; -const Placeholder = () => ( +const MAX_TIME_LOADING_IMAGE = 5000; /* 5 seconds */ + +const LoadingPlaceholder = () => ( ( ); -const CachedImageContent = ({ - uri, -}: { - uri?: string; - className?: string; - preview?: boolean; - style?: React.CSSProperties; -}) => { - const [loaded, setLoaded] = useState(false); +const ErrorPlaceHolder = () => ( + Solana Logo +); + +const CachedImageContent = ({ uri }: { uri?: string }) => { + const [isLoading, setIsLoading] = useState(true); + const [showError, setShowError] = useState(false); + const [timeout, setTimeout] = useState(undefined); + + useEffect(() => { + // Set the timeout if we don't have a valid uri + if (!uri && !timeout) { + setTimeout(setInterval(() => setShowError(true), MAX_TIME_LOADING_IMAGE)); + } + + // We have a uri - clear the timeout + if (uri && timeout) { + clearInterval(timeout); + } + + return () => { + if (timeout) { + clearInterval(timeout); + } + }; + }, [uri, setShowError, timeout, setTimeout]); + const { cachedBlob } = useCachedImage(uri || ""); return ( <> - {!loaded && } - {"nft"} { - setLoaded(true); - }} - onError={() => { - setLoaded(true); - }} - /> + {showError ? ( +
+ +
Error Loading Image
+
+ ) : ( + <> + {isLoading && } + {"nft"} { + setIsLoading(false); + }} + onError={() => { + setShowError(true); + }} + /> + + )} ); }; const VideoArtContent = ({ - className, - style, files, uri, animationURL, active, }: { - className?: string; - style?: React.CSSProperties; files?: (MetadataFile | string)[]; uri?: string; animationURL?: string; @@ -97,7 +122,7 @@ const VideoArtContent = ({ const content = likelyVideo && likelyVideo.startsWith("https://watch.videodelivery.net/") ? ( -
+
playerRef(e)} src={likelyVideo.replace("https://watch.videodelivery.net/", "")} @@ -116,26 +141,21 @@ const VideoArtContent = ({
) : ( ); @@ -145,13 +165,9 @@ const VideoArtContent = ({ const HTMLContent = ({ animationUrl, - className, - style, files, }: { animationUrl?: string; - className?: string; - style?: React.CSSProperties; files?: (MetadataFile | string)[]; }) => { const [loaded, setLoaded] = useState(false); @@ -162,15 +178,15 @@ const HTMLContent = ({ return ( <> - {!loaded && } + {!loaded && }