refactor: extract reaction AvatarStack (#454)
This commit is contained in:
parent
7e6702ae32
commit
d51b713d2c
|
|
@ -4,12 +4,12 @@ import { CharacterFloatCard } from "~/components/common/CharacterFloatCard"
|
|||
import { BlockchainIcon } from "~/components/icons/BlockchainIcon"
|
||||
import { CSB_SCAN } from "~/lib/env"
|
||||
import { getSiteLink } from "~/lib/helpers"
|
||||
import { noopArr } from "~/lib/noop"
|
||||
|
||||
import { Avatar } from "../ui/Avatar"
|
||||
import { UniLink } from "../ui/UniLink"
|
||||
import { FollowingButton } from "./FollowingButton"
|
||||
|
||||
const noopArr = [] as any[]
|
||||
const CharacterListItem: React.FC<{
|
||||
character: any
|
||||
sub: any
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import confetti from "canvas-confetti"
|
||||
import { Trans, useTranslation } from "next-i18next"
|
||||
import { useEffect, useRef, useState } from "react"
|
||||
import { useEffect, useMemo, useRef, useState } from "react"
|
||||
|
||||
import { CharacterList } from "~/components/common/CharacterList"
|
||||
import { Modal } from "~/components/ui/Modal"
|
||||
|
|
@ -16,7 +16,7 @@ import {
|
|||
useToggleLikePage,
|
||||
} from "~/queries/page"
|
||||
|
||||
import { Avatar } from "../ui/Avatar"
|
||||
import { AvatarStack } from "../ui/AvatarStack"
|
||||
import { Button } from "../ui/Button"
|
||||
|
||||
export const ReactionLike: React.FC<{
|
||||
|
|
@ -77,6 +77,19 @@ export const ReactionLike: React.FC<{
|
|||
}
|
||||
}, [toggleLikePage.isSuccess])
|
||||
|
||||
const avatars = useMemo(
|
||||
() =>
|
||||
likes
|
||||
?.sort((a, b) =>
|
||||
b.character?.metadata?.content?.avatars?.[0] ? 1 : -1,
|
||||
)
|
||||
.slice(0, 3)
|
||||
.map(($) => ({
|
||||
images: $.character?.metadata?.content?.avatars,
|
||||
name: $.character?.metadata?.content?.name,
|
||||
})),
|
||||
[likes],
|
||||
)
|
||||
return (
|
||||
<>
|
||||
<div className={cn("xlog-reactions-like flex items-center sm:mb-0")}>
|
||||
|
|
@ -108,33 +121,11 @@ export const ReactionLike: React.FC<{
|
|||
<span>{likeCount}</span>
|
||||
</Button>
|
||||
{size !== "sm" && (
|
||||
<ul
|
||||
className="-space-x-4 cursor-pointer hidden sm:inline-block"
|
||||
<AvatarStack
|
||||
avatars={avatars}
|
||||
count={likeCount}
|
||||
onClick={() => setIsLikeListOpen(true)}
|
||||
>
|
||||
{likes
|
||||
?.sort((a, b) =>
|
||||
b.character?.metadata?.content?.avatars?.[0] ? 1 : -1,
|
||||
)
|
||||
.slice(0, 3)
|
||||
?.map((like, index) => (
|
||||
<li className="inline-block" key={index}>
|
||||
<Avatar
|
||||
className="relative align-middle border-2 border-white"
|
||||
images={like.character?.metadata?.content?.avatars || []}
|
||||
name={like.character?.metadata?.content?.name}
|
||||
size={40}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
{likeCount > 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">
|
||||
+{likeCount - 3}
|
||||
</div>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<Modal
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import confetti from "canvas-confetti"
|
||||
import { Trans, useTranslation } from "next-i18next"
|
||||
import { useEffect, useRef, useState } from "react"
|
||||
import { useEffect, useMemo, useRef, useState } from "react"
|
||||
|
||||
import { useAccountState } from "@crossbell/connect-kit"
|
||||
|
||||
|
|
@ -10,11 +10,12 @@ import { Modal } from "~/components/ui/Modal"
|
|||
import { Tooltip } from "~/components/ui/Tooltip"
|
||||
import { UniLink } from "~/components/ui/UniLink"
|
||||
import { CSB_SCAN, CSB_XCHAR } from "~/lib/env"
|
||||
import { noopArr } from "~/lib/noop"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { parsePageId } from "~/models/page.model"
|
||||
import { useCheckMint, useGetMints, useMintPage } from "~/queries/page"
|
||||
|
||||
import { Avatar } from "../ui/Avatar"
|
||||
import { AvatarStack } from "../ui/AvatarStack"
|
||||
import { Button } from "../ui/Button"
|
||||
|
||||
export const ReactionMint: React.FC<{
|
||||
|
|
@ -73,6 +74,20 @@ export const ReactionMint: React.FC<{
|
|||
}
|
||||
}, [mintPage.isSuccess])
|
||||
|
||||
const avatars = useMemo(
|
||||
() =>
|
||||
mints.data?.pages?.[0]?.list
|
||||
?.sort((a, b: any) =>
|
||||
b.character?.metadata?.content?.avatars?.[0] ? 1 : -1,
|
||||
)
|
||||
.slice(0, 3)
|
||||
.map((mint: any) => ({
|
||||
images: mint.character?.metadata?.content?.avatars,
|
||||
name: mint.character?.metadata?.content?.name,
|
||||
})) || noopArr,
|
||||
[mints],
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="xlog-reactions-mint flex items-center">
|
||||
|
|
@ -101,33 +116,11 @@ export const ReactionMint: React.FC<{
|
|||
<span className="ml-2">{mints.data?.pages?.[0]?.count || 0}</span>
|
||||
</Button>
|
||||
{size !== "sm" && (
|
||||
<ul
|
||||
className="-space-x-4 cursor-pointer hidden sm:inline-block"
|
||||
<AvatarStack
|
||||
avatars={avatars}
|
||||
onClick={() => setIsMintListOpen(true)}
|
||||
>
|
||||
{mints.data?.pages?.[0]?.list
|
||||
?.sort((a, b: any) =>
|
||||
b.character?.metadata?.content?.avatars?.[0] ? 1 : -1,
|
||||
)
|
||||
.slice(0, 3)
|
||||
.map((mint: any, index) => (
|
||||
<li className="inline-block" key={index}>
|
||||
<Avatar
|
||||
className="relative align-middle border-2 border-white"
|
||||
images={mint.character?.metadata?.content?.avatars || []}
|
||||
name={mint.character?.metadata?.content?.name}
|
||||
size={40}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
{(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!.pages?.[0]?.count - 3}
|
||||
</div>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
count={mints.data?.pages?.[0]?.count || 0}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<Modal
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
import { useTranslation } from "next-i18next"
|
||||
import { useRef, useState } from "react"
|
||||
import { useMemo, useRef, useState } from "react"
|
||||
|
||||
import { useAccountState } from "@crossbell/connect-kit"
|
||||
|
||||
import { PatronModal } from "~/components/common/PatronModal"
|
||||
import { Tooltip } from "~/components/ui/Tooltip"
|
||||
import { noopArr } from "~/lib/noop"
|
||||
import { Note, Profile } from "~/lib/types"
|
||||
import { parsePageId } from "~/models/page.model"
|
||||
import { useGetTips } from "~/queries/site"
|
||||
|
||||
import { Avatar } from "../ui/Avatar"
|
||||
import { AvatarStack } from "../ui/AvatarStack"
|
||||
import { Button } from "../ui/Button"
|
||||
|
||||
export const ReactionTip: React.FC<{
|
||||
|
|
@ -41,6 +42,14 @@ export const ReactionTip: React.FC<{
|
|||
}
|
||||
}
|
||||
|
||||
const avatars = useMemo(
|
||||
() =>
|
||||
tips.data?.pages?.[0]?.list?.sort((a, b: any) =>
|
||||
b.character?.metadata?.content?.avatars?.[0] ? 1 : -1,
|
||||
) || noopArr,
|
||||
[tips.data?.pages],
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="xlog-reactions-tip flex items-center">
|
||||
|
|
@ -63,35 +72,12 @@ export const ReactionTip: React.FC<{
|
|||
})()}
|
||||
<span className="ml-2">{tips.data?.pages?.[0]?.count || 0}</span>
|
||||
</Button>
|
||||
{
|
||||
<ul
|
||||
className="-space-x-4 cursor-pointer hidden sm:inline-block"
|
||||
onClick={tip}
|
||||
>
|
||||
{tips.data?.pages?.[0]?.list
|
||||
?.sort((a, b: any) =>
|
||||
b.character?.metadata?.content?.avatars?.[0] ? 1 : -1,
|
||||
)
|
||||
.slice(0, 3)
|
||||
.map((tip: any, index) => (
|
||||
<li className="inline-block" key={index}>
|
||||
<Avatar
|
||||
className="relative align-middle border-2 border-white"
|
||||
images={tip.character?.metadata?.content?.avatars || []}
|
||||
name={tip.character?.metadata?.content?.name}
|
||||
size={40}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
{(tips.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">
|
||||
+{tips.data!.pages?.[0]?.count - 3}
|
||||
</div>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
}
|
||||
|
||||
<AvatarStack
|
||||
avatars={avatars}
|
||||
count={tips.data?.pages?.[0]?.count || 0}
|
||||
onClick={tip}
|
||||
/>
|
||||
</div>
|
||||
<PatronModal
|
||||
site={site}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
import { FC } from "react"
|
||||
|
||||
import { noopArr } from "~/lib/noop"
|
||||
|
||||
import { Avatar } from "./Avatar"
|
||||
|
||||
interface AvatarStackProps {
|
||||
onClick?: () => void
|
||||
avatars: {
|
||||
name: string | null | undefined
|
||||
images: string[] | null | undefined
|
||||
}[]
|
||||
count: number
|
||||
|
||||
/**
|
||||
* @default 3
|
||||
*/
|
||||
showCount?: number
|
||||
}
|
||||
export const AvatarStack: FC<AvatarStackProps> = (props) => {
|
||||
const { avatars, count, onClick, showCount = 3 } = props
|
||||
return (
|
||||
<ul
|
||||
className="-space-x-4 cursor-pointer hidden sm:inline-flex"
|
||||
onClick={onClick}
|
||||
>
|
||||
{avatars.slice(0, showCount).map((avatar) => {
|
||||
return (
|
||||
<li className="inline-block" key={avatar.name}>
|
||||
<Avatar
|
||||
className="relative align-middle border-2 border-white"
|
||||
images={avatar.images || noopArr}
|
||||
name={avatar.name || ""}
|
||||
size={40}
|
||||
/>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
{count > showCount && (
|
||||
<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">
|
||||
+{count - showCount}
|
||||
</div>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import { useEffect, useRef, useState } from "react"
|
||||
import { create } from "zustand"
|
||||
|
||||
import { noop } from "~/lib/noop"
|
||||
import { delStorage, getStorage, setStorage } from "~/lib/storage"
|
||||
import { isServerSide } from "~/lib/utils"
|
||||
|
||||
|
|
@ -150,8 +151,6 @@ const useDarkModeInternal = (
|
|||
}
|
||||
}
|
||||
|
||||
const noop = () => {}
|
||||
|
||||
const mockElement = {
|
||||
classList: {
|
||||
add: noop,
|
||||
|
|
|
|||
|
|
@ -3,3 +3,8 @@ export const IS_BROWSER = typeof document !== "undefined"
|
|||
export const IS_PROD = IS_BROWSER
|
||||
? !location.hostname.endsWith("localhost")
|
||||
: process.env.NODE_ENV === "production"
|
||||
export const IS_DEV = process.env.NODE_ENV === "development"
|
||||
|
||||
export const IS_VERCEL_PREVIEW =
|
||||
process.env.NEXT_PUBLIC_VERCEL_ENV === "preview" ||
|
||||
process.env.VERCEL_ENV === "preview"
|
||||
|
|
|
|||
|
|
@ -20,8 +20,3 @@ export const IPFS_GATEWAY =
|
|||
process.env.NEXT_PUBLIC_IPFS_GATEWAY || "https://ipfs.4everland.xyz/ipfs/"
|
||||
export const MIRA_LINK =
|
||||
process.env.NEXT_PUBLIC_MIRA_LINK || "https://mira.crossbell.io"
|
||||
export const IS_VERCEL_PREVIEW =
|
||||
process.env.NEXT_PUBLIC_VERCEL_ENV === "preview" ||
|
||||
process.env.VERCEL_ENV === "preview"
|
||||
|
||||
export const IS_DEV = process.env.NODE_ENV === "development"
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import { NoteEntity } from "crossbell.js"
|
|||
|
||||
import { Note, Profile } from "~/lib/types"
|
||||
|
||||
import { IS_PROD } from "./constants"
|
||||
import { IS_VERCEL_PREVIEW, OUR_DOMAIN } from "./env"
|
||||
import { IS_PROD, IS_VERCEL_PREVIEW } from "./constants"
|
||||
import { OUR_DOMAIN } from "./env"
|
||||
import { isServerSide } from "./utils"
|
||||
|
||||
export const getSiteLink = ({
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
export const noop = () => void 0
|
||||
|
||||
export const noopArr = [] as any[]
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import { NoteEntity } from "crossbell.js"
|
||||
import { NextApiRequest, NextApiResponse } from "next"
|
||||
|
||||
import { IS_VERCEL_PREVIEW } from "~/lib/constants"
|
||||
import { getDefaultSlug } from "~/lib/default-slug"
|
||||
import { IS_VERCEL_PREVIEW } from "~/lib/env"
|
||||
import { getSiteLink } from "~/lib/helpers"
|
||||
import { checkDomainServer } from "~/models/site.model"
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue