1
0
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:
Matthias Kretschmann 2020-11-05 14:43:13 +01:00 committed by GitHub
parent b55362f309
commit ad107c5415
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 518 additions and 136 deletions

18
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -9,6 +9,12 @@
flex-direction: column; flex-direction: column;
} }
@media (min-width: 2000px) {
.app {
background-size: contain;
}
}
.app > * { .app > * {
width: 100%; width: 100%;
} }

View 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%;
}

View 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>
)
}

View File

@ -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);
} }

View 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>
)
}

View File

@ -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;
} }

View File

@ -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}
/>
)

View File

@ -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>

View File

@ -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>
)
}

View File

@ -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

View File

@ -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'

View 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);
}

View 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>
)
}

View File

@ -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

View File

@ -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

View 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;
}

View 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

View File

@ -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>
)} )}

View File

@ -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
}, },

View File

@ -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;
}

View File

@ -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> />
</> </>
) )
} }

View File

@ -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
} }

View 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
View 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