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 PageLayout from "~/layouts/PageLayout.astro";
|
||||||
import { getSlugFromFile } from "~/utils.ts";
|
import { getSlugFromFile } from "~/utils.ts";
|
||||||
|
|
||||||
|
@ -11,50 +12,21 @@ const filteredPosts = posts
|
||||||
|
|
||||||
const sortedPosts = filteredPosts
|
const sortedPosts = filteredPosts
|
||||||
.map((post) => {
|
.map((post) => {
|
||||||
const slug = getSlugFromFile(post.file);
|
const slug = `/blog/${getSlugFromFile(post.file)}`;
|
||||||
|
|
||||||
return { post, slug };
|
return { item: post, slug };
|
||||||
})
|
})
|
||||||
.sort(
|
.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
new Date(b.post.frontmatter.date).valueOf() -
|
new Date(b.item.frontmatter.date).valueOf() -
|
||||||
new Date(a.post.frontmatter.date).valueOf()
|
new Date(a.item.frontmatter.date).valueOf()
|
||||||
);
|
);
|
||||||
---
|
---
|
||||||
|
|
||||||
<PageLayout title="Blog">
|
<ListingPage items={sortedPosts} title="Blog">
|
||||||
<p>
|
<p slot="intro">
|
||||||
This is where I publish my personal blog posts as well as technical posts
|
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
|
and tutorials on topics such as Drupal, PHP, Tailwind CSS, automated
|
||||||
testing, and systems administration.
|
testing, and systems administration.
|
||||||
</p>
|
</p>
|
||||||
|
</ListingPage>
|
||||||
<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>
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import PageLayout from "~/layouts/PageLayout.astro";
|
import PageLayout from "~/layouts/PageLayout.astro";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { getSlugFromFile } from "~/utils.ts";
|
import { getSlugFromFile } from "~/utils.ts";
|
||||||
|
import ListingPage from "~/components/ListingPage.astro";
|
||||||
|
|
||||||
const talks = await Astro.glob("../../talks/*.md");
|
const talks = await Astro.glob("../../talks/*.md");
|
||||||
|
|
||||||
|
@ -11,14 +12,14 @@ const talkCount = _(talks)
|
||||||
|
|
||||||
const sortedTalks = talks
|
const sortedTalks = talks
|
||||||
.map((talk) => {
|
.map((talk) => {
|
||||||
const slug = getSlugFromFile(talk.file);
|
const slug = `/talks/${getSlugFromFile(talk.file)}`;
|
||||||
|
|
||||||
return { slug, talk };
|
return { slug, item: talk };
|
||||||
})
|
})
|
||||||
.sort((b, a) => {
|
.sort((b, a) => {
|
||||||
const events = [
|
const events = [
|
||||||
a.talk.frontmatter.events[a.talk.frontmatter.events.length - 1],
|
a.item.frontmatter.events[a.item.frontmatter.events.length - 1],
|
||||||
b.talk.frontmatter.events[b.talk.frontmatter.events.length - 1],
|
b.item.frontmatter.events[b.item.frontmatter.events.length - 1],
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -27,24 +28,10 @@ const sortedTalks = talks
|
||||||
});
|
});
|
||||||
---
|
---
|
||||||
|
|
||||||
<PageLayout title="Talks and workshops">
|
<ListingPage items={sortedTalks} title="Talks and workshops">
|
||||||
<p>
|
<p slot="intro">
|
||||||
Starting with my first talk in September 2012, I have given {talkCount} presentations
|
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
|
and workshops at various conferences and meetups, in-person and remotely, on
|
||||||
topics including PHP, Drupal, automated testing, Git, CSS, and systems administration.
|
topics including PHP, Drupal, automated testing, Git, CSS, and systems administration.
|
||||||
</p>
|
</p>
|
||||||
|
</ListingPage>
|
||||||
<div>
|
|
||||||
{
|
|
||||||
sortedTalks.map((talk) => (
|
|
||||||
<article>
|
|
||||||
<a href={`/talks/${talk.slug}`}>
|
|
||||||
<h2>{talk.talk.frontmatter.title}</h2>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
{talk.talk.frontmatter.description}
|
|
||||||
</article>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</PageLayout>
|
|
||||||
|
|
Loading…
Reference in a new issue