Spaces:
Building
Building
File size: 3,912 Bytes
f152ae2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
import { Carousel } from "@mantine/carousel";
import { Button, Group, Stack, Text, Transition, rem } from "@mantine/core";
import { useEffect, useState } from "react";
import type { SearchResults } from "../../../../modules/search";
import "@mantine/carousel/styles.css";
import Lightbox from "yet-another-react-lightbox";
import Captions from "yet-another-react-lightbox/plugins/captions";
import "yet-another-react-lightbox/styles.css";
import "yet-another-react-lightbox/plugins/captions.css";
import { addLogEntry } from "../../../../modules/logEntries";
import { getHostname } from "../../../../modules/stringFormatters";
export default function ImageResultsList({
imageResults,
}: {
imageResults: SearchResults["imageResults"];
}) {
const [isLightboxOpen, setLightboxOpen] = useState(false);
const [lightboxIndex, setLightboxIndex] = useState(0);
const [isMounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
const handleImageClick = (index: number) => {
setLightboxIndex(index);
setLightboxOpen(true);
};
const imageStyle = {
objectFit: "cover",
height: rem(180),
width: rem(240),
borderRadius: rem(4),
border: `${rem(2)} solid var(--mantine-color-default-border)`,
cursor: "zoom-in",
} as const;
return (
<>
<Carousel slideSize="0" slideGap="xs" align="start" dragFree loop>
{imageResults.map(([title, sourceUrl, thumbnailUrl], index) => (
<Transition
key={`${title}-${sourceUrl}-${thumbnailUrl}`}
mounted={isMounted}
transition="fade"
timingFunction="ease"
enterDelay={index * 250}
duration={1500}
>
{(styles) => (
<Carousel.Slide style={styles}>
<img
alt={title}
src={thumbnailUrl}
onClick={() => handleImageClick(index)}
onKeyDown={(e) => {
if (e.key === "Enter") {
handleImageClick(index);
}
}}
style={imageStyle}
/>
</Carousel.Slide>
)}
</Transition>
))}
</Carousel>
<Lightbox
open={isLightboxOpen}
close={() => setLightboxOpen(false)}
plugins={[Captions]}
index={lightboxIndex}
slides={imageResults.map(([title, url, thumbnailUrl, sourceUrl]) => ({
src: thumbnailUrl,
description: (
<Stack align="center" gap="md">
{title && (
<Text component="cite" ta="center">
{title}
</Text>
)}
<Group align="center" justify="center" gap="xs">
<Button
variant="subtle"
component="a"
size="xs"
href={sourceUrl}
target="_blank"
title="Click to see the image in full size"
rel="noopener noreferrer"
onClick={() => {
addLogEntry("User visited an image result in full size");
}}
>
View in full resolution
</Button>
<Button
variant="subtle"
component="a"
href={url}
target="_blank"
size="xs"
title="Click to visit the page where the image was found"
rel="noopener noreferrer"
onClick={() => {
addLogEntry("User visited an image result source");
}}
>
Visit {getHostname(url)}
</Button>
</Group>
</Stack>
),
}))}
/>
</>
);
}
|