diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index 46cc61643a..284721db54 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -720,6 +720,7 @@ "links": { "bridge": "Bridge", "buy": "Buy", + "marketplace": "Marketplace", "portfolio": "Portfolio", "sell": "Sell", "swap": "Swap" diff --git a/src/frontend/OverlayManager/Overlay/NavBarOverlayWrapper/MarketplaceNavItem/MarketplaceSublinks/index.tsx b/src/frontend/OverlayManager/Overlay/NavBarOverlayWrapper/MarketplaceNavItem/MarketplaceSublinks/index.tsx new file mode 100644 index 0000000000..22df5a02ce --- /dev/null +++ b/src/frontend/OverlayManager/Overlay/NavBarOverlayWrapper/MarketplaceNavItem/MarketplaceSublinks/index.tsx @@ -0,0 +1,33 @@ +import React from 'react' +import { ContractMetadata } from '@valist/sdk/dist/typesApi' +import { SubLink } from '@hyperplay/ui' +import { Link, useLocation } from 'react-router-dom' +import styles from '../../index.module.scss' + +export function MarketplaceSublinks(contractMetadata?: ContractMetadata[]) { + const location = useLocation() + const { pathname, search } = location + const searchParams = new URLSearchParams(search) + const urlQueryParam = searchParams.get('url') + + const marketplaceSublinks = contractMetadata + ?.filter((val) => !!val.marketplace_urls) + .flatMap((val) => + (val.marketplace_urls ?? []) + .filter((val) => !!val) + .map((mktUrl) => { + return ( + + {val.name} + + ) + }) + ) + return marketplaceSublinks +} diff --git a/src/frontend/OverlayManager/Overlay/NavBarOverlayWrapper/MarketplaceNavItem/index.tsx b/src/frontend/OverlayManager/Overlay/NavBarOverlayWrapper/MarketplaceNavItem/index.tsx new file mode 100644 index 0000000000..32d21a7ee2 --- /dev/null +++ b/src/frontend/OverlayManager/Overlay/NavBarOverlayWrapper/MarketplaceNavItem/index.tsx @@ -0,0 +1,62 @@ +import React, { useState } from 'react' +import { Images, NavItem } from '@hyperplay/ui' +import { useLocation } from 'react-router-dom' +import { useQuery } from '@tanstack/react-query' +import { BrowserGameProps } from 'frontend/OverlayManager/types' +import styles from '../index.module.scss' +import classNames from 'classnames' +import { useTranslation } from 'react-i18next' +import { MarketplaceSublinks } from './MarketplaceSublinks' + +export interface MarketplaceNavItemProps extends BrowserGameProps { + collapsed: boolean +} + +export function MarketplaceNavItem({ + appName, + runner, + collapsed, + ...props +}: MarketplaceNavItemProps) { + const location = useLocation() + const { pathname } = location + const [mktCollapsed, setMktCollapsed] = useState(false) + const { t } = useTranslation() + + const { data: gameInfo } = useQuery({ + queryKey: ['getGameInfo', appName], + queryFn: async () => { + return window.api.getGameInfo(appName, runner) + } + }) + + const gameInfoExists = !!gameInfo + const gameInfoHasSomeMarketplaceUrls = !!gameInfo?.networks?.some( + (val) => !!val.marketplace_urls?.length + ) + const marketplaceEnabled = gameInfoExists && gameInfoHasSomeMarketplaceUrls + const marketplaceClass: Record = {} + marketplaceClass[styles.disabled] = !marketplaceEnabled + + if (!marketplaceEnabled) { + return null + } + + return ( + } + key={'/marketplace'} + collapsed={collapsed} + selected={pathname === '/marketplace'} + classNames={{ link: classNames(marketplaceClass) }} + subLinks={ + marketplaceEnabled ? MarketplaceSublinks(gameInfo?.networks) : undefined + } + subLinksCollapsed={mktCollapsed} + setSubLinksCollapsed={() => setMktCollapsed(!mktCollapsed)} + onClick={() => setMktCollapsed(!mktCollapsed)} + {...props} + /> + ) +} diff --git a/src/frontend/OverlayManager/Overlay/NavBarOverlayWrapper/PortfolioNavItem/index.tsx b/src/frontend/OverlayManager/Overlay/NavBarOverlayWrapper/PortfolioNavItem/index.tsx new file mode 100644 index 0000000000..f46adf1004 --- /dev/null +++ b/src/frontend/OverlayManager/Overlay/NavBarOverlayWrapper/PortfolioNavItem/index.tsx @@ -0,0 +1,76 @@ +import React, { useState } from 'react' +import styles from '../index.module.scss' +import { NavItem, Images, SubLink } from '@hyperplay/ui' +import { Link, useLocation } from 'react-router-dom' +import { useTranslation } from 'react-i18next' + +export interface PortfolioNavItemProps { + collapsed: boolean +} + +export function PortfolioNavItem({ collapsed }: PortfolioNavItemProps) { + const location = useLocation() + const { pathname } = location + const [mmCollapsed, mmSetCollapsed] = useState(false) + const { t } = useTranslation() + + return ( + } + key={'/portfolio'} + collapsed={collapsed} + selected={pathname.startsWith('/portfolio')} + onClick={() => mmSetCollapsed(!mmCollapsed)} + subLinksCollapsed={mmCollapsed} + setSubLinksCollapsed={() => mmSetCollapsed(!mmCollapsed)} + subLinks={[ + + {t('overlay.links.portfolio', 'Portfolio')} + , + + {t('overlay.links.swap', 'Swap')} + , + + {t('overlay.links.bridge', 'Bridge')} + , + + {t('overlay.links.buy', 'Buy')} + , + + {t('overlay.links.sell', 'Sell')} + + ]} + /> + ) +} diff --git a/src/frontend/OverlayManager/Overlay/NavBarOverlayWrapper/index.tsx b/src/frontend/OverlayManager/Overlay/NavBarOverlayWrapper/index.tsx index 4cf9a3c663..0513f242bd 100644 --- a/src/frontend/OverlayManager/Overlay/NavBarOverlayWrapper/index.tsx +++ b/src/frontend/OverlayManager/Overlay/NavBarOverlayWrapper/index.tsx @@ -1,16 +1,18 @@ import React, { useState } from 'react' import styles from './index.module.scss' -import { NavBarOverlay, NavItem, Images, SubLink } from '@hyperplay/ui' +import { NavBarOverlay, NavItem, Images } from '@hyperplay/ui' import { Link, useLocation } from 'react-router-dom' +import { BrowserGameProps } from 'frontend/OverlayManager/types' +import { MarketplaceNavItem } from './MarketplaceNavItem' import { useTranslation } from 'react-i18next' +import { PortfolioNavItem } from './PortfolioNavItem' -export function NavBarOverlayWrapper() { +export function NavBarOverlayWrapper({ appName, runner }: BrowserGameProps) { const location = useLocation() const { pathname } = location const [collapsed, setCollapsed] = useState(false) const { t } = useTranslation() const comingSoonText = t('overlay.comingSoon', 'Coming Soon') - const [mmCollapsed, mmSetCollapsed] = useState(false) return ( , - } - key={'/portfolio'} - collapsed={collapsed} - selected={pathname.startsWith('/portfolio')} - onClick={() => mmSetCollapsed(!mmCollapsed)} - subLinksCollapsed={mmCollapsed} - setSubLinksCollapsed={() => mmSetCollapsed(!mmCollapsed)} - subLinks={[ - - {t('overlay.links.portfolio', 'Portfolio')} - , - - {t('overlay.links.swap', 'Swap')} - , - - {t('overlay.links.bridge', 'Bridge')} - , - - {t('overlay.links.buy', 'Buy')} - , - - {t('overlay.links.sell', 'Sell')} - - ]} - />, - } - key={'/marketplace'} + , + ,
- + }> } /> + } + />
diff --git a/src/frontend/screens/WebView/index.css b/src/frontend/screens/WebView/index.scss similarity index 63% rename from src/frontend/screens/WebView/index.css rename to src/frontend/screens/WebView/index.scss index c9c3f2c0bd..65a268fcde 100644 --- a/src/frontend/screens/WebView/index.css +++ b/src/frontend/screens/WebView/index.scss @@ -1,7 +1,10 @@ +@import '@hyperplay/ui/utilities/_loading.scss'; + .WebView { grid-area: content; width: var(--content-width); position: relative; + width: 100%; } .WebView.collapsed { @@ -9,8 +12,9 @@ } .WebView__webview { - height: calc(100vh - 40px); - width: var(--content-width); + height: 100%; + width: 100%; + position: absolute; } .WebView__webview.collapsed { @@ -35,3 +39,18 @@ align-self: center; padding: var(--space-xl); } + +.webviewLoader { + @include shinyLoader; + height: 100%; + width: 100%; + position: absolute; + z-index: 0; +} + +.webviewContentContainer { + height: 100%; + width: 100%; + position: absolute; + z-index: 1; +} diff --git a/src/frontend/screens/WebView/index.tsx b/src/frontend/screens/WebView/index.tsx index 85e0ea1b6b..cf76dda24b 100644 --- a/src/frontend/screens/WebView/index.tsx +++ b/src/frontend/screens/WebView/index.tsx @@ -9,12 +9,11 @@ import { useTranslation } from 'react-i18next' import { useNavigate, useLocation, useParams } from 'react-router-dom' import { DidNavigateEvent, WebviewTag } from 'electron' -import { UpdateComponent } from 'frontend/components/UI' import WebviewControls from 'frontend/components/UI/WebviewControls' import ContextProvider from 'frontend/state/ContextProvider' import webviewNavigationStore from 'frontend/store/WebviewNavigationStore' import { Runner } from 'common/types' -import './index.css' +import './index.scss' import LoginWarning from '../Login/components/LoginWarning' import authState from 'frontend/state/authState' import { observer } from 'mobx-react-lite' @@ -100,6 +99,12 @@ function WebView({ startUrl = queryParam + queryParamAppends } + } else if (pathname.match('/marketplace')) { + const searchParams = new URLSearchParams(search) + const queryParam = searchParams.get('url') + if (queryParam) { + startUrl = decodeURIComponent(queryParam) + } } const isEpicLogin = runner === 'legendary' && startUrl === EPIC_LOGIN_URL @@ -270,35 +275,37 @@ function WebView({ if (pathname === '/game7Portal') partitionForWebview = 'persist:g7portal' if (urlIsHpUrl(startUrl)) partitionForWebview = 'persist:hyperplaystore' - else if (shouldInjectProvider(startUrl)) + else if (shouldInjectProvider(startUrl) || pathname.match('/marketplace')) partitionForWebview = 'persist:InPageWindowEthereumExternalWallet' return (
- {webviewRef.current && ( - - )} - {loading.refresh && } - - {showLoginWarningFor && ( -
+
+ {webviewRef.current && ( + + )} + - )} + {showLoginWarningFor && ( + + )} +
) }