1
0
mirror of https://github.com/oceanprotocol/market.git synced 2024-12-02 05:57:29 +01:00

Multinetwork UI additions (#729)

* add BSC to default chains

* searchbar visual tweaks

* race condition fix

* network name tweaks

* beta → v3

* use publish form titles to inform about network

* form actions refactor

* simplify network name on asset details

* visual indicator for selected chains on button

* lint fix

* more layout flow tinkering, collapsed search by default

* search field layout tweaks

* unknown network/gaia-x name fixes

* put back search cancel button in webkit

* space fixes

* cross browser visual fixes
This commit is contained in:
Matthias Kretschmann 2021-07-26 15:48:24 +02:00 committed by GitHub
parent ac1c1fd31a
commit a7998abb99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 402 additions and 296 deletions

View File

@ -5,7 +5,7 @@ module.exports = {
// List of chainIds which metadata cache queries will return by default. // List of chainIds which metadata cache queries will return by default.
// This preselects the Chains user preferences. // This preselects the Chains user preferences.
chainIds: [1, 137], chainIds: [1, 137, 56],
// List of all supported chainIds. Used to populate the Chains user preferences list. // List of all supported chainIds. Used to populate the Chains user preferences list.
chainIdsSupported: [1, 3, 4, 137, 80001, 1287, 56], chainIdsSupported: [1, 3, 4, 137, 80001, 1287, 56],

View File

@ -1,5 +1,6 @@
{ {
"title": "Publish", "title": "Publish",
"description": "Highlight the important features of your data set or algorithm to make it more discoverable and catch the interest of data consumers.", "description": "Highlight the important features of your data set or algorithm to make it more discoverable and catch the interest of data consumers.",
"warning": "Given the beta status, publishing on Ropsten or Rinkeby first is strongly recommended. Please familiarize yourself with [the market](https://oceanprotocol.com/technology/marketplaces), [the risks](https://blog.oceanprotocol.com/on-staking-on-data-in-ocean-market-3d8e09eb0a13), and the [Terms of Use](/terms)." "warning": "Given the beta status, publishing on Ropsten or Rinkeby first is strongly recommended. Please familiarize yourself with [the market](https://oceanprotocol.com/technology/marketplaces), [the risks](https://blog.oceanprotocol.com/on-staking-on-data-in-ocean-market-3d8e09eb0a13), and the [Terms of Use](/terms).",
"tooltipNetwork": "Assets are published into the network your wallet is connected to. Switch your wallet's network to publish into another one."
} }

View File

@ -10,19 +10,7 @@
.typeLabel { .typeLabel {
display: inline-block; display: inline-block;
text-transform: uppercase; text-transform: uppercase;
border-right: 1px solid var(--border-color);
padding-right: calc(var(--spacer) / 3.5);
margin-right: calc(var(--spacer) / 4);
border-left: 1px solid var(--border-color); border-left: 1px solid var(--border-color);
padding-left: calc(var(--spacer) / 3.5); padding-left: calc(var(--spacer) / 3.5);
margin-left: calc(var(--spacer) / 4); margin-left: calc(var(--spacer) / 4);
} }
.network {
display: inline-block;
}
.network svg {
vertical-align: baseline;
margin-bottom: -0.15em;
}

View File

@ -4,19 +4,16 @@ import classNames from 'classnames/bind'
import { ReactComponent as Compute } from '../../images/compute.svg' import { ReactComponent as Compute } from '../../images/compute.svg'
import { ReactComponent as Download } from '../../images/download.svg' import { ReactComponent as Download } from '../../images/download.svg'
import { ReactComponent as Lock } from '../../images/lock.svg' import { ReactComponent as Lock } from '../../images/lock.svg'
import NetworkName from './NetworkName'
const cx = classNames.bind(styles) const cx = classNames.bind(styles)
export default function AssetType({ export default function AssetType({
type, type,
accessType, accessType,
className, className
chainId
}: { }: {
type: string type: string
accessType: string accessType: string
chainId: number
className?: string className?: string
}): ReactElement { }): ReactElement {
const styleClasses = cx({ const styleClasses = cx({
@ -35,10 +32,6 @@ export default function AssetType({
<div className={styles.typeLabel}> <div className={styles.typeLabel}>
{type === 'dataset' ? 'data set' : 'algorithm'} {type === 'dataset' ? 'data set' : 'algorithm'}
</div> </div>
{/* TODO: networkId needs to come from the multinetwork DDO for each asset */}
{chainId && (
<NetworkName networkId={chainId} className={styles.network} minimal />
)}
</div> </div>
) )
} }

View File

@ -4,7 +4,6 @@
border-radius: var(--border-radius); border-radius: var(--border-radius);
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
box-shadow: 0 6px 17px 0 var(--box-shadow-color); box-shadow: 0 6px 17px 0 var(--box-shadow-color);
overflow: hidden;
padding: calc(var(--spacer) / 1.5); padding: calc(var(--spacer) / 1.5);
} }

View File

@ -49,7 +49,6 @@ export interface InputProps {
defaultChecked?: boolean defaultChecked?: boolean
size?: 'mini' | 'small' | 'large' | 'default' size?: 'mini' | 'small' | 'large' | 'default'
className?: string className?: string
divClassName?: string
} }
export default function Input(props: Partial<InputProps>): ReactElement { export default function Input(props: Partial<InputProps>): ReactElement {
@ -58,13 +57,10 @@ export default function Input(props: Partial<InputProps>): ReactElement {
const hasError = const hasError =
props.form?.touched[field.name] && props.form?.errors[field.name] props.form?.touched[field.name] && props.form?.errors[field.name]
const styleClasses = cx( const styleClasses = cx({
{ field: true,
field: true, hasError: hasError
hasError: hasError })
},
props.divClassName
)
return ( return (
<div <div

View File

@ -10,11 +10,11 @@
} }
.icon { .icon {
width: 1rem; width: 1em;
height: 1rem; height: 1em;
cursor: help; cursor: help;
display: inline-block; display: inline-block;
margin-bottom: -0.1rem; margin-bottom: -0.1em;
margin-left: calc(var(--spacer) / 6); margin-left: calc(var(--spacer) / 6);
fill: var(--color-secondary); fill: var(--color-secondary);
} }

View File

@ -70,5 +70,4 @@
position: absolute; position: absolute;
right: calc(var(--spacer) / 3); right: calc(var(--spacer) / 3);
bottom: calc(var(--spacer) / 3); bottom: calc(var(--spacer) / 3);
text-transform: uppercase !important;
} }

View File

@ -19,7 +19,6 @@ const AssetTeaser: React.FC<AssetTeaserProps> = ({
ddo, ddo,
price price
}: AssetTeaserProps) => { }: AssetTeaserProps) => {
const { config } = useOcean()
const { attributes } = ddo.findServiceByType('metadata') const { attributes } = ddo.findServiceByType('metadata')
const { name, type } = attributes.main const { name, type } = attributes.main
const { dataTokenInfo } = ddo const { dataTokenInfo } = ddo
@ -42,7 +41,6 @@ const AssetTeaser: React.FC<AssetTeaserProps> = ({
type={type} type={type}
accessType={accessType} accessType={accessType}
className={styles.typeDetails} className={styles.typeDetails}
chainId={ddo.chainId}
/> />
<div className={styles.content}> <div className={styles.content}>
@ -55,6 +53,7 @@ const AssetTeaser: React.FC<AssetTeaserProps> = ({
<footer className={styles.foot}> <footer className={styles.foot}>
<Price price={price} small /> <Price price={price} small />
<NetworkName networkId={ddo.chainId} className={styles.network} />
</footer> </footer>
</Link> </Link>
</article> </article>

View File

@ -2,88 +2,55 @@
width: 100%; width: 100%;
padding: calc(var(--spacer) / 2); padding: calc(var(--spacer) / 2);
display: flex; display: flex;
flex-wrap: wrap;
align-items: center; align-items: center;
justify-content: space-between;
flex-wrap: wrap;
} }
.logo { .logo {
order: 1;
white-space: nowrap; white-space: nowrap;
display: flex; display: flex;
flex: 0 0 auto;
flex-direction: row;
justify-content: center;
align-items: center; align-items: center;
} }
.navigation { .navigation {
width: auto; order: 3;
margin: 0; margin-top: calc(var(--spacer) / 2);
text-align: left; text-align: center;
border: none; border-top: 1px solid var(--border-color);
} border-bottom: 1px solid var(--border-color);
margin-left: -1rem;
.search { margin-right: -1rem;
display: flex; width: calc(100% + 2rem);
flex: 1 0 auto;
justify-content: center;
align-items: center;
align-self: flex-start;
padding-left: 20px;
margin-left: auto;
} }
.actions { .actions {
order: 2;
display: flex; display: flex;
flex: 0 0 auto;
flex-direction: row;
justify-content: center;
align-items: center;
align-self: flex-start;
} }
.title { .title {
display: none; display: none;
} }
@media (max-width: 38rem) {
.actions {
margin-left: auto;
}
.navigation {
order: 3;
display: block;
justify-content: center;
align-items: center;
margin-top: calc(var(--spacer) / 2);
text-align: center;
border-top: 1px solid var(--border-color);
border-bottom: 1px solid var(--border-color);
margin-left: -1rem;
margin-right: -1rem;
width: calc(50% + 2rem);
}
}
@media (max-width: 75rem) {
.navigation {
flex: 1 0 auto;
justify-content: left;
align-items: left;
}
.search {
flex: 0 0 100%;
padding-top: 10px;
order: 4;
}
}
@media screen and (min-width: 42rem) { @media screen and (min-width: 42rem) {
.menu {
justify-content: start;
}
.navigation { .navigation {
order: 2;
width: auto; width: auto;
margin: 0; margin: 0;
text-align: left; text-align: left;
border: none; border: none;
} }
.actions {
order: 3;
margin-left: auto;
}
} }
@media screen and (min-width: 55rem) { @media screen and (min-width: 55rem) {
@ -135,7 +102,7 @@
.link:hover, .link:hover,
.link:focus, .link:focus,
.link:active { .link:active {
color: var(--brand-grey); color: var(--font-color-text);
} }
.link[aria-current], .link[aria-current],

View File

@ -40,7 +40,7 @@ export default function Menu(): ReactElement {
<Link to="/" className={styles.logo}> <Link to="/" className={styles.logo}>
<Logo noWordmark /> <Logo noWordmark />
<h1 className={styles.title}> <h1 className={styles.title}>
{siteTitle} <Badge label="beta" /> {siteTitle} <Badge label="v3" />
</h1> </h1>
</Link> </Link>
@ -52,10 +52,8 @@ export default function Menu(): ReactElement {
))} ))}
</ul> </ul>
<div className={styles.search}>
<SearchBar />
</div>
<div className={styles.actions}> <div className={styles.actions}>
<SearchBar />
<Networks /> <Networks />
<Wallet /> <Wallet />
<UserPreferences /> <UserPreferences />

View File

@ -1,49 +1,72 @@
.search { .search {
display: flex; display: flex;
flex: 1 0 auto; position: relative;
align-self: stretch;
} }
.button { .button {
padding: calc(var(--spacer) / 6) calc(var(--spacer) / 3); color: var(--color-secondary);
cursor: pointer; cursor: pointer;
border: 1px solid var(--border-color); background: var(--background-content);
border-radius: var(--border-radius); border: none;
background-color: var(--background-content); box-shadow: none;
border-left: none; padding: 0;
white-space: nowrap; position: absolute;
min-width: 4rem; padding: calc(var(--spacer) / 4);
width: 100%;
right: 1px;
left: 1px;
top: 1px;
bottom: 1px;
z-index: -1;
} }
.button:hover, .button:hover,
.button:focus { .button:focus {
color: var(--brand-white); color: var(--font-color-text);
text-decoration: none;
transform: translate3d(0, -0.05rem, 0);
box-shadow: 0 12px 30px 0 rgba(0, 0, 0, 0.1);
} }
.input { .input {
height: 36px !important; background-color: transparent;
border-top-right-radius: 0px; height: 36px;
border-bottom-right-radius: 0px; margin: 0;
outline: 0;
padding-right: var(--spacer);
width: 0;
transition: none;
} }
.searchInput {
flex-grow: 2; .input:focus {
margin-bottom: 0px; width: calc(100% - var(--spacer));
background-color: var(--background-content);
position: fixed;
left: calc(var(--spacer) / 2);
right: 0;
z-index: 2;
}
@media screen and (min-width: 78rem) {
.input,
.input:focus {
width: auto;
position: relative;
left: initial;
right: initial;
}
.button {
width: auto;
left: auto;
background: none;
}
.input:focus + .button {
z-index: 3;
}
} }
.searchIcon { .searchIcon {
fill: var(--brand-grey-light); fill: currentColor;
transition: 0.2s ease-out; transition: 0.2s ease-out;
} width: var(--font-size-h5);
.search > div > div { height: var(--font-size-h5);
margin: 0;
}
.search label {
display: none;
}
.search input {
background-color: var(--background-content);
} }

View File

@ -3,36 +3,49 @@ import React, {
useEffect, useEffect,
ChangeEvent, ChangeEvent,
FormEvent, FormEvent,
KeyboardEvent,
ReactElement ReactElement
} from 'react' } from 'react'
import { navigate } from 'gatsby' import { navigate } from 'gatsby'
import queryString from 'query-string' import queryString from 'query-string'
import styles from './SearchBar.module.css'
import Button from '../atoms/Button'
import Input from '../atoms/Input'
import InputGroup from '../atoms/Input/InputGroup'
import { addExistingParamsToUrl } from '../templates/Search/utils' import { addExistingParamsToUrl } from '../templates/Search/utils'
import { ReactComponent as SearchIcon } from '../../images/search.svg' import { ReactComponent as SearchIcon } from '../../images/search.svg'
import InputElement from '../atoms/Input/InputElement'
import styles from './SearchBar.module.css'
async function emptySearch() {
const searchParams = new URLSearchParams(window.location.href)
const text = searchParams.get('text')
if (text !== ('' || undefined || null)) {
const url = await addExistingParamsToUrl(location, [
'text',
'owner',
'tags'
])
navigate(`${url}&text=%20`)
}
}
export default function SearchBar({ export default function SearchBar({
placeholder, placeholder,
initialValue, initialValue
size
}: { }: {
placeholder?: string placeholder?: string
initialValue?: string initialValue?: string
size?: 'small' | 'large'
}): ReactElement { }): ReactElement {
let [value, setValue] = useState(initialValue || '') const [value, setValue] = useState(initialValue || '')
const parsed = queryString.parse(location.search) const parsed = queryString.parse(location.search)
const { text, owner } = parsed const { text, owner } = parsed
useEffect(() => { useEffect(() => {
;(text || owner) && setValue((text || owner) as string) ;(text || owner) && setValue((text || owner) as string)
}, [text, owner]) }, [text, owner])
async function startSearch(e: FormEvent<HTMLButtonElement>) { async function startSearch(e: FormEvent<HTMLButtonElement>) {
e.preventDefault() e.preventDefault()
if (value === '') value = ' '
if (value === '') setValue(' ')
const urlEncodedValue = encodeURIComponent(value) const urlEncodedValue = encodeURIComponent(value)
const url = await addExistingParamsToUrl(location, [ const url = await addExistingParamsToUrl(location, [
'text', 'text',
@ -42,52 +55,38 @@ export default function SearchBar({
navigate(`${url}&text=${urlEncodedValue}`) navigate(`${url}&text=${urlEncodedValue}`)
} }
async function emptySearch() {
const searchParams = new URLSearchParams(window.location.href)
const text = searchParams.get('text')
if (text !== ('' || undefined || null)) {
const url = await addExistingParamsToUrl(location, [
'text',
'owner',
'tags'
])
navigate(`${url}&text=%20`)
}
}
function handleChange(e: ChangeEvent<HTMLInputElement>) { function handleChange(e: ChangeEvent<HTMLInputElement>) {
setValue(e.target.value) setValue(e.target.value)
e.target.value === '' && emptySearch() e.target.value === '' && emptySearch()
} }
async function handleKeyPress(e: KeyboardEvent<HTMLInputElement>) {
if (e.key === 'Enter') {
await startSearch(e)
}
}
async function handleButtonClick(e: FormEvent<HTMLButtonElement>) {
e.preventDefault()
await startSearch(e)
}
return ( return (
<form className={styles.search}> <form className={styles.search}>
<Input <InputElement
type="search" type="search"
name="search" name="search"
placeholder={placeholder || 'What are you looking for?'} placeholder={placeholder || 'Search...'}
value={value} value={value}
onChange={handleChange} onChange={handleChange}
required required
size="small" size="small"
divClassName={styles.searchInput}
className={styles.input} className={styles.input}
onKeyPress={async (e: React.KeyboardEvent<HTMLInputElement>) => { onKeyPress={handleKeyPress}
if (e.key === 'Enter') {
await startSearch(e)
}
}}
/> />
<Button <button onClick={handleButtonClick} className={styles.button}>
onClick={async (e: FormEvent<HTMLButtonElement>) =>
await startSearch(e)
}
style="text"
size="small"
className={styles.button}
>
<SearchIcon className={styles.searchIcon} /> <SearchIcon className={styles.searchIcon} />
</Button> </button>
</form> </form>
) )
} }

View File

@ -1,3 +1,22 @@
.network { .networks {
margin-right: calc(var(--spacer) / 3); margin-right: calc(var(--spacer) / 3);
position: relative;
overflow: hidden;
}
.chainsSelected {
text-align: center;
position: absolute;
bottom: -8px;
left: 0;
width: 100%;
}
.chainsSelectedIndicator {
width: 4px;
height: 4px;
border-radius: 50%;
margin: 0 1px;
display: inline-block;
background-color: var(--color-primary);
} }

View File

@ -10,6 +10,7 @@ import NetworksList from './NetworksList'
import stylesIndex from '../index.module.css' import stylesIndex from '../index.module.css'
import styles from './index.module.css' import styles from './index.module.css'
import useNetworkMetadata from '../../../../hooks/useNetworkMetadata' import useNetworkMetadata from '../../../../hooks/useNetworkMetadata'
import { useUserPreferences } from '../../../../providers/UserPreferences'
export function filterNetworksByType( export function filterNetworksByType(
type: 'mainnet' | 'testnet', type: 'mainnet' | 'testnet',
@ -32,6 +33,7 @@ export function filterNetworksByType(
export default function Networks(): ReactElement { export default function Networks(): ReactElement {
const { networksList } = useNetworkMetadata() const { networksList } = useNetworkMetadata()
const { appConfig } = useSiteMetadata() const { appConfig } = useSiteMetadata()
const { chainIds } = useUserPreferences()
const networksMain = filterNetworksByType( const networksMain = filterNetworksByType(
'mainnet', 'mainnet',
@ -59,10 +61,16 @@ export default function Networks(): ReactElement {
</ul> </ul>
} }
trigger="click focus" trigger="click focus"
className={`${stylesIndex.preferences} ${styles.network}`} className={`${stylesIndex.preferences} ${styles.networks}`}
> >
<Network aria-label="Networks" className={stylesIndex.icon} /> <Network aria-label="Networks" className={stylesIndex.icon} />
<Caret aria-hidden="true" /> <Caret aria-hidden="true" className={stylesIndex.caret} />
<div className={styles.chainsSelected}>
{chainIds.map((chainId) => (
<span className={styles.chainsSelectedIndicator} key={chainId} />
))}
</div>
</Tooltip> </Tooltip>
) )
} }

View File

@ -17,12 +17,21 @@
transform: rotate(180deg); transform: rotate(180deg);
} }
.preferences svg:last-child { .caret,
svg.caret {
width: var(--font-size-small); width: var(--font-size-small);
height: var(--font-size-small); height: var(--font-size-small);
fill: var(--border-color); fill: var(--border-color);
margin-left: calc(var(--spacer) / 4); margin-left: calc(var(--spacer) / 4);
transition: transform 0.2s ease-out; transition: transform 0.2s ease-out;
display: none;
}
@media screen and (min-width: 42rem) {
.caret,
svg.caret {
display: inline-block;
}
} }
.icon { .icon {

View File

@ -26,7 +26,7 @@ export default function UserPreferences(): ReactElement {
className={styles.preferences} className={styles.preferences}
> >
<Cog aria-label="Preferences" className={styles.icon} /> <Cog aria-label="Preferences" className={styles.icon} />
<Caret aria-hidden="true" /> <Caret aria-hidden="true" className={styles.caret} />
</Tooltip> </Tooltip>
) )
} }

View File

@ -31,6 +31,16 @@
color: var(--color-primary); color: var(--color-primary);
} }
.button.initial span {
display: none;
}
@media screen and (min-width: 42rem) {
.button.initial span {
display: inline;
}
}
.blockies { .blockies {
width: var(--font-size-large); width: var(--font-size-large);
height: var(--font-size-large); height: var(--font-size-large);
@ -76,3 +86,15 @@
position: relative; position: relative;
top: 1px; top: 1px;
} }
.caret,
svg.caret {
display: none;
}
@media screen and (min-width: 42rem) {
.caret,
svg.caret {
display: inline-block;
}
}

View File

@ -35,7 +35,7 @@ const Account = React.forwardRef((props, ref: any) => {
return !accountId && web3Modal?.cachedProvider ? ( return !accountId && web3Modal?.cachedProvider ? (
// Improve user experience for cached provider when connecting takes some time // Improve user experience for cached provider when connecting takes some time
<button className={styles.button} onClick={(e) => e.preventDefault()}> <button className={styles.button} onClick={(e) => e.preventDefault()}>
<Loader message="Reconnecting wallet..." /> <Loader message="Reconnecting..." />
</button> </button>
) : accountId ? ( ) : accountId ? (
<button <button
@ -48,7 +48,7 @@ const Account = React.forwardRef((props, ref: any) => {
<span className={styles.address} title={accountId}> <span className={styles.address} title={accountId}>
{accountTruncate(accountId)} {accountTruncate(accountId)}
</span> </span>
<Caret aria-hidden="true" /> <Caret aria-hidden="true" className={styles.caret} />
</button> </button>
) : ( ) : (
<button <button
@ -58,7 +58,7 @@ const Account = React.forwardRef((props, ref: any) => {
// the Tippy to show in this state. // the Tippy to show in this state.
ref={ref} ref={ref}
> >
Connect Wallet Connect <span>Wallet</span>
</button> </button>
) )
}) })

View File

@ -32,6 +32,8 @@ export default function Details(): ReactElement {
// const [portisNetwork, setPortisNetwork] = useState<string>() // const [portisNetwork, setPortisNetwork] = useState<string>()
useEffect(() => { useEffect(() => {
if (!networkId) return
const symbol = const symbol =
networkId === 2021000 ? 'GX' : networkData?.nativeCurrency.symbol networkId === 2021000 ? 'GX' : networkData?.nativeCurrency.symbol
setMainCurrency(symbol) setMainCurrency(symbol)

View File

@ -1,4 +1,4 @@
import React, { ReactElement, useState } from 'react' import React, { ReactElement } from 'react'
import Account from './Account' import Account from './Account'
import Details from './Details' import Details from './Details'
import Tooltip from '../../atoms/Tooltip' import Tooltip from '../../atoms/Tooltip'

View File

@ -1,6 +1,6 @@
.bookmark { .bookmark {
position: absolute; position: absolute;
top: -10px; top: -3px;
right: calc(var(--spacer) / 8); right: calc(var(--spacer) / 8);
appearance: none; appearance: none;
background: none; background: none;
@ -20,7 +20,7 @@
.bookmark:hover, .bookmark:hover,
.bookmark:focus { .bookmark:focus {
transform: translate3d(0, 6px, 0); transform: translate3d(0, -3px, 0);
} }
.bookmark.active svg { .bookmark.active svg {

View File

@ -20,7 +20,6 @@ export default function MetaMain(): ReactElement {
<AssetType <AssetType
type={type} type={type}
accessType={accessType} accessType={accessType}
chainId={ddo.chainId}
className={styles.assetType} className={styles.assetType}
/> />
<ExplorerLink <ExplorerLink

View File

@ -1,8 +1,13 @@
.networkWrap {
display: block;
margin-top: -1rem;
}
.grid { .grid {
display: grid; display: grid;
gap: calc(var(--spacer) * 1.5); gap: calc(var(--spacer) * 1.5);
position: relative; position: relative;
margin-top: -1.5rem; margin-top: -1rem;
} }
.grid > div { .grid > div {

View File

@ -19,6 +19,7 @@ import { useWeb3 } from '../../../providers/Web3'
import styles from './index.module.css' import styles from './index.module.css'
import EditAdvancedSettings from '../AssetActions/Edit/EditAdvancedSettings' import EditAdvancedSettings from '../AssetActions/Edit/EditAdvancedSettings'
import { useSiteMetadata } from '../../../hooks/useSiteMetadata' import { useSiteMetadata } from '../../../hooks/useSiteMetadata'
import NetworkName from '../../atoms/NetworkName'
export interface AssetContentProps { export interface AssetContentProps {
path?: string path?: string
@ -87,72 +88,82 @@ export default function AssetContent(props: AssetContentProps): ReactElement {
) : showEditAdvancedSettings ? ( ) : showEditAdvancedSettings ? (
<EditAdvancedSettings setShowEdit={setShowEditAdvancedSettings} /> <EditAdvancedSettings setShowEdit={setShowEditAdvancedSettings} />
) : ( ) : (
<article className={styles.grid}> <>
<div> <div className={styles.networkWrap}>
{showPricing && <Pricing ddo={ddo} />} <NetworkName networkId={ddo.chainId} className={styles.network} />
<div className={styles.content}> </div>
<MetaMain />
<Bookmark did={ddo.id} />
{isInPurgatory ? ( <article className={styles.grid}>
<Alert <div>
title={content.title} {showPricing && <Pricing ddo={ddo} />}
badge={`Reason: ${purgatoryData?.reason}`} <div className={styles.content}>
text={content.description} <MetaMain />
state="error" <Bookmark did={ddo.id} />
/>
) : ( {isInPurgatory ? (
<> <Alert
<Markdown title={content.title}
className={styles.description} badge={`Reason: ${purgatoryData?.reason}`}
text={metadata?.additionalInformation?.description || ''} text={content.description}
state="error"
/> />
) : (
<>
<Markdown
className={styles.description}
text={metadata?.additionalInformation?.description || ''}
/>
<MetaSecondary /> <MetaSecondary />
{isOwner && isAssetNetwork && ( {isOwner && isAssetNetwork && (
<div className={styles.ownerActions}> <div className={styles.ownerActions}>
<Button style="text" size="small" onClick={handleEditButton}> <Button
Edit Metadata style="text"
</Button> size="small"
{appConfig.allowAdvancedSettings === 'true' && ( onClick={handleEditButton}
<> >
<span className={styles.separator}>|</span> Edit Metadata
<Button </Button>
style="text" {appConfig.allowAdvancedSettings === 'true' && (
size="small" <>
onClick={handleEditAdvancedSettingsButton} <span className={styles.separator}>|</span>
> <Button
Edit Advanced Settings style="text"
</Button> size="small"
</> onClick={handleEditAdvancedSettingsButton}
)} >
{ddo.findServiceByType('compute') && type === 'dataset' && ( Edit Advanced Settings
<> </Button>
<span className={styles.separator}>|</span> </>
<Button )}
style="text" {ddo.findServiceByType('compute') && type === 'dataset' && (
size="small" <>
onClick={handleEditComputeButton} <span className={styles.separator}>|</span>
> <Button
Edit Compute Settings style="text"
</Button> size="small"
</> onClick={handleEditComputeButton}
)} >
</div> Edit Compute Settings
)} </Button>
</> </>
)} )}
</div>
)}
</>
)}
<MetaFull /> <MetaFull />
<EditHistory /> <EditHistory />
{debug === true && <DebugOutput title="DDO" output={ddo} />} {debug === true && <DebugOutput title="DDO" output={ddo} />}
</div>
</div> </div>
</div>
<div className={styles.actions}> <div className={styles.actions}>
<AssetActions /> <AssetActions />
</div> </div>
</article> </article>
</>
) )
} }

View File

@ -0,0 +1,5 @@
.actions {
display: flex;
justify-content: space-between;
align-items: center;
}

View File

@ -0,0 +1,32 @@
import React, { FormEvent, ReactElement } from 'react'
import { useOcean } from '../../../providers/Ocean'
import Button from '../../atoms/Button'
import styles from './FormActions.module.css'
export default function FormActions({
isValid,
resetFormAndClearStorage
}: {
isValid: boolean
resetFormAndClearStorage: (e: FormEvent<Element>) => void
}): ReactElement {
const { ocean, account } = useOcean()
return (
<footer className={styles.actions}>
<Button
style="primary"
type="submit"
disabled={!ocean || !account || !isValid || status === 'empty'}
>
Submit
</Button>
{status !== 'empty' && (
<Button style="text" size="small" onClick={resetFormAndClearStorage}>
Reset Form
</Button>
)}
</footer>
)
}

View File

@ -6,15 +6,14 @@ import React, {
ChangeEvent ChangeEvent
} from 'react' } from 'react'
import { useStaticQuery, graphql } from 'gatsby' import { useStaticQuery, graphql } from 'gatsby'
import styles from './FormPublish.module.css'
import { useOcean } from '../../../providers/Ocean'
import { useFormikContext, Field, Form, FormikContextType } from 'formik' import { useFormikContext, Field, Form, FormikContextType } from 'formik'
import Input from '../../atoms/Input' import Input from '../../atoms/Input'
import Button from '../../atoms/Button'
import { FormContent, FormFieldProps } from '../../../@types/Form' import { FormContent, FormFieldProps } from '../../../@types/Form'
import { MetadataPublishFormAlgorithm } from '../../../@types/MetaData' import { MetadataPublishFormAlgorithm } from '../../../@types/MetaData'
import { initialValues as initialValuesAlgorithm } from '../../../models/FormAlgoPublish' import { initialValues as initialValuesAlgorithm } from '../../../models/FormAlgoPublish'
import stylesIndex from './index.module.css' import FormTitle from './FormTitle'
import FormActions from './FormActions'
import styles from './FormPublish.module.css'
const query = graphql` const query = graphql`
query { query {
@ -46,7 +45,7 @@ const query = graphql`
export default function FormPublish(): ReactElement { export default function FormPublish(): ReactElement {
const data = useStaticQuery(query) const data = useStaticQuery(query)
const content: FormContent = data.content.edges[0].node.childPublishJson const content: FormContent = data.content.edges[0].node.childPublishJson
const { ocean, account } = useOcean()
const { const {
status, status,
setStatus, setStatus,
@ -142,7 +141,8 @@ export default function FormPublish(): ReactElement {
// do we need this? // do we need this?
onChange={() => status === 'empty' && setStatus(null)} onChange={() => status === 'empty' && setStatus(null)}
> >
<h2 className={stylesIndex.formTitle}>{content.title}</h2> <FormTitle title={content.title} />
{content.data.map( {content.data.map(
(field: FormFieldProps) => (field: FormFieldProps) =>
((field.name !== 'entrypoint' && ((field.name !== 'entrypoint' &&
@ -165,21 +165,10 @@ export default function FormPublish(): ReactElement {
) )
)} )}
<footer className={styles.actions}> <FormActions
<Button isValid={isValid}
style="primary" resetFormAndClearStorage={resetFormAndClearStorage}
type="submit" />
disabled={!ocean || !account || !isValid || status === 'empty'}
>
Submit
</Button>
{status !== 'empty' && (
<Button style="text" size="small" onClick={resetFormAndClearStorage}>
Reset Form
</Button>
)}
</footer>
</Form> </Form>
) )
} }

View File

@ -5,9 +5,3 @@
border-top-left-radius: 0; border-top-left-radius: 0;
border-top-right-radius: 0; border-top-right-radius: 0;
} }
.actions {
display: flex;
justify-content: space-between;
align-items: center;
}

View File

@ -2,14 +2,14 @@ import React, { ReactElement, useEffect, FormEvent, ChangeEvent } from 'react'
import { useStaticQuery, graphql } from 'gatsby' import { useStaticQuery, graphql } from 'gatsby'
import { useFormikContext, Field, Form, FormikContextType } from 'formik' import { useFormikContext, Field, Form, FormikContextType } from 'formik'
import Input from '../../atoms/Input' import Input from '../../atoms/Input'
import Button from '../../atoms/Button'
import { FormContent, FormFieldProps } from '../../../@types/Form' import { FormContent, FormFieldProps } from '../../../@types/Form'
import { MetadataPublishFormDataset } from '../../../@types/MetaData' import { MetadataPublishFormDataset } from '../../../@types/MetaData'
import { initialValues as initialValuesDataset } from '../../../models/FormAlgoPublish' import { initialValues as initialValuesDataset } from '../../../models/FormAlgoPublish'
import { useOcean } from '../../../providers/Ocean' import { useOcean } from '../../../providers/Ocean'
import { ReactComponent as Download } from '../../../images/download.svg' import { ReactComponent as Download } from '../../../images/download.svg'
import { ReactComponent as Compute } from '../../../images/compute.svg' import { ReactComponent as Compute } from '../../../images/compute.svg'
import stylesIndex from './index.module.css' import FormTitle from './FormTitle'
import FormActions from './FormActions'
import styles from './FormPublish.module.css' import styles from './FormPublish.module.css'
const query = graphql` const query = graphql`
@ -42,6 +42,7 @@ const query = graphql`
export default function FormPublish(): ReactElement { export default function FormPublish(): ReactElement {
const data = useStaticQuery(query) const data = useStaticQuery(query)
const content: FormContent = data.content.edges[0].node.childPublishJson const content: FormContent = data.content.edges[0].node.childPublishJson
const { ocean, account } = useOcean() const { ocean, account } = useOcean()
const { const {
status, status,
@ -50,7 +51,6 @@ export default function FormPublish(): ReactElement {
setErrors, setErrors,
setTouched, setTouched,
resetForm, resetForm,
initialValues,
validateField, validateField,
setFieldValue setFieldValue
}: FormikContextType<MetadataPublishFormDataset> = useFormikContext() }: FormikContextType<MetadataPublishFormDataset> = useFormikContext()
@ -104,7 +104,8 @@ export default function FormPublish(): ReactElement {
// do we need this? // do we need this?
onChange={() => status === 'empty' && setStatus(null)} onChange={() => status === 'empty' && setStatus(null)}
> >
<h2 className={stylesIndex.formTitle}>{content.title}</h2> <FormTitle title={content.title} />
{content.data.map((field: FormFieldProps) => ( {content.data.map((field: FormFieldProps) => (
<Field <Field
key={field.name} key={field.name}
@ -119,21 +120,10 @@ export default function FormPublish(): ReactElement {
/> />
))} ))}
<footer className={styles.actions}> <FormActions
<Button isValid={isValid}
style="primary" resetFormAndClearStorage={resetFormAndClearStorage}
type="submit" />
disabled={!ocean || !account || !isValid || status === 'empty'}
>
Submit
</Button>
{status !== 'empty' && (
<Button style="text" size="small" onClick={resetFormAndClearStorage}>
Reset Form
</Button>
)}
</footer>
</Form> </Form>
) )
} }

View File

@ -0,0 +1,21 @@
.title {
font-size: var(--font-size-h4);
display: inline-flex;
}
.network {
color: var(--font-color-heading);
margin-left: calc(var(--spacer) / 8);
}
.network svg {
width: 1em;
height: 1em;
margin-top: -0.25em;
fill: var(--color-secondary);
}
.tooltip {
width: 0.75em;
height: 0.75em;
}

View File

@ -0,0 +1,42 @@
import React, { ReactElement } from 'react'
import NetworkName from '../../atoms/NetworkName'
import Tooltip from '../../atoms/Tooltip'
import { useWeb3 } from '../../../providers/Web3'
import styles from './FormTitle.module.css'
import { graphql, useStaticQuery } from 'gatsby'
const query = graphql`
query {
content: allFile(
filter: { relativePath: { eq: "pages/publish/index.json" } }
) {
edges {
node {
childPublishJson {
tooltipNetwork
}
}
}
}
}
`
export default function FormTitle({ title }: { title: string }): ReactElement {
const data = useStaticQuery(query)
const contentTooltip =
data.content.edges[0].node.childPublishJson.tooltipNetwork
const { networkId } = useWeb3()
return (
<h2 className={styles.title}>
{title}{' '}
{networkId && (
<>
into <NetworkName networkId={networkId} className={styles.network} />
<Tooltip content={contentTooltip} className={styles.tooltip} />
</>
)}
</h2>
)
}

View File

@ -39,7 +39,3 @@ div.alert {
top: calc(var(--spacer) / 2); top: calc(var(--spacer) / 2);
} }
} }
.formTitle {
font-size: var(--font-size-h4);
}

View File

@ -1 +1,3 @@
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd"><path d="M15.853 16.56c-1.683 1.517-3.911 2.44-6.353 2.44-5.243 0-9.5-4.257-9.5-9.5s4.257-9.5 9.5-9.5 9.5 4.257 9.5 9.5c0 2.442-.923 4.67-2.44 6.353l7.44 7.44-.707.707-7.44-7.44zm-6.353-15.56c4.691 0 8.5 3.809 8.5 8.5s-3.809 8.5-8.5 8.5-8.5-3.809-8.5-8.5 3.809-8.5 8.5-8.5z"/></svg> <svg width="19" height="19" viewBox="0 0 19 19" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.5846 12.6731C10.3622 13.6572 8.81213 14.2501 7.12507 14.2501C3.19599 14.2501 0 11.0534 0 7.12507C0 3.19599 3.19599 0 7.12507 0C11.0542 0 14.2501 3.19599 14.2501 7.12507C14.2501 8.7963 13.6675 10.3329 12.6993 11.549L18.7698 17.6496C19.0778 17.9591 19.077 18.4603 18.7667 18.769C18.4555 19.0778 17.9552 19.077 17.6472 18.7667L11.5846 12.6731ZM12.6668 7.12507C12.6668 4.06921 10.1801 1.58335 7.12507 1.58335C4.06921 1.58335 1.58335 4.06921 1.58335 7.12507C1.58335 10.1801 4.06921 12.6668 7.12507 12.6668C10.1801 12.6668 12.6668 10.1801 12.6668 7.12507Z" />
</svg>

Before

Width:  |  Height:  |  Size: 385 B

After

Width:  |  Height:  |  Size: 698 B

View File

@ -40,8 +40,6 @@ export function getNetworkDisplayName(
data: EthereumListsChain, data: EthereumListsChain,
networkId: number networkId: number
): string { ): string {
if (!data) return 'Unknown'
let displayName let displayName
switch (networkId) { switch (networkId) {
@ -61,9 +59,9 @@ export function getNetworkDisplayName(
displayName = 'GAIA-X' displayName = 'GAIA-X'
break break
default: default:
displayName = `${data.chain} ${ displayName = data
data.network === 'mainnet' ? '' : data.network ? `${data.chain} ${data.network === 'mainnet' ? '' : data.network}`
}` : 'Unknown'
break break
} }