feat: sorting reaction component
This commit is contained in:
parent
d7d710005e
commit
f9ff893763
|
|
@ -30,6 +30,7 @@
|
|||
"Cancel Reply": "取消回复",
|
||||
"ago": "{{time}}前",
|
||||
"joined ago": "{{time}}前加入",
|
||||
"Like": "点赞",
|
||||
"Mint to an NFT": "铸造为 NFT",
|
||||
"Like successfull": "点赞成功",
|
||||
"Mint successfull": "铸造成功",
|
||||
|
|
@ -59,5 +60,6 @@
|
|||
"One-time": "一次性",
|
||||
"Monthly and NFT Rewards": "每月和 NFT 奖励",
|
||||
"Coming soon": "即将推出",
|
||||
"What is Mira? Where can I get some?" : "Mira 是什么?我在哪里可以获得?"
|
||||
"What is Mira? Where can I get some?" : "Mira 是什么?我在哪里可以获得?",
|
||||
"Tip": "赞赏"
|
||||
}
|
||||
|
|
@ -14,7 +14,9 @@ export const CharacterList: React.FC<{
|
|||
setOpen: (open: boolean) => void
|
||||
hasMore: boolean
|
||||
loadMore: () => Promise<void>
|
||||
list: any[]
|
||||
list: {
|
||||
list: any[]
|
||||
}[]
|
||||
title: string
|
||||
}> = ({ open, setOpen, hasMore, loadMore, list, title }) => {
|
||||
const { t } = useTranslation("common")
|
||||
|
|
@ -33,44 +35,49 @@ export const CharacterList: React.FC<{
|
|||
useWindow={false}
|
||||
>
|
||||
{list?.length ? (
|
||||
list.map((sub: any, index) => (
|
||||
<div
|
||||
className="py-3 flex items-center space-x-2 text-sm"
|
||||
key={index}
|
||||
>
|
||||
<UniLink
|
||||
href={getSiteLink({
|
||||
subdomain: sub?.character?.handle,
|
||||
})}
|
||||
className="flex items-center space-x-2 text-sm"
|
||||
>
|
||||
<CharacterFloatCard siteId={sub?.character?.handle}>
|
||||
<Avatar
|
||||
className="align-middle border-2 border-white"
|
||||
images={sub.character?.metadata?.content?.avatars || []}
|
||||
name={
|
||||
sub.character?.metadata?.content?.name ||
|
||||
sub.character?.handle
|
||||
list.map((page) =>
|
||||
page.list?.map((sub: any, index) => {
|
||||
const character = sub?.character || sub?.fromCharacter
|
||||
return (
|
||||
<div
|
||||
className="py-3 flex items-center space-x-2 text-sm"
|
||||
key={index}
|
||||
>
|
||||
<UniLink
|
||||
href={getSiteLink({
|
||||
subdomain: character?.handle,
|
||||
})}
|
||||
className="flex items-center space-x-2 text-sm"
|
||||
>
|
||||
<CharacterFloatCard siteId={character?.handle}>
|
||||
<Avatar
|
||||
className="align-middle border-2 border-white"
|
||||
images={character?.metadata?.content?.avatars || []}
|
||||
name={
|
||||
character?.metadata?.content?.name ||
|
||||
character?.handle
|
||||
}
|
||||
size={40}
|
||||
/>
|
||||
</CharacterFloatCard>
|
||||
<span>{character?.metadata?.content?.name}</span>
|
||||
<span className="text-zinc-400 truncate max-w-xs">
|
||||
@{character?.handle}
|
||||
</span>
|
||||
</UniLink>
|
||||
<UniLink
|
||||
href={
|
||||
CSB_SCAN +
|
||||
"/tx/" +
|
||||
(sub.metadata?.proof || sub.transactionHash)
|
||||
}
|
||||
size={40}
|
||||
/>
|
||||
</CharacterFloatCard>
|
||||
<span>{sub.character?.metadata?.content?.name}</span>
|
||||
<span className="text-zinc-400 truncate max-w-xs">
|
||||
@{sub.character?.handle}
|
||||
</span>
|
||||
</UniLink>
|
||||
<UniLink
|
||||
href={
|
||||
CSB_SCAN +
|
||||
"/tx/" +
|
||||
(sub.metadata?.proof || sub.transactionHash)
|
||||
}
|
||||
>
|
||||
<BlockchainIcon />
|
||||
</UniLink>
|
||||
</div>
|
||||
))
|
||||
>
|
||||
<BlockchainIcon />
|
||||
</UniLink>
|
||||
</div>
|
||||
)
|
||||
}),
|
||||
)
|
||||
) : (
|
||||
<div className="py-3 text-center text-zinc-300">
|
||||
{t("No Content Yet.")}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import { CharacterFloatCard } from "./CharacterFloatCard"
|
|||
import { UniLink } from "../ui/UniLink"
|
||||
import { getSiteLink } from "~/lib/helpers"
|
||||
import { CSB_SCAN } from "~/lib/env"
|
||||
import { BlockchainIcon } from "../icons/BlockchainIcon"
|
||||
|
||||
export const PatronModal: React.FC<{
|
||||
site: Profile | undefined | null
|
||||
|
|
|
|||
|
|
@ -21,23 +21,23 @@ import { cn } from "~/lib/utils"
|
|||
import { Tooltip } from "~/components/ui/Tooltip"
|
||||
import confetti from "canvas-confetti"
|
||||
import { Trans, useTranslation } from "next-i18next"
|
||||
import { Profile } from "~/lib/types"
|
||||
|
||||
export const Reactions: React.FC<{
|
||||
className?: string
|
||||
size?: "sm" | "base"
|
||||
pageId?: string
|
||||
}> = ({ className, size, pageId }) => {
|
||||
site?: Profile | null
|
||||
}> = ({ className, size, pageId, site }) => {
|
||||
const toggleLikePage = useToggleLikePage()
|
||||
const mintPage = useMintPage()
|
||||
const { t } = useTranslation("common")
|
||||
|
||||
// like
|
||||
const userSite = useAccountSites()
|
||||
const [isLikeOpen, setIsLikeOpen] = useState(false)
|
||||
const [isMintOpen, setIsMintOpen] = useState(false)
|
||||
const [isLikeListOpen, setIsLikeListOpen] = useState(false)
|
||||
const [isMintListOpen, setIsMintListOpen] = useState(false)
|
||||
const likeRef = useRef<HTMLButtonElement>(null)
|
||||
const mintRef = useRef<HTMLButtonElement>(null)
|
||||
|
||||
const [likes, likesMutation] = useGetLikes({ pageId })
|
||||
const [likeStatus] = useCheckLike({
|
||||
|
|
@ -51,12 +51,6 @@ export const Reactions: React.FC<{
|
|||
}
|
||||
}
|
||||
|
||||
const mints = useGetMints({
|
||||
pageId: pageId,
|
||||
includeCharacter: size !== "sm",
|
||||
})
|
||||
const isMint = useCheckMint(pageId)
|
||||
|
||||
const like = () => {
|
||||
if (pageId) {
|
||||
if (likeStatus.isLiked) {
|
||||
|
|
@ -87,6 +81,23 @@ export const Reactions: React.FC<{
|
|||
}
|
||||
}, [toggleLikePage.isSuccess])
|
||||
|
||||
// mint
|
||||
const [isMintOpen, setIsMintOpen] = useState(false)
|
||||
const [isMintListOpen, setIsMintListOpen] = useState(false)
|
||||
const mintRef = useRef<HTMLButtonElement>(null)
|
||||
|
||||
const mints = useGetMints({
|
||||
pageId: pageId,
|
||||
includeCharacter: size !== "sm",
|
||||
})
|
||||
const isMint = useCheckMint(pageId)
|
||||
|
||||
const loadMoreMints = async () => {
|
||||
if (mints.hasNextPage && !mints.isFetchingNextPage) {
|
||||
await mints.fetchNextPage()
|
||||
}
|
||||
}
|
||||
|
||||
const mint = () => {
|
||||
if (pageId) {
|
||||
if (isMint.data?.count) {
|
||||
|
|
@ -123,41 +134,16 @@ export const Reactions: React.FC<{
|
|||
}
|
||||
}, [mintPage.isSuccess])
|
||||
|
||||
const [mintList, setMintList] = useState<any[]>([])
|
||||
const [mintCursor, setMintCursor] = useState<string>()
|
||||
useEffect(() => {
|
||||
if (mints.isSuccess && mints.data) {
|
||||
setMintList(mints.data.list || [])
|
||||
setMintCursor(mints.data.cursor || "")
|
||||
}
|
||||
}, [mints.isSuccess, mints.data])
|
||||
|
||||
const loadMoreMints = async () => {
|
||||
if (mintCursor && pageId) {
|
||||
const subs = await getMints({
|
||||
pageId: pageId,
|
||||
cursor: mintCursor,
|
||||
})
|
||||
setMintList((prev) => [...prev, ...(subs?.list || [])])
|
||||
setMintCursor(subs?.cursor || "")
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={cn(
|
||||
"xlog-reactions flex fill-gray-400 text-gray-500 items-center",
|
||||
size === "sm" ? "text-sm" : "",
|
||||
"xlog-reactions flex fill-gray-400 text-gray-500 sm:items-center",
|
||||
size === "sm" ? "text-sm space-x-3" : "space-x-6 sm:space-x-10",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
"xlog-reactions-like flex items-center",
|
||||
size === "sm" ? "mr-3" : "mr-10",
|
||||
)}
|
||||
>
|
||||
<div className={cn("xlog-reactions-like flex items-center sm:mb-0")}>
|
||||
<Button
|
||||
variant="like"
|
||||
className={`flex items-center mr-2 ${
|
||||
|
|
@ -168,17 +154,28 @@ export const Reactions: React.FC<{
|
|||
isLoading={userSite.isLoading || toggleLikePage.isPending}
|
||||
ref={likeRef}
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
"i-mingcute:thumb-up-2-fill mr-1",
|
||||
size === "sm" ? "text-base" : "text-[40px]",
|
||||
)}
|
||||
></span>
|
||||
{(() => {
|
||||
const inner = (
|
||||
<span
|
||||
className={cn(
|
||||
"i-mingcute:thumb-up-2-fill mr-1",
|
||||
size === "sm" ? "text-base" : "text-[40px]",
|
||||
)}
|
||||
></span>
|
||||
)
|
||||
return size !== "sm" ? (
|
||||
<Tooltip label={t("Like")} placement="top">
|
||||
{inner}
|
||||
</Tooltip>
|
||||
) : (
|
||||
inner
|
||||
)
|
||||
})()}
|
||||
<span>{likeCount}</span>
|
||||
</Button>
|
||||
{size !== "sm" && (
|
||||
<ul
|
||||
className="-space-x-4 cursor-pointer"
|
||||
className="-space-x-4 cursor-pointer hidden sm:inline-block"
|
||||
onClick={() => setIsLikeListOpen(true)}
|
||||
>
|
||||
{likes
|
||||
|
|
@ -207,38 +204,38 @@ export const Reactions: React.FC<{
|
|||
)}
|
||||
</div>
|
||||
<div className="xlog-reactions-mint flex items-center">
|
||||
{(() => {
|
||||
const inner = (
|
||||
<Button
|
||||
variant="collect"
|
||||
className={`flex items-center mr-2 ${
|
||||
isMint.isSuccess && isMint.data.count && "active"
|
||||
}`}
|
||||
isAutoWidth={true}
|
||||
onClick={mint}
|
||||
isLoading={mintPage.isLoading}
|
||||
ref={mintRef}
|
||||
>
|
||||
<Button
|
||||
variant="collect"
|
||||
className={`flex items-center mr-2 ${
|
||||
isMint.isSuccess && isMint.data.count && "active"
|
||||
}`}
|
||||
isAutoWidth={true}
|
||||
onClick={mint}
|
||||
isLoading={mintPage.isLoading}
|
||||
ref={mintRef}
|
||||
>
|
||||
{(() => {
|
||||
const inner = (
|
||||
<MintIcon
|
||||
className={cn("mr-2", size === "sm" ? "w-3 h-3" : "w-8 h-8")}
|
||||
className={cn(size === "sm" ? "w-3 h-3" : "w-8 h-8")}
|
||||
/>
|
||||
<span>{mints.data?.count || 0}</span>
|
||||
</Button>
|
||||
)
|
||||
return size !== "sm" ? (
|
||||
<Tooltip label={t("Mint to an NFT")} placement="top">
|
||||
{inner}
|
||||
</Tooltip>
|
||||
) : (
|
||||
inner
|
||||
)
|
||||
})()}
|
||||
)
|
||||
return size !== "sm" ? (
|
||||
<Tooltip label={t("Mint to an NFT")} placement="top">
|
||||
{inner}
|
||||
</Tooltip>
|
||||
) : (
|
||||
inner
|
||||
)
|
||||
})()}
|
||||
<span className="ml-2">{mints.data?.pages?.[0]?.count || 0}</span>
|
||||
</Button>
|
||||
{size !== "sm" && (
|
||||
<ul
|
||||
className="-space-x-4 cursor-pointer"
|
||||
className="-space-x-4 cursor-pointer hidden sm:inline-block"
|
||||
onClick={() => setIsMintListOpen(true)}
|
||||
>
|
||||
{mints.data?.list
|
||||
{mints.data?.pages?.[0]?.list
|
||||
?.sort((a, b: any) =>
|
||||
b.character?.metadata?.content?.avatars?.[0] ? 1 : -1,
|
||||
)
|
||||
|
|
@ -253,10 +250,10 @@ export const Reactions: React.FC<{
|
|||
/>
|
||||
</li>
|
||||
))}
|
||||
{(mints.data?.count || 0) > 3 && (
|
||||
{(mints.data?.pages?.[0]?.count || 0) > 3 && (
|
||||
<li className="inline-block">
|
||||
<div className="relative align-middle border-2 border-white w-10 h-10 rounded-full inline-flex bg-gray-100 items-center justify-center text-gray-400 font-medium">
|
||||
+{mints.data!.count - 3}
|
||||
+{mints.data!.pages?.[0]?.count - 3}
|
||||
</div>
|
||||
</li>
|
||||
)}
|
||||
|
|
@ -320,15 +317,15 @@ export const Reactions: React.FC<{
|
|||
title={t("Like List")}
|
||||
loadMore={loadMoreLikes}
|
||||
hasMore={!!likesMutation.hasNextPage}
|
||||
list={likes}
|
||||
list={likesMutation.data?.pages || []}
|
||||
></CharacterList>
|
||||
<CharacterList
|
||||
open={isMintListOpen}
|
||||
setOpen={setIsMintListOpen}
|
||||
title={t("Mint List")}
|
||||
loadMore={loadMoreMints}
|
||||
hasMore={!!mintCursor}
|
||||
list={mintList}
|
||||
hasMore={!!mints.hasNextPage}
|
||||
list={mints.data?.pages || []}
|
||||
></CharacterList>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
import { Note } from "~/lib/types"
|
||||
import { Note, Profile } from "~/lib/types"
|
||||
import { Comment } from "~/components/common/Comment"
|
||||
import { Reactions } from "~/components/common/Reactions"
|
||||
|
||||
export const PostFooter: React.FC<{
|
||||
page?: Note | null
|
||||
}> = ({ page }) => {
|
||||
site?: Profile | null
|
||||
}> = ({ page, site }) => {
|
||||
return (
|
||||
<>
|
||||
<Reactions className="mt-14 mb-12" pageId={page?.id} />
|
||||
<Reactions className="mt-14 mb-12" pageId={page?.id} site={site} />
|
||||
<Comment page={page} />
|
||||
</>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ export const SitePage: React.FC<{
|
|||
toc={true}
|
||||
></PageContent>
|
||||
</article>
|
||||
{page?.metadata && <PostFooter page={page} />}
|
||||
{page?.metadata && <PostFooter page={page} site={site} />}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export type Variant =
|
|||
| "collect"
|
||||
| "crossbell"
|
||||
| "outline"
|
||||
| "patron"
|
||||
|
||||
export type VariantColor = "green" | "red" | "gray" | "gradient" | "black"
|
||||
|
||||
|
|
|
|||
|
|
@ -153,6 +153,19 @@ a {
|
|||
fill: #ffcf55;
|
||||
}
|
||||
|
||||
.button.is-patron {
|
||||
@apply shadow-none p-0;
|
||||
@apply text-gray-500 fill-gray-500;
|
||||
}
|
||||
.button.is-patron:hover {
|
||||
color: #f87171;
|
||||
fill: #f87171;
|
||||
}
|
||||
.button.is-patron.active {
|
||||
color: #f87171;
|
||||
fill: #f87171;
|
||||
}
|
||||
|
||||
.button.is-crossbell {
|
||||
background-color: #fff5e1;
|
||||
fill: #e5b65a;
|
||||
|
|
|
|||
|
|
@ -89,9 +89,9 @@ export const useGetMints = (input: {
|
|||
pageId?: string
|
||||
includeCharacter?: boolean
|
||||
}) => {
|
||||
return useQuery(
|
||||
["getMints", input.pageId, input.includeCharacter],
|
||||
async () => {
|
||||
return useInfiniteQuery({
|
||||
queryKey: ["getMints", input.pageId, input],
|
||||
queryFn: async ({ pageParam }) => {
|
||||
if (!input.pageId) {
|
||||
return {
|
||||
count: 0,
|
||||
|
|
@ -102,9 +102,11 @@ export const useGetMints = (input: {
|
|||
return pageModel.getMints({
|
||||
pageId: input.pageId,
|
||||
includeCharacter: input.includeCharacter,
|
||||
cursor: pageParam,
|
||||
})
|
||||
},
|
||||
)
|
||||
getNextPageParam: (lastPage) => lastPage.cursor || undefined,
|
||||
})
|
||||
}
|
||||
|
||||
export const useCheckMint = (pageId: string | undefined) => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue