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.
// 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.
chainIdsSupported: [1, 3, 4, 137, 80001, 1287, 56],

View File

@ -1,5 +1,6 @@
{
"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.",
"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 {
display: inline-block;
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);
padding-left: calc(var(--spacer) / 3.5);
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 Download } from '../../images/download.svg'
import { ReactComponent as Lock } from '../../images/lock.svg'
import NetworkName from './NetworkName'
const cx = classNames.bind(styles)
export default function AssetType({
type,
accessType,
className,
chainId
className
}: {
type: string
accessType: string
chainId: number
className?: string
}): ReactElement {
const styleClasses = cx({
@ -35,10 +32,6 @@ export default function AssetType({
<div className={styles.typeLabel}>
{type === 'dataset' ? 'data set' : 'algorithm'}
</div>
{/* TODO: networkId needs to come from the multinetwork DDO for each asset */}
{chainId && (
<NetworkName networkId={chainId} className={styles.network} minimal />
)}
</div>
)
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,36 +3,49 @@ import React, {
useEffect,
ChangeEvent,
FormEvent,
KeyboardEvent,
ReactElement
} from 'react'
import { navigate } from 'gatsby'
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 { 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({
placeholder,
initialValue,
size
initialValue
}: {
placeholder?: string
initialValue?: string
size?: 'small' | 'large'
}): ReactElement {
let [value, setValue] = useState(initialValue || '')
const [value, setValue] = useState(initialValue || '')
const parsed = queryString.parse(location.search)
const { text, owner } = parsed
useEffect(() => {
;(text || owner) && setValue((text || owner) as string)
}, [text, owner])
async function startSearch(e: FormEvent<HTMLButtonElement>) {
e.preventDefault()
if (value === '') value = ' '
if (value === '') setValue(' ')
const urlEncodedValue = encodeURIComponent(value)
const url = await addExistingParamsToUrl(location, [
'text',
@ -42,52 +55,38 @@ export default function SearchBar({
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>) {
setValue(e.target.value)
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 (
<form className={styles.search}>
<Input
<InputElement
type="search"
name="search"
placeholder={placeholder || 'What are you looking for?'}
placeholder={placeholder || 'Search...'}
value={value}
onChange={handleChange}
required
size="small"
divClassName={styles.searchInput}
className={styles.input}
onKeyPress={async (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
await startSearch(e)
}
}}
onKeyPress={handleKeyPress}
/>
<Button
onClick={async (e: FormEvent<HTMLButtonElement>) =>
await startSearch(e)
}
style="text"
size="small"
className={styles.button}
>
<button onClick={handleButtonClick} className={styles.button}>
<SearchIcon className={styles.searchIcon} />
</Button>
</button>
</form>
)
}

View File

@ -1,3 +1,22 @@
.network {
.networks {
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 styles from './index.module.css'
import useNetworkMetadata from '../../../../hooks/useNetworkMetadata'
import { useUserPreferences } from '../../../../providers/UserPreferences'
export function filterNetworksByType(
type: 'mainnet' | 'testnet',
@ -32,6 +33,7 @@ export function filterNetworksByType(
export default function Networks(): ReactElement {
const { networksList } = useNetworkMetadata()
const { appConfig } = useSiteMetadata()
const { chainIds } = useUserPreferences()
const networksMain = filterNetworksByType(
'mainnet',
@ -59,10 +61,16 @@ export default function Networks(): ReactElement {
</ul>
}
trigger="click focus"
className={`${stylesIndex.preferences} ${styles.network}`}
className={`${stylesIndex.preferences} ${styles.networks}`}
>
<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>
)
}

View File

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

View File

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

View File

@ -31,6 +31,16 @@
color: var(--color-primary);
}
.button.initial span {
display: none;
}
@media screen and (min-width: 42rem) {
.button.initial span {
display: inline;
}
}
.blockies {
width: var(--font-size-large);
height: var(--font-size-large);
@ -76,3 +86,15 @@
position: relative;
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 ? (
// Improve user experience for cached provider when connecting takes some time
<button className={styles.button} onClick={(e) => e.preventDefault()}>
<Loader message="Reconnecting wallet..." />
<Loader message="Reconnecting..." />
</button>
) : accountId ? (
<button
@ -48,7 +48,7 @@ const Account = React.forwardRef((props, ref: any) => {
<span className={styles.address} title={accountId}>
{accountTruncate(accountId)}
</span>
<Caret aria-hidden="true" />
<Caret aria-hidden="true" className={styles.caret} />
</button>
) : (
<button
@ -58,7 +58,7 @@ const Account = React.forwardRef((props, ref: any) => {
// the Tippy to show in this state.
ref={ref}
>
Connect Wallet
Connect <span>Wallet</span>
</button>
)
})

View File

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

View File

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

View File

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

View File

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

View File

@ -19,6 +19,7 @@ import { useWeb3 } from '../../../providers/Web3'
import styles from './index.module.css'
import EditAdvancedSettings from '../AssetActions/Edit/EditAdvancedSettings'
import { useSiteMetadata } from '../../../hooks/useSiteMetadata'
import NetworkName from '../../atoms/NetworkName'
export interface AssetContentProps {
path?: string
@ -87,72 +88,82 @@ export default function AssetContent(props: AssetContentProps): ReactElement {
) : showEditAdvancedSettings ? (
<EditAdvancedSettings setShowEdit={setShowEditAdvancedSettings} />
) : (
<article className={styles.grid}>
<div>
{showPricing && <Pricing ddo={ddo} />}
<div className={styles.content}>
<MetaMain />
<Bookmark did={ddo.id} />
<>
<div className={styles.networkWrap}>
<NetworkName networkId={ddo.chainId} className={styles.network} />
</div>
{isInPurgatory ? (
<Alert
title={content.title}
badge={`Reason: ${purgatoryData?.reason}`}
text={content.description}
state="error"
/>
) : (
<>
<Markdown
className={styles.description}
text={metadata?.additionalInformation?.description || ''}
<article className={styles.grid}>
<div>
{showPricing && <Pricing ddo={ddo} />}
<div className={styles.content}>
<MetaMain />
<Bookmark did={ddo.id} />
{isInPurgatory ? (
<Alert
title={content.title}
badge={`Reason: ${purgatoryData?.reason}`}
text={content.description}
state="error"
/>
) : (
<>
<Markdown
className={styles.description}
text={metadata?.additionalInformation?.description || ''}
/>
<MetaSecondary />
<MetaSecondary />
{isOwner && isAssetNetwork && (
<div className={styles.ownerActions}>
<Button style="text" size="small" onClick={handleEditButton}>
Edit Metadata
</Button>
{appConfig.allowAdvancedSettings === 'true' && (
<>
<span className={styles.separator}>|</span>
<Button
style="text"
size="small"
onClick={handleEditAdvancedSettingsButton}
>
Edit Advanced Settings
</Button>
</>
)}
{ddo.findServiceByType('compute') && type === 'dataset' && (
<>
<span className={styles.separator}>|</span>
<Button
style="text"
size="small"
onClick={handleEditComputeButton}
>
Edit Compute Settings
</Button>
</>
)}
</div>
)}
</>
)}
{isOwner && isAssetNetwork && (
<div className={styles.ownerActions}>
<Button
style="text"
size="small"
onClick={handleEditButton}
>
Edit Metadata
</Button>
{appConfig.allowAdvancedSettings === 'true' && (
<>
<span className={styles.separator}>|</span>
<Button
style="text"
size="small"
onClick={handleEditAdvancedSettingsButton}
>
Edit Advanced Settings
</Button>
</>
)}
{ddo.findServiceByType('compute') && type === 'dataset' && (
<>
<span className={styles.separator}>|</span>
<Button
style="text"
size="small"
onClick={handleEditComputeButton}
>
Edit Compute Settings
</Button>
</>
)}
</div>
)}
</>
)}
<MetaFull />
<EditHistory />
{debug === true && <DebugOutput title="DDO" output={ddo} />}
<MetaFull />
<EditHistory />
{debug === true && <DebugOutput title="DDO" output={ddo} />}
</div>
</div>
</div>
<div className={styles.actions}>
<AssetActions />
</div>
</article>
<div className={styles.actions}>
<AssetActions />
</div>
</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
} from 'react'
import { useStaticQuery, graphql } from 'gatsby'
import styles from './FormPublish.module.css'
import { useOcean } from '../../../providers/Ocean'
import { useFormikContext, Field, Form, FormikContextType } from 'formik'
import Input from '../../atoms/Input'
import Button from '../../atoms/Button'
import { FormContent, FormFieldProps } from '../../../@types/Form'
import { MetadataPublishFormAlgorithm } from '../../../@types/MetaData'
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`
query {
@ -46,7 +45,7 @@ const query = graphql`
export default function FormPublish(): ReactElement {
const data = useStaticQuery(query)
const content: FormContent = data.content.edges[0].node.childPublishJson
const { ocean, account } = useOcean()
const {
status,
setStatus,
@ -142,7 +141,8 @@ export default function FormPublish(): ReactElement {
// do we need this?
onChange={() => status === 'empty' && setStatus(null)}
>
<h2 className={stylesIndex.formTitle}>{content.title}</h2>
<FormTitle title={content.title} />
{content.data.map(
(field: FormFieldProps) =>
((field.name !== 'entrypoint' &&
@ -165,21 +165,10 @@ export default function FormPublish(): ReactElement {
)
)}
<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>
<FormActions
isValid={isValid}
resetFormAndClearStorage={resetFormAndClearStorage}
/>
</Form>
)
}

View File

@ -5,9 +5,3 @@
border-top-left-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 { useFormikContext, Field, Form, FormikContextType } from 'formik'
import Input from '../../atoms/Input'
import Button from '../../atoms/Button'
import { FormContent, FormFieldProps } from '../../../@types/Form'
import { MetadataPublishFormDataset } from '../../../@types/MetaData'
import { initialValues as initialValuesDataset } from '../../../models/FormAlgoPublish'
import { useOcean } from '../../../providers/Ocean'
import { ReactComponent as Download } from '../../../images/download.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'
const query = graphql`
@ -42,6 +42,7 @@ const query = graphql`
export default function FormPublish(): ReactElement {
const data = useStaticQuery(query)
const content: FormContent = data.content.edges[0].node.childPublishJson
const { ocean, account } = useOcean()
const {
status,
@ -50,7 +51,6 @@ export default function FormPublish(): ReactElement {
setErrors,
setTouched,
resetForm,
initialValues,
validateField,
setFieldValue
}: FormikContextType<MetadataPublishFormDataset> = useFormikContext()
@ -104,7 +104,8 @@ export default function FormPublish(): ReactElement {
// do we need this?
onChange={() => status === 'empty' && setStatus(null)}
>
<h2 className={stylesIndex.formTitle}>{content.title}</h2>
<FormTitle title={content.title} />
{content.data.map((field: FormFieldProps) => (
<Field
key={field.name}
@ -119,21 +120,10 @@ export default function FormPublish(): ReactElement {
/>
))}
<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>
<FormActions
isValid={isValid}
resetFormAndClearStorage={resetFormAndClearStorage}
/>
</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);
}
}
.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,
networkId: number
): string {
if (!data) return 'Unknown'
let displayName
switch (networkId) {
@ -61,9 +59,9 @@ export function getNetworkDisplayName(
displayName = 'GAIA-X'
break
default:
displayName = `${data.chain} ${
data.network === 'mainnet' ? '' : data.network
}`
displayName = data
? `${data.chain} ${data.network === 'mainnet' ? '' : data.network}`
: 'Unknown'
break
}