mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
Data Partners (#214)
* datapartners prototype * output partner name on asset teasers * badge, output partner data * deprioritize pool badge * teaser spacing tweaks * styling * carousel pattern * carousel fixes * styling tweaks * cleanup, useDataPartner hook * large screen fixes * add partner badge to all data set list titles * byline links tweaks * byline tweaks * switch list data source * fixes, link to https://github.com/oceanprotocol/list-datapartners * refactor * refactor
This commit is contained in:
parent
b55362f309
commit
ad107c5415
18
package-lock.json
generated
18
package-lock.json
generated
@ -3866,6 +3866,11 @@
|
|||||||
"web3-eth-contract": "^1.3.0"
|
"web3-eth-contract": "^1.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@oceanprotocol/list-datapartners": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oceanprotocol/list-datapartners/-/list-datapartners-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-FkavpY56HhTLZetBNH0NXE6t+5G/0lF8r8LFHwcFBNpyLba87tPe30PqzR++4W9Ilrf4KnpU8pHfL6NwYzv8nw=="
|
||||||
|
},
|
||||||
"@oceanprotocol/react": {
|
"@oceanprotocol/react": {
|
||||||
"version": "0.3.16",
|
"version": "0.3.16",
|
||||||
"resolved": "https://registry.npmjs.org/@oceanprotocol/react/-/react-0.3.16.tgz",
|
"resolved": "https://registry.npmjs.org/@oceanprotocol/react/-/react-0.3.16.tgz",
|
||||||
@ -27964,6 +27969,14 @@
|
|||||||
"prop-types": "^15.6.2"
|
"prop-types": "^15.6.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-alice-carousel": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-alice-carousel/-/react-alice-carousel-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-Uy9tOPAmwazPbq9uTygkk0zvCbMDWrtiBk7XnK5DTxkN3dLGxaCL3AKiCLLQOfnKbxZRGyXROLjlGYZ1aEpALg==",
|
||||||
|
"requires": {
|
||||||
|
"vanilla-swipe": "^2.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-color": {
|
"react-color": {
|
||||||
"version": "2.18.1",
|
"version": "2.18.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-color/-/react-color-2.18.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-color/-/react-color-2.18.1.tgz",
|
||||||
@ -33685,6 +33698,11 @@
|
|||||||
"spdx-expression-parse": "^3.0.0"
|
"spdx-expression-parse": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"vanilla-swipe": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vanilla-swipe/-/vanilla-swipe-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-iNXEIpPTe2KMOzHyi0lKP9rSSHry+SoHAc0aBHH4xcJBjKX5cnw6DcxgT3OoWsqxHQ6O1wmG4PAG9BOzzR5jGQ=="
|
||||||
|
},
|
||||||
"varint": {
|
"varint": {
|
||||||
"version": "5.0.2",
|
"version": "5.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz",
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
"@loadable/component": "5.13.1",
|
"@loadable/component": "5.13.1",
|
||||||
"@oceanprotocol/art": "^3.0.0",
|
"@oceanprotocol/art": "^3.0.0",
|
||||||
"@oceanprotocol/lib": "^0.9.9",
|
"@oceanprotocol/lib": "^0.9.9",
|
||||||
|
"@oceanprotocol/list-datapartners": "^1.0.0",
|
||||||
"@oceanprotocol/react": "^0.3.16",
|
"@oceanprotocol/react": "^0.3.16",
|
||||||
"@oceanprotocol/typographies": "^0.1.0",
|
"@oceanprotocol/typographies": "^0.1.0",
|
||||||
"@sindresorhus/slugify": "^1.0.0",
|
"@sindresorhus/slugify": "^1.0.0",
|
||||||
@ -62,6 +63,7 @@
|
|||||||
"lodash.omit": "^4.5.0",
|
"lodash.omit": "^4.5.0",
|
||||||
"query-string": "^6.13.6",
|
"query-string": "^6.13.6",
|
||||||
"react": "^16.14.0",
|
"react": "^16.14.0",
|
||||||
|
"react-alice-carousel": "^2.0.2",
|
||||||
"react-data-table-component": "^6.11.5",
|
"react-data-table-component": "^6.11.5",
|
||||||
"react-datepicker": "^3.3.0",
|
"react-datepicker": "^3.3.0",
|
||||||
"react-dom": "^16.14.0",
|
"react-dom": "^16.14.0",
|
||||||
|
@ -9,6 +9,12 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width: 2000px) {
|
||||||
|
.app {
|
||||||
|
background-size: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.app > * {
|
.app > * {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
24
src/components/atoms/Partner.module.css
Normal file
24
src/components/atoms/Partner.module.css
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
.partner {
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
|
margin-top: calc(var(--spacer) / 8);
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
composes: badge from '../atoms/Badge.module.css';
|
||||||
|
border-radius: 50%;
|
||||||
|
width: var(--font-size-h4);
|
||||||
|
height: var(--font-size-h4);
|
||||||
|
padding: 0.15rem;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 0.2rem;
|
||||||
|
position: relative;
|
||||||
|
top: -0.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge svg {
|
||||||
|
fill: currentColor;
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
48
src/components/atoms/Partner.tsx
Normal file
48
src/components/atoms/Partner.tsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import React, { ReactElement } from 'react'
|
||||||
|
import { ReactComponent as PartnerIcon } from '../../images/partner.svg'
|
||||||
|
import styles from './Partner.module.css'
|
||||||
|
import classNames from 'classnames/bind'
|
||||||
|
import Tooltip from './Tooltip'
|
||||||
|
import { PartnerData } from '@oceanprotocol/list-datapartners/types'
|
||||||
|
|
||||||
|
const cx = classNames.bind(styles)
|
||||||
|
|
||||||
|
export function PartnerBadge(): ReactElement {
|
||||||
|
return (
|
||||||
|
<span className={styles.badge}>
|
||||||
|
<PartnerIcon />
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Partner({
|
||||||
|
partner,
|
||||||
|
className
|
||||||
|
}: {
|
||||||
|
partner: PartnerData
|
||||||
|
className?: string
|
||||||
|
}): ReactElement {
|
||||||
|
const styleClasses = cx({
|
||||||
|
partner: true,
|
||||||
|
[className]: className
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className={styleClasses}>
|
||||||
|
<Tooltip
|
||||||
|
content={
|
||||||
|
<>
|
||||||
|
Ocean Protocol{' '}
|
||||||
|
<a href="https://github.com/oceanprotocol/list-datapartners">
|
||||||
|
Data Partner
|
||||||
|
</a>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
|
<PartnerBadge />
|
||||||
|
{partner.name}
|
||||||
|
</Tooltip>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
@ -28,4 +28,5 @@
|
|||||||
.badge {
|
.badge {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin-left: calc(var(--spacer) / 6);
|
margin-left: calc(var(--spacer) / 6);
|
||||||
|
background: var(--color-secondary);
|
||||||
}
|
}
|
||||||
|
27
src/components/molecules/AssetListTitle.tsx
Normal file
27
src/components/molecules/AssetListTitle.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { useMetadata } from '@oceanprotocol/react'
|
||||||
|
import { Link } from 'gatsby'
|
||||||
|
import React, { ReactElement } from 'react'
|
||||||
|
import { useDataPartner } from '../../hooks/useDataPartner'
|
||||||
|
import { PartnerBadge } from '../atoms/Partner'
|
||||||
|
import styles from './AssetListTitle.module.css'
|
||||||
|
|
||||||
|
export default function AssetListTitle({
|
||||||
|
did,
|
||||||
|
title,
|
||||||
|
owner
|
||||||
|
}: {
|
||||||
|
did?: string
|
||||||
|
title?: string
|
||||||
|
owner?: string
|
||||||
|
}): ReactElement {
|
||||||
|
const metadata = useMetadata(did)
|
||||||
|
const { partner } = useDataPartner(owner)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<h3 className={styles.title}>
|
||||||
|
<Link to={`/asset/${did}`}>
|
||||||
|
{partner && <PartnerBadge />} {title || metadata.title || did}
|
||||||
|
</Link>
|
||||||
|
</h3>
|
||||||
|
)
|
||||||
|
}
|
@ -15,6 +15,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
|
margin-top: calc(var(--spacer) / 2);
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
@ -29,7 +30,13 @@
|
|||||||
|
|
||||||
.title {
|
.title {
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-large);
|
||||||
margin-bottom: calc(var(--spacer) / 2);
|
margin-top: calc(var(--spacer) / 12);
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.partner {
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
margin-top: calc(var(--spacer) / 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
.foot {
|
.foot {
|
||||||
@ -53,5 +60,5 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.symbol {
|
.symbol {
|
||||||
display: inline-block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,4 @@ export default {
|
|||||||
title: 'Molecules/Asset Teaser'
|
title: 'Molecules/Asset Teaser'
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Default = () => (
|
export const Default = () => <AssetTeaser ddo={ddo as DDO} />
|
||||||
<AssetTeaser
|
|
||||||
ddo={ddo as DDO}
|
|
||||||
metadata={new DDO(ddo).findServiceByType('metadata').attributes as any}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
|
@ -1,23 +1,25 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Link } from 'gatsby'
|
import { Link } from 'gatsby'
|
||||||
import Dotdotdot from 'react-dotdotdot'
|
import Dotdotdot from 'react-dotdotdot'
|
||||||
import { MetadataMarket } from '../../@types/MetaData'
|
|
||||||
import Price from '../atoms/Price'
|
import Price from '../atoms/Price'
|
||||||
import styles from './AssetTeaser.module.css'
|
import styles from './AssetTeaser.module.css'
|
||||||
import { DDO } from '@oceanprotocol/lib'
|
import { DDO } from '@oceanprotocol/lib'
|
||||||
import removeMarkdown from 'remove-markdown'
|
import removeMarkdown from 'remove-markdown'
|
||||||
import Tooltip from '../atoms/Tooltip'
|
import Tooltip from '../atoms/Tooltip'
|
||||||
|
import { useMetadata } from '@oceanprotocol/react'
|
||||||
|
import Partner from '../atoms/Partner'
|
||||||
|
import { useDataPartner } from '../../hooks/useDataPartner'
|
||||||
|
|
||||||
declare type AssetTeaserProps = {
|
declare type AssetTeaserProps = {
|
||||||
ddo: DDO
|
ddo: DDO
|
||||||
metadata: MetadataMarket
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const AssetTeaser: React.FC<AssetTeaserProps> = ({
|
const AssetTeaser: React.FC<AssetTeaserProps> = ({ ddo }: AssetTeaserProps) => {
|
||||||
ddo,
|
const { owner } = useMetadata(ddo)
|
||||||
metadata
|
const { partner } = useDataPartner(owner)
|
||||||
}: AssetTeaserProps) => {
|
|
||||||
const { name } = metadata.main
|
const { attributes } = ddo.findServiceByType('metadata')
|
||||||
|
const { name } = attributes.main
|
||||||
const { dataTokenInfo } = ddo
|
const { dataTokenInfo } = ddo
|
||||||
const isCompute = Boolean(ddo.findServiceByType('compute'))
|
const isCompute = Boolean(ddo.findServiceByType('compute'))
|
||||||
|
|
||||||
@ -32,12 +34,14 @@ const AssetTeaser: React.FC<AssetTeaserProps> = ({
|
|||||||
{dataTokenInfo?.symbol}
|
{dataTokenInfo?.symbol}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<h1 className={styles.title}>{name}</h1>
|
<h1 className={styles.title}>{name}</h1>
|
||||||
|
{partner && <Partner className={styles.partner} partner={partner} />}
|
||||||
{isCompute && <div className={styles.accessLabel}>Compute</div>}
|
{isCompute && <div className={styles.accessLabel}>Compute</div>}
|
||||||
|
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
<Dotdotdot tagName="p" clamp={3}>
|
<Dotdotdot tagName="p" clamp={3}>
|
||||||
{removeMarkdown(metadata?.additionalInformation?.description || '')}
|
{removeMarkdown(
|
||||||
|
attributes?.additionalInformation?.description || ''
|
||||||
|
)}
|
||||||
</Dotdotdot>
|
</Dotdotdot>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
import { useMetadata } from '@oceanprotocol/react'
|
|
||||||
import { Link } from 'gatsby'
|
|
||||||
import React, { ReactElement } from 'react'
|
|
||||||
import styles from './AssetTitle.module.css'
|
|
||||||
|
|
||||||
export default function AssetTitle({
|
|
||||||
did,
|
|
||||||
title
|
|
||||||
}: {
|
|
||||||
did?: string
|
|
||||||
title?: string
|
|
||||||
}): ReactElement {
|
|
||||||
const metadata = useMetadata(did)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<h3 className={styles.title}>
|
|
||||||
<Link to={`/asset/${did}`}>{title || metadata.title || did}</Link>
|
|
||||||
</h3>
|
|
||||||
)
|
|
||||||
}
|
|
@ -6,7 +6,7 @@ import { useOcean } from '@oceanprotocol/react'
|
|||||||
import Price from '../atoms/Price'
|
import Price from '../atoms/Price'
|
||||||
import Tooltip from '../atoms/Tooltip'
|
import Tooltip from '../atoms/Tooltip'
|
||||||
import { ConfigHelperConfig } from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'
|
import { ConfigHelperConfig } from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'
|
||||||
import AssetTitle from './AssetTitle'
|
import AssetTitle from './AssetListTitle'
|
||||||
|
|
||||||
async function getAssetsBookmarked(
|
async function getAssetsBookmarked(
|
||||||
bookmarks: string[],
|
bookmarks: string[],
|
||||||
@ -28,7 +28,13 @@ const columns = [
|
|||||||
name: 'Data Set',
|
name: 'Data Set',
|
||||||
selector: function getAssetRow(row: DDO) {
|
selector: function getAssetRow(row: DDO) {
|
||||||
const { attributes } = row.findServiceByType('metadata')
|
const { attributes } = row.findServiceByType('metadata')
|
||||||
return <AssetTitle title={attributes.main.name} did={row.id} />
|
return (
|
||||||
|
<AssetTitle
|
||||||
|
title={attributes.main.name}
|
||||||
|
did={row.id}
|
||||||
|
owner={row.publicKey[0].owner}
|
||||||
|
/>
|
||||||
|
)
|
||||||
},
|
},
|
||||||
maxWidth: '45rem',
|
maxWidth: '45rem',
|
||||||
grow: 1
|
grow: 1
|
||||||
|
@ -4,7 +4,7 @@ import React, { ReactElement, useEffect, useState } from 'react'
|
|||||||
import EtherscanLink from '../atoms/EtherscanLink'
|
import EtherscanLink from '../atoms/EtherscanLink'
|
||||||
import Time from '../atoms/Time'
|
import Time from '../atoms/Time'
|
||||||
import Table from '../atoms/Table'
|
import Table from '../atoms/Table'
|
||||||
import AssetTitle from './AssetTitle'
|
import AssetTitle from './AssetListTitle'
|
||||||
import styles from './PoolTransactions.module.css'
|
import styles from './PoolTransactions.module.css'
|
||||||
import { formatCurrency } from '@coingecko/cryptoformat'
|
import { formatCurrency } from '@coingecko/cryptoformat'
|
||||||
import { useUserPreferences } from '../../providers/UserPreferences'
|
import { useUserPreferences } from '../../providers/UserPreferences'
|
||||||
|
31
src/components/organisms/AssetContent/Byline.module.css
Normal file
31
src/components/organisms/AssetContent/Byline.module.css
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
.byline {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 40rem) {
|
||||||
|
.bylineLinks {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bylineLinks a {
|
||||||
|
margin-left: calc(var(--spacer) / 3);
|
||||||
|
color: inherit;
|
||||||
|
font-size: var(--font-size-mini);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bylineLinks a:first-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bylineLinks a:hover,
|
||||||
|
.bylineLinks a:focus {
|
||||||
|
color: var(--brand-pink);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bylineExternal {
|
||||||
|
width: 0.6em;
|
||||||
|
height: 0.6em;
|
||||||
|
display: inline-block;
|
||||||
|
fill: var(--brand-grey-light);
|
||||||
|
}
|
48
src/components/organisms/AssetContent/Byline.tsx
Normal file
48
src/components/organisms/AssetContent/Byline.tsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import React, { ReactElement } from 'react'
|
||||||
|
import styles from './Byline.module.css'
|
||||||
|
import { accountTruncate } from '../../../utils/wallet'
|
||||||
|
import Partner from '../../atoms/Partner'
|
||||||
|
import { ReactComponent as External } from '../../../images/external.svg'
|
||||||
|
import { Link } from 'gatsby'
|
||||||
|
import EtherscanLink from '../../atoms/EtherscanLink'
|
||||||
|
import { useOcean } from '@oceanprotocol/react'
|
||||||
|
import { useDataPartner } from '../../../hooks/useDataPartner'
|
||||||
|
|
||||||
|
export default function Byline({
|
||||||
|
owner,
|
||||||
|
prefix
|
||||||
|
}: {
|
||||||
|
owner: string
|
||||||
|
prefix?: string
|
||||||
|
}): ReactElement {
|
||||||
|
const { networkId } = useOcean()
|
||||||
|
const { partner } = useDataPartner(owner)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.byline}>
|
||||||
|
{prefix}
|
||||||
|
<Link
|
||||||
|
to={`/search/?owner=${owner}`}
|
||||||
|
title="Show all data sets created by this account."
|
||||||
|
>
|
||||||
|
{partner ? (
|
||||||
|
<Partner partner={partner} />
|
||||||
|
) : (
|
||||||
|
owner && accountTruncate(owner)
|
||||||
|
)}
|
||||||
|
</Link>
|
||||||
|
<div className={styles.bylineLinks}>
|
||||||
|
{' — '}
|
||||||
|
{partner &&
|
||||||
|
Object.entries(partner.links).map(([key, value]) => (
|
||||||
|
<a href={value} key={key} target="_blank" rel="noreferrer">
|
||||||
|
{key} <External className={styles.bylineExternal} />
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
<EtherscanLink networkId={networkId} path={`address/${owner}`}>
|
||||||
|
Etherscan
|
||||||
|
</EtherscanLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -4,6 +4,7 @@ import MetaItem from './MetaItem'
|
|||||||
import styles from './MetaFull.module.css'
|
import styles from './MetaFull.module.css'
|
||||||
import { MetadataMarket } from '../../../@types/MetaData'
|
import { MetadataMarket } from '../../../@types/MetaData'
|
||||||
import { DDO } from '@oceanprotocol/lib'
|
import { DDO } from '@oceanprotocol/lib'
|
||||||
|
import Byline from './Byline'
|
||||||
|
|
||||||
export default function MetaFull({
|
export default function MetaFull({
|
||||||
ddo,
|
ddo,
|
||||||
@ -12,12 +13,13 @@ export default function MetaFull({
|
|||||||
ddo: DDO
|
ddo: DDO
|
||||||
metadata: MetadataMarket
|
metadata: MetadataMarket
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { id } = ddo
|
const { id, publicKey } = ddo
|
||||||
const { dateCreated, datePublished } = metadata.main
|
const { dateCreated, datePublished } = metadata.main
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.metaFull}>
|
<div className={styles.metaFull}>
|
||||||
<MetaItem title="Author" content={metadata?.main.author} />
|
<MetaItem title="Author" content={metadata?.main.author} />
|
||||||
|
<MetaItem title="Owner" content={<Byline owner={publicKey[0].owner} />} />
|
||||||
|
|
||||||
{metadata?.additionalInformation?.categories && (
|
{metadata?.additionalInformation?.categories && (
|
||||||
<MetaItem
|
<MetaItem
|
||||||
|
@ -12,7 +12,7 @@ import Pricing from './Pricing'
|
|||||||
import { useMetadata, useOcean, usePricing } from '@oceanprotocol/react'
|
import { useMetadata, useOcean, usePricing } from '@oceanprotocol/react'
|
||||||
import EtherscanLink from '../../atoms/EtherscanLink'
|
import EtherscanLink from '../../atoms/EtherscanLink'
|
||||||
import Bookmark from './Bookmark'
|
import Bookmark from './Bookmark'
|
||||||
import { accountTruncate } from '../../../utils/wallet'
|
import Byline from './Byline'
|
||||||
|
|
||||||
export interface AssetContentProps {
|
export interface AssetContentProps {
|
||||||
metadata: MetadataMarket
|
metadata: MetadataMarket
|
||||||
@ -39,11 +39,20 @@ export default function AssetContent({
|
|||||||
{showPricing && <Pricing ddo={ddo} />}
|
{showPricing && <Pricing ddo={ddo} />}
|
||||||
|
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
<aside className={styles.meta}>
|
<p className={styles.author} title="Author">
|
||||||
<p className={styles.author} title="Author">
|
{metadata?.main.author}
|
||||||
{metadata?.main.author}
|
</p>
|
||||||
|
{metadata?.additionalInformation?.categories?.length && (
|
||||||
|
<p>
|
||||||
|
<Link
|
||||||
|
to={`/search?categories=${metadata?.additionalInformation?.categories[0]}`}
|
||||||
|
>
|
||||||
|
{metadata?.additionalInformation?.categories[0]}
|
||||||
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<aside className={styles.meta}>
|
||||||
<p className={styles.datatoken}>
|
<p className={styles.datatoken}>
|
||||||
<EtherscanLink
|
<EtherscanLink
|
||||||
networkId={networkId}
|
networkId={networkId}
|
||||||
@ -56,30 +65,7 @@ export default function AssetContent({
|
|||||||
)}
|
)}
|
||||||
</EtherscanLink>
|
</EtherscanLink>
|
||||||
</p>
|
</p>
|
||||||
|
<Byline owner={owner} prefix="Published by " />
|
||||||
<p>
|
|
||||||
Published by{' '}
|
|
||||||
<Link
|
|
||||||
to={`/search/?owner=${owner}`}
|
|
||||||
title="Show all data sets created by this account."
|
|
||||||
>
|
|
||||||
{owner && accountTruncate(owner)}
|
|
||||||
</Link>
|
|
||||||
{' — '}
|
|
||||||
<EtherscanLink networkId={networkId} path={`address/${owner}`}>
|
|
||||||
Etherscan
|
|
||||||
</EtherscanLink>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{metadata?.additionalInformation?.categories?.length && (
|
|
||||||
<p>
|
|
||||||
<Link
|
|
||||||
to={`/search?categories=${metadata?.additionalInformation?.categories[0]}`}
|
|
||||||
>
|
|
||||||
{metadata?.additionalInformation?.categories[0]}
|
|
||||||
</Link>
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<Markdown
|
<Markdown
|
||||||
|
31
src/components/organisms/AssetQueryCarousel.module.css
Normal file
31
src/components/organisms/AssetQueryCarousel.module.css
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
.assetCarousel [class*='alice-carousel__dots-item'] {
|
||||||
|
width: var(--font-size-mini);
|
||||||
|
height: var(--font-size-mini);
|
||||||
|
background: var(--color-secondary);
|
||||||
|
border: 1px solid var(--font-color-heading);
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assetCarousel [class*='alice-carousel__dots-item']:hover,
|
||||||
|
.assetCarousel [class*='alice-carousel__dots-item __active'] {
|
||||||
|
background: var(--font-color-heading) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assetCarousel [class='alice-carousel__wrapper'] {
|
||||||
|
padding-bottom: calc(var(--spacer) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.assetCarousel [class='alice-carousel__stage'] > li article {
|
||||||
|
margin-left: calc(var(--spacer) / 2);
|
||||||
|
margin-right: calc(var(--spacer) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.assetCarousel [class='alice-carousel__dots'] {
|
||||||
|
margin-top: calc(var(--spacer) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty {
|
||||||
|
color: var(--color-secondary);
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
font-style: italic;
|
||||||
|
}
|
59
src/components/organisms/AssetQueryCarousel.tsx
Normal file
59
src/components/organisms/AssetQueryCarousel.tsx
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import AssetTeaser from '../molecules/AssetTeaser'
|
||||||
|
import React from 'react'
|
||||||
|
import { QueryResult } from '@oceanprotocol/lib/dist/node/metadatacache/MetadataCache'
|
||||||
|
import styles from './AssetQueryCarousel.module.css'
|
||||||
|
import { DDO } from '@oceanprotocol/lib'
|
||||||
|
import classNames from 'classnames/bind'
|
||||||
|
import AliceCarousel from 'react-alice-carousel'
|
||||||
|
import 'react-alice-carousel/lib/alice-carousel.css'
|
||||||
|
|
||||||
|
const cx = classNames.bind(styles)
|
||||||
|
|
||||||
|
declare type AssetQueryCarouselProps = {
|
||||||
|
queryResult: QueryResult
|
||||||
|
className?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const responsive = {
|
||||||
|
0: { items: 1 },
|
||||||
|
600: { items: 2 },
|
||||||
|
1280: { items: 3 },
|
||||||
|
1600: { items: 4 },
|
||||||
|
2400: { items: 6 }
|
||||||
|
}
|
||||||
|
|
||||||
|
const AssetQueryCarousel: React.FC<AssetQueryCarouselProps> = ({
|
||||||
|
queryResult,
|
||||||
|
className
|
||||||
|
}) => {
|
||||||
|
const styleClasses = cx({
|
||||||
|
assetCarousel: true,
|
||||||
|
[className]: className
|
||||||
|
})
|
||||||
|
|
||||||
|
const items =
|
||||||
|
queryResult?.results.length > 0
|
||||||
|
? queryResult.results.map((ddo: DDO) => (
|
||||||
|
<AssetTeaser key={ddo.id} ddo={ddo} />
|
||||||
|
))
|
||||||
|
: [
|
||||||
|
<div className={styles.empty} key="empty">
|
||||||
|
No results found.
|
||||||
|
</div>
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styleClasses}>
|
||||||
|
<AliceCarousel
|
||||||
|
items={items}
|
||||||
|
responsive={responsive}
|
||||||
|
paddingLeft={10}
|
||||||
|
paddingRight={10}
|
||||||
|
disableButtonsControls
|
||||||
|
animationDuration={300}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AssetQueryCarousel
|
@ -5,14 +5,20 @@ import { useLocation, useNavigate } from '@reach/router'
|
|||||||
import Pagination from '../molecules/Pagination'
|
import Pagination from '../molecules/Pagination'
|
||||||
import { updateQueryStringParameter } from '../../utils'
|
import { updateQueryStringParameter } from '../../utils'
|
||||||
import styles from './AssetQueryList.module.css'
|
import styles from './AssetQueryList.module.css'
|
||||||
import { MetadataMarket } from '../../@types/MetaData'
|
|
||||||
import { DDO } from '@oceanprotocol/lib'
|
import { DDO } from '@oceanprotocol/lib'
|
||||||
|
import classNames from 'classnames/bind'
|
||||||
|
|
||||||
|
const cx = classNames.bind(styles)
|
||||||
|
|
||||||
declare type AssetQueryListProps = {
|
declare type AssetQueryListProps = {
|
||||||
queryResult: QueryResult
|
queryResult: QueryResult
|
||||||
|
className?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const AssetQueryList: React.FC<AssetQueryListProps> = ({ queryResult }) => {
|
const AssetQueryList: React.FC<AssetQueryListProps> = ({
|
||||||
|
queryResult,
|
||||||
|
className
|
||||||
|
}) => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
|
||||||
@ -38,21 +44,18 @@ const AssetQueryList: React.FC<AssetQueryListProps> = ({ queryResult }) => {
|
|||||||
return navigate(newUrl)
|
return navigate(newUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const styleClasses = cx({
|
||||||
|
assetList: true,
|
||||||
|
[className]: className
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={styles.assetList}>
|
<div className={styleClasses}>
|
||||||
{queryResult?.results.length > 0 ? (
|
{queryResult?.results.length > 0 ? (
|
||||||
queryResult.results.map((ddo: DDO) => {
|
queryResult.results.map((ddo: DDO) => (
|
||||||
const { attributes } = ddo.findServiceByType('metadata')
|
<AssetTeaser ddo={ddo} key={ddo.id} />
|
||||||
|
))
|
||||||
return (
|
|
||||||
<AssetTeaser
|
|
||||||
ddo={ddo}
|
|
||||||
metadata={(attributes as unknown) as MetadataMarket}
|
|
||||||
key={ddo.id}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
) : (
|
) : (
|
||||||
<div className={styles.empty}>No results found.</div>
|
<div className={styles.empty}>No results found.</div>
|
||||||
)}
|
)}
|
||||||
|
@ -5,7 +5,7 @@ import { DDO, Logger, MetadataCache } from '@oceanprotocol/lib'
|
|||||||
import PriceUnit from '../../atoms/Price/PriceUnit'
|
import PriceUnit from '../../atoms/Price/PriceUnit'
|
||||||
import Conversion from '../../atoms/Price/Conversion'
|
import Conversion from '../../atoms/Price/Conversion'
|
||||||
import styles from './PoolShares.module.css'
|
import styles from './PoolShares.module.css'
|
||||||
import AssetTitle from '../../molecules/AssetTitle'
|
import AssetTitle from '../../molecules/AssetListTitle'
|
||||||
|
|
||||||
interface Asset {
|
interface Asset {
|
||||||
ddo: DDO
|
ddo: DDO
|
||||||
@ -28,8 +28,9 @@ const columns = [
|
|||||||
{
|
{
|
||||||
name: 'Data Set',
|
name: 'Data Set',
|
||||||
selector: function getAssetRow(row: Asset) {
|
selector: function getAssetRow(row: Asset) {
|
||||||
const did = row.ddo.id
|
const { attributes } = row.ddo.findServiceByType('metadata')
|
||||||
return <AssetTitle did={did} />
|
const { owner } = row.ddo.publicKey[0]
|
||||||
|
return <AssetTitle title={attributes.main.name} owner={owner} />
|
||||||
},
|
},
|
||||||
grow: 2
|
grow: 2
|
||||||
},
|
},
|
||||||
|
@ -4,15 +4,34 @@
|
|||||||
margin-top: calc(var(--spacer) * var(--line-height));
|
margin-top: calc(var(--spacer) * var(--line-height));
|
||||||
}
|
}
|
||||||
|
|
||||||
.latest {
|
.section {
|
||||||
margin-top: calc(var(--spacer) * 2);
|
margin-top: calc(var(--spacer) * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.latest h3 {
|
.section h3 {
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-large);
|
||||||
color: var(--color-secondary);
|
color: var(--color-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.latest [class*='button'] {
|
.section [class*='button'] {
|
||||||
margin-top: var(--spacer);
|
margin-top: var(--spacer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.listPartners {
|
||||||
|
composes: section;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listPartners > div {
|
||||||
|
background: var(--background-highlight);
|
||||||
|
padding-top: var(--spacer);
|
||||||
|
padding-bottom: var(--spacer);
|
||||||
|
min-height: 360px;
|
||||||
|
margin-left: calc(-50vw + 50%);
|
||||||
|
margin-right: calc(-50vw + 50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.loaderWrap {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
@ -12,18 +12,25 @@ import Loader from '../atoms/Loader'
|
|||||||
import { useOcean } from '@oceanprotocol/react'
|
import { useOcean } from '@oceanprotocol/react'
|
||||||
import Button from '../atoms/Button'
|
import Button from '../atoms/Button'
|
||||||
import Bookmarks from '../molecules/Bookmarks'
|
import Bookmarks from '../molecules/Bookmarks'
|
||||||
|
import listPartners from '@oceanprotocol/list-datapartners'
|
||||||
|
import Tooltip from '../atoms/Tooltip'
|
||||||
|
import AssetQueryCarousel from '../organisms/AssetQueryCarousel'
|
||||||
|
|
||||||
|
const partnerAccounts = listPartners.map((partner) =>
|
||||||
|
partner.accounts.join(',')
|
||||||
|
)
|
||||||
|
|
||||||
const queryHighest = {
|
const queryHighest = {
|
||||||
page: 1,
|
page: 1,
|
||||||
offset: 6,
|
offset: 9,
|
||||||
query: { 'price.type': ['pool'] },
|
query: { 'price.type': ['pool'] },
|
||||||
sort: { 'price.ocean': -1 }
|
sort: { 'price.ocean': -1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
const queryPoolsLatest = {
|
const queryPartners = {
|
||||||
page: 1,
|
page: 1,
|
||||||
offset: 6,
|
offset: 100,
|
||||||
query: { 'price.type': ['pool'] },
|
query: { 'publicKey.owner': partnerAccounts },
|
||||||
sort: { created: -1 }
|
sort: { created: -1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,20 +45,49 @@ async function getAssets(query: SearchQuery, metadataCacheUri: string) {
|
|||||||
try {
|
try {
|
||||||
const metadataCache = new MetadataCache(metadataCacheUri, Logger)
|
const metadataCache = new MetadataCache(metadataCacheUri, Logger)
|
||||||
const result = await metadataCache.queryMetadata(query)
|
const result = await metadataCache.queryMetadata(query)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Logger.error(error.message)
|
Logger.error(error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function LoaderArea() {
|
||||||
|
return (
|
||||||
|
<div className={styles.loaderWrap}>
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SectionQuery({
|
||||||
|
title,
|
||||||
|
result,
|
||||||
|
loading,
|
||||||
|
action
|
||||||
|
}: {
|
||||||
|
title: ReactElement | string
|
||||||
|
result: QueryResult
|
||||||
|
loading: boolean
|
||||||
|
action?: ReactElement
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<section className={styles.section}>
|
||||||
|
<h3>{title}</h3>
|
||||||
|
{loading ? (
|
||||||
|
<LoaderArea />
|
||||||
|
) : (
|
||||||
|
result && <AssetQueryList queryResult={result} />
|
||||||
|
)}
|
||||||
|
{action && action}
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default function HomePage(): ReactElement {
|
export default function HomePage(): ReactElement {
|
||||||
const { config } = useOcean()
|
const { config } = useOcean()
|
||||||
|
|
||||||
const [queryResultLatest, setQueryResultLatest] = useState<QueryResult>()
|
const [queryResultLatest, setQueryResultLatest] = useState<QueryResult>()
|
||||||
const [queryResultPoolsLatest, setQueryResultPoolsLatest] = useState<
|
const [queryResultPartners, setQueryResultPartners] = useState<QueryResult>()
|
||||||
QueryResult
|
|
||||||
>()
|
|
||||||
const [queryResultHighest, setQueryResultHighest] = useState<QueryResult>()
|
const [queryResultHighest, setQueryResultHighest] = useState<QueryResult>()
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
|
|
||||||
@ -63,11 +99,11 @@ export default function HomePage(): ReactElement {
|
|||||||
)
|
)
|
||||||
setQueryResultHighest(queryResultHighest)
|
setQueryResultHighest(queryResultHighest)
|
||||||
|
|
||||||
const queryResultPoolsLatest = await getAssets(
|
const queryResultPartners = await getAssets(
|
||||||
queryPoolsLatest,
|
queryPartners,
|
||||||
config.metadataCacheUri
|
config.metadataCacheUri
|
||||||
)
|
)
|
||||||
setQueryResultPoolsLatest(queryResultPoolsLatest)
|
setQueryResultPartners(queryResultPartners)
|
||||||
|
|
||||||
const queryResultLatest = await getAssets(
|
const queryResultLatest = await getAssets(
|
||||||
queryLatest,
|
queryLatest,
|
||||||
@ -85,48 +121,56 @@ export default function HomePage(): ReactElement {
|
|||||||
<SearchBar size="large" />
|
<SearchBar size="large" />
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
<section className={styles.latest}>
|
<section className={styles.listPartners}>
|
||||||
|
<h3>
|
||||||
|
Data Partners{' '}
|
||||||
|
<Tooltip
|
||||||
|
content={
|
||||||
|
<>
|
||||||
|
Ocean Protocol{' '}
|
||||||
|
<a href="https://github.com/oceanprotocol/list-datapartners">
|
||||||
|
Data Partners
|
||||||
|
</a>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</h3>
|
||||||
|
{loading ? (
|
||||||
|
<LoaderArea />
|
||||||
|
) : (
|
||||||
|
queryResultPartners && (
|
||||||
|
<AssetQueryCarousel queryResult={queryResultPartners} />
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
{/* <Button
|
||||||
|
style="text"
|
||||||
|
to={`/search/?owner=${partnerAccounts?.toString()}`}
|
||||||
|
>
|
||||||
|
All data partner sets →
|
||||||
|
</Button> */}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className={styles.section}>
|
||||||
<h3>Bookmarks</h3>
|
<h3>Bookmarks</h3>
|
||||||
<Bookmarks />
|
<Bookmarks />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className={styles.latest}>
|
<SectionQuery
|
||||||
<h3>Highest Liquidity Pools</h3>
|
title="Highest Liquidity Pools"
|
||||||
{loading ? (
|
loading={loading}
|
||||||
<Loader />
|
result={queryResultHighest}
|
||||||
) : (
|
/>
|
||||||
queryResultHighest && (
|
|
||||||
<AssetQueryList queryResult={queryResultHighest} />
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className={styles.latest}>
|
<SectionQuery
|
||||||
<h3>New Liquidity Pools</h3>
|
title="New Data Sets"
|
||||||
{loading ? (
|
loading={loading}
|
||||||
<Loader />
|
result={queryResultLatest}
|
||||||
) : (
|
action={
|
||||||
queryResultPoolsLatest && (
|
|
||||||
<AssetQueryList queryResult={queryResultPoolsLatest} />
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className={styles.latest}>
|
|
||||||
<h3>New Data Sets</h3>
|
|
||||||
{loading ? (
|
|
||||||
<Loader />
|
|
||||||
) : (
|
|
||||||
queryResultLatest && (
|
|
||||||
<AssetQueryList queryResult={queryResultLatest} />
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
{queryResultLatest?.results.length === 9 && (
|
|
||||||
<Button style="text" to="/search">
|
<Button style="text" to="/search">
|
||||||
All data sets →
|
All data sets →
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
}
|
||||||
</section>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -46,9 +46,16 @@ export async function getResults(
|
|||||||
const { text, owner, tags, page, offset, categories } = params
|
const { text, owner, tags, page, offset, categories } = params
|
||||||
|
|
||||||
const metadataCache = new MetadataCache(metadataCacheUri, Logger)
|
const metadataCache = new MetadataCache(metadataCacheUri, Logger)
|
||||||
const queryResult = await metadataCache.queryMetadata(
|
const searchQuery = getSearchQuery(
|
||||||
getSearchQuery(text, owner, tags, categories, page, offset)
|
text,
|
||||||
|
owner,
|
||||||
|
tags,
|
||||||
|
categories,
|
||||||
|
page,
|
||||||
|
offset
|
||||||
)
|
)
|
||||||
|
console.log(searchQuery)
|
||||||
|
const queryResult = await metadataCache.queryMetadata(searchQuery)
|
||||||
|
|
||||||
return queryResult
|
return queryResult
|
||||||
}
|
}
|
||||||
|
28
src/hooks/useDataPartner.ts
Normal file
28
src/hooks/useDataPartner.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import listPartners from '@oceanprotocol/list-datapartners'
|
||||||
|
import { PartnerData } from '@oceanprotocol/list-datapartners/types'
|
||||||
|
|
||||||
|
export function useDataPartner(
|
||||||
|
owner?: string
|
||||||
|
): {
|
||||||
|
partner: PartnerData
|
||||||
|
partnerAccounts: string[]
|
||||||
|
} {
|
||||||
|
const [partnerAccounts, setPartnerAccounts] = useState<string[]>()
|
||||||
|
const [partner, setPartner] = useState<PartnerData>()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const accounts = [] as string[]
|
||||||
|
listPartners.map((partner) => accounts.push(...partner.accounts))
|
||||||
|
setPartnerAccounts(accounts)
|
||||||
|
|
||||||
|
if (!owner) return
|
||||||
|
|
||||||
|
const partner = listPartners.filter((partner) =>
|
||||||
|
partner.accounts.includes(owner)
|
||||||
|
)[0]
|
||||||
|
setPartner(partner)
|
||||||
|
}, [owner])
|
||||||
|
|
||||||
|
return { partner, partnerAccounts }
|
||||||
|
}
|
5
src/images/partner.svg
Normal file
5
src/images/partner.svg
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<svg width="21" height="24" viewBox="0 0 21 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M19 13C17.897 13 17 13.896 17 15V17.5C17 18.327 16.327 19 15.5 19C14.673 19 14 18.327 14 17.5V9.119L10.5 2.119L7 9.119V17.5C7 18.327 6.327 19 5.5 19C4.673 19 4 18.327 4 17.5V15C4 13.896 3.102 13 2 13C0.898 13 0 13.896 0 15V17C0 17.276 0.224 17.5 0.5 17.5C0.776 17.5 1 17.276 1 17V15C1 14.449 1.448 14 2 14C2.552 14 3 14.449 3 15V17.5C3 18.879 4.121 20 5.5 20C6.879 20 8 18.879 8 17.5V16H9V20C9 21.654 7.654 23 6 23C4.262 23 3 21.844 3 20.25C3 19.974 2.776 19.75 2.5 19.75C2.224 19.75 2 19.974 2 20.25C2 22.388 3.72 24 6 24C8.206 24 10 22.206 10 20V16H11V20C11 22.169 12.889 24 15.125 24C17.406 24 19.063 22.423 19.063 20.25C19.063 19.974 18.839 19.75 18.563 19.75C18.287 19.75 18.063 19.974 18.063 20.25C18.063 21.844 16.828 23 15.125 23C13.431 23 12 21.626 12 20V16H13V17.5C13 18.879 14.121 20 15.5 20C16.879 20 18 18.879 18 17.5V15C18 14.449 18.448 14 19 14C19.552 14 20 14.449 20 15V16C20 16.276 20.224 16.5 20.5 16.5C20.776 16.5 21 16.276 21 16V15C21 13.896 20.103 13 19 13Z" />
|
||||||
|
<path d="M16.967 6.734L10.938 0.729004C10.933 0.737004 10.927 0.744004 10.923 0.751004C10.929 0.761004 10.941 0.765004 10.947 0.775004L15.059 9H16.032C17.041 9 17.379 8.547 17.49 8.276C17.602 8.007 17.682 7.447 16.967 6.734Z" />
|
||||||
|
<path d="M10.063 0.730004L4.061 6.732C3.348 7.446 3.43 8.006 3.541 8.276C3.653 8.547 3.991 9 5 9H5.941L10.052 0.776004C10.058 0.765004 10.071 0.761004 10.076 0.752004C10.073 0.744004 10.067 0.737004 10.063 0.730004Z" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
Loading…
Reference in New Issue
Block a user