2024-12-23 21:18:55 +00:00
|
|
|
---
|
|
|
|
import Layout from "@layouts/Layout.astro";
|
|
|
|
import Prose from "@components/Prose.astro";
|
|
|
|
import FormattedDate from "@components/FormattedDate.astro";
|
|
|
|
import { readingTime } from "@lib/utils";
|
|
|
|
import { Icon } from "astro-icon/components";
|
2024-12-26 15:02:43 +00:00
|
|
|
import RelatedArticles from "@components/RelatedArticles.astro";
|
2024-12-23 21:18:55 +00:00
|
|
|
|
|
|
|
const { article, isPost = false } = Astro.props;
|
|
|
|
const { Content } = await article.render();
|
|
|
|
|
|
|
|
let datesMatch = false;
|
|
|
|
if (article.data.date.getTime() == article.data.updated?.getTime()) {
|
|
|
|
datesMatch = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const listFormatter = new Intl.ListFormat("en-GB", {
|
|
|
|
style: "long",
|
|
|
|
type: "conjunction",
|
|
|
|
});
|
|
|
|
---
|
|
|
|
|
|
|
|
<Layout
|
|
|
|
title={article.data.title}
|
|
|
|
description={article.data.description}
|
|
|
|
image={article.data.image.url.src}
|
|
|
|
date={article.data.date}
|
|
|
|
updated={article.data.updated}
|
|
|
|
tags={article.data.tags}
|
|
|
|
>
|
|
|
|
<div class="mx-auto mb-16 max-w-prose">
|
|
|
|
<h1
|
2024-12-26 22:45:38 +00:00
|
|
|
class="animate-reveal break-words text-start text-4xl font-semibold opacity-0"
|
2024-12-23 21:18:55 +00:00
|
|
|
>
|
2024-12-26 22:45:38 +00:00
|
|
|
<span class="text-secondary">{article.data.title}</span><span
|
|
|
|
class="ml-2 text-tertiary">{article.data.description}</span
|
|
|
|
>
|
2024-12-23 21:18:55 +00:00
|
|
|
</h1>
|
|
|
|
<div
|
2024-12-26 15:02:43 +00:00
|
|
|
class="flex animate-reveal flex-col items-start opacity-0 [animation-delay:0.1s]"
|
2024-12-23 21:18:55 +00:00
|
|
|
>
|
|
|
|
<div
|
2024-12-26 22:45:38 +00:00
|
|
|
class="mt-4 flex flex-col items-start gap-2 text-lg text-accent md:flex-row"
|
2024-12-23 21:18:55 +00:00
|
|
|
>
|
|
|
|
<div class="flex items-center gap-2">
|
|
|
|
<Icon name="mdi:calendar" />
|
|
|
|
{
|
|
|
|
datesMatch ? (
|
|
|
|
<p title="Date">
|
|
|
|
<FormattedDate date={article.data.date} />
|
|
|
|
</p>
|
|
|
|
) : (
|
|
|
|
<>
|
|
|
|
<p title="Date">
|
|
|
|
<FormattedDate date={article.data.date} />
|
|
|
|
</p>
|
|
|
|
<Icon name="mdi:trending-up" />
|
|
|
|
<p title="Updated">
|
|
|
|
<FormattedDate date={article.data.updated} />
|
|
|
|
</p>
|
|
|
|
</>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
</div>
|
|
|
|
{
|
|
|
|
isPost ? (
|
|
|
|
<div class="flex items-center gap-2">
|
|
|
|
<Icon name="mdi:timer" />
|
|
|
|
<p title="Word count">{readingTime(article.body)}</p>
|
|
|
|
</div>
|
|
|
|
) : null
|
|
|
|
}
|
|
|
|
</div>
|
|
|
|
{
|
|
|
|
article.data.extraAuthors ? (
|
2024-12-26 22:45:38 +00:00
|
|
|
<div class="mt-2 flex items-center gap-2">
|
2024-12-23 21:18:55 +00:00
|
|
|
<p>
|
|
|
|
In collaboration with{" "}
|
|
|
|
{listFormatter.format(article.data.extraAuthors)}
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
) : null
|
|
|
|
}
|
|
|
|
<ul class="mt-4 flex flex-wrap gap-1">
|
|
|
|
{
|
|
|
|
article.data.categories.map((category: string) => (
|
2024-12-26 22:45:38 +00:00
|
|
|
<li class="rounded border border-accent bg-accent px-1 py-0.5 text-sm capitalize text-primary">
|
2024-12-23 21:18:55 +00:00
|
|
|
{category}
|
|
|
|
</li>
|
|
|
|
))
|
|
|
|
}
|
|
|
|
{
|
|
|
|
article.data.tags.map((tag: string) => (
|
2024-12-26 22:45:38 +00:00
|
|
|
<li class="rounded border border-accent bg-primary px-1 py-0.5 text-sm capitalize text-accent">
|
2024-12-23 21:18:55 +00:00
|
|
|
{tag}
|
|
|
|
</li>
|
|
|
|
))
|
|
|
|
}
|
|
|
|
</ul>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div
|
2024-12-26 15:02:43 +00:00
|
|
|
class="mx-auto max-w-prose animate-reveal opacity-0 [animation-delay:0.2s]"
|
2024-12-23 21:18:55 +00:00
|
|
|
>
|
|
|
|
<Prose>
|
|
|
|
<Content />
|
|
|
|
</Prose>
|
|
|
|
</div>
|
2024-12-26 15:02:43 +00:00
|
|
|
<RelatedArticles entry={article} />
|
2024-12-23 21:18:55 +00:00
|
|
|
</Layout>
|