refactor: add a generic listing page component
This commit is contained in:
parent
bcd846f08c
commit
2efcb575f1
24
website/src/components/ListingPage.astro
Normal file
24
website/src/components/ListingPage.astro
Normal file
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
import PageLayout from "~/layouts/PageLayout.astro";
|
||||
import ListingPageItem from "./ListingPageItem.astro";
|
||||
|
||||
interface Item {
|
||||
description: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
items: Array<Item>;
|
||||
title: string;
|
||||
}
|
||||
|
||||
const { items, title } = Astro.props as Props;
|
||||
---
|
||||
|
||||
<PageLayout title={title}>
|
||||
<slot name="intro" />
|
||||
|
||||
<div class="mt-6 space-y-6">
|
||||
{items.map((item) => <ListingPageItem item={item} />)}
|
||||
</div>
|
||||
</PageLayout>
|
31
website/src/components/ListingPageItem.astro
Normal file
31
website/src/components/ListingPageItem.astro
Normal file
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
interface ItemProps {
|
||||
date: string;
|
||||
description?: string;
|
||||
excerpt?: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
const { date, description, excerpt, title } = Astro.props.item.item
|
||||
.frontmatter as ItemProps;
|
||||
const { slug } = Astro.props.item;
|
||||
---
|
||||
|
||||
<article>
|
||||
<a href={slug} class="mb-2"><h2>{title}</h2></a>
|
||||
|
||||
{
|
||||
date && (
|
||||
<time class="mt-0 mb-2 block text-base" datetime={date}>
|
||||
{new Date(date).toLocaleDateString("en-GB", {
|
||||
day: "numeric",
|
||||
month: "long",
|
||||
year: "numeric",
|
||||
})}
|
||||
</time>
|
||||
)
|
||||
}
|
||||
|
||||
{description && <p>{description}</p>}
|
||||
{excerpt && <p>{excerpt}</p>}
|
||||
</article>
|
|
@ -1,4 +1,5 @@
|
|||
---
|
||||
import ListingPage from "~/components/ListingPage.astro";
|
||||
import PageLayout from "~/layouts/PageLayout.astro";
|
||||
import { getSlugFromFile } from "~/utils.ts";
|
||||
|
||||
|
@ -11,50 +12,21 @@ const filteredPosts = posts
|
|||
|
||||
const sortedPosts = filteredPosts
|
||||
.map((post) => {
|
||||
const slug = getSlugFromFile(post.file);
|
||||
const slug = `/blog/${getSlugFromFile(post.file)}`;
|
||||
|
||||
return { post, slug };
|
||||
return { item: post, slug };
|
||||
})
|
||||
.sort(
|
||||
(a, b) =>
|
||||
new Date(b.post.frontmatter.date).valueOf() -
|
||||
new Date(a.post.frontmatter.date).valueOf()
|
||||
new Date(b.item.frontmatter.date).valueOf() -
|
||||
new Date(a.item.frontmatter.date).valueOf()
|
||||
);
|
||||
---
|
||||
|
||||
<PageLayout title="Blog">
|
||||
<p>
|
||||
<ListingPage items={sortedPosts} title="Blog">
|
||||
<p slot="intro">
|
||||
This is where I publish my personal blog posts as well as technical posts
|
||||
and tutorials on topics such as Drupal, PHP, Tailwind CSS, automated
|
||||
testing, and systems administration.
|
||||
</p>
|
||||
|
||||
<div>
|
||||
{
|
||||
sortedPosts.map((post) => (
|
||||
<article>
|
||||
<a href={`/blog/${post.slug}`}>
|
||||
<h2>{post.post.frontmatter.title}</h2>
|
||||
</a>
|
||||
|
||||
{post.post.frontmatter.date && (
|
||||
<time class="text-base" datetime={post.post.frontmatter.date}>
|
||||
{new Date(post.post.frontmatter.date).toLocaleDateString(
|
||||
"en-GB",
|
||||
{
|
||||
day: "numeric",
|
||||
month: "long",
|
||||
year: "numeric",
|
||||
}
|
||||
)}
|
||||
</time>
|
||||
)}
|
||||
|
||||
<div class="mt-1">
|
||||
<p>{post.post.frontmatter.excerpt}</p>
|
||||
</div>
|
||||
</article>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</PageLayout>
|
||||
</ListingPage>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import PageLayout from "~/layouts/PageLayout.astro";
|
||||
import _ from "lodash";
|
||||
import { getSlugFromFile } from "~/utils.ts";
|
||||
import ListingPage from "~/components/ListingPage.astro";
|
||||
|
||||
const talks = await Astro.glob("../../talks/*.md");
|
||||
|
||||
|
@ -11,14 +12,14 @@ const talkCount = _(talks)
|
|||
|
||||
const sortedTalks = talks
|
||||
.map((talk) => {
|
||||
const slug = getSlugFromFile(talk.file);
|
||||
const slug = `/talks/${getSlugFromFile(talk.file)}`;
|
||||
|
||||
return { slug, talk };
|
||||
return { slug, item: talk };
|
||||
})
|
||||
.sort((b, a) => {
|
||||
const events = [
|
||||
a.talk.frontmatter.events[a.talk.frontmatter.events.length - 1],
|
||||
b.talk.frontmatter.events[b.talk.frontmatter.events.length - 1],
|
||||
a.item.frontmatter.events[a.item.frontmatter.events.length - 1],
|
||||
b.item.frontmatter.events[b.item.frontmatter.events.length - 1],
|
||||
];
|
||||
|
||||
return (
|
||||
|
@ -27,24 +28,10 @@ const sortedTalks = talks
|
|||
});
|
||||
---
|
||||
|
||||
<PageLayout title="Talks and workshops">
|
||||
<p>
|
||||
<ListingPage items={sortedTalks} title="Talks and workshops">
|
||||
<p slot="intro">
|
||||
Starting with my first talk in September 2012, I have given {talkCount} presentations
|
||||
and workshops at various conferences and meetups, in-person and remotely, on
|
||||
topics including PHP, Drupal, automated testing, Git, CSS, and systems administration.
|
||||
</p>
|
||||
|
||||
<div>
|
||||
{
|
||||
sortedTalks.map((talk) => (
|
||||
<article>
|
||||
<a href={`/talks/${talk.slug}`}>
|
||||
<h2>{talk.talk.frontmatter.title}</h2>
|
||||
</a>
|
||||
|
||||
{talk.talk.frontmatter.description}
|
||||
</article>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</PageLayout>
|
||||
</ListingPage>
|
||||
|
|
Loading…
Reference in a new issue