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

Bookmarks (#159)

* handle pinned items in UserPreferencesProvider

* prototype add/remove pins

* output pins

* pins → bookmarks

* styling

* output datatoken info
This commit is contained in:
Matthias Kretschmann 2020-10-28 23:59:14 +01:00 committed by GitHub
parent a80c6ff5e8
commit 0972944e03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 201 additions and 9 deletions

View File

@ -14,7 +14,8 @@ function Empty(): ReactElement {
export default function Table({
data,
columns,
isLoading
isLoading,
...props
}: TableProps): ReactElement {
return (
<DataTable
@ -27,6 +28,7 @@ export default function Table({
noDataComponent={<Empty />}
progressPending={isLoading}
progressComponent={<Loader />}
{...props}
/>
)
}

View File

@ -53,5 +53,5 @@
}
.symbol {
margin-bottom: 0;
display: inline-block;
}

View File

@ -6,6 +6,7 @@ import Price from '../atoms/Price'
import styles from './AssetTeaser.module.css'
import { DDO } from '@oceanprotocol/lib'
import removeMarkdown from 'remove-markdown'
import Tooltip from '../atoms/Tooltip'
declare type AssetTeaserProps = {
ddo: DDO
@ -23,7 +24,13 @@ const AssetTeaser: React.FC<AssetTeaserProps> = ({
return (
<article className={styles.teaser}>
<Link to={`/asset/${ddo.id}`} className={styles.link}>
<p className={styles.symbol}>{dataTokenInfo?.symbol}</p>
<Tooltip
placement="left"
content={dataTokenInfo?.name}
className={styles.symbol}
>
{dataTokenInfo?.symbol}
</Tooltip>
<h1 className={styles.title}>{name}</h1>
{isCompute && <div className={styles.accessLabel}>Compute</div>}

View File

@ -0,0 +1,16 @@
.title {
line-height: var(--line-height);
margin: 0;
display: inline;
}
.title a {
font-size: var(--font-size-base);
color: var(--brand-black);
}
.empty {
font-size: var(--font-size-small);
color: var(--color-secondary);
font-style: italic;
}

View File

@ -0,0 +1,87 @@
import { useUserPreferences } from '../../providers/UserPreferences'
import React, { ReactElement, useEffect, useState } from 'react'
import Table from '../atoms/Table'
import { DDO, Logger, MetadataCache } from '@oceanprotocol/lib'
import { useOcean } from '@oceanprotocol/react'
import { Link } from 'gatsby'
import styles from './Bookmarks.module.css'
import Price from '../atoms/Price'
import Tooltip from '../atoms/Tooltip'
async function getAssetsBookmarked(pins: string[], metadataCacheUri: string) {
try {
const metadataCache = new MetadataCache(metadataCacheUri, Logger)
const result: DDO[] = []
for (const pin of pins) {
result.push(await metadataCache.retrieveDDO(pin))
}
return result
} catch (error) {
Logger.error(error.message)
}
}
const columns = [
{
name: 'Data Set',
selector: function getAssetRow(row: DDO) {
const { attributes } = row.findServiceByType('metadata')
return (
<h3 className={styles.title}>
<Link to={`/asset/${row.id}`}>{attributes.main.name}</Link>
</h3>
)
},
grow: 2
},
{
name: 'Datatoken Symbol',
selector: function getAssetRow(row: DDO) {
return (
<Tooltip content={row.dataTokenInfo.name}>
{row.dataTokenInfo.symbol}
</Tooltip>
)
}
},
{
name: 'Price',
selector: function getAssetRow(row: DDO) {
return <Price ddo={row} small conversion />
},
right: true
}
]
export default function Bookmarks(): ReactElement {
const { config } = useOcean()
const { bookmarks } = useUserPreferences()
const [pinned, setPinned] = useState<DDO[]>()
const [isLoading, setIsLoading] = useState<boolean>()
const noBookmarks = !bookmarks || !bookmarks.length
useEffect(() => {
if (noBookmarks) return
async function init() {
setIsLoading(true)
const resultPinned = await getAssetsBookmarked(
bookmarks,
config.metadataCacheUri
)
setPinned(resultPinned)
setIsLoading(false)
}
init()
}, [bookmarks, config.metadataCacheUri, noBookmarks])
return noBookmarks ? (
<div className={styles.empty}>Your bookmarks will appear here.</div>
) : (
<Table columns={columns} data={pinned} isLoading={isLoading} noTableHead />
)
}

View File

@ -0,0 +1,28 @@
.bookmark {
position: absolute;
top: -10px;
right: calc(var(--spacer) / 4);
appearance: none;
background: none;
border: none;
box-shadow: none;
outline: 0;
cursor: pointer;
transition: 0.2s ease-out;
}
.bookmark svg {
fill: var(--brand-grey-light);
height: 40px;
width: 40px;
filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.2));
}
.bookmark:hover,
.bookmark:focus {
transform: translate3d(0, 6px, 0);
}
.bookmark.active svg {
fill: var(--brand-violet);
}

View File

@ -0,0 +1,23 @@
import { useUserPreferences } from '../../../providers/UserPreferences'
import React, { ReactElement } from 'react'
import styles from './Bookmark.module.css'
import { ReactComponent as BookmarkIcon } from '../../../images/bookmark.svg'
export default function Bookmark({ did }: { did: string }): ReactElement {
const { bookmarks, addBookmark, removeBookmark } = useUserPreferences()
const isBookmarked = bookmarks?.includes(did)
function handleBookmark() {
isBookmarked ? removeBookmark(did) : addBookmark(did)
}
return (
<button
onClick={handleBookmark}
className={`${styles.bookmark} ${isBookmarked ? styles.active : ''} `}
title={isBookmarked ? 'Remove Bookmark' : 'Add Bookmark'}
>
<BookmarkIcon />
</button>
)
}

View File

@ -12,6 +12,7 @@
.content {
composes: box from '../../atoms/Box.module.css';
margin-top: var(--spacer);
position: relative;
}
@media (min-width: 60rem) {

View File

@ -1,6 +1,5 @@
import { MetadataMarket } from '../../../@types/MetaData'
import React, { ReactElement } from 'react'
import Time from '../../atoms/Time'
import { Link } from 'gatsby'
import Markdown from '../../atoms/Markdown'
import MetaFull from './MetaFull'
@ -12,7 +11,7 @@ import { useUserPreferences } from '../../../providers/UserPreferences'
import Pricing from './Pricing'
import { useOcean, usePricing } from '@oceanprotocol/react'
import EtherscanLink from '../../atoms/EtherscanLink'
import MetaItem from './MetaItem'
import Bookmark from './Bookmark'
export interface AssetContentProps {
metadata: MetadataMarket
@ -89,6 +88,8 @@ export default function AssetContent({
<code>{JSON.stringify(ddo, null, 2)}</code>
</pre>
)}
<Bookmark did={ddo.id} />
</div>
</div>

View File

@ -11,6 +11,7 @@ import Container from '../atoms/Container'
import Loader from '../atoms/Loader'
import { useOcean } from '@oceanprotocol/react'
import Button from '../atoms/Button'
import Bookmarks from '../molecules/Bookmarks'
const queryHighest = {
page: 1,
@ -46,6 +47,7 @@ async function getAssets(query: SearchQuery, metadataCacheUri: string) {
export default function HomePage(): ReactElement {
const { config } = useOcean()
const [queryResultLatest, setQueryResultLatest] = useState<QueryResult>()
const [queryResultPoolsLatest, setQueryResultPoolsLatest] = useState<
QueryResult
@ -83,6 +85,11 @@ export default function HomePage(): ReactElement {
<SearchBar />
</Container>
<section className={styles.latest}>
<h3>Bookmarks</h3>
<Bookmarks />
</section>
<section className={styles.latest}>
<h3>Highest Liquidity Pools</h3>
{loading ? (

3
src/images/bookmark.svg Normal file
View File

@ -0,0 +1,3 @@
<svg width="8" height="24" viewBox="0 0 8 24" xmlns="http://www.w3.org/2000/svg">
<path d="M8 1.00001V24L4 20L0 24V1.00001C0 0.447009 0.585 -0.0199908 1 9.18139e-06H7C7.689 -0.0199908 8 0.447009 8 1.00001Z" />
</svg>

After

Width:  |  Height:  |  Size: 217 B

View File

@ -13,8 +13,11 @@ interface UserPreferencesValue {
debug: boolean
currency: string
locale: string
bookmarks: string[]
setDebug: (value: boolean) => void
setCurrency: (value: string) => void
addBookmark: (did: string) => void
removeBookmark: (did: string) => void
}
const UserPreferencesContext = createContext(null)
@ -48,13 +51,14 @@ function UserPreferencesProvider({
localStorage?.currency || 'EUR'
)
const [locale, setLocale] = useState<string>()
const [bookmarks, setBookmarks] = useState(localStorage?.bookmarks || [])
// Write values to localStorage on change
useEffect(() => {
setLocalStorage({ debug, currency })
}, [debug, currency])
setLocalStorage({ debug, currency, bookmarks })
}, [debug, currency, bookmarks])
// Set ocean-lib-js log levels, default: Error
// Set ocean.js log levels, default: Error
useEffect(() => {
debug === true
? Logger.setLevel(LogLevel.Verbose)
@ -67,6 +71,16 @@ function UserPreferencesProvider({
setLocale(window.navigator.language)
}, [])
function addBookmark(didToAdd: string): void {
const newPinned = bookmarks.concat(didToAdd)
setBookmarks(newPinned)
}
function removeBookmark(didToAdd: string): void {
const newPinned = bookmarks.filter((did: string) => did !== didToAdd)
setBookmarks(newPinned)
}
return (
<UserPreferencesContext.Provider
value={
@ -74,8 +88,11 @@ function UserPreferencesProvider({
debug,
currency,
locale,
bookmarks,
setDebug,
setCurrency
setCurrency,
addBookmark,
removeBookmark
} as UserPreferencesValue
}
>