diff --git a/src/components/common/CommentItem.tsx b/src/components/common/CommentItem.tsx index d115f1a4..8b7f94c1 100644 --- a/src/components/common/CommentItem.tsx +++ b/src/components/common/CommentItem.tsx @@ -7,7 +7,7 @@ import { useAccountState } from "@crossbell/connect-kit" import { CharacterFloatCard } from "~/components/common/CharacterFloatCard" import { CommentInput } from "~/components/common/CommentInput" import { PageContent } from "~/components/common/PageContent" -import { Reactions } from "~/components/common/Reactions" +import { ReactionLike } from "~/components/common/ReactionLike" import { Titles } from "~/components/common/Titles" import { BlockchainIcon } from "~/components/icons/BlockchainIcon" import { Avatar } from "~/components/ui/Avatar" @@ -102,11 +102,15 @@ export const CommentItem: React.FC<{ isComment={true} >
- +
+ +
{depth < 2 && ( + {size !== "sm" && ( + + )} +
+ +
+ + Your like has been stored on the blockchain, view it on{" "} + + Crossbell Scan + + +
+
+ + +
+
+ +
+ + Do you really want to revert this like action? + +
+
+ + +
+
+ + + ) +} diff --git a/src/components/common/ReactionMint.tsx b/src/components/common/ReactionMint.tsx new file mode 100644 index 00000000..6b4e2f93 --- /dev/null +++ b/src/components/common/ReactionMint.tsx @@ -0,0 +1,172 @@ +import confetti from "canvas-confetti" +import { Trans, useTranslation } from "next-i18next" +import { useEffect, useRef, useState } from "react" + +import { useAccountState } from "@crossbell/connect-kit" + +import { CharacterList } from "~/components/common/CharacterList" +import { MintIcon } from "~/components/icons/MintIcon" +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 { cn } from "~/lib/utils" +import { parsePageId } from "~/models/page.model" +import { useCheckMint, useGetMints, useMintPage } from "~/queries/page" + +import { Avatar } from "../ui/Avatar" +import { Button } from "../ui/Button" + +export const ReactionMint: React.FC<{ + size?: "sm" | "base" + pageId?: string +}> = ({ size, pageId }) => { + const mintPage = useMintPage() + const { t } = useTranslation("common") + + const account = useAccountState((s) => s.computed.account) + + const [isMintOpen, setIsMintOpen] = useState(false) + const [isMintListOpen, setIsMintListOpen] = useState(false) + const mintRef = useRef(null) + + const mints = useGetMints({ + pageId: pageId, + includeCharacter: size !== "sm", + }) + const isMint = useCheckMint(pageId) + + const mint = () => { + if (pageId) { + if (isMint.data?.count) { + setIsMintOpen(true) + } else { + mintPage.mutate(parsePageId(pageId)) + } + } + } + + useEffect(() => { + if (mintPage.isSuccess) { + if (mintRef.current?.getBoundingClientRect()) { + confetti({ + particleCount: 150, + spread: 360, + ticks: 50, + gravity: 0, + decay: 0.94, + startVelocity: 30, + origin: { + x: + (mintRef.current.getBoundingClientRect().left + + mintRef.current.getBoundingClientRect().width / 2 || 0.5) / + window.innerWidth, + y: + (mintRef.current.getBoundingClientRect().top || 0.5) / + window.innerHeight, + }, + shapes: ["star"], + // cspell:disable-next-line + colors: ["FFE400", "FFBD00", "E89400", "FFCA6C", "FDFFB8"], + }) + } + } + }, [mintPage.isSuccess]) + + return ( + <> +
+ + {size !== "sm" && ( + + )} +
+ +
+ + This post has been minted to NFT by you, view it on{" "} + + xChar + {" "} + or{" "} + + Crossbell Scan + + +
+
+ +
+
+ + + ) +} diff --git a/src/components/common/ReactionTip.tsx b/src/components/common/ReactionTip.tsx new file mode 100644 index 00000000..9b7edb07 --- /dev/null +++ b/src/components/common/ReactionTip.tsx @@ -0,0 +1,104 @@ +import { useTranslation } from "next-i18next" +import { useRef, useState } from "react" + +import { useAccountState } from "@crossbell/connect-kit" + +import { PatronModal } from "~/components/common/PatronModal" +import { Tooltip } from "~/components/ui/Tooltip" +import { Note, Profile } from "~/lib/types" +import { parsePageId } from "~/models/page.model" +import { useGetTips } from "~/queries/site" + +import { Avatar } from "../ui/Avatar" +import { Button } from "../ui/Button" + +export const ReactionTip: React.FC<{ + pageId?: string + site?: Profile | null + page?: Note | null +}> = ({ pageId, site, page }) => { + const { t } = useTranslation("common") + + const account = useAccountState((s) => s.computed.account) + + const [isTipOpen, setIsTipOpen] = useState(false) + const tipRef = useRef(null) + + const { characterId, noteId } = parsePageId(pageId || "") + const tips = useGetTips({ + toCharacterId: characterId, + toNoteId: noteId, + }) + const isTip = useGetTips({ + toCharacterId: characterId, + toNoteId: noteId, + characterId: account?.characterId || "0", + }) + + const tip = () => { + if (pageId) { + setIsTipOpen(true) + } + } + + return ( + <> +
+ + { +
    + {tips.data?.pages?.[0]?.list + ?.sort((a, b: any) => + b.character?.metadata?.content?.avatars?.[0] ? 1 : -1, + ) + .slice(0, 3) + .map((tip: any, index) => ( +
  • + +
  • + ))} + {(tips.data?.pages?.[0]?.count || 0) > 3 && ( +
  • +
    + +{tips.data!.pages?.[0]?.count - 3} +
    +
  • + )} +
+ } +
+ + + ) +} diff --git a/src/components/common/Reactions.tsx b/src/components/common/Reactions.tsx deleted file mode 100644 index 9a7d955b..00000000 --- a/src/components/common/Reactions.tsx +++ /dev/null @@ -1,450 +0,0 @@ -import confetti from "canvas-confetti" -import { Trans, useTranslation } from "next-i18next" -import { useEffect, useRef, useState } from "react" - -import { useAccountState } from "@crossbell/connect-kit" - -import { CharacterList } from "~/components/common/CharacterList" -import { PatronModal } from "~/components/common/PatronModal" -import { MintIcon } from "~/components/icons/MintIcon" -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 { Note, Profile } from "~/lib/types" -import { cn } from "~/lib/utils" -import { parsePageId } from "~/models/page.model" -import { - useCheckLike, - useCheckMint, - useGetLikeCounts, - useGetLikes, - useGetMints, - useMintPage, - useToggleLikePage, -} from "~/queries/page" -import { useGetTips } from "~/queries/site" - -import { Avatar } from "../ui/Avatar" -import { Button } from "../ui/Button" - -export const Reactions: React.FC<{ - className?: string - size?: "sm" | "base" - pageId?: string - site?: Profile | null - page?: Note | null -}> = ({ className, size, pageId, site, page }) => { - const toggleLikePage = useToggleLikePage() - const mintPage = useMintPage() - const { t } = useTranslation("common") - - // like - const account = useAccountState((s) => s.computed.account) - const [isLikeOpen, setIsLikeOpen] = useState(false) - const [isLikeListOpen, setIsLikeListOpen] = useState(false) - const likeRef = useRef(null) - - const [likes, likesMutation] = useGetLikes({ pageId }) - const [likeStatus] = useCheckLike({ - pageId, - }) - const { data: likeCount = 0 } = useGetLikeCounts({ pageId }) - - const [isUnlikeOpen, setIsUnlikeOpen] = useState(false) - - const like = () => { - if (pageId) { - if (likeStatus.isLiked) { - setIsLikeOpen(true) - } else { - toggleLikePage.mutate({ ...parsePageId(pageId), action: "link" }) - } - } - } - - const unlike = () => { - if (pageId) { - setIsUnlikeOpen(false) - if (likeStatus.isLiked) { - toggleLikePage.mutate({ ...parsePageId(pageId), action: "unlink" }) - } // else do nothing - } - } - - useEffect(() => { - if (toggleLikePage.isSuccess) { - if (likeRef.current?.getBoundingClientRect() && likeStatus.isLiked) { - confetti({ - particleCount: 150, - spread: 70, - origin: { - x: - (likeRef.current.getBoundingClientRect().left + - likeRef.current.getBoundingClientRect().width / 2 || 0.5) / - window.innerWidth, - y: - (likeRef.current.getBoundingClientRect().top || 0.5) / - window.innerHeight, - }, - }) - } - } - }, [toggleLikePage.isSuccess]) - - // mint - const [isMintOpen, setIsMintOpen] = useState(false) - const [isMintListOpen, setIsMintListOpen] = useState(false) - const mintRef = useRef(null) - - const mints = useGetMints({ - pageId: pageId, - includeCharacter: size !== "sm", - }) - const isMint = useCheckMint(pageId) - - const mint = () => { - if (pageId) { - if (isMint.data?.count) { - setIsMintOpen(true) - } else { - mintPage.mutate(parsePageId(pageId)) - } - } - } - - useEffect(() => { - if (mintPage.isSuccess) { - if (mintRef.current?.getBoundingClientRect()) { - confetti({ - particleCount: 150, - spread: 360, - ticks: 50, - gravity: 0, - decay: 0.94, - startVelocity: 30, - origin: { - x: - (mintRef.current.getBoundingClientRect().left + - mintRef.current.getBoundingClientRect().width / 2 || 0.5) / - window.innerWidth, - y: - (mintRef.current.getBoundingClientRect().top || 0.5) / - window.innerHeight, - }, - shapes: ["star"], - // cspell:disable-next-line - colors: ["FFE400", "FFBD00", "E89400", "FFCA6C", "FDFFB8"], - }) - } - } - }, [mintPage.isSuccess]) - - // tip - const [isTipOpen, setIsTipOpen] = useState(false) - const tipRef = useRef(null) - - const { characterId, noteId } = parsePageId(pageId || "") - const tips = useGetTips({ - toCharacterId: characterId, - toNoteId: noteId, - }) - const isTip = useGetTips({ - toCharacterId: characterId, - toNoteId: noteId, - characterId: account?.characterId || "0", - }) - - const tip = () => { - if (pageId) { - setIsTipOpen(true) - } - } - - return ( - <> -
-
- - {size !== "sm" && ( -
    setIsLikeListOpen(true)} - > - {likes - ?.sort((a, b) => - b.character?.metadata?.content?.avatars?.[0] ? 1 : -1, - ) - .slice(0, 3) - ?.map((like, index) => ( -
  • - -
  • - ))} - {likeCount > 3 && ( -
  • -
    - +{likeCount - 3} -
    -
  • - )} -
- )} -
-
- - {size !== "sm" && ( -
    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) => ( -
  • - -
  • - ))} - {(mints.data?.pages?.[0]?.count || 0) > 3 && ( -
  • -
    - +{mints.data!.pages?.[0]?.count - 3} -
    -
  • - )} -
- )} -
- {size !== "sm" && ( -
- - { -
    - {tips.data?.pages?.[0]?.list - ?.sort((a, b: any) => - b.character?.metadata?.content?.avatars?.[0] ? 1 : -1, - ) - .slice(0, 3) - .map((tip: any, index) => ( -
  • - -
  • - ))} - {(tips.data?.pages?.[0]?.count || 0) > 3 && ( -
  • -
    - +{tips.data!.pages?.[0]?.count - 3} -
    -
  • - )} -
- } -
- )} - -
- - Your like has been stored on the blockchain, view it on{" "} - - Crossbell Scan - - -
-
- - -
-
- -
- - Do you really want to revert this like action? - -
-
- - -
-
- -
- - This post has been minted to NFT by you, view it on{" "} - - xChar - {" "} - or{" "} - - Crossbell Scan - - -
-
- -
-
- - - -
- - ) -} diff --git a/src/components/dashboard/DashboardLayout.server.tsx b/src/components/dashboard/DashboardLayout.server.tsx index 3632e720..91387c77 100644 --- a/src/components/dashboard/DashboardLayout.server.tsx +++ b/src/components/dashboard/DashboardLayout.server.tsx @@ -9,6 +9,7 @@ export const getServerSideProps = async (ctx: any) => { "common", "dashboard", "index", + "site", ])), }, } diff --git a/src/components/site/PostFooter.tsx b/src/components/site/PostFooter.tsx index 3bce9653..36831aa6 100644 --- a/src/components/site/PostFooter.tsx +++ b/src/components/site/PostFooter.tsx @@ -1,5 +1,7 @@ import { Comment } from "~/components/common/Comment" -import { Reactions } from "~/components/common/Reactions" +import { ReactionLike } from "~/components/common/ReactionLike" +import { ReactionMint } from "~/components/common/ReactionMint" +import { ReactionTip } from "~/components/common/ReactionTip" import { Note, Profile } from "~/lib/types" export const PostFooter: React.FC<{ @@ -8,12 +10,14 @@ export const PostFooter: React.FC<{ }> = ({ page, site }) => { return ( <> - +
+ + + +
) diff --git a/src/models/site.model.ts b/src/models/site.model.ts index b746a7e3..599403fd 100644 --- a/src/models/site.model.ts +++ b/src/models/site.model.ts @@ -412,6 +412,9 @@ export async function getCommentsBySite(input: { limit: 7, includeCharacter: true, cursor: input.cursor, + includeNestedNotes: true, + nestedNotesDepth: 3 as 3, + nestedNotesLimit: 20, }) notes.list = notes.list.filter((item) =>