Spaces:
Paused
Paused
| import { Carousel } from "@mantine/carousel"; | |
| import { SearchResults } from "../../../../modules/search"; | |
| import { useState, useEffect } from "react"; | |
| import { Button, Group, rem, Stack, Transition, Text } from "@mantine/core"; | |
| 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, , thumbnailUrl], index) => ( | |
| <Transition | |
| key={index} | |
| mounted={isMounted} | |
| transition="fade" | |
| timingFunction="ease" | |
| enterDelay={index * 250} | |
| duration={1500} | |
| > | |
| {(styles) => ( | |
| <Carousel.Slide style={styles}> | |
| <img | |
| alt={title} | |
| src={thumbnailUrl} | |
| onClick={() => 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> | |
| ), | |
| }))} | |
| /> | |
| </> | |
| ); | |
| } | |