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:
parent
a80c6ff5e8
commit
0972944e03
@ -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}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -53,5 +53,5 @@
|
||||
}
|
||||
|
||||
.symbol {
|
||||
margin-bottom: 0;
|
||||
display: inline-block;
|
||||
}
|
||||
|
@ -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>}
|
||||
|
16
src/components/molecules/Bookmarks.module.css
Normal file
16
src/components/molecules/Bookmarks.module.css
Normal 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;
|
||||
}
|
87
src/components/molecules/Bookmarks.tsx
Normal file
87
src/components/molecules/Bookmarks.tsx
Normal 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 />
|
||||
)
|
||||
}
|
28
src/components/organisms/AssetContent/Bookmark.module.css
Normal file
28
src/components/organisms/AssetContent/Bookmark.module.css
Normal 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);
|
||||
}
|
23
src/components/organisms/AssetContent/Bookmark.tsx
Normal file
23
src/components/organisms/AssetContent/Bookmark.tsx
Normal 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>
|
||||
)
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
.content {
|
||||
composes: box from '../../atoms/Box.module.css';
|
||||
margin-top: var(--spacer);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@media (min-width: 60rem) {
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
3
src/images/bookmark.svg
Normal 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 |
@ -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
|
||||
}
|
||||
>
|
||||
|
Loading…
Reference in New Issue
Block a user