210 lines
5.2 KiB
Plaintext
210 lines
5.2 KiB
Plaintext
---
|
|
import Credits from "./Credits.astro";
|
|
import DownloadButton from "./DownloadButton.astro";
|
|
import AppLayoutTitle from "./AppLayout/components/AppLayoutTitle.astro";
|
|
import type { ComponentProps } from "astro/types";
|
|
import Attributes from "./Attributes.astro";
|
|
import { sizesToSrcset } from "src/utils/img";
|
|
import { Icon } from "astro-icon/components";
|
|
import RichText from "./RichText/RichText.astro";
|
|
import type {
|
|
EndpointImage,
|
|
EndpointScanImage,
|
|
EndpointPayloadImage,
|
|
EndpointCredit,
|
|
} from "src/shared/payload/endpoint-types";
|
|
import type { RichTextContent } from "src/shared/payload/rich-text";
|
|
|
|
interface Props {
|
|
previousImageHref?: string | undefined;
|
|
nextImageHref?: string | undefined;
|
|
image: EndpointImage | EndpointScanImage | EndpointPayloadImage;
|
|
pretitle?: string | undefined;
|
|
title: string;
|
|
subtitle?: string | undefined;
|
|
description?: RichTextContent | undefined;
|
|
lang?: string | undefined;
|
|
attributes?: ComponentProps<typeof Attributes>["attributes"] | undefined;
|
|
metaAttributes?: ComponentProps<typeof Attributes>["attributes"] | undefined;
|
|
credits?: EndpointCredit[] | undefined;
|
|
filename?: string | undefined;
|
|
smallTitle?: boolean | undefined;
|
|
}
|
|
|
|
const {
|
|
nextImageHref,
|
|
previousImageHref,
|
|
image: { url, width, height, sizes },
|
|
attributes = [],
|
|
metaAttributes = [],
|
|
credits = [],
|
|
description,
|
|
lang,
|
|
pretitle,
|
|
title,
|
|
subtitle,
|
|
filename,
|
|
smallTitle = false,
|
|
} = Astro.props;
|
|
|
|
const hasNavigation = previousImageHref || nextImageHref;
|
|
---
|
|
|
|
{/* ------------------------------------------- HTML ------------------------------------------- */}
|
|
|
|
<div id="container">
|
|
<div id="image-viewer" class:list={{ "with-buttons": hasNavigation }}>
|
|
{
|
|
hasNavigation && (
|
|
<a
|
|
id="previous-button"
|
|
class:list={{ hidden: !previousImageHref, pressable: true }}
|
|
href={previousImageHref}>
|
|
<Icon name="material-symbols:chevron-left" />
|
|
</a>
|
|
)
|
|
}
|
|
|
|
<a id="image-anchor" href={url} target="_blank" style=`aspect-ratio:${width}/${height};`>
|
|
<img
|
|
src={url}
|
|
srcset={sizesToSrcset(sizes)}
|
|
sizes={`(max-aspect-ratio: ${width / 0.9}/${height / 0.7}) 90vw, ${(width / height) * 70}vh`}
|
|
width={width}
|
|
height={height}
|
|
/>
|
|
</a>
|
|
|
|
{
|
|
hasNavigation && (
|
|
<a
|
|
id="next-button"
|
|
class:list={{ hidden: !nextImageHref, pressable: true }}
|
|
href={nextImageHref}>
|
|
<Icon name="material-symbols:chevron-right" />
|
|
</a>
|
|
)
|
|
}
|
|
</div>
|
|
|
|
<div
|
|
id="info"
|
|
class:list={{
|
|
complex:
|
|
attributes.length > 0 || metaAttributes.length > 0 || credits.length > 0 || description,
|
|
}}>
|
|
<div>
|
|
{
|
|
smallTitle ? (
|
|
<h1 class="font-4xl" lang={lang}>
|
|
{title}
|
|
</h1>
|
|
) : (
|
|
<AppLayoutTitle pretitle={pretitle} title={title} subtitle={subtitle} lang={lang} />
|
|
)
|
|
}
|
|
{description && <RichText content={description} context={{ lang }} />}
|
|
</div>
|
|
{attributes.length > 0 && <Attributes attributes={attributes} />}
|
|
{credits.length > 0 && <Credits credits={credits} />}
|
|
{metaAttributes.length > 0 && <Attributes attributes={metaAttributes} />}
|
|
{filename && <DownloadButton href={url} filename={filename} useBlob />}
|
|
</div>
|
|
</div>
|
|
|
|
{/* ------------------------------------------- CSS -------------------------------------------- */}
|
|
|
|
<style>
|
|
#container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 3em;
|
|
align-items: center;
|
|
margin-top: 3em;
|
|
|
|
& > #image-viewer {
|
|
&.with-buttons {
|
|
display: grid;
|
|
grid-template-columns: auto 1fr auto;
|
|
gap: 1em;
|
|
place-items: center;
|
|
}
|
|
|
|
& > a.hidden {
|
|
visibility: hidden;
|
|
}
|
|
|
|
& > a {
|
|
&.pressable {
|
|
border-radius: 9999px;
|
|
padding-left: 1em;
|
|
padding-right: 1em;
|
|
height: 2.5em;
|
|
|
|
display: flex;
|
|
place-items: center;
|
|
place-content: center;
|
|
|
|
& > svg {
|
|
width: 1.5em;
|
|
height: 1.5em;
|
|
}
|
|
}
|
|
}
|
|
|
|
& > #image-anchor {
|
|
transition: 100ms scale;
|
|
box-shadow: 0 5px 20px -10px var(--color-shadow-0);
|
|
|
|
&:hover,
|
|
&:focus-visible {
|
|
scale: 102%;
|
|
}
|
|
|
|
max-height: 70vh;
|
|
}
|
|
}
|
|
|
|
& > #info {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4em;
|
|
align-items: start;
|
|
|
|
@media (max-width: 35rem) {
|
|
gap: 6em;
|
|
}
|
|
|
|
&:not(.complex) {
|
|
align-items: center;
|
|
gap: 2em;
|
|
}
|
|
|
|
& > div {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 32px;
|
|
}
|
|
}
|
|
}
|
|
|
|
h1 {
|
|
max-width: 35em;
|
|
}
|
|
</style>
|
|
|
|
{/* ------------------------------------------- JS --------------------------------------------- */}
|
|
|
|
<script>
|
|
document.addEventListener("keydown", async (e) => {
|
|
const previousButton = document.getElementById("previous-button");
|
|
const nextButton = document.getElementById("next-button");
|
|
|
|
if (previousButton && e.key === "ArrowLeft") {
|
|
previousButton.click();
|
|
} else if (nextButton && e.key === "ArrowRight") {
|
|
nextButton.click();
|
|
}
|
|
});
|
|
</script>
|