Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
1import { EyeIcon } from "@heroicons/react/24/outline";
2import getPostData from "@hey/helpers/getPostData";
3import getURLs from "@hey/helpers/getURLs";
4import { isRepost } from "@hey/helpers/postHelpers";
5import type { AnyPostFragment } from "@hey/indexer";
6import { getSrc } from "@livepeer/react/external";
7import { memo } from "react";
8import Quote from "@/components/Shared/Embed/Quote";
9import Markup from "@/components/Shared/Markup";
10import Attachments from "@/components/Shared/Post/Attachments";
11import Oembed from "@/components/Shared/Post/Oembed";
12import PostLink from "@/components/Shared/Post/PostLink";
13import Video from "@/components/Shared/Post/Video";
14import { H6 } from "@/components/Shared/UI";
15import cn from "@/helpers/cn";
16
17interface PostBodyProps {
18 contentClassName?: string;
19 post: AnyPostFragment;
20 quoted?: boolean;
21 showMore?: boolean;
22}
23
24const PostBody = ({
25 contentClassName = "",
26 post,
27 quoted = false,
28 showMore = false
29}: PostBodyProps) => {
30 const targetPost = isRepost(post) ? post.repostOf : post;
31 const { metadata } = targetPost;
32
33 const filteredContent = getPostData(metadata)?.content || "";
34 const filteredAttachments = getPostData(metadata)?.attachments || [];
35 const filteredAsset = getPostData(metadata)?.asset;
36
37 const canShowMore = filteredContent?.length > 450 && showMore;
38 const urls = getURLs(filteredContent);
39 const hasURLs = urls.length > 0;
40
41 let content = filteredContent;
42
43 if (canShowMore) {
44 const lines = content?.split("\n");
45 if (lines && lines.length > 0) {
46 content = lines.slice(0, 5).join("\n");
47 }
48 }
49
50 // Show live if it's there
51 const showLive = metadata.__typename === "LivestreamMetadata";
52 // Show attachments if they're there
53 const showAttachments = filteredAttachments.length > 0 || filteredAsset;
54 // Show sharing link
55 const showSharingLink = metadata.__typename === "LinkMetadata";
56 const showOembed =
57 !showSharingLink &&
58 hasURLs &&
59 !showLive &&
60 !showAttachments &&
61 !quoted &&
62 !targetPost.quoteOf;
63
64 return (
65 <div className="break-words">
66 <Markup
67 className={cn(
68 { "line-clamp-5": canShowMore },
69 "markup linkify break-words",
70 contentClassName
71 )}
72 mentions={targetPost.mentions}
73 >
74 {content}
75 </Markup>
76 {canShowMore ? (
77 <H6 className="mt-4 flex items-center space-x-1 text-gray-500 dark:text-gray-200">
78 <EyeIcon className="size-4" />
79 <PostLink post={post}>Show more</PostLink>
80 </H6>
81 ) : null}
82 {/* Attachments and Quotes */}
83 {showAttachments ? (
84 <Attachments asset={filteredAsset} attachments={filteredAttachments} />
85 ) : null}
86 {showLive ? (
87 <div className="mt-3">
88 <Video src={getSrc(metadata.liveUrl || metadata.playbackUrl)} />
89 </div>
90 ) : null}
91 {showOembed ? <Oembed url={urls[0]} /> : null}
92 {showSharingLink ? <Oembed url={metadata.sharingLink} /> : null}
93 {targetPost.quoteOf ? <Quote post={targetPost.quoteOf} /> : null}
94 </div>
95 );
96};
97
98export default memo(PostBody);