mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
new changes
This commit is contained in:
parent
1c3baad181
commit
e639b419d8
0
content/repo-metadata.json
Normal file
0
content/repo-metadata.json
Normal file
8805
package-lock.json
generated
8805
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -58,6 +58,7 @@
|
||||
"react-modal": "^3.15.1",
|
||||
"react-paginate": "^8.1.3",
|
||||
"react-spring": "^9.5.2",
|
||||
"react-string-replace": "^1.1.0",
|
||||
"react-tabs": "^5.1.0",
|
||||
"react-toastify": "^9.0.4",
|
||||
"remark": "^13.0.0",
|
||||
|
@ -8,49 +8,68 @@ import React, {
|
||||
} from 'react'
|
||||
import { sleep } from '@utils/index'
|
||||
import { Orbis } from '@orbisclub/orbis-sdk'
|
||||
import { useWeb3 } from './Web3'
|
||||
|
||||
const OrbisContext = createContext(null)
|
||||
|
||||
function OrbisProvider({ children }: { children: ReactNode }): ReactElement {
|
||||
const { web3Provider } = useWeb3()
|
||||
const [orbis, setOrbis] = useState<OrbisInterface>()
|
||||
const [account, setAccount] = useState<AccountInterface>()
|
||||
const [account, setAccount] = useState<OrbisAccountInterface>()
|
||||
|
||||
// Connecting to Orbis
|
||||
const connectOrbis = async (): Promise<void> => {
|
||||
const connectOrbis = async (provider: object): Promise<void> => {
|
||||
if (!orbis) return
|
||||
|
||||
const res = await orbis.connect()
|
||||
const res = await orbis.connect(provider)
|
||||
if (res.status !== 200) {
|
||||
await sleep(2000)
|
||||
connectOrbis()
|
||||
connectOrbis(provider)
|
||||
} else {
|
||||
setAccount(res)
|
||||
}
|
||||
}
|
||||
|
||||
const checkConnection = async (provider: object): Promise<void> => {
|
||||
const res = await orbis.isConnected()
|
||||
|
||||
if (res.status === 200) {
|
||||
setAccount(res)
|
||||
} else {
|
||||
connectOrbis(web3Provider)
|
||||
}
|
||||
}
|
||||
|
||||
// Init Orbis
|
||||
useEffect(() => {
|
||||
const _orbis = new Orbis()
|
||||
setOrbis(_orbis)
|
||||
}, [])
|
||||
|
||||
// Check if already has ceramic-session
|
||||
// Check if already connected to orbis
|
||||
// useEffect(() => {
|
||||
// if (!orbis) return
|
||||
|
||||
// const isConnected = async (): Promise<void> => {
|
||||
// const res = await orbis.isConnected()
|
||||
|
||||
// if (res.status !== 200) {
|
||||
// await sleep(2000)
|
||||
// isConnected()
|
||||
// } else {
|
||||
// setAccount(res)
|
||||
// }
|
||||
// }
|
||||
|
||||
// isConnected()
|
||||
// }, [orbis])
|
||||
|
||||
// Check if wallet connected
|
||||
useEffect(() => {
|
||||
if (!orbis) return
|
||||
|
||||
const isConnected = async (): Promise<void> => {
|
||||
const res = await orbis.isConnected()
|
||||
|
||||
if (res.status !== 200) {
|
||||
await sleep(2000)
|
||||
isConnected()
|
||||
} else {
|
||||
setAccount(res)
|
||||
}
|
||||
if (!account && orbis && web3Provider) {
|
||||
checkConnection(web3Provider)
|
||||
}
|
||||
|
||||
isConnected()
|
||||
}, [orbis])
|
||||
}, [account, orbis, web3Provider])
|
||||
|
||||
return (
|
||||
<OrbisContext.Provider value={{ orbis, account, connectOrbis }}>
|
||||
|
@ -1,7 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="24" height="24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M20.25 8.511c.884.284 1.5 1.128 1.5 2.097v4.286c0 1.136-.847 2.1-1.98 2.193-.34.027-.68.052-1.02.072v3.091l-3-3c-1.354 0-2.694-.055-4.02-.163a2.115 2.115 0 01-.825-.242m9.345-8.334a2.126 2.126 0 00-.476-.095 48.64 48.64 0 00-8.048 0c-1.131.094-1.976 1.057-1.976 2.192v4.286c0 .837.46 1.58 1.155 1.951m9.345-8.334V6.637c0-1.621-1.152-3.026-2.76-3.235A48.455 48.455 0 0011.25 3c-2.115 0-4.198.137-6.24.402-1.608.209-2.76 1.614-2.76 3.235v6.226c0 1.621 1.152 3.026 2.76 3.235.577.075 1.157.14 1.74.194V21l4.155-4.155" />
|
||||
</svg>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="-1.6 -1.6 19.2 19.2">
|
||||
<path d="M16 8c0 3.866-3.582 7-8 7a9.06 9.06 0 01-2.347-.306c-.584.296-1.925.864-4.181 1.234-.2.032-.352-.176-.273-.362.354-.836.674-1.95.77-2.966C.744 11.37 0 9.76 0 8c0-3.866 3.582-7 8-7s8 3.134 8 7zM5 8a1 1 0 10-2 0 1 1 0 002 0zm4 0a1 1 0 10-2 0 1 1 0 002 0zm3 1a1 1 0 100-2 1 1 0 000 2z" />
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="19.2" height="19.2" viewBox="-1.6 -1.6 19.2 19.2"><path d="M16 8c0 3.866-3.582 7-8 7a9.06 9.06 0 01-2.347-.306c-.584.296-1.925.864-4.181 1.234-.2.032-.352-.176-.273-.362.354-.836.674-1.95.77-2.966C.744 11.37 0 9.76 0 8c0-3.866 3.582-7 8-7s8 3.134 8 7zM5 8a1 1 0 10-2 0 1 1 0 002 0zm4 0a1 1 0 10-2 0 1 1 0 002 0zm3 1a1 1 0 100-2 1 1 0 000 2z" /></svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 399 B |
2
src/@images/comment.svg
Normal file
2
src/@images/comment.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<svg width="19.2" height="19.2" viewBox="-1.6 -1.6 19.2 19.2"><path fill-rule="evenodd" d="M1.5 2.75a.25.25 0 01.25-.25h8.5a.25.25 0 01.25.25v5.5a.25.25 0 01-.25.25h-3.5a.75.75 0 00-.53.22L3.5 11.44V9.25a.75.75 0 00-.75-.75h-1a.25.25 0 01-.25-.25v-5.5zM1.75 1A1.75 1.75 0 000 2.75v5.5C0 9.216.784 10 1.75 10H2v1.543a1.457 1.457 0 002.487 1.03L7.061 10h3.189A1.75 1.75 0 0012 8.25v-5.5A1.75 1.75 0 0010.25 1h-8.5zM14.5 4.75a.25.25 0 00-.25-.25h-.5a.75.75 0 110-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0114.25 12H14v1.543a1.457 1.457 0 01-2.487 1.03L9.22 12.28a.75.75 0 111.06-1.06l2.22 2.22v-2.19a.75.75 0 01.75-.75h1a.25.25 0 00.25-.25v-5.5z"></path></svg>
|
||||
|
After Width: | Height: | Size: 667 B |
1
src/@images/laugh.svg
Normal file
1
src/@images/laugh.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="24" height="24" viewBox="-51.52 -43.52 599.04 599.04"><path d="M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm141.4 389.4c-37.8 37.8-88 58.6-141.4 58.6s-103.6-20.8-141.4-58.6S48 309.4 48 256s20.8-103.6 58.6-141.4S194.6 56 248 56s103.6 20.8 141.4 58.6S448 202.6 448 256s-20.8 103.6-58.6 141.4zM343.6 196l33.6-40.3c8.6-10.3-3.8-24.8-15.4-18l-80 48c-7.8 4.7-7.8 15.9 0 20.6l80 48c11.5 6.8 24-7.6 15.4-18L343.6 196zm-209.4 58.3l80-48c7.8-4.7 7.8-15.9 0-20.6l-80-48c-11.6-6.9-24 7.7-15.4 18l33.6 40.3-33.6 40.3c-8.7 10.4 3.8 24.8 15.4 18zM362.4 288H133.6c-8.2 0-14.5 7-13.5 15 7.5 59.2 58.9 105 121.1 105h13.6c62.2 0 113.6-45.8 121.1-105 1-8-5.3-15-13.5-15z"></path></svg>
|
After Width: | Height: | Size: 703 B |
1
src/@images/thumbsdown.svg
Normal file
1
src/@images/thumbsdown.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="24" height="24" viewBox="-43.52 -43.52 599.04 599.04"><path d="M466.27 225.31c4.674-22.647.864-44.538-8.99-62.99 2.958-23.868-4.021-48.565-17.34-66.99C438.986 39.423 404.117 0 327 0c-7 0-15 .01-22.22.01C201.195.01 168.997 40 128 40h-10.845c-5.64-4.975-13.042-8-21.155-8H32C14.327 32 0 46.327 0 64v240c0 17.673 14.327 32 32 32h64c11.842 0 22.175-6.438 27.708-16h7.052c19.146 16.953 46.013 60.653 68.76 83.4 13.667 13.667 10.153 108.6 71.76 108.6 57.58 0 95.27-31.936 95.27-104.73 0-18.41-3.93-33.73-8.85-46.54h36.48c48.602 0 85.82-41.565 85.82-85.58 0-19.15-4.96-34.99-13.73-49.84zM64 296c-13.255 0-24-10.745-24-24s10.745-24 24-24 24 10.745 24 24-10.745 24-24 24zm330.18 16.73H290.19c0 37.82 28.36 55.37 28.36 94.54 0 23.75 0 56.73-47.27 56.73-18.91-18.91-9.46-66.18-37.82-94.54C206.9 342.89 167.28 272 138.92 272H128V85.83c53.611 0 100.001-37.82 171.64-37.82h37.82c35.512 0 60.82 17.12 53.12 65.9 15.2 8.16 26.5 36.44 13.94 57.57 21.581 20.384 18.699 51.065 5.21 65.62 9.45 0 22.36 18.91 22.27 37.81-.09 18.91-16.71 37.82-37.82 37.82z"></path></svg>
|
After Width: | Height: | Size: 1.0 KiB |
1
src/@images/thumbsup.svg
Normal file
1
src/@images/thumbsup.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="24" height="24" viewBox="-43.52 -43.52 599.04 599.04"><path d="M466.27 286.69C475.04 271.84 480 256 480 236.85c0-44.015-37.218-85.58-85.82-85.58H357.7c4.92-12.81 8.85-28.13 8.85-46.54C366.55 31.936 328.86 0 271.28 0c-61.607 0-58.093 94.933-71.76 108.6-22.747 22.747-49.615 66.447-68.76 83.4H32c-17.673 0-32 14.327-32 32v240c0 17.673 14.327 32 32 32h64c14.893 0 27.408-10.174 30.978-23.95 44.509 1.001 75.06 39.94 177.802 39.94 7.22 0 15.22.01 22.22.01 77.117 0 111.986-39.423 112.94-95.33 13.319-18.425 20.299-43.122 17.34-66.99 9.854-18.452 13.664-40.343 8.99-62.99zm-61.75 53.83c12.56 21.13 1.26 49.41-13.94 57.57 7.7 48.78-17.608 65.9-53.12 65.9h-37.82c-71.639 0-118.029-37.82-171.64-37.82V240h10.92c28.36 0 67.98-70.89 94.54-97.46 28.36-28.36 18.91-75.63 37.82-94.54 47.27 0 47.27 32.98 47.27 56.73 0 39.17-28.36 56.72-28.36 94.54h103.99c21.11 0 37.73 18.91 37.82 37.82.09 18.9-12.82 37.81-22.27 37.81 13.489 14.555 16.371 45.236-5.21 65.62zM88 432c0 13.255-10.745 24-24 24s-24-10.745-24-24 10.745-24 24-24 24 10.745 24 24z"></path></svg>
|
After Width: | Height: | Size: 1.0 KiB |
89
src/@types/Orbis.d.ts
vendored
89
src/@types/Orbis.d.ts
vendored
@ -3,7 +3,7 @@
|
||||
|
||||
declare module '@orbisclub/orbis-sdk'
|
||||
|
||||
interface OrbisInterface {
|
||||
declare interface OrbisInterface {
|
||||
connect: function
|
||||
connectLit: function
|
||||
connectWithSeed: function
|
||||
@ -52,9 +52,94 @@ interface OrbisInterface {
|
||||
updateTileDocument: function
|
||||
}
|
||||
|
||||
interface AccountInterface {
|
||||
declare interface OrbisAccountInterface {
|
||||
details: object
|
||||
did: string
|
||||
result: string
|
||||
status: number
|
||||
}
|
||||
|
||||
declare interface OrbisPostCreatorDetailsInterface {
|
||||
a_r: number
|
||||
did: string
|
||||
metadata: {
|
||||
chain: string
|
||||
}
|
||||
}
|
||||
|
||||
declare interface OrbisPostMentionsInterface {
|
||||
did: string
|
||||
username: string
|
||||
}
|
||||
|
||||
interface OrbisPostContentInterface {
|
||||
body: string
|
||||
context: string
|
||||
master: string
|
||||
mentions: OrbisPostMentionsInterface[]
|
||||
reply_to: string
|
||||
type: string
|
||||
}
|
||||
|
||||
interface OrbisCreatorMetadataInterface {
|
||||
address?: string
|
||||
chain?: string
|
||||
ensName?: string
|
||||
}
|
||||
|
||||
interface OrbisCreatorProfileInterface {
|
||||
description?: string
|
||||
pfp?: string
|
||||
pfpIsNft?: {
|
||||
chain: string
|
||||
contract: string
|
||||
timestamp: string
|
||||
tokenId: string
|
||||
}
|
||||
username?: string
|
||||
}
|
||||
|
||||
declare interface OrbisPostInterface {
|
||||
content: OrbisPostContentInterface
|
||||
context: string
|
||||
context_details?: {
|
||||
channel_details?: {
|
||||
description: string
|
||||
group_id: string
|
||||
name: string
|
||||
type: string
|
||||
}
|
||||
channel_id?: string
|
||||
group_details?: {
|
||||
description: string
|
||||
name: string
|
||||
pfp: string
|
||||
}
|
||||
group_id?: string
|
||||
}
|
||||
count_commits: number
|
||||
count_downvotes: number
|
||||
count_haha: number
|
||||
count_likes: number
|
||||
count_replies: number
|
||||
creator: string
|
||||
creator_details?: {
|
||||
a_r: number
|
||||
did: string
|
||||
metadata: OrbisCreatorMetadataInterface
|
||||
nonces?: object
|
||||
profile?: OrbisCreatorProfileInterface
|
||||
}
|
||||
group_id?: string | null
|
||||
master?: string | null
|
||||
reply_to?: string | null
|
||||
reply_to_creator_details?: {
|
||||
did: string
|
||||
metadata: OrbisCreatorMetadataInterface
|
||||
profile: OrbisCreatorProfileInterface
|
||||
}
|
||||
reply_to_details?: OrbisPostContentInterface
|
||||
stream_id: string
|
||||
timestamp: number
|
||||
type: string
|
||||
}
|
||||
|
85
src/@utils/orbis.tsx
Normal file
85
src/@utils/orbis.tsx
Normal file
@ -0,0 +1,85 @@
|
||||
import React, { ReactNode } from 'react'
|
||||
import Link from 'next/link'
|
||||
import reactStringReplace from 'react-string-replace'
|
||||
|
||||
/** Regex patterns to use */
|
||||
const patternMentions = /\B@[a-z0-9_.⍙-]+/gi
|
||||
|
||||
export function didToAddress(did: string) {
|
||||
if (!did) return
|
||||
|
||||
const _did = did.split(':')
|
||||
return _did[4]
|
||||
}
|
||||
|
||||
export function formatMessage(content: OrbisPostContentInterface): ReactNode {
|
||||
if (!content || !content.body) return null
|
||||
|
||||
let { body }: { body: any } = content
|
||||
|
||||
/** Replace all <br> generated by the postbox to \n to handle line breaks */
|
||||
body = reactStringReplace(body, '<br>', function (match, i) {
|
||||
return <br key={match + i} />
|
||||
})
|
||||
|
||||
body = reactStringReplace(body, '\n', function (match, i) {
|
||||
return <br key={match + i} />
|
||||
})
|
||||
|
||||
/** Replace URLs */
|
||||
body = reactStringReplace(
|
||||
body,
|
||||
/(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})/g,
|
||||
function (match, i) {
|
||||
const shortUrl =
|
||||
match.substring(0, 25) +
|
||||
'...' +
|
||||
match.substring(match.length - 15, match.length)
|
||||
return (
|
||||
<a
|
||||
key={match + i}
|
||||
href={match}
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
title={match}
|
||||
>
|
||||
{match.length > 40 ? shortUrl : match}
|
||||
</a>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
/** Identify and replace mentions */
|
||||
|
||||
/** Get mentions in post metadata */
|
||||
const { mentions } = content
|
||||
|
||||
/** Retrieve mentions in the body */
|
||||
const mentionsInBody = content.body.toString().match(patternMentions)
|
||||
|
||||
/** Compare both and replace in body */
|
||||
if (mentionsInBody && mentions && Array.isArray(mentions)) {
|
||||
mentionsInBody.forEach((_m) => {
|
||||
/** Find mention with the same name */
|
||||
const mention = mentions.find((obj) => obj.username === _m)
|
||||
if (mention !== undefined) {
|
||||
body = reactStringReplace(body, _m, (match, i) =>
|
||||
mention.did ? (
|
||||
<Link
|
||||
href={`/profile/${didToAddress(mention.did)}`}
|
||||
key={match + i}
|
||||
>
|
||||
{mention.username}
|
||||
</Link>
|
||||
) : (
|
||||
<span className="link" key={i}>
|
||||
{mention.username}
|
||||
</span>
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
18
src/components/@shared/Orbis/Comment/Posts.module.css
Normal file
18
src/components/@shared/Orbis/Comment/Posts.module.css
Normal file
@ -0,0 +1,18 @@
|
||||
.posts {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.loader {
|
||||
border-top: 1px solid var(--border-color);
|
||||
padding: calc(var(--spacer) / 2) var(--spacer);
|
||||
}
|
||||
|
||||
.loadMore {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: calc(var(--spacer) / 2) var(--spacer);
|
||||
border-top: 1px solid var(--border-color);
|
||||
}
|
64
src/components/@shared/Orbis/Comment/Posts.tsx
Normal file
64
src/components/@shared/Orbis/Comment/Posts.tsx
Normal file
@ -0,0 +1,64 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { useOrbis } from '@context/Orbis'
|
||||
import Loader from '@shared/atoms/Loader'
|
||||
import Button from '@shared/atoms/Button'
|
||||
import Post from '../Post'
|
||||
import styles from './Posts.module.css'
|
||||
|
||||
export default function Posts({ id }: { id: string }) {
|
||||
const { orbis } = useOrbis()
|
||||
const [posts, setPosts] = useState<OrbisPostInterface[]>([])
|
||||
const [page, setPage] = useState(0)
|
||||
const [hasMore, setHasMore] = useState(false)
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const loadPosts = async () => {
|
||||
setLoading(true)
|
||||
const context = process.env.NODE_ENV
|
||||
? 'kjzl6cwe1jw149vvm1f8p9qlohhtkjuc302f22mipq95q7mevdljgx3tv9swujy'
|
||||
: id
|
||||
const { data, error } = await orbis.getPosts({ context }, page)
|
||||
if (error) {
|
||||
console.log(error)
|
||||
}
|
||||
if (data) {
|
||||
const newPosts = posts.concat(data)
|
||||
setPosts(newPosts)
|
||||
|
||||
const _hasMore = data.length >= 50
|
||||
setHasMore(_hasMore)
|
||||
|
||||
if (_hasMore) setPage((prev) => prev + 1)
|
||||
}
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
loadPosts()
|
||||
}
|
||||
}, [id])
|
||||
|
||||
return (
|
||||
<div className={styles.posts}>
|
||||
<div>
|
||||
{posts.length > 0 &&
|
||||
posts.map((post, index) => <Post key={index} post={post} />)}
|
||||
</div>
|
||||
|
||||
{loading && (
|
||||
<div className={styles.loader}>
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!loading && hasMore && (
|
||||
<div className={styles.loadMore}>
|
||||
<Button style="text" size="small" onClick={loadPosts}>
|
||||
Load More
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
37
src/components/@shared/Orbis/Comment/index.module.css
Normal file
37
src/components/@shared/Orbis/Comment/index.module.css
Normal file
@ -0,0 +1,37 @@
|
||||
.comment {
|
||||
composes: box from '@shared/atoms/Box.module.css';
|
||||
padding: 0;
|
||||
margin-top: var(--spacer);
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 620px;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
padding: calc(0.35 * var(--spacer)) var(--spacer);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
font-size: var(--font-size-h5);
|
||||
font-weight: var(--font-weight-bold);
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin: 0 1em 0 0;
|
||||
width: 1.75em;
|
||||
fill: var(--font-color-text);
|
||||
}
|
||||
|
||||
.postBox {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
padding: calc(0.35 * var(--spacer)) var(--spacer);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.content {
|
||||
overflow-y: auto;
|
||||
}
|
22
src/components/@shared/Orbis/Comment/index.tsx
Normal file
22
src/components/@shared/Orbis/Comment/index.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import React from 'react'
|
||||
import styles from './index.module.css'
|
||||
import Posts from './Posts'
|
||||
import Postbox from '../Postbox'
|
||||
import CommentIcon from '@images/comment.svg'
|
||||
|
||||
export default function Comment({ asset }: { asset: AssetExtended }) {
|
||||
return (
|
||||
<div className={styles.comment}>
|
||||
<div className={styles.header}>
|
||||
<CommentIcon role="img" aria-label="Comment" className={styles.icon} />
|
||||
<span>Public Comment</span>
|
||||
</div>
|
||||
<div className={styles.postBox}>
|
||||
<Postbox placeholder="Share your comment here..." />
|
||||
</div>
|
||||
<div className={styles.content}>
|
||||
<Posts id={asset?.id} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
.conversation {
|
||||
position: fixed;
|
||||
width: 400px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
right: calc(var(--spacer) / 3);
|
||||
bottom: calc(var(--spacer) / 3);
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.toggler {
|
||||
width: 3.5rem;
|
||||
height: 3.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 50%;
|
||||
margin-left: calc(var(--spacer) / 3);
|
||||
background-color: var(--background-content);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.toggler svg {
|
||||
fill: var(--brand-grey-light);
|
||||
transition: 0.2s ease-out;
|
||||
width: 1.75em;
|
||||
}
|
||||
|
||||
.toggler:hover svg {
|
||||
fill: var(--font-color-text);
|
||||
}
|
||||
|
||||
.box {
|
||||
height: 600px;
|
||||
max-height: 100%;
|
||||
width: 350px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 42rem) {
|
||||
.conversation {
|
||||
right: calc(var(--spacer) / 2);
|
||||
bottom: calc(var(--spacer) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 55rem) {
|
||||
.conversation {
|
||||
right: var(--spacer);
|
||||
bottom: var(--spacer);
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
import React, { useState } from 'react'
|
||||
import Tooltip from '@shared/atoms/Tooltip'
|
||||
import ChatBubble from '@images/chatbubble.svg'
|
||||
import styles from './index.module.css'
|
||||
|
||||
export default function FloatingChat() {
|
||||
const [opened, setOpened] = useState(false)
|
||||
|
||||
return (
|
||||
<div className={`${styles.conversation}`}>
|
||||
<Tooltip
|
||||
content={
|
||||
<div className={styles.box}>
|
||||
<div className={styles.header}>Header</div>
|
||||
<div className={styles.body}>Messages</div>
|
||||
<div className={styles.footer}>Postbox</div>
|
||||
</div>
|
||||
}
|
||||
trigger="click focus"
|
||||
className={styles.toggler}
|
||||
placement="top-end"
|
||||
>
|
||||
<ChatBubble aria-label="Messages" className={styles.icon} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
)
|
||||
}
|
5
src/components/@shared/Orbis/FloatingChat/DmDetails.tsx
Normal file
5
src/components/@shared/Orbis/FloatingChat/DmDetails.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import React from 'react'
|
||||
|
||||
export default function DmDetails() {
|
||||
return <div>DmDetails</div>
|
||||
}
|
@ -47,6 +47,7 @@
|
||||
margin-left: 0;
|
||||
width: 1.5rem;
|
||||
margin-right: calc(0.5 * var(--spacer));
|
||||
fill: var(--font-color-text);
|
||||
}
|
||||
|
||||
.toggle {
|
||||
@ -59,10 +60,28 @@
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.toggle .icon {
|
||||
fill: transparent;
|
||||
}
|
||||
|
||||
.isFlipped {
|
||||
transform: scaleY(-1);
|
||||
}
|
||||
|
||||
.dmItem {
|
||||
padding: calc(var(--spacer) / 2);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.dmDetails {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: var(--background-body);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 42rem) {
|
||||
.wrapper {
|
||||
padding: 0 calc(var(--spacer) / 2);
|
||||
|
@ -5,13 +5,20 @@ import styles from './index.module.css'
|
||||
|
||||
export default function FloatingChat() {
|
||||
const [opened, setOpened] = useState(false)
|
||||
const [dmDetails, setDmDetails] = useState(null)
|
||||
|
||||
const dummyData = [{ name: 'John' }, { name: 'Jane' }]
|
||||
|
||||
const openDetails = (name: string) => {
|
||||
setDmDetails(name)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`${styles.wrapper} ${!opened && styles.isClosed}`}>
|
||||
<div className={styles.floating}>
|
||||
<div className={styles.header}>
|
||||
<ChatBubble role="img" aria-label="Chat" className={styles.icon} />
|
||||
<span>Messages</span>
|
||||
<span>Direct Messages</span>
|
||||
<button
|
||||
type="button"
|
||||
className={styles.toggle}
|
||||
@ -24,6 +31,21 @@ export default function FloatingChat() {
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<div style={{ position: 'relative' }}>
|
||||
{dummyData.map((dm, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={styles.dmItem}
|
||||
onClick={() => openDetails(dm.name)}
|
||||
>
|
||||
{dm.name}
|
||||
</div>
|
||||
))}
|
||||
|
||||
{dmDetails && (
|
||||
<div className={styles.dmDetails}>Details {dmDetails}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
72
src/components/@shared/Orbis/Post.module.css
Normal file
72
src/components/@shared/Orbis/Post.module.css
Normal file
@ -0,0 +1,72 @@
|
||||
.post {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: calc(var(--spacer) / 2) var(--spacer);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.post:last-of-type {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
.profile {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: calc(var(--spacer) / 4);
|
||||
margin-bottom: calc(var(--spacer) / 8);
|
||||
}
|
||||
|
||||
.profile > .name {
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
|
||||
.profile > .metadata {
|
||||
font-size: var(--font-size-mini);
|
||||
}
|
||||
|
||||
.blockies {
|
||||
aspect-ratio: 1/1;
|
||||
flex-shrink: 0;
|
||||
width: calc(var(--font-size-large) * 1.5) !important;
|
||||
height: calc(var(--font-size-large) * 1.5) !important;
|
||||
/* border-radius: 50%; */
|
||||
margin-left: 0;
|
||||
margin-right: calc(var(--spacer) / 2);
|
||||
}
|
||||
|
||||
.reactions {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: calc(var(--spacer) / 2);
|
||||
margin-top: calc(var(--spacer) / 2);
|
||||
}
|
||||
|
||||
.reactions button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
color: var(--font-color-text);
|
||||
}
|
||||
|
||||
.reactions button:hover,
|
||||
.reactions button.reacted {
|
||||
color: var(--brand-pink);
|
||||
}
|
||||
|
||||
.reactions svg {
|
||||
fill: currentColor;
|
||||
width: var(--font-size-large);
|
||||
margin-right: calc(var(--spacer) / 8);
|
||||
}
|
160
src/components/@shared/Orbis/Post.tsx
Normal file
160
src/components/@shared/Orbis/Post.tsx
Normal file
@ -0,0 +1,160 @@
|
||||
import React, { useState, useEffect, ReactNode } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { accountTruncate } from '@utils/web3'
|
||||
import { didToAddress, formatMessage } from '@utils/orbis'
|
||||
import get3BoxProfile from '@utils/profile'
|
||||
import Blockies from '@shared/atoms/Blockies'
|
||||
import Time from '@shared/atoms/Time'
|
||||
import { useCancelToken } from '@hooks/useCancelToken'
|
||||
import { useOrbis } from '@context/Orbis'
|
||||
import styles from './Post.module.css'
|
||||
|
||||
import ThumbsUp from '@images/thumbsup.svg'
|
||||
import ThumbsDown from '@images/thumbsdown.svg'
|
||||
import Laugh from '@images/laugh.svg'
|
||||
|
||||
export default function Post({
|
||||
post,
|
||||
showProfile = true
|
||||
}: {
|
||||
post: OrbisPostInterface
|
||||
showProfile?: boolean
|
||||
}) {
|
||||
const { orbis, account } = useOrbis()
|
||||
|
||||
const [address, setAddress] = useState('')
|
||||
const [name, setName] = useState('')
|
||||
const [profile, setProfile] = useState<Profile>()
|
||||
const [parsedBody, setParsedBody] = useState<ReactNode>()
|
||||
const [reacted, setReacted] = useState('')
|
||||
|
||||
const newCancelToken = useCancelToken()
|
||||
|
||||
const reactions = [
|
||||
// {
|
||||
// ctx: 'reply',
|
||||
// countKey: 'count_replies',
|
||||
// count: post.count_replies,
|
||||
// title: 'Reply',
|
||||
// icon:
|
||||
// },
|
||||
{
|
||||
ctx: 'like',
|
||||
countKey: 'count_likes',
|
||||
count: post.count_likes,
|
||||
title: 'Like',
|
||||
icon: <ThumbsUp role="img" aria-label="Like" />
|
||||
},
|
||||
{
|
||||
ctx: 'downvote',
|
||||
countKey: 'count_downvotes',
|
||||
count: post.count_downvotes,
|
||||
title: 'Downvote',
|
||||
icon: <ThumbsDown role="img" aria-label="Downvote" />
|
||||
},
|
||||
{
|
||||
ctx: 'haha',
|
||||
countKey: 'count_haha',
|
||||
count: post.count_haha,
|
||||
title: 'HA HA',
|
||||
icon: <Laugh role="img" aria-label="Downvote" />
|
||||
}
|
||||
]
|
||||
|
||||
const getUserReaction = async () => {
|
||||
if (!account?.did || !post?.stream_id) return
|
||||
|
||||
const { data, error } = await orbis.api
|
||||
.from('orbis_reactions')
|
||||
.select('type')
|
||||
.eq('post_id', post.stream_id)
|
||||
.eq('creator', account.did)
|
||||
|
||||
if (error) {
|
||||
console.log(error)
|
||||
}
|
||||
|
||||
if (data) {
|
||||
if (data.length > 0) {
|
||||
console.log(data[0].type, post.content.body)
|
||||
setReacted(data[0].type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleReaction = (type: string) => {
|
||||
console.log(type)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!post) return
|
||||
|
||||
const address =
|
||||
post?.creator_details?.metadata?.address ||
|
||||
didToAddress(post?.creator_details?.did)
|
||||
|
||||
setAddress(address)
|
||||
|
||||
if (post?.creator_details?.metadata?.ensName) {
|
||||
setName(post?.creator_details?.metadata?.ensName)
|
||||
} else if (post?.creator_details?.profile?.username) {
|
||||
setName(post?.creator_details?.profile?.username)
|
||||
} else {
|
||||
setName(accountTruncate(address))
|
||||
}
|
||||
|
||||
async function getProfileData() {
|
||||
const profile = await get3BoxProfile(address, newCancelToken())
|
||||
if (!profile) return
|
||||
setProfile(profile)
|
||||
}
|
||||
getProfileData()
|
||||
|
||||
setParsedBody(formatMessage(post.content))
|
||||
|
||||
getUserReaction()
|
||||
}, [post])
|
||||
|
||||
useEffect(() => {
|
||||
if (orbis && account) getUserReaction()
|
||||
}, [orbis, account])
|
||||
|
||||
return (
|
||||
<div className={styles.post}>
|
||||
<Blockies
|
||||
accountId={address}
|
||||
className={styles.blockies}
|
||||
image={profile?.image}
|
||||
/>
|
||||
<div className={styles.content}>
|
||||
{showProfile && (
|
||||
<div className={styles.profile}>
|
||||
<Link href={`/profile/${address}`}>
|
||||
<a className={styles.name}>{name}</a>
|
||||
</Link>
|
||||
<span>•</span>
|
||||
<div className={styles.metadata}>{accountTruncate(address)}</div>
|
||||
<span>•</span>
|
||||
<div className={styles.metadata}>
|
||||
<Time date={post.timestamp.toString()} isUnix={true} relative />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className={styles.message}>{parsedBody}</div>
|
||||
<div className={styles.reactions}>
|
||||
{reactions.map(({ ctx, count, icon, title }) => (
|
||||
<button
|
||||
key={ctx}
|
||||
onClick={() => handleReaction(ctx)}
|
||||
title={title}
|
||||
className={ctx === reacted && styles.reacted}
|
||||
>
|
||||
{icon}
|
||||
<span>{count}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
20
src/components/@shared/Orbis/Postbox.module.css
Normal file
20
src/components/@shared/Orbis/Postbox.module.css
Normal file
@ -0,0 +1,20 @@
|
||||
.postbox {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.postbox .editable {
|
||||
padding: calc(var(--spacer) / 4);
|
||||
border-radius: var(--border-radius);
|
||||
border: 1px solid var(--border-color);
|
||||
min-height: 80px;
|
||||
margin-bottom: calc(var(--spacer) / 4);
|
||||
}
|
||||
|
||||
.postbox .editable:empty:before {
|
||||
content: attr(data-placeholder);
|
||||
color: var(--font-color-text);
|
||||
}
|
||||
|
||||
.postbox .sendButtonWrap {
|
||||
text-align: right;
|
||||
}
|
34
src/components/@shared/Orbis/Postbox.tsx
Normal file
34
src/components/@shared/Orbis/Postbox.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import React, { useRef } from 'react'
|
||||
import Button from '@shared/atoms/Button'
|
||||
import styles from './Postbox.module.css'
|
||||
|
||||
export default function Postbox({
|
||||
placeholder = 'Share your post here...'
|
||||
}: {
|
||||
placeholder: string
|
||||
}) {
|
||||
const postBoxArea = useRef(null)
|
||||
|
||||
// const handleInput = (e: Event): FormEvent<HTMLDivElement> => {
|
||||
// e.preventDefault()
|
||||
// console.log(e)
|
||||
// }
|
||||
return (
|
||||
<>
|
||||
<div className={styles.postbox}>
|
||||
<div
|
||||
id="postbox-area"
|
||||
ref={postBoxArea}
|
||||
className={styles.editable}
|
||||
contentEditable={true}
|
||||
data-placeholder={placeholder}
|
||||
></div>
|
||||
<div className={styles.sendButtonWrap}>
|
||||
<Button style="primary" type="submit" size="small" disabled={false}>
|
||||
Send
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
@ -2,7 +2,7 @@ import React, { ReactElement } from 'react'
|
||||
import Alert from '@shared/atoms/Alert'
|
||||
import Footer from '../Footer/Footer'
|
||||
import Header from '../Header'
|
||||
import Conversation from '@shared/Orbis/Conversation'
|
||||
import FloatingChat from '@shared/Orbis/FloatingChat'
|
||||
import { useWeb3 } from '@context/Web3'
|
||||
import { useAccountPurgatory } from '@hooks/useAccountPurgatory'
|
||||
import AnnouncementBanner from '@shared/AnnouncementBanner'
|
||||
@ -39,7 +39,7 @@ export default function App({
|
||||
<main className={styles.main}>{children}</main>
|
||||
<Footer />
|
||||
|
||||
<Conversation />
|
||||
<FloatingChat />
|
||||
|
||||
{appConfig?.privacyPreferenceCenter === 'true' && (
|
||||
<PrivacyPreferenceCenter style="small" />
|
||||
|
@ -4,7 +4,6 @@ import MetaFull from './MetaFull'
|
||||
import MetaSecondary from './MetaSecondary'
|
||||
import AssetActions from '../AssetActions'
|
||||
import { useUserPreferences } from '@context/UserPreferences'
|
||||
import { useOrbis } from '@context/Orbis'
|
||||
import Bookmark from './Bookmark'
|
||||
import { useAsset } from '@context/Asset'
|
||||
import Alert from '@shared/atoms/Alert'
|
||||
@ -16,6 +15,7 @@ import NetworkName from '@shared/NetworkName'
|
||||
import content from '../../../../content/purgatory.json'
|
||||
import Web3 from 'web3'
|
||||
import Button from '@shared/atoms/Button'
|
||||
import Comment from '../../@shared/Orbis/Comment'
|
||||
|
||||
export default function AssetContent({
|
||||
asset
|
||||
@ -23,7 +23,6 @@ export default function AssetContent({
|
||||
asset: AssetExtended
|
||||
}): ReactElement {
|
||||
const { isInPurgatory, purgatoryData, isOwner, isAssetNetwork } = useAsset()
|
||||
const { account, connectOrbis } = useOrbis()
|
||||
const { debug } = useUserPreferences()
|
||||
const [receipts, setReceipts] = useState([])
|
||||
const [nftPublisher, setNftPublisher] = useState<string>()
|
||||
@ -36,10 +35,6 @@ export default function AssetContent({
|
||||
)
|
||||
}, [receipts])
|
||||
|
||||
useEffect(() => {
|
||||
console.log(account)
|
||||
}, [account])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles.networkWrap}>
|
||||
@ -74,9 +69,7 @@ export default function AssetContent({
|
||||
{debug === true && <DebugOutput title="DDO" output={asset} />}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button onClick={() => connectOrbis()}>Connect Orbis</button>
|
||||
</div>
|
||||
<Comment asset={asset} />
|
||||
</div>
|
||||
|
||||
<div className={styles.actions}>
|
||||
|
Loading…
x
Reference in New Issue
Block a user