157 lines
4.7 KiB
Plaintext
157 lines
4.7 KiB
Plaintext
---
|
|
import { Image } from 'astro:assets';
|
|
import { marked } from 'marked';
|
|
import markedShiki from 'marked-shiki';
|
|
import { createHighlighter } from 'shiki';
|
|
import { readItems, readSingleton } from '@directus/sdk';
|
|
import "photoswipe/style.css";
|
|
|
|
import type { Post } from '@/lib/directusTypes'
|
|
|
|
import SocialShareButton from '@components/buttons/SocialShareButton.astro';
|
|
import PostMetadataSnippet from '@/components/snippets/PostMetadataSnippet.astro';
|
|
import BaseLayout from '@layouts/BaseLayout.astro';
|
|
import directus from '@lib/directus';
|
|
import { getDirectusImageURL } from '@/scripts/url';
|
|
|
|
export async function getStaticPaths() {
|
|
const posts = await directus.request(readItems('posts', {
|
|
fields: ['*', { category: ['*'] }],
|
|
}));
|
|
const globalData = await directus.request(readSingleton('site_global'));
|
|
const highlighter = await createHighlighter({
|
|
themes: ['github-light', 'github-dark'],
|
|
langs: ['typescript', 'python', 'css', 'html', 'yaml', 'bash', 'json'],
|
|
});
|
|
const renderer = {
|
|
image({ href, title, text }: { href: string; title: string | null; text: string }) {
|
|
return `
|
|
<a
|
|
href="${href}"
|
|
class="pswp-link"
|
|
data-pswp-src="${href}"
|
|
target="_blank"
|
|
>
|
|
<img src="${href}" alt="${text}" title="${title || ''}" loading="lazy" />
|
|
</a>
|
|
`;
|
|
},
|
|
};
|
|
marked.use({ renderer });
|
|
marked.use(markedShiki({
|
|
highlight(code, lang) {
|
|
return highlighter.codeToHtml(code, {
|
|
lang: lang || 'plaintext',
|
|
themes: { light: 'github-light', dark: 'github-dark' },
|
|
defaultColor: false,
|
|
});
|
|
}
|
|
}));
|
|
|
|
return posts.map((post: Post) => ({
|
|
params: { slug: post.slug },
|
|
props: {
|
|
post,
|
|
global: globalData,
|
|
content: marked.parse(post.content || ''),
|
|
},
|
|
}));
|
|
}
|
|
|
|
const { post, global, content } = Astro.props;
|
|
---
|
|
|
|
<BaseLayout
|
|
title={post.title}
|
|
description={post.description}
|
|
ogImage={getDirectusImageURL(post.image)}
|
|
structuredData={{
|
|
'@context': 'https://schema.org',
|
|
'@type': 'NewsArticle',
|
|
inLanguage: 'en-US',
|
|
'@id': Astro.url.href,
|
|
url: Astro.url.href,
|
|
description: post.description,
|
|
isPartOf: {
|
|
'@type': 'WebSite',
|
|
url: `${global.site_url}/blog`,
|
|
name: global.name,
|
|
description: global.about,
|
|
},
|
|
image: [getDirectusImageURL(post.image)],
|
|
headline: post.title,
|
|
datePublished: post.published_date,
|
|
dateModified: post.updated_date,
|
|
author: [
|
|
{
|
|
'@type': 'Person',
|
|
name: `${global.name}`,
|
|
url: `${global.site_url}`,
|
|
},
|
|
],
|
|
}}
|
|
>
|
|
|
|
<section class="max-w-6xl px-4 sm:px-6 lg:px-8 pt-8 lg:pt-12 pb-12 mx-auto">
|
|
<div class="smooth-reveal relative w-full">
|
|
<div class="sm:shadow-xs sm:dark:shadow-md rounded-2xl mt-4 sm:mt-0">
|
|
<Image
|
|
class="rounded-2xl sm:rounded-b-none w-full max-h-150 object-cover"
|
|
src={getDirectusImageURL(post.image)}
|
|
alt={post.image_alt || post.title}
|
|
draggable="false"
|
|
format="webp"
|
|
loading="lazy"
|
|
inferSize={true}
|
|
/>
|
|
<div class="sm:bg-background-card rounded-b-2xl px-0 sm:px-6 md:px-10 lg:px-14 py-6">
|
|
<div class="text-center sm:text-left mt-4">
|
|
<h2 class="card-text-header block">
|
|
{post.title}
|
|
</h2>
|
|
<div class="mt-4 sm:mt-6">
|
|
<PostMetadataSnippet
|
|
post={post}
|
|
dateFormat='long'
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div class="border-t border-divider mt-10 mb-10"/>
|
|
|
|
<article class="text-header prose prose-blog sm:prose-lg dark:prose-invert max-w-none">
|
|
<div set:html={content} />
|
|
</article>
|
|
|
|
<div class="grid sm:flex sm:items-center sm:justify-between gap-y-5 sm:gap-y-0 max-w-5xl mx-auto mt-10 md:mt-14">
|
|
{post.tags && post.tags.length > 0 && (
|
|
<div class="flex flex-wrap sm:flex-nowrap sm:items-center gap-x-2 gap-y-1 sm:gap-y-0">
|
|
{post.tags.map((tag: string) => (
|
|
<span class="inline-flex items-center button-base bg-cobalt dark:bg-turquoise text-neutral-100 text-xs font-bold rounded-lg gap-x-1.5 px-3 py-1.5">
|
|
{tag}
|
|
</span>
|
|
))}
|
|
</div>
|
|
)}
|
|
<SocialShareButton pageTitle={post.title}/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<style is:inline>
|
|
code[data-theme*=' '],
|
|
code[data-theme*=' '] span {
|
|
color: var(--shiki-light);
|
|
}
|
|
|
|
html.dark {
|
|
code[data-theme*=' '],
|
|
code[data-theme*=' '] span {
|
|
color: var(--shiki-dark);
|
|
}
|
|
}
|
|
</style>
|
|
|
|
</BaseLayout>
|