This repository has no description
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}