Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
at main 126 lines 4.3 kB view raw
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);