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