blog/src/components/PostList.astro

95 lines
1.9 KiB
Plaintext
Raw Normal View History

2023-08-31 03:47:22 +00:00
---
2023-08-31 08:07:03 +00:00
import { getCollection, type CollectionEntry } from "astro:content";
import Timestamp from "./Timestamp.astro";
import { sortBy } from "lodash-es";
interface Props {
basePath: string;
2023-08-31 14:05:06 +00:00
drafts?: "exclude" | "include" | "only";
2023-09-01 14:16:36 +00:00
filteredPosts?: Post[];
2023-08-31 08:07:03 +00:00
}
type Post = CollectionEntry<"posts">;
2023-09-01 14:16:36 +00:00
const { basePath, drafts: includeDrafts, filteredPosts } = Astro.props;
2023-08-31 14:05:06 +00:00
2023-09-01 14:16:36 +00:00
type FilterFn = (_: Post) => boolean;
function unreachable(): never {
throw new Error("unreachable");
}
function getFilter(): FilterFn {
switch (includeDrafts) {
case "exclude":
case undefined:
return (post: Post) => !post.data.draft;
case "include":
return (_: Post) => true;
case "only":
return (post: Post) => post.data.draft === true;
}
return unreachable();
2023-08-31 14:05:06 +00:00
}
2023-09-01 14:16:36 +00:00
const filter = getFilter();
let allPosts;
if (filteredPosts) allPosts = filteredPosts.filter(filter);
else allPosts = await getCollection("posts", filter);
2023-08-31 08:07:03 +00:00
const sortedPosts = sortBy(allPosts, (post) => -post.data.date);
2023-08-31 03:47:22 +00:00
---
2023-08-31 08:07:03 +00:00
<table class="postListing">
2023-08-31 03:47:22 +00:00
{
2023-08-31 08:07:03 +00:00
sortedPosts.map((post) => {
2023-08-31 03:47:22 +00:00
return (
2023-08-31 08:07:03 +00:00
<tr class="row">
<td class="info">
<Timestamp timestamp={post.data.date} />
</td>
2023-08-31 03:47:22 +00:00
<td>
<span class="title">
2023-08-31 08:07:03 +00:00
<a href={`${basePath}/${post.slug}`} class="brand-colorlink">
2023-08-31 03:47:22 +00:00
{post.data.title}
</a>
</span>
</td>
</tr>
);
})
}
</table>
2023-08-31 08:07:03 +00:00
<style lang="scss">
.postListing {
width: 100%;
border-spacing: 6px;
td {
// padding-bottom: 10px;
// line-height: 1;
.title {
font-size: 1.1em;
}
.summary {
padding-top: 4px;
font-size: 0.64em;
color: var(--smaller-text-color);
p {
display: inline;
}
}
}
td.info {
color: var(--smaller-text-color);
font-size: 0.75em;
white-space: nowrap;
text-align: right;
}
}
</style>