From dac47bf5246b08c9a2830410fbdbd3469e0abfe0 Mon Sep 17 00:00:00 2001 From: mihaisc Date: Fri, 27 Nov 2020 13:04:35 +0200 Subject: [PATCH] 3Box publisher profiles (#264) * install 3box Signed-off-by: mihaisc * tinkering * check tweak * load library on init only * add profile Signed-off-by: mihaisc * get 3box profile Signed-off-by: mihaisc * fix return type Signed-off-by: mihaisc * remove console.log * fix travis Signed-off-by: mihaisc * fix eslit Signed-off-by: mihaisc * fix travis Signed-off-by: mihaisc * 3box data structure tweaks, prepare output in byline * refactor * new Publisher component * tweaks * remove data partners * link/profile splitup * profile tweaks * component splitup * lots of styling, add image * affordance for publisher, refactor, server response tinkering * use 3Box proxy * open all 3box links in new tab/window * mobile fixes Co-authored-by: Matthias Kretschmann --- package-lock.json | 83 +++------------- package.json | 5 +- src/components/atoms/Partner.module.css | 24 ----- src/components/atoms/Partner.tsx | 48 --------- src/components/atoms/Publisher/Add.module.css | 7 ++ src/components/atoms/Publisher/Add.tsx | 16 +++ .../atoms/Publisher/ProfileDetails.module.css | 71 +++++++++++++ .../atoms/Publisher/ProfileDetails.tsx | 51 ++++++++++ .../atoms/Publisher/PublisherLinks.module.css | 23 +++++ .../atoms/Publisher/PublisherLinks.tsx | 30 ++++++ .../atoms/Publisher/index.module.css | 47 +++++++++ src/components/atoms/Publisher/index.tsx | 99 +++++++++++++++++++ src/components/atoms/Tooltip.module.css | 1 + src/components/atoms/Tooltip.tsx | 2 +- src/components/molecules/AssetListTitle.tsx | 11 +-- src/components/molecules/AssetTeaser.tsx | 7 +- src/components/molecules/Bookmarks.tsx | 8 +- .../organisms/AssetContent/Byline.module.css | 31 ------ .../organisms/AssetContent/Byline.tsx | 48 --------- .../organisms/AssetContent/MetaFull.tsx | 9 +- .../organisms/AssetContent/index.module.css | 4 - .../organisms/AssetContent/index.tsx | 11 +-- .../organisms/AssetQueryCarousel.module.css | 36 ------- .../organisms/AssetQueryCarousel.tsx | 59 ----------- src/components/pages/History/PoolShares.tsx | 3 +- src/components/pages/Home.module.css | 13 --- src/components/pages/Home.tsx | 80 --------------- .../templates/PageMarkdown.module.css | 2 +- src/hooks/useDataPartner.ts | 28 ------ src/images/partner.svg | 5 - src/models/Profile.ts | 35 +++++++ src/utils/profile.ts | 97 ++++++++++++++++++ src/utils/wallet.ts | 1 + 33 files changed, 510 insertions(+), 485 deletions(-) delete mode 100644 src/components/atoms/Partner.module.css delete mode 100644 src/components/atoms/Partner.tsx create mode 100644 src/components/atoms/Publisher/Add.module.css create mode 100644 src/components/atoms/Publisher/Add.tsx create mode 100644 src/components/atoms/Publisher/ProfileDetails.module.css create mode 100644 src/components/atoms/Publisher/ProfileDetails.tsx create mode 100644 src/components/atoms/Publisher/PublisherLinks.module.css create mode 100644 src/components/atoms/Publisher/PublisherLinks.tsx create mode 100644 src/components/atoms/Publisher/index.module.css create mode 100644 src/components/atoms/Publisher/index.tsx delete mode 100644 src/components/organisms/AssetContent/Byline.module.css delete mode 100644 src/components/organisms/AssetContent/Byline.tsx delete mode 100644 src/components/organisms/AssetQueryCarousel.module.css delete mode 100644 src/components/organisms/AssetQueryCarousel.tsx delete mode 100644 src/hooks/useDataPartner.ts delete mode 100644 src/images/partner.svg create mode 100644 src/models/Profile.ts create mode 100644 src/utils/profile.ts diff --git a/package-lock.json b/package-lock.json index 86068f144..51dfdb82c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3566,40 +3566,16 @@ "web3-eth-contract": "^1.3.0" } }, - "@oceanprotocol/list-datapartners": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@oceanprotocol/list-datapartners/-/list-datapartners-1.0.3.tgz", - "integrity": "sha512-MMyy81FvnRGwl2cQ4+cucq/YWjUTGzStHyAUVM6P2pFA8zMc3jouuWN2WSAjmvhxeKZU7jvJRwZCoi+miEYKjw==" - }, "@oceanprotocol/react": { - "version": "0.3.21", - "resolved": "https://registry.npmjs.org/@oceanprotocol/react/-/react-0.3.21.tgz", - "integrity": "sha512-3fY3oYbJ1I2bTZzWqaHbQvVCI9Xdn3Oa0BOeWPA0757wT6gOQzdMcE/zKAFqzI6L/4006kTQF3Ls0UnKVkocUA==", + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/@oceanprotocol/react/-/react-0.3.22.tgz", + "integrity": "sha512-pPXi+4syzYWczfJXd292Wu7eJoaUZ1cjB7Js3TWE5E/YAZzQAYuaiUn9Lh5P8vHmxz8dl4Xn586jhRPWzyIRIw==", "requires": { "@oceanprotocol/lib": "^0.9.18", "axios": "^0.21.0", "decimal.js": "^10.2.1", "web3": "^1.3.0", "web3modal": "^1.9.1" - }, - "dependencies": { - "@oceanprotocol/lib": { - "version": "0.9.18", - "resolved": "https://registry.npmjs.org/@oceanprotocol/lib/-/lib-0.9.18.tgz", - "integrity": "sha512-RsP4CjAnauI2kDH0923LOO3NhdKNB1y8WwpAviVwIwz9sYqsIIcac6MKXIm5oDeLNhmCIhJXbwvQehf17wRL5Q==", - "requires": { - "@ethereum-navigator/navigator": "^0.5.0", - "@oceanprotocol/contracts": "^0.5.7", - "decimal.js": "^10.2.0", - "fs": "0.0.1-security", - "lzma": "^2.3.2", - "node-fetch": "^2.6.1", - "save-file": "^2.3.1", - "uuid": "^8.3.0", - "web3": "^1.3.0", - "web3-eth-contract": "^1.3.0" - } - } } }, "@oceanprotocol/typographies": { @@ -5807,17 +5783,6 @@ "@types/reactcss": "*" } }, - "@types/react-datepicker": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@types/react-datepicker/-/react-datepicker-3.1.1.tgz", - "integrity": "sha512-vwNrgaIMJThvvwmtnA8jSVVJZ0FNgljQrq1jDA4MtYJIDmVmd9NNrFaXf9u2JqR2nS+8Kvi8OVs/tnAbUqZhHw==", - "dev": true, - "requires": { - "@types/react": "*", - "date-fns": "^2.0.1", - "popper.js": "^1.14.1" - } - }, "@types/react-helmet": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@types/react-helmet/-/react-helmet-6.1.0.tgz", @@ -23236,6 +23201,11 @@ "resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz", "integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==" }, + "jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, "keccak": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.1.tgz", @@ -26351,7 +26321,8 @@ "popper.js": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", - "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==" + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", + "dev": true }, "portfinder": { "version": "1.0.28", @@ -27586,14 +27557,6 @@ "object-assign": "^4.1.1" } }, - "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-chartjs-2": { "version": "2.11.1", "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-2.11.1.tgz", @@ -27628,18 +27591,6 @@ "shortid": "^2.2.15" } }, - "react-datepicker": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-3.3.0.tgz", - "integrity": "sha512-QnIlBxDSWEGBi2X5P1BqWzvfnPFRKhtrsgAcujUVwyWeID/VatFaAOEjEjfD1bXR9FuSYVLlLR3j/vbG19hWOA==", - "requires": { - "classnames": "^2.2.6", - "date-fns": "^2.0.1", - "prop-types": "^15.7.2", - "react-onclickoutside": "^6.9.0", - "react-popper": "^1.3.4" - } - }, "react-dev-utils": { "version": "10.2.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-10.2.1.tgz", @@ -28288,11 +28239,6 @@ "warning": "^4.0.3" } }, - "react-onclickoutside": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.9.0.tgz", - "integrity": "sha512-8ltIY3bC7oGhj2nPAvWOGi+xGFybPNhJM0V1H8hY/whNcXgmDeaeoCMPPd8VatrpTsUWjb/vGzrmu6SrXVty3A==" - }, "react-paginate": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/react-paginate/-/react-paginate-6.5.0.tgz", @@ -28305,6 +28251,7 @@ "version": "1.3.7", "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.7.tgz", "integrity": "sha512-nmqYTx7QVjCm3WUZLeuOomna138R1luC4EqkW3hxJUrAe+3eNz3oFCLYdnPwILfn0mX1Ew2c3wctrjlUMYYUww==", + "dev": true, "requires": { "@babel/runtime": "^7.1.2", "create-react-context": "^0.3.0", @@ -32889,7 +32836,8 @@ "typed-styles": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz", - "integrity": "sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q==" + "integrity": "sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q==", + "dev": true }, "typedarray": { "version": "0.0.6", @@ -33601,11 +33549,6 @@ "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": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz", diff --git a/package.json b/package.json index 6f3ce36f3..3e28a13d6 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,6 @@ "@loadable/component": "^5.14.1", "@oceanprotocol/art": "^3.0.0", "@oceanprotocol/lib": "^0.9.18", - "@oceanprotocol/list-datapartners": "^1.0.3", "@oceanprotocol/react": "^0.3.22", "@oceanprotocol/typographies": "^0.1.0", "@sindresorhus/slugify": "^1.0.0", @@ -62,14 +61,13 @@ "gatsby-transformer-sharp": "^2.5.21", "intersection-observer": "^0.11.0", "is-url-superb": "^4.0.0", + "jwt-decode": "^3.1.2", "lodash.debounce": "^4.0.8", "lodash.omit": "^4.5.0", "query-string": "^6.13.7", "react": "^17.0.1", - "react-alice-carousel": "^2.0.2", "react-chartjs-2": "^2.11.1", "react-data-table-component": "^6.11.5", - "react-datepicker": "^3.3.0", "react-dom": "^17.0.1", "react-dotdotdot": "^1.3.1", "react-dropzone": "^11.2.3", @@ -104,7 +102,6 @@ "@types/lodash.omit": "^4.5.6", "@types/node": "^14.14.6", "@types/react": "^16.9.56", - "@types/react-datepicker": "^3.1.1", "@types/react-helmet": "^6.1.0", "@types/react-modal": "^3.10.6", "@types/react-paginate": "^6.2.1", diff --git a/src/components/atoms/Partner.module.css b/src/components/atoms/Partner.module.css deleted file mode 100644 index 2d66cd343..000000000 --- a/src/components/atoms/Partner.module.css +++ /dev/null @@ -1,24 +0,0 @@ -.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%; -} diff --git a/src/components/atoms/Partner.tsx b/src/components/atoms/Partner.tsx deleted file mode 100644 index d0cd85a76..000000000 --- a/src/components/atoms/Partner.tsx +++ /dev/null @@ -1,48 +0,0 @@ -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 ( - - - - ) -} - -export default function Partner({ - partner, - className -}: { - partner: PartnerData - className?: string -}): ReactElement { - const styleClasses = cx({ - partner: true, - [className]: className - }) - - return ( - - - Ocean Protocol{' '} - - Data Partner - - - } - placement="top" - > - - {partner.name} - - - ) -} diff --git a/src/components/atoms/Publisher/Add.module.css b/src/components/atoms/Publisher/Add.module.css new file mode 100644 index 000000000..3482d355f --- /dev/null +++ b/src/components/atoms/Publisher/Add.module.css @@ -0,0 +1,7 @@ +.add { + color: var(--brand-pink); +} + +.linksExternal { + composes: linksExternal from './index.module.css'; +} diff --git a/src/components/atoms/Publisher/Add.tsx b/src/components/atoms/Publisher/Add.tsx new file mode 100644 index 000000000..6abd071f0 --- /dev/null +++ b/src/components/atoms/Publisher/Add.tsx @@ -0,0 +1,16 @@ +import React, { ReactElement } from 'react' +import { ReactComponent as External } from '../../../images/external.svg' +import styles from './Add.module.css' + +export default function Add(): ReactElement { + return ( + + Add profile on 3Box + + ) +} diff --git a/src/components/atoms/Publisher/ProfileDetails.module.css b/src/components/atoms/Publisher/ProfileDetails.module.css new file mode 100644 index 000000000..5160bc109 --- /dev/null +++ b/src/components/atoms/Publisher/ProfileDetails.module.css @@ -0,0 +1,71 @@ +.profile { + background: var(--background-highlight); + border-radius: var(--border-radius); + padding: calc(var(--spacer) / 2); + margin-bottom: calc(var(--spacer) / 4); +} + +@media (min-width: 40rem) { + .profile { + margin: calc(var(--spacer) / 4); + } +} + +.profile p { + margin-bottom: calc(var(--spacer) / 4); +} + +.profile code { + padding: 0; + color: var(--color-secondary); + font-size: var(--font-size-mini); + overflow-wrap: break-word; + word-wrap: break-word; + word-break: break-word; +} + +.header { + margin-bottom: calc(var(--spacer) / 4); + text-align: center; +} + +.header::after { + content: ''; + display: block; + margin: calc(var(--spacer) / 2) auto; + width: 20%; + height: 2px; + background: var(--border-color); +} + +.image { + width: 48px; + height: 48px; + border-radius: 50%; + overflow: hidden; + display: inline-block; + margin-bottom: calc(var(--spacer) / 4); + border: 1px solid var(--border-color); + box-shadow: 0 6px 17px 0 var(--box-shadow-color); +} + +.title { + font-size: var(--font-size-base); + margin-bottom: 0; +} + +.description { + font-size: var(--font-size-small); +} + +.profile p:last-child { + margin-bottom: 0; +} + +.meta { + color: var(--color-secondary); + font-size: var(--font-size-mini); + text-align: right; + margin-left: calc(var(--spacer) / 4); + margin-right: calc(var(--spacer) / 4); +} diff --git a/src/components/atoms/Publisher/ProfileDetails.tsx b/src/components/atoms/Publisher/ProfileDetails.tsx new file mode 100644 index 000000000..fd8d2bd91 --- /dev/null +++ b/src/components/atoms/Publisher/ProfileDetails.tsx @@ -0,0 +1,51 @@ +import React, { ReactElement } from 'react' +import styles from './ProfileDetails.module.css' +import { Profile } from '../../../models/Profile' +import EtherscanLink from '../EtherscanLink' +import PublisherLinks from './PublisherLinks' + +export default function ProfileDetails({ + profile, + networkId, + account +}: { + profile: Profile + networkId: number + account: string +}): ReactElement { + return ( + <> +
+
+ {profile?.image && ( +
+ +
+ )} +

+ {profile?.emoji} {profile?.name} +

+ + + {account} + +
+ + {profile?.description && ( +

{profile?.description}

+ )} + +
+
+ Profile data from{' '} + + 3Box Hub + +
+ + ) +} diff --git a/src/components/atoms/Publisher/PublisherLinks.module.css b/src/components/atoms/Publisher/PublisherLinks.module.css new file mode 100644 index 000000000..fb52e55ef --- /dev/null +++ b/src/components/atoms/Publisher/PublisherLinks.module.css @@ -0,0 +1,23 @@ +.links, +.links a { + font-size: var(--font-size-small); + color: var(--color-secondary); +} + +.links a { + margin-left: calc(var(--spacer) / 3); + color: inherit; +} + +.links a:first-child { + margin-left: 0; +} + +.links a:hover, +.links a:focus { + color: var(--brand-pink); +} + +.linksExternal { + composes: linksExternal from './index.module.css'; +} diff --git a/src/components/atoms/Publisher/PublisherLinks.tsx b/src/components/atoms/Publisher/PublisherLinks.tsx new file mode 100644 index 000000000..71e6fd4cb --- /dev/null +++ b/src/components/atoms/Publisher/PublisherLinks.tsx @@ -0,0 +1,30 @@ +import React, { ReactElement } from 'react' +import styles from './PublisherLinks.module.css' +import { ProfileLink } from '../../../models/Profile' +import { ReactComponent as External } from '../../../images/external.svg' + +export default function PublisherLinks({ + links +}: { + links: ProfileLink[] +}): ReactElement { + return ( +
+ {' — '} + {links?.map((link: ProfileLink) => { + const href = + link.name === 'Twitter' + ? `https://twitter.com/${link.value}` + : link.name === 'GitHub' + ? `https://github.com/${link.value}` + : link.value + + return ( + + {link.name} + + ) + })} +
+ ) +} diff --git a/src/components/atoms/Publisher/index.module.css b/src/components/atoms/Publisher/index.module.css new file mode 100644 index 000000000..71a0287b8 --- /dev/null +++ b/src/components/atoms/Publisher/index.module.css @@ -0,0 +1,47 @@ +.publisher { + margin: 0; +} + +@media (min-width: 32rem) { + .publisher { + display: inline-block; + } +} + +.links { + display: inline; +} + +.links a, +.links span { + margin-left: calc(var(--spacer) / 3); + font-size: var(--font-size-mini); +} + +.links a:first-child, +.links span:first-child { + margin-left: 0; +} + +.links a:hover, +.links a:focus { + color: var(--brand-pink); +} + +.linksExternal { + width: 6px; + height: 6px; + display: inline-block; + fill: var(--color-secondary); +} + +.detailsTrigger { + cursor: help; +} + +.detailsTrigger svg { + width: 10px; + height: 10px; + position: relative; + bottom: -1px; +} diff --git a/src/components/atoms/Publisher/index.tsx b/src/components/atoms/Publisher/index.tsx new file mode 100644 index 000000000..2b58f9f8c --- /dev/null +++ b/src/components/atoms/Publisher/index.tsx @@ -0,0 +1,99 @@ +import React, { ReactElement, useEffect, useState } from 'react' +import styles from './index.module.css' +import classNames from 'classnames/bind' +import Tooltip from '../Tooltip' +import { Profile } from '../../../models/Profile' +import { Link } from 'gatsby' +import get3BoxProfile from '../../../utils/profile' +import EtherscanLink from '../EtherscanLink' +import { accountTruncate } from '../../../utils/wallet' +import axios from 'axios' +import { useOcean } from '@oceanprotocol/react' +import { ReactComponent as Info } from '../../../images/info.svg' +import ProfileDetails from './ProfileDetails' +import Add from './Add' + +const cx = classNames.bind(styles) + +export default function Publisher({ + account, + minimal, + className +}: { + account: string + minimal?: boolean + className?: string +}): ReactElement { + const { networkId, accountId } = useOcean() + const [profile, setProfile] = useState() + const [name, setName] = useState() + + const showAdd = account === accountId && !profile + + useEffect(() => { + if (!account) return + + setName(accountTruncate(account)) + const source = axios.CancelToken.source() + + async function get3Box() { + const profile = await get3BoxProfile(account, source.token) + if (!profile) return + + setProfile(profile) + const { name } = profile + name && setName(name) + } + get3Box() + + return () => { + source.cancel() + } + }, [account]) + + const styleClasses = cx({ + publisher: true, + [className]: className + }) + + return ( +
+ {minimal ? ( + name + ) : ( + <> + + {name} + + +
+ {' — '} + {profile && ( + + } + > + + Profile + + + )} + {showAdd && } + + Etherscan + +
+ + )} +
+ ) +} diff --git a/src/components/atoms/Tooltip.module.css b/src/components/atoms/Tooltip.module.css index ba87d2708..a98694279 100644 --- a/src/components/atoms/Tooltip.module.css +++ b/src/components/atoms/Tooltip.module.css @@ -5,6 +5,7 @@ .content { composes: box from './Box.module.css'; padding: calc(var(--spacer) / 4); + width: calc(100% - var(--spacer) / 3); max-width: 25rem; font-size: var(--font-size-small); } diff --git a/src/components/atoms/Tooltip.tsx b/src/components/atoms/Tooltip.tsx index 8a7301cd6..1719ff0a0 100644 --- a/src/components/atoms/Tooltip.tsx +++ b/src/components/atoms/Tooltip.tsx @@ -41,7 +41,7 @@ export default function Tooltip({ function onMount() { setSpring({ - transform: 'scale(1) translateY(0)', + ...animation.to, onRest: (): void => null, config: animation.config }) diff --git a/src/components/molecules/AssetListTitle.tsx b/src/components/molecules/AssetListTitle.tsx index 0410996e4..7c4084e5a 100644 --- a/src/components/molecules/AssetListTitle.tsx +++ b/src/components/molecules/AssetListTitle.tsx @@ -2,25 +2,20 @@ import { DDO } from '@oceanprotocol/lib' import { useOcean } from '@oceanprotocol/react' import { Link } from 'gatsby' import React, { ReactElement, useEffect, useState } from 'react' -import { useDataPartner } from '../../hooks/useDataPartner' import { retrieveDDO } from '../../utils/aquarius' -import { PartnerBadge } from '../atoms/Partner' import styles from './AssetListTitle.module.css' import axios from 'axios' export default function AssetListTitle({ ddo, did, - title, - owner + title }: { ddo?: DDO did?: string title?: string - owner?: string }): ReactElement { const { config } = useOcean() - const { partner } = useDataPartner(owner) const [assetTitle, setAssetTitle] = useState(title) useEffect(() => { @@ -49,9 +44,7 @@ export default function AssetListTitle({ return (

- - {partner && } {assetTitle} - + {assetTitle}

) } diff --git a/src/components/molecules/AssetTeaser.tsx b/src/components/molecules/AssetTeaser.tsx index 578f5419f..86c2f4642 100644 --- a/src/components/molecules/AssetTeaser.tsx +++ b/src/components/molecules/AssetTeaser.tsx @@ -6,9 +6,8 @@ import styles from './AssetTeaser.module.css' import { DDO } from '@oceanprotocol/lib' import removeMarkdown from 'remove-markdown' import Tooltip from '../atoms/Tooltip' +import Publisher from '../atoms/Publisher' import { useMetadata } from '@oceanprotocol/react' -import Partner from '../atoms/Partner' -import { useDataPartner } from '../../hooks/useDataPartner' declare type AssetTeaserProps = { ddo: DDO @@ -16,8 +15,6 @@ declare type AssetTeaserProps = { const AssetTeaser: React.FC = ({ ddo }: AssetTeaserProps) => { const { owner } = useMetadata(ddo) - const { partner } = useDataPartner(owner) - const { attributes } = ddo.findServiceByType('metadata') const { name } = attributes.main const { dataTokenInfo } = ddo @@ -34,7 +31,7 @@ const AssetTeaser: React.FC = ({ ddo }: AssetTeaserProps) => { {dataTokenInfo?.symbol}

{name}

- {partner && } + {isCompute &&
Compute
}
diff --git a/src/components/molecules/Bookmarks.tsx b/src/components/molecules/Bookmarks.tsx index a752a0dac..20be927be 100644 --- a/src/components/molecules/Bookmarks.tsx +++ b/src/components/molecules/Bookmarks.tsx @@ -54,13 +54,7 @@ const columns = [ name: 'Data Set', selector: function getAssetRow(row: DDO) { const { attributes } = row.findServiceByType('metadata') - return ( - - ) + return }, maxWidth: '45rem', grow: 1 diff --git a/src/components/organisms/AssetContent/Byline.module.css b/src/components/organisms/AssetContent/Byline.module.css deleted file mode 100644 index a49dcc043..000000000 --- a/src/components/organisms/AssetContent/Byline.module.css +++ /dev/null @@ -1,31 +0,0 @@ -.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); -} diff --git a/src/components/organisms/AssetContent/Byline.tsx b/src/components/organisms/AssetContent/Byline.tsx deleted file mode 100644 index 5ab932e4c..000000000 --- a/src/components/organisms/AssetContent/Byline.tsx +++ /dev/null @@ -1,48 +0,0 @@ -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 ( -
- {prefix} - - {partner ? ( - - ) : ( - owner && accountTruncate(owner) - )} - -
- {' — '} - {partner && - Object.entries(partner.links).map(([key, value]) => ( - - {key} - - ))} - - Etherscan - -
-
- ) -} diff --git a/src/components/organisms/AssetContent/MetaFull.tsx b/src/components/organisms/AssetContent/MetaFull.tsx index fbd33ee54..4e161bf16 100644 --- a/src/components/organisms/AssetContent/MetaFull.tsx +++ b/src/components/organisms/AssetContent/MetaFull.tsx @@ -4,7 +4,7 @@ import MetaItem from './MetaItem' import styles from './MetaFull.module.css' import { MetadataMarket } from '../../../@types/MetaData' import { DDO } from '@oceanprotocol/lib' -import Byline from './Byline' +import Publisher from '../../atoms/Publisher' export default function MetaFull({ ddo, @@ -18,8 +18,11 @@ export default function MetaFull({ return (
- - } /> + + } + /> {metadata?.additionalInformation?.categories && ( {showPricing && }
-

- {metadata?.main.author} -

{metadata?.additionalInformation?.categories?.length && (

- + Published By 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); -} - -.assetCarousel [class*='alice-carousel__stage-item'] *, -.assetCarousel [class*='alice-carousel__stage-item'] { - line-height: var(--line-height); -} - -.empty { - color: var(--color-secondary); - font-size: var(--font-size-small); - font-style: italic; -} diff --git a/src/components/organisms/AssetQueryCarousel.tsx b/src/components/organisms/AssetQueryCarousel.tsx deleted file mode 100644 index 37bc05218..000000000 --- a/src/components/organisms/AssetQueryCarousel.tsx +++ /dev/null @@ -1,59 +0,0 @@ -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 = ({ - queryResult, - className -}) => { - const styleClasses = cx({ - assetCarousel: true, - [className]: className - }) - - const items = - queryResult?.results.length > 0 - ? queryResult.results.map((ddo: DDO) => ( - - )) - : [ -
- No results found. -
- ] - - return ( -
- -
- ) -} - -export default AssetQueryCarousel diff --git a/src/components/pages/History/PoolShares.tsx b/src/components/pages/History/PoolShares.tsx index 05e1e0141..b892c4658 100644 --- a/src/components/pages/History/PoolShares.tsx +++ b/src/components/pages/History/PoolShares.tsx @@ -28,8 +28,7 @@ const columns = [ { name: 'Data Set', selector: function getAssetRow(row: Asset) { - const { owner } = row.ddo.publicKey[0] - return + return }, grow: 2 }, diff --git a/src/components/pages/Home.module.css b/src/components/pages/Home.module.css index 8c5922f98..7491c49aa 100644 --- a/src/components/pages/Home.module.css +++ b/src/components/pages/Home.module.css @@ -17,19 +17,6 @@ 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; diff --git a/src/components/pages/Home.tsx b/src/components/pages/Home.tsx index ed1004759..66c1b6cff 100644 --- a/src/components/pages/Home.tsx +++ b/src/components/pages/Home.tsx @@ -8,33 +8,9 @@ import Loader from '../atoms/Loader' import { useOcean } from '@oceanprotocol/react' import Button from '../atoms/Button' import Bookmarks from '../molecules/Bookmarks' -import listPartners from '@oceanprotocol/list-datapartners' -import Tooltip from '../atoms/Tooltip' -import AssetQueryCarousel from '../organisms/AssetQueryCarousel' import axios from 'axios' import { queryMetadata } from '../../utils/aquarius' -const partnerAccounts = listPartners - .map((partner) => partner.accounts.join(',')) - .filter((account) => account !== '') - -const searchAccounts = JSON.stringify(partnerAccounts) - .replace(/"/g, '') - .replace(/,/g, ' OR ') - .replace(/(\[|\])/g, '') - -const queryPartners = { - page: 1, - offset: 100, - query: { - nativeSearch: 1, - query_string: { - query: `(publicKey.owner:${searchAccounts}) -isInPurgatory:true` - } - }, - sort: { created: -1 } -} - const queryHighest = { page: 1, offset: 9, @@ -116,68 +92,12 @@ function SectionQueryResult({ } export default function HomePage(): ReactElement { - const { config } = useOcean() - - const [queryResultPartners, setQueryResultPartners] = useState() - const [loading, setLoading] = useState(true) - - useEffect(() => { - if (!config?.metadataCacheUri) return - - const source = axios.CancelToken.source() - - async function init() { - // TODO: remove any once ocean.js has nativeSearch typings - const queryResultPartners = await queryMetadata( - queryPartners as any, - config.metadataCacheUri, - source.token - ) - setQueryResultPartners(queryResultPartners) - setLoading(false) - } - init() - - return () => { - source.cancel() - } - }, [config?.metadataCacheUri]) - return ( <> -
-

- Data Partners{' '} - - Ocean Protocol{' '} - - Data Partners - - - } - /> -

- {loading ? ( - - ) : ( - queryResultPartners && ( - - ) - )} - {/* */} -
-

Bookmarks

diff --git a/src/components/templates/PageMarkdown.module.css b/src/components/templates/PageMarkdown.module.css index 19fc7a81a..072b9dc4a 100644 --- a/src/components/templates/PageMarkdown.module.css +++ b/src/components/templates/PageMarkdown.module.css @@ -76,7 +76,7 @@ margin: calc(var(--spacer) * 2) auto; max-width: 20%; border: 0; - border-top: 2px solid var(--brand-black); + border-top: 2px solid var(--border-color); } .content figure { diff --git a/src/hooks/useDataPartner.ts b/src/hooks/useDataPartner.ts deleted file mode 100644 index 7f209cb71..000000000 --- a/src/hooks/useDataPartner.ts +++ /dev/null @@ -1,28 +0,0 @@ -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() - const [partner, setPartner] = useState() - - 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 } -} diff --git a/src/images/partner.svg b/src/images/partner.svg deleted file mode 100644 index 94b485545..000000000 --- a/src/images/partner.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/models/Profile.ts b/src/models/Profile.ts new file mode 100644 index 000000000..e1850b445 --- /dev/null +++ b/src/models/Profile.ts @@ -0,0 +1,35 @@ +export interface ProfileLink { + name: string + value: string +} + +export interface Profile { + did: string + name?: string + description?: string + emoji?: string + image?: string + links?: ProfileLink[] +} + +export interface ResponseData3Box { + name: string + description: string + website: string + status?: 'error' + /* eslint-disable camelcase */ + proof_did: string + proof_twitter: string + proof_github: string + /* eslint-enable camelcase */ + emoji: string + job: string + employer: string + location: string + memberSince: string + image: { + contentUrl: { + [key: string]: string + } + }[] +} diff --git a/src/utils/profile.ts b/src/utils/profile.ts new file mode 100644 index 000000000..5b52a69fc --- /dev/null +++ b/src/utils/profile.ts @@ -0,0 +1,97 @@ +import { Profile, ProfileLink, ResponseData3Box } from '../models/Profile' +import axios, { AxiosResponse, CancelToken } from 'axios' +import jwtDecode from 'jwt-decode' +import { Logger } from '@oceanprotocol/lib' + +// https://docs.3box.io/api/rest-api +const apiUri = 'https://market-stats.oceanprotocol.com/api' +const ipfsUrl = 'https://ipfs.oceanprotocol.com' + +function decodeProof(proofJWT: string) { + if (!proofJWT) return + const proof = jwtDecode(proofJWT) as any + return proof +} + +function getLinks( + website: string, + twitterProof: string, + githubProof: string +): ProfileLink[] { + // Conditionally add links if they exist + const links = [ + ...(website ? [{ name: 'Website', value: website }] : []), + ...(twitterProof + ? [ + { + name: 'Twitter', + value: decodeProof(twitterProof).claim.twitter_handle + } + ] + : []), + ...(githubProof + ? [{ name: 'GitHub', value: githubProof.split('/')[3] }] + : []) + ] + + return links +} + +function transformResponse({ + name, + description, + website, + emoji, + image, + /* eslint-disable camelcase */ + proof_twitter, + proof_github, + proof_did +}: ResponseData3Box) { + /* eslint-enable camelcase */ + const links = getLinks(website, proof_twitter, proof_github) + + const profile: Profile = { + did: decodeProof(proof_did).iss, + // Conditionally add profile items if they exist + ...(name && { name }), + ...(description && { description }), + ...(emoji && { emoji }), + ...(image && { + image: `${ipfsUrl}/ipfs/${ + image.map( + (img: { contentUrl: { [key: string]: string } }) => + img.contentUrl['/'] + )[0] + }` + }), + ...(links.length && { links }) + } + + return profile +} + +export default async function get3BoxProfile( + accountId: string, + cancelToken: CancelToken +): Promise { + try { + const response: AxiosResponse = await axios( + `${apiUri}/profile?address=${accountId}`, + { cancelToken } + ) + + if ( + !response || + !response.data || + response.status !== 200 || + response.data.status === 'error' + ) + return + + Logger.log(`3Box profile found for ${accountId}`, response.data) + const profile = transformResponse(response.data) + return profile + // eslint-disable-next-line no-empty + } catch (error) {} +} diff --git a/src/utils/wallet.ts b/src/utils/wallet.ts index 09a0ae791..ae0144cf3 100644 --- a/src/utils/wallet.ts +++ b/src/utils/wallet.ts @@ -56,6 +56,7 @@ export function isDefaultNetwork(networkId: number): boolean { } export function accountTruncate(account: string): string { + if (!account) return const middle = account.substring(6, 38) const truncated = account.replace(middle, '…') return truncated