207 lines
5.2 KiB
Plaintext

---
import AppLayout from "components/AppLayout/AppLayout.astro";
import AppLayoutTitle from "components/AppLayout/components/AppLayoutTitle.astro";
import Attributes from "components/Attributes.astro";
import Credits from "components/Credits.astro";
import DownloadButton from "components/DownloadButton.astro";
import RichText from "components/RichText/RichText.astro";
import { getI18n } from "src/i18n/i18n";
import { payload } from "src/services";
import { formatInlineTitle, formatRichTextToString } from "src/utils/format";
import { fetchOr404 } from "src/utils/responses";
import { getFileIcon } from "src/utils/attributes";
import { Icon } from "astro-icon/components";
import { sizesToSrcset } from "src/utils/img";
const id = Astro.params.id!;
const response = await fetchOr404(() => payload.getFileByID(id));
if (response instanceof Response) {
return response;
}
const {
translations,
attributes,
filename,
url,
credits,
mimeType,
filesize,
updatedAt,
createdAt,
thumbnail,
backlinks,
} = response.data;
const { getLocalizedMatch, t, formatFilesize, formatDate } = await getI18n(
Astro.locals.currentLocale
);
const { pretitle, title, subtitle, description, language } =
translations.length > 0
? getLocalizedMatch(translations)
: {
pretitle: undefined,
title: filename,
subtitle: undefined,
description: undefined,
language: undefined,
};
const metaAttributes = [
...(filename && title !== filename && thumbnail
? [
{
title: t("global.media.attributes.filename"),
icon: getFileIcon(mimeType),
values: [{ name: filename }],
withBorder: false,
},
]
: []),
{
title: t("global.media.attributes.filesize"),
icon: "material-symbols:hard-drive",
values: [{ name: formatFilesize(filesize) }],
withBorder: false,
},
{
title: t("global.media.attributes.createdAt"),
icon: "material-symbols:calendar-add-on",
values: [{ name: formatDate(new Date(createdAt)) }],
withBorder: false,
},
{
title: t("global.media.attributes.updatedAt"),
icon: "material-symbols:edit-calendar",
values: [{ name: formatDate(new Date(updatedAt)) }],
withBorder: false,
},
];
const smallTitle = title === filename;
---
{/* ------------------------------------------- HTML ------------------------------------------- */}
<AppLayout
openGraph={{
title: formatInlineTitle({ pretitle, title, subtitle }),
description: description && formatRichTextToString(description),
thumbnail,
}}
topBar={{ relations: backlinks }}>
<div id="container">
{
thumbnail ? (
<a
id="image-anchor"
href={url}
target="_blank"
style={`aspect-ratio:${thumbnail.width}/${thumbnail.height};`}>
<img
src={url}
srcset={sizesToSrcset(thumbnail.sizes)}
sizes={`(max-aspect-ratio: ${thumbnail.width / 0.9}/${thumbnail.height / 0.7}) 90vw, ${(thumbnail.width / thumbnail.height) * 70}vh`}
width={thumbnail.width}
height={thumbnail.height}
/>
</a>
) : (
<a href={url} id="icon-container">
<Icon name={getFileIcon(mimeType)} width={32} height={32} />
<p>{filename}</p>
</a>
)
}
<div id="info">
{
smallTitle ? (
<h1 class="font-4xl" lang={language}>
{title}
</h1>
) : (
<AppLayoutTitle pretitle={pretitle} title={title} subtitle={subtitle} lang={language} />
)
}
{description && <RichText content={description} context={{ lang: language }} />}
{attributes.length > 0 && <Attributes attributes={attributes} />}
{credits.length > 0 && <Credits credits={credits} />}
{metaAttributes.length > 0 && <Attributes attributes={metaAttributes} />}
{filename && <DownloadButton href={url} filename={filename} />}
</div>
</div>
</AppLayout>
{/* ------------------------------------------- CSS -------------------------------------------- */}
<style>
#container {
display: flex;
flex-direction: column;
gap: 6em;
align-items: center;
h1 {
max-width: 35em;
}
& > #image-anchor {
transition: 100ms scale;
box-shadow: 0 5px 20px -10px var(--color-shadow-0);
&:hover,
&:focus-visible {
scale: 102%;
}
max-height: 70vh;
}
& > #icon-container {
display: grid;
place-content: center;
place-items: center;
gap: 0.5em;
border-radius: 16px;
padding: 3em;
box-sizing: border-box;
margin: 0.4em;
max-width: 35em;
width: 100%;
aspect-ratio: 3/2;
background-color: var(--color-elevation-2);
text-align: center;
& > svg {
width: clamp(16px, 25vw, 96px);
height: clamp(16px, 25vw, 96px);
color: var(--color-base-400);
}
& > p {
color: var(--color-base-600);
}
transition: 100ms scale;
&:hover,
&:focus-visible {
scale: 102%;
}
}
& > #info {
display: flex;
flex-direction: column;
gap: 4em;
align-items: start;
@media (max-width: 35rem) {
gap: 6em;
}
}
}
</style>