diff --git a/bridge_ui/src/components/Home/index.tsx b/bridge_ui/src/components/Home/index.tsx index 572ecf8ae..eb9013111 100644 --- a/bridge_ui/src/components/Home/index.tsx +++ b/bridge_ui/src/components/Home/index.tsx @@ -1,18 +1,21 @@ import { Card, + Chip, Container, Link, makeStyles, Typography, } from "@material-ui/core"; import { Link as RouterLink } from "react-router-dom"; +import polygonLogo from "../../icons/polygon.svg"; import { COLORS } from "../../muiTheme"; +import { CHAINS } from "../../utils/consts"; import HeaderText from "../HeaderText"; const useStyles = makeStyles((theme) => ({ header: { marginTop: theme.spacing(12), - marginBottom: theme.spacing(15), + marginBottom: theme.spacing(8), [theme.breakpoints.down("sm")]: { marginBottom: theme.spacing(6), }, @@ -37,6 +40,55 @@ const useStyles = makeStyles((theme) => ({ spacer: { height: theme.spacing(5), }, + chainList: { + display: "flex", + flexWrap: "wrap", + justifyContent: "center", + margin: theme.spacing(-1, -1, 8), + [theme.breakpoints.down("sm")]: { + margin: theme.spacing(-1, -1, 6), + }, + }, + chainCard: { + backgroundColor: COLORS.nearBlackWithMinorTransparency, + borderRadius: 8, + display: "flex", + flexDirection: "column", + margin: theme.spacing(1), + minHeight: "100%", + padding: theme.spacing(2), + width: 149, // makes it square + maxWidth: 149, + [theme.breakpoints.down("sm")]: { + padding: theme.spacing(1.5), + width: 141, // keeps it square + maxWidth: 141, + }, + }, + chainLogoWrapper: { + position: "relative", + textAlign: "center", + }, + chainLogo: { + height: 64, + maxWidth: 64, + }, + chainName: { + marginTop: theme.spacing(1), + flex: "1", + display: "flex", + alignItems: "center", + justifyContent: "center", + textAlign: "center", + minHeight: 40, // 2 lines + }, + chip: { + backgroundColor: COLORS.blueWithTransparency, + position: "absolute", + top: "50%", + right: "50%", + transform: "translate(50%, -50%)", + }, })); function Home() { @@ -48,6 +100,45 @@ function Home() { The Portal is Open + +
+ {CHAINS.map((chain) => ( +
+
+ {chain.name} +
+ +
{chain.name}
+
+
+ ))} +
+
+ Polygon + +
+ +
Polygon
+
+
+
+
@@ -55,7 +146,7 @@ function Home() { The Wormhole Token Bridge allows you to seamlessly transfer - tokenized assets across Solana and Ethereum. + tokenized assets across Solana, Ethereum, BSC, and Terra.
diff --git a/bridge_ui/src/components/TokenSelectors/NFTViewer.tsx b/bridge_ui/src/components/TokenSelectors/NFTViewer.tsx index fd359b96a..4607b9302 100644 --- a/bridge_ui/src/components/TokenSelectors/NFTViewer.tsx +++ b/bridge_ui/src/components/TokenSelectors/NFTViewer.tsx @@ -216,20 +216,31 @@ export default function NFTViewer({ }) { const uri = safeIPFS(value.uri || ""); const [metadata, setMetadata] = useState({ + uri, image: value.image, animation_url: value.animation_url, nftName: value.nftName, description: value.description, isLoading: !!uri, }); + const [isMediaLoading, setIsMediaLoading] = useState(false); + const onLoad = useCallback(() => { + setIsMediaLoading(false); + }, []); + const isLoading = isMediaLoading || metadata.isLoading; useEffect(() => { - setMetadata({ - image: value.image, - animation_url: value.animation_url, - nftName: value.nftName, - description: value.description, - isLoading: !!uri, - }); + setMetadata((m) => + m.uri === uri + ? m + : { + uri, + image: value.image, + animation_url: value.animation_url, + nftName: value.nftName, + description: value.description, + isLoading: !!uri, + } + ); }, [value, uri]); useEffect(() => { if (uri) { @@ -239,6 +250,7 @@ export default function NFTViewer({ const result = await axios.get(uri); if (!cancelled && result && result.data) { setMetadata({ + uri, image: result.data.image, animation_url: result.data.animation_url, nftName: result.data.name, @@ -246,10 +258,10 @@ export default function NFTViewer({ isLoading: false, }); } else if (!cancelled) { - setIsLoading(false); + setMetadata((m) => ({ ...m, isLoading: false })); } } catch (e) { - setIsLoading(false); + setMetadata((m) => ({ ...m, isLoading: false })); } })(); return () => { @@ -257,13 +269,6 @@ export default function NFTViewer({ }; } }, [uri]); - const [isLoading, setIsLoading] = useState(true); - const onLoad = useCallback(() => { - setIsLoading(false); - }, []); - useLayoutEffect(() => { - setIsLoading(true); - }, [value, chainId]); const classes = useStyles(); const animLower = metadata.animation_url?.toLowerCase(); @@ -282,24 +287,29 @@ export default function NFTViewer({ animLower?.endsWith("wav") || animLower?.endsWith("oga"); const hasImage = metadata.image; + const copyTokenId = useCopyToClipboard(value.tokenId || ""); + const videoSrc = hasVideo && safeIPFS(metadata.animation_url || ""); + const imageSrc = hasImage && safeIPFS(metadata.image || ""); + const audioSrc = hasAudio && safeIPFS(metadata.animation_url || ""); + + //set loading when the media src changes + useLayoutEffect(() => { + if (videoSrc || imageSrc || audioSrc) { + setIsMediaLoading(true); + } else { + setIsMediaLoading(false); + } + }, [videoSrc, imageSrc, audioSrc]); + const image = ( {metadata.nftName ); - const copyTokenId = useCopyToClipboard(value.tokenId || ""); - - //report that loading is done, if the item has no reasonable media - useEffect(() => { - if (!metadata.isLoading && !hasVideo && !hasAudio && !hasImage) { - setIsLoading(false); - } - }, [metadata.isLoading, hasVideo, hasAudio, hasImage]); - const media = ( <> {hasVideo ? ( @@ -308,10 +318,10 @@ export default function NFTViewer({ controls loop style={{ maxWidth: "100%" }} - onLoad={onLoad} + onLoadedData={onLoad} onError={onLoad} > - + {image} ) : hasImage ? ( @@ -320,8 +330,8 @@ export default function NFTViewer({ {hasAudio ? (