Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
1import { TRANSFORMS } from "@hey/data/constants";
2import imageKit from "@hey/helpers/imageKit";
3import type { MetadataAsset } from "@hey/types/misc";
4import type { VideoSrc } from "@livepeer/react";
5import { getSrc } from "@livepeer/react/external";
6import { memo, useState } from "react";
7import Audio from "@/components/Shared/Audio";
8import { Image, LightBox } from "@/components/Shared/UI";
9import cn from "@/helpers/cn";
10import stopEventPropagation from "@/helpers/stopEventPropagation";
11import Video from "./Video";
12
13const getClass = (attachments: number) => {
14 const aspect = "aspect-w-16 aspect-h-12";
15 if (attachments === 1) return { aspect: "", row: "grid-cols-1 grid-rows-1" };
16 if (attachments === 2) return { aspect, row: "grid-cols-2 grid-rows-1" };
17 if (attachments <= 4) return { aspect, row: "grid-cols-2 grid-rows-2" };
18 if (attachments <= 6) return { aspect, row: "grid-cols-3 grid-rows-2" };
19 if (attachments <= 8) return { aspect, row: "grid-cols-4 grid-rows-2" };
20 return { aspect, row: "grid-cols-5 grid-rows-2" };
21};
22
23interface MetadataAttachment {
24 type: "Audio" | "Image" | "Video";
25 uri: string;
26}
27
28interface AttachmentsProps {
29 asset?: MetadataAsset;
30 attachments: MetadataAttachment[];
31}
32
33const Attachments = ({ asset, attachments }: AttachmentsProps) => {
34 const [expandedImageIndex, setExpandedImageIndex] = useState<number>(0);
35 const [showLightBox, setShowLightBox] = useState<boolean>(false);
36 const processedAttachments = attachments.slice(0, 10);
37
38 const assetType = asset?.type;
39 const hasImageAttachment =
40 processedAttachments.some((attachment) => attachment.type === "Image") ||
41 assetType === "Image";
42
43 const determineDisplay = () => {
44 if (assetType === "Video") return "displayVideoAsset";
45 if (assetType === "Audio") return "displayAudioAsset";
46 if (hasImageAttachment) {
47 const imageAttachments = processedAttachments
48 .filter((attachment) => attachment.type === "Image")
49 .map((attachment) => attachment.uri);
50 if (asset?.uri) imageAttachments.unshift(asset.uri);
51 return [...new Set(imageAttachments)];
52 }
53 return null;
54 };
55
56 const displayDecision = determineDisplay();
57
58 const ImageComponent = ({ uri, index }: { uri: string; index: number }) => (
59 <Image
60 alt={imageKit(uri, TRANSFORMS.ATTACHMENT)}
61 className="max-h-[300px] cursor-pointer rounded-lg border border-gray-200 bg-gray-100 object-cover md:max-h-[500px] dark:border-gray-700 dark:bg-gray-800"
62 height={1000}
63 loading="lazy"
64 onClick={() => {
65 setExpandedImageIndex(index);
66 setShowLightBox(true);
67 }}
68 onError={({ currentTarget }) => (currentTarget.src = uri)}
69 src={imageKit(uri, TRANSFORMS.ATTACHMENT)}
70 width={1000}
71 />
72 );
73
74 return (
75 <div className="mt-3">
76 {Array.isArray(displayDecision) && (
77 <div
78 className={cn("grid gap-2", getClass(displayDecision.length)?.row)}
79 >
80 {displayDecision.map((attachment, index) => (
81 <div
82 className={cn(
83 getClass(displayDecision.length)?.aspect,
84 { "row-span-2": displayDecision.length === 3 && index === 0 },
85 { "w-2/3": displayDecision.length === 1 }
86 )}
87 key={attachment}
88 onClick={stopEventPropagation}
89 >
90 <ImageComponent index={index} uri={attachment} />
91 </div>
92 ))}
93 <LightBox
94 images={displayDecision?.map((attachment) => attachment)}
95 initialIndex={expandedImageIndex}
96 onClose={() => {
97 setShowLightBox(false);
98 setExpandedImageIndex(0);
99 }}
100 show={showLightBox}
101 />
102 </div>
103 )}
104 {displayDecision === "displayVideoAsset" && (
105 <Video
106 poster={asset?.cover as string}
107 src={
108 getSrc(asset?.uri) || [
109 { src: asset?.uri as string, type: "video" } as VideoSrc
110 ]
111 }
112 />
113 )}
114 {displayDecision === "displayAudioAsset" && (
115 <Audio
116 artist={asset?.artist}
117 poster={asset?.cover as string}
118 src={asset?.uri as string}
119 title={asset?.title}
120 />
121 )}
122 </div>
123 );
124};
125
126export default memo(Attachments);