207 lines
5.2 KiB
Plaintext
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>
|