xLog/src/components/common/CommentItem.tsx

121 lines
3.8 KiB
TypeScript

import { Avatar } from "~/components/ui/Avatar"
import dayjs from "dayjs"
import duration from "dayjs/plugin/duration"
import relativeTime from "dayjs/plugin/relativeTime"
import { UniLink } from "~/components/ui/UniLink"
import { BlockchainIcon } from "~/components/icons/BlockchainIcon"
import { CSB_SCAN } from "~/lib/env"
import { getSiteLink } from "~/lib/helpers"
import { PageContent } from "~/components/common/PageContent"
import { NoteEntity, CharacterEntity } from "crossbell.js"
import { Button } from "~/components/ui/Button"
import { Reactions } from "~/components/common/Reactions"
import { useState } from "react"
import { CommentInput } from "~/components/common/CommentInput"
dayjs.extend(duration)
dayjs.extend(relativeTime)
export const CommentItem: React.FC<{
comment: NoteEntity & {
character?: CharacterEntity | null
}
isSub?: boolean
originalId?: string
}> = ({ comment, isSub, originalId }) => {
const [replyOpen, setReplyOpen] = useState(false)
return (
<div
key={comment.transactionHash}
className={isSub ? "" : "border-b border-dashed pb-6"}
>
<div className="flex group">
<UniLink
href={
comment?.character?.handle &&
getSiteLink({
subdomain: comment.character.handle,
})
}
className="align-middle mr-3"
>
<Avatar
images={comment?.character?.metadata?.content?.avatars || []}
name={comment?.character?.metadata?.content?.name}
size={45}
/>
</UniLink>
<div className="flex-1 flex flex-col rounded-lg">
<div className="mb-1 text-sm">
<UniLink
href={
comment?.character?.handle &&
getSiteLink({
subdomain: comment.character.handle,
})
}
className="font-medium text-accent"
>
{comment?.character?.metadata?.content?.name}
</UniLink>{" "}
·{" "}
{dayjs
.duration(
dayjs(comment?.createdAt).diff(dayjs(), "minute"),
"minute",
)
.humanize()}{" "}
ago ·{" "}
<UniLink href={`${CSB_SCAN}/tx/${comment.transactionHash}`}>
<BlockchainIcon className="w-3 h-3 inline-block" />
</UniLink>
</div>
<PageContent
content={comment.metadata?.content?.content}
></PageContent>
<div className="mt-1 flex items-center">
<Reactions
className="inline-flex"
size="sm"
pageId={`${comment.characterId}-${comment.noteId}`}
/>
<Button
className="text-gray-500 text-[13px] ml-2 mt-[-1px]"
variant="text"
onClick={() => setReplyOpen(!replyOpen)}
>
{replyOpen ? "Cancel" : "Reply"}
</Button>
</div>
{replyOpen && (
<div className="pt-6">
<CommentInput
originalId={originalId}
pageId={`${comment.characterId}-${comment.noteId}`}
/>
</div>
)}
</div>
</div>
{(comment as any)?.fromNotes?.list?.length > 0 && (
<div className="pl-[57px] space-y-6 pt-6">
{(comment as any)?.fromNotes?.list?.map(
(
subcomment: NoteEntity & {
character?: CharacterEntity | null
},
) => (
<CommentItem
comment={subcomment}
key={subcomment.transactionHash}
isSub={true}
/>
),
)}
</div>
)}
</div>
)
}