github-actions[bot]
Sync from https://github.com/felladrin/MiniSearch
1e22bf6
import { Carousel } from "@mantine/carousel";
import { Button, Group, Stack, Text, Transition, rem } from "@mantine/core";
import { useEffect, useState } from "react";
import type { ImageSearchResult } from "../../../../modules/types";
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";
interface ImageResultsState {
isLightboxOpen: boolean;
lightboxIndex: number;
canStartTransition: boolean;
}
export default function ImageResultsList({
imageResults,
}: {
imageResults: ImageSearchResult[];
}) {
const [state, setState] = useState<ImageResultsState>({
isLightboxOpen: false,
lightboxIndex: 0,
canStartTransition: false,
});
useEffect(() => {
setState((prev) => ({ ...prev, canStartTransition: true }));
}, []);
const handleImageClick = (index: number) => {
setState((prev) => ({
...prev,
lightboxIndex: index,
isLightboxOpen: 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, url, thumbnailUrl], index) => (
<Transition
key={url}
mounted={state.canStartTransition}
transition="fade"
timingFunction="ease"
enterDelay={index * 250}
duration={1500}
>
{(styles) => (
<Carousel.Slide style={styles}>
<img
alt={title}
src={thumbnailUrl}
loading="lazy"
onClick={() => handleImageClick(index)}
onKeyDown={(e) => {
if (e.key === "Enter") {
handleImageClick(index);
}
}}
style={imageStyle}
/>
</Carousel.Slide>
)}
</Transition>
))}
</Carousel>
<Lightbox
open={state.isLightboxOpen}
close={() => setState((prev) => ({ ...prev, isLightboxOpen: false }))}
plugins={[Captions]}
index={state.lightboxIndex}
slides={imageResults.map(([title, url, thumbnailUrl, sourceUrl]) => ({
src: thumbnailUrl,
alt: title,
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>
),
}))}
/>
</>
);
}