93 lines
3.9 KiB
Text
93 lines
3.9 KiB
Text
---
|
|
import Layout from '../../layouts/Layout.astro';
|
|
|
|
import { getCollection, getEntry } from 'astro:content';
|
|
import Comments from "../../components/Comments.astro";
|
|
import {getImage, Image} from "astro:assets";
|
|
import {siteConfig} from "../../config";
|
|
import ReplyViaEmail from "../../components/ReplyViaEmail.astro";
|
|
import { ExtractFirstImage } from '../../plugins/extract-images';
|
|
import AuthorInfo from "../../components/helper/authors/Info.astro";
|
|
import TableOfContents from "../../components/TableOfContents.astro";
|
|
import "katex/dist/katex.css"
|
|
|
|
export async function getStaticPaths() {
|
|
const blogEntries = await getCollection('posts');
|
|
return blogEntries.map(entry => ({
|
|
params: { slug: entry.slug }, props: { entry },
|
|
}));
|
|
}
|
|
|
|
const { entry } = Astro.props;
|
|
const { Content, headings, remarkPluginFrontmatter } = await entry.render();
|
|
|
|
const noscript = siteConfig.noClientJavaScript
|
|
const slug = Astro.params.slug;
|
|
const author = Array.isArray(entry.data.author) ? entry.data.author : (entry.data.author !== undefined ? [entry.data.author] : [{collection: 'authors', id: siteConfig.defaultAuthor.id}]);
|
|
|
|
// Get Wordcount and Last Updated Date
|
|
const wordcount = remarkPluginFrontmatter.wordcount;
|
|
const lastUpdated = remarkPluginFrontmatter.lastModified;
|
|
|
|
// Get author data
|
|
const authorData = await Promise.all((author).map((singleAuthor) => getEntry(singleAuthor).then(authorEntry => authorEntry?.data)))
|
|
const authorInfo = authorData.includes(undefined) ? [{data: siteConfig.defaultAuthor}] : authorData;
|
|
|
|
// get featured image and use it as og:image
|
|
// use the custom cover image if it exists, otherwise use the featured image file in the same directory
|
|
const featuredImages = import.meta.glob(`/src/content/posts/*/featured.{avif,png,jpg,jpeg,webp}`,{import:'default',eager:true});
|
|
const customFeaturedImage = entry.data.cover?.src
|
|
const matchedImage = Object.keys(featuredImages).find(path => path.includes(slug));
|
|
let matchedImage_src;
|
|
if (matchedImage && !customFeaturedImage) {
|
|
matchedImage_src = await getImage({src: featuredImages[matchedImage] as ImageMetadata, format: 'webp'}) || null;
|
|
}
|
|
const firstImageURL = await ExtractFirstImage(Content)
|
|
|
|
const cover = customFeaturedImage || matchedImage_src?.src || firstImageURL || `/blog/${slug}/featured.png` || '';
|
|
---
|
|
|
|
<Layout
|
|
title={entry.data.title}
|
|
description={entry.data.description}
|
|
ogImage={cover}
|
|
author={authorInfo.map((a: any) => a.name).join(', ')}
|
|
>
|
|
<article>
|
|
<h1 class="title">{entry.data.title}</h1>
|
|
{authorInfo.map((a: any) => <AuthorInfo data={a} />)}
|
|
<span class="date">{new Date(entry.data.pubDate).toISOString().split('T')[0]}</span>
|
|
<span class="date">(Updated on {new Date(lastUpdated).toISOString().split('T')[0]})</span>
|
|
<span>|</span>
|
|
<span class="wordcount">{wordcount.words} words</span>
|
|
{ (cover && cover !== firstImageURL && cover !== `/blog/${slug}/featured.png`) && <Image class="cover" width=720 height=480 src={cover} alt={`cover of ${entry.data.title}`} /> }
|
|
{headings.length !== 0 && <TableOfContents headings={headings} />}
|
|
{entry.data.summary && <p class="summary">{entry.data.summary}</p> }
|
|
<div class="content">
|
|
<Content />
|
|
</div>
|
|
</article>
|
|
<div class="extra-post" style="margin-top: 2rem; border-top: 1px solid var(--border-color); padding-top: 1rem;">
|
|
<ReplyViaEmail title={entry.data.title} email={authorInfo[0].email} />
|
|
<br>
|
|
<a href="/blog">← Back to posts</a>
|
|
{!noscript && <h2>Comments</h2> <Comments />}
|
|
{!noscript &&
|
|
<script>
|
|
import "katex/dist/contrib/copy-tex.js"
|
|
</script>
|
|
}
|
|
</div>
|
|
</Layout>
|
|
<style>
|
|
p.summary {
|
|
font-style: italic;
|
|
color: var(--secondary-text-color);
|
|
margin: 1rem;
|
|
}
|
|
img.cover {
|
|
width: 100%;
|
|
height: auto;
|
|
margin: 1rem auto;
|
|
}
|
|
</style>
|