mirror of
https://github.com/kogakure/website-astro-stefanimhoff.de.git
synced 2026-02-03 20:15:27 +00:00
258 lines
6.5 KiB
Plaintext
258 lines
6.5 KiB
Plaintext
---
|
|
import type { CollectionEntry } from 'astro:content';
|
|
type Journal = CollectionEntry<'journal'>;
|
|
import { getCollection } from 'astro:content';
|
|
|
|
import { site } from '../data/site';
|
|
|
|
import { formatPosts, sortByDate } from '../utils';
|
|
import { dateToFormat, dateToISO, wordCount } from '../utils';
|
|
|
|
import Banner from '../components/Banner.astro';
|
|
import GridLayout from '../layouts/GridLayout.astro';
|
|
import Image from '../components/Image.astro';
|
|
import ListItem from '../components/ListItem.astro';
|
|
import OrderedList from '../components/OrderedList.astro';
|
|
import PageTitle from '../components/PageTitle.astro';
|
|
import Pagination from '../components/Pagination.astro';
|
|
import Tag from '../components/Tag.astro';
|
|
import TextLink from '../components/TextLink.astro';
|
|
|
|
import { mapping } from '../mdx-components';
|
|
|
|
export async function getStaticPaths() {
|
|
const journalEntries = await getCollection('journal', ({ data }: Journal) => !data.draft);
|
|
const numberOfPages = journalEntries.length;
|
|
const formattedJournalEntries: Journal[] = formatPosts(journalEntries, { sortOrder: 'asc' });
|
|
|
|
return formattedJournalEntries.map((entry, index) => ({
|
|
params: { slug: entry.slug },
|
|
props: {
|
|
entry,
|
|
next:
|
|
index + 1 === numberOfPages
|
|
? { slug: null, data: null }
|
|
: formattedJournalEntries[index + 1],
|
|
prev: index === 0 ? { slug: null, data: null } : formattedJournalEntries[index - 1],
|
|
},
|
|
}));
|
|
}
|
|
|
|
const { entry, prev, next } = Astro.props;
|
|
const {
|
|
Content,
|
|
remarkPluginFrontmatter: { minutesRead },
|
|
} = await entry.render();
|
|
|
|
const seriesEntries: Journal[] = await getCollection('journal', ({ data }: Journal) => {
|
|
return data.series === entry.data.series && !data.draft;
|
|
});
|
|
|
|
seriesEntries.sort(sortByDate).reverse();
|
|
|
|
const title = entry.data.title;
|
|
const description = entry.data.description;
|
|
|
|
const schema = JSON.stringify({
|
|
'@context': 'https://schema.org',
|
|
'@type': 'Article',
|
|
headline: entry.data.title,
|
|
description: entry.data.description,
|
|
datePublished: entry.data.date,
|
|
dateModified: entry.data.updated,
|
|
image: [
|
|
entry.data.cover
|
|
? site.url + entry.data.cover
|
|
: `${site.url}/assets/images/branding/og/bonsai.jpg`,
|
|
],
|
|
author: [
|
|
{
|
|
'@type': 'Person',
|
|
name: entry.data.author || site.author,
|
|
url: `${site.url}/about`,
|
|
},
|
|
],
|
|
mainEntityOfPage: {
|
|
'@type': 'webPage',
|
|
id: `${site.url}/${entry.slug}/}`,
|
|
},
|
|
});
|
|
---
|
|
|
|
<GridLayout
|
|
backLink="/journal/"
|
|
cover={entry.data.cover}
|
|
description={description}
|
|
grid="fullsize"
|
|
innerGrid
|
|
nofollow={entry.data.nofollow}
|
|
noindex={entry.data.noindex}
|
|
title={title}
|
|
>
|
|
<PageTitle slot="title" class="!text-6">
|
|
{entry.data.title}
|
|
</PageTitle>
|
|
{
|
|
entry.data.cover && (
|
|
<Image
|
|
alt={entry.data.title}
|
|
class="col-span-full aspect-video h-auto !mbe-0 xl:col-start-1 xl:col-end-14 3xl:col-end-13 print:hidden [&_img]:!w-full [&_img]:!max-w-none [&_picture]:!w-full [&_picture]:!max-w-none"
|
|
loading="eager"
|
|
src={entry.data.cover}
|
|
/>
|
|
)
|
|
}
|
|
|
|
<aside
|
|
class:list={[
|
|
'col-start-2 col-end-18 md:col-start-5 md:col-end-15 xl:col-start-15 xl:col-end-18 xl:row-start-2 3xl:col-start-14 3xl:col-end-18',
|
|
{ 'row-start-3': entry.data.cover },
|
|
]}
|
|
>
|
|
<div class="leading-none mbe-6">
|
|
<em>By</em>{' '}
|
|
<TextLink href="/about/">{entry.data.author}</TextLink>
|
|
</div>
|
|
<div class="leading-tight">
|
|
<time datetime={dateToISO(entry.data.date)}>{dateToFormat(entry.data.date)}</time>
|
|
</div>
|
|
<div class="leading-none mbe-6">
|
|
{wordCount(entry.body)}{' '}
|
|
<span class="italic">words</span> • {Math.round(minutesRead)}{' '}
|
|
<span class="italic">min read</span>
|
|
</div>
|
|
<div class="flex flex-wrap gap-y-3">
|
|
{
|
|
entry.data.tags
|
|
.sort((a: string, b: string) => a.localeCompare(b))
|
|
.map((t: string) => <Tag href={`/tag/${t}/`}>{t}</Tag>)
|
|
}
|
|
</div>
|
|
</aside>
|
|
<div
|
|
class="journal-post col-start-2 col-end-18 md:col-start-5 md:col-end-15 xl:col-start-6 xl:col-end-14 3xl:col-start-7 3xl:col-end-13"
|
|
>
|
|
{
|
|
entry.data.series && seriesEntries.length > 1 && (
|
|
<Banner>
|
|
<OrderedList class="!mbe-0 !pis-7">
|
|
{seriesEntries.map((item) => (
|
|
<ListItem class="!text-[0.85em]">
|
|
{entry.slug === item.slug ? (
|
|
<>
|
|
<i>{item.data.title}</i>
|
|
📍
|
|
</>
|
|
) : (
|
|
<TextLink href={`/${item.slug}/`}>{item.data.title}</TextLink>
|
|
)}
|
|
</ListItem>
|
|
))}
|
|
</OrderedList>
|
|
</Banner>
|
|
)
|
|
}
|
|
<Content components={mapping} />
|
|
{
|
|
entry.data.updated && (
|
|
<footer class="mbs-10">
|
|
<b>Last Updated:</b>
|
|
<time datetime={dateToISO(entry.data.updated)}>
|
|
{dateToFormat(entry.data.updated)}
|
|
</time>
|
|
</footer>
|
|
)
|
|
}
|
|
</div>
|
|
|
|
<Pagination
|
|
nextText="Next"
|
|
nextUrl={next.slug ? `/${next.slug}/` : undefined}
|
|
previousText="Previous"
|
|
previousUrl={prev.slug ? `/${prev.slug}/` : undefined}
|
|
/>
|
|
</GridLayout>
|
|
|
|
<script type="application/ld+json" set:html={schema} />
|
|
|
|
<style is:global>
|
|
.journal-post {
|
|
& > h2 {
|
|
@apply text-4 mbe-9;
|
|
}
|
|
|
|
& > h3,
|
|
& > h4,
|
|
& > h5,
|
|
& > h6 {
|
|
@apply text-3;
|
|
}
|
|
|
|
& h2 + h3,
|
|
& p + h2,
|
|
& p + h3,
|
|
& p + h4,
|
|
& p + h5,
|
|
& p + h6 {
|
|
@apply !mbs-12;
|
|
}
|
|
|
|
& > pre {
|
|
@apply md:-mie-[5.55vw] md:-mis-[5.55vw];
|
|
}
|
|
|
|
& > figure.figure-wide {
|
|
@apply md:-mie-[16.65vw] md:-mis-[16.65vw] xl:-mie-[11.1vw] xl:-mis-[11.1vw] [&_img]:w-full [&_img]:max-w-none;
|
|
}
|
|
|
|
& > figure.figure-fullsize {
|
|
@apply -mie-[5.55vw] -mis-[5.55vw] md:-mie-[22.2vw] md:-mis-[22.2vw] xl:-mie-[27.75vw] xl:-mis-[27.75vw] 3xl:-mie-[33.3vw] 3xl:-mis-[33.3vw] [&_img]:w-full [&_img]:max-w-none;
|
|
}
|
|
|
|
& > figure .image-shadow,
|
|
& > figure p {
|
|
@apply m-0;
|
|
}
|
|
|
|
/** Footnotes */
|
|
.footnotes {
|
|
@apply relative pis-[2rem];
|
|
}
|
|
|
|
.footnotes ol {
|
|
@apply m-0 list-none p-0 [counter-reset:item];
|
|
}
|
|
|
|
.footnotes li::before {
|
|
@apply absolute align-super text-[smaller] font-thin opacity-60 content-[counter(item)] pbs-[0.15rem] inline-start-0 [counter-increment:item];
|
|
}
|
|
|
|
.footnotes .data-footnote-backref {
|
|
@apply font-light text-accent no-underline;
|
|
}
|
|
|
|
.footnotes p {
|
|
@apply mbe-0;
|
|
}
|
|
|
|
.footnotes p a {
|
|
@apply break-words;
|
|
}
|
|
|
|
.footnotes :target {
|
|
@apply bg-black/5 p-5 dark:bg-white/5;
|
|
}
|
|
|
|
[data-footnote-ref] {
|
|
@apply relative rounded-full font-light not-italic !text-shibui-400 no-underline mis-[0.2em] dark:!text-shibui-100;
|
|
}
|
|
|
|
p:hover [data-footnote-ref],
|
|
p:focus [data-footnote-ref],
|
|
[data-footnote-ref]:hover,
|
|
[data-footnote-ref]:focus {
|
|
@apply relative rounded-full font-light not-italic !text-accent no-underline mis-[0.2em];
|
|
}
|
|
}
|
|
</style>
|