This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

semble / src / webapp / features / platforms / bluesky / components / imageEmbed / ImageEmbed.tsx
7.1 kB 240 lines
1'use client'; 2 3import { AppBskyEmbedImages } from '@atproto/api'; 4import { Lightbox } from '@mantine-bites/lightbox'; 5import { AspectRatio, SimpleGrid, Image, Spoiler, Button } from '@mantine/core'; 6import { useState } from 'react'; 7import styles from './ImageEmbed.module.css'; 8import { useUserSettings } from '@/features/settings/lib/queries/useUserSettings'; 9 10interface Props { 11 images: AppBskyEmbedImages.ViewImage[]; 12} 13 14export default function ImageEmbed(props: Props) { 15 const { settings } = useUserSettings(); 16 const [lightboxOpened, setLightboxOpened] = useState(false); 17 18 const lightboxImages = props.images.map((img) => ({ 19 src: img.fullsize, 20 alt: img.alt, 21 })); 22 23 const openLightbox = (e: React.MouseEvent, index: number) => { 24 e.stopPropagation(); 25 setLightboxOpened(true); 26 }; 27 28 const lightbox = ( 29 <div onClick={(e) => e.stopPropagation()}> 30 <Lightbox.Root 31 opened={lightboxOpened} 32 onClose={() => setLightboxOpened(false)} 33 > 34 <Lightbox.Toolbar> 35 <Lightbox.CloseButton /> 36 </Lightbox.Toolbar> 37 <Lightbox.Controls /> 38 <Lightbox.Counter /> 39 <Lightbox.Slides> 40 {lightboxImages.map((img) => ( 41 <Lightbox.Slide key={img.src}> 42 <Image src={img.src} alt={img.alt} /> 43 </Lightbox.Slide> 44 ))} 45 </Lightbox.Slides> 46 </Lightbox.Root> 47 </div> 48 ); 49 50 if (settings.cardView === 'grid') { 51 if (props.images.length === 3) { 52 return ( 53 <> 54 <SimpleGrid cols={2} spacing="xs"> 55 <AspectRatio 56 ratio={ 57 props.images[0]?.aspectRatio 58 ? props.images[0].aspectRatio.width / 59 props.images[0].aspectRatio.height 60 : 1 / 1 61 } 62 > 63 <Image 64 src={props.images[0].thumb} 65 alt={props.images[0].alt} 66 radius="sm" 67 h={'100%'} 68 w={'100%'} 69 mah={160} 70 style={{ cursor: 'pointer' }} 71 onClick={(e) => openLightbox(e, 0)} 72 /> 73 </AspectRatio> 74 <SimpleGrid cols={1} spacing="xs"> 75 {props.images.slice(1).map((img, i) => { 76 const ratio = img?.aspectRatio 77 ? img.aspectRatio.width / img.aspectRatio.height 78 : 1 / 1; 79 80 return ( 81 <AspectRatio ratio={ratio} key={i + 1}> 82 <Image 83 src={img.thumb} 84 alt={img.alt} 85 radius="sm" 86 h={'100%'} 87 w={'100%'} 88 mah={75} 89 style={{ cursor: 'pointer' }} 90 onClick={(e) => openLightbox(e, i + 1)} 91 /> 92 </AspectRatio> 93 ); 94 })} 95 </SimpleGrid> 96 </SimpleGrid> 97 {lightbox} 98 </> 99 ); 100 } 101 102 return ( 103 <> 104 <SimpleGrid cols={props.images.length > 1 ? 2 : 1} spacing="xs"> 105 {props.images.map((img, i) => { 106 const ratio = 107 props.images.length === 1 108 ? img?.aspectRatio 109 ? img.aspectRatio.width / img.aspectRatio.height 110 : 16 / 9 111 : img?.aspectRatio 112 ? img.aspectRatio.width / img.aspectRatio.height 113 : 1 / 1; 114 115 return ( 116 <AspectRatio ratio={ratio} key={i}> 117 <Image 118 src={img.thumb} 119 alt={img.alt} 120 radius="sm" 121 h={'100%'} 122 w={'100%'} 123 mah={props.images.length === 1 ? 200 : 150} 124 style={{ cursor: 'pointer' }} 125 onClick={(e) => openLightbox(e, i)} 126 /> 127 </AspectRatio> 128 ); 129 })} 130 </SimpleGrid> 131 {lightbox} 132 </> 133 ); 134 } 135 136 return ( 137 <> 138 <Spoiler 139 classNames={styles} 140 showLabel={ 141 <Button 142 component="span" 143 size="xs" 144 variant="light" 145 color="gray" 146 radius={'sm'} 147 fullWidth 148 > 149 Expand image 150 </Button> 151 } 152 hideLabel={ 153 <Button 154 component="span" 155 size="xs" 156 variant="light" 157 color="gray" 158 radius={'sm'} 159 fullWidth 160 > 161 Collape image 162 </Button> 163 } 164 maxHeight={280} 165 > 166 {props.images.length === 3 ? ( 167 <SimpleGrid cols={2} spacing="xs"> 168 <AspectRatio 169 ratio={ 170 props.images[0]?.aspectRatio 171 ? props.images[0].aspectRatio.width / 172 props.images[0].aspectRatio.height 173 : 1 / 1 174 } 175 > 176 <Image 177 src={props.images[0].thumb} 178 alt={props.images[0].alt} 179 radius="sm" 180 h={'100%'} 181 w={'100%'} 182 style={{ cursor: 'pointer' }} 183 onClick={(e) => openLightbox(e, 0)} 184 /> 185 </AspectRatio> 186 <SimpleGrid cols={1} spacing="xs"> 187 {props.images.slice(1).map((img, i) => { 188 const ratio = img?.aspectRatio 189 ? img.aspectRatio.width / img.aspectRatio.height 190 : 1 / 1; 191 192 return ( 193 <AspectRatio ratio={ratio} key={i + 1}> 194 <Image 195 src={img.thumb} 196 alt={img.alt} 197 radius="sm" 198 h={'100%'} 199 w={'100%'} 200 style={{ cursor: 'pointer' }} 201 onClick={(e) => openLightbox(e, i + 1)} 202 /> 203 </AspectRatio> 204 ); 205 })} 206 </SimpleGrid> 207 </SimpleGrid> 208 ) : ( 209 <SimpleGrid cols={props.images.length > 1 ? 2 : 1} spacing="xs"> 210 {props.images.map((img, i) => { 211 const ratio = 212 props.images.length === 1 213 ? img?.aspectRatio 214 ? img.aspectRatio.width / img.aspectRatio.height 215 : 16 / 9 216 : img?.aspectRatio 217 ? img.aspectRatio.width / img.aspectRatio.height 218 : 1 / 1; 219 220 return ( 221 <AspectRatio ratio={ratio} key={i}> 222 <Image 223 src={img.thumb} 224 alt={img.alt} 225 radius="sm" 226 h={'100%'} 227 w={'100%'} 228 style={{ cursor: 'pointer' }} 229 onClick={(e) => openLightbox(e, i)} 230 /> 231 </AspectRatio> 232 ); 233 })} 234 </SimpleGrid> 235 )} 236 </Spoiler> 237 {lightbox} 238 </> 239 ); 240}