summaryrefslogtreecommitdiff
path: root/src/pages/posts
diff options
context:
space:
mode:
Diffstat (limited to 'src/pages/posts')
-rw-r--r--src/pages/posts/[...page].astro125
-rw-r--r--src/pages/posts/[...slug].astro24
2 files changed, 149 insertions, 0 deletions
diff --git a/src/pages/posts/[...page].astro b/src/pages/posts/[...page].astro
new file mode 100644
index 0000000..495fc7b
--- /dev/null
+++ b/src/pages/posts/[...page].astro
@@ -0,0 +1,125 @@
+---
+import type { CollectionEntry } from "astro:content";
+import Pagination from "@/components/Paginator.astro";
+import PostPreview from "@/components/blog/PostPreview.astro";
+import { getAllPosts, getUniqueTags, groupPostsByYear } from "@/data/post";
+import PageLayout from "@/layouts/Base.astro";
+import { collectionDateSort } from "@/utils/date";
+import type { GetStaticPaths, Page } from "astro";
+import { Icon } from "astro-icon/components";
+
+export const getStaticPaths = (async ({ paginate }) => {
+ const MAX_POSTS_PER_PAGE = 10;
+ const MAX_TAGS = 7;
+ const allPosts = await getAllPosts();
+ const uniqueTags = getUniqueTags(allPosts).slice(0, MAX_TAGS);
+ return paginate(allPosts.sort(collectionDateSort), {
+ pageSize: MAX_POSTS_PER_PAGE,
+ props: { uniqueTags },
+ });
+}) satisfies GetStaticPaths;
+
+interface Props {
+ page: Page<CollectionEntry<"post">>;
+ uniqueTags: string[];
+}
+
+const { page, uniqueTags } = Astro.props;
+
+const meta = {
+ description: "Read my collection of posts and the things that interest me",
+ title: "Posts",
+};
+
+const paginationProps = {
+ ...(page.url.prev && {
+ prevUrl: {
+ text: "← Previous Page",
+ url: page.url.prev,
+ },
+ }),
+ ...(page.url.next && {
+ nextUrl: {
+ text: "Next Page →",
+ url: page.url.next,
+ },
+ }),
+};
+
+const groupedByYear = groupPostsByYear(page.data);
+const descYearKeys = Object.keys(groupedByYear).sort((a, b) => +b - +a);
+---
+
+<PageLayout meta={meta}>
+ <div class="mb-6 flex items-center gap-3">
+ <h1 class="title">Posts</h1>
+ <a class="text-accent" href="/rss.xml" target="_blank">
+ <span class="sr-only">RSS feed</span>
+ <Icon aria-hidden="true" class="h-6 w-6" focusable="false" name="mdi:rss" />
+ </a>
+ </div>
+ <div class="grid sm:grid-cols-[3fr_1fr] sm:gap-x-8 sm:gap-y-16">
+ <div>
+ {
+ descYearKeys.map((yearKey) => (
+ <section aria-labelledby={`year-${yearKey}`}>
+ <h2 id={`year-${yearKey}`} class="title text-lg">
+ <span class="sr-only">Posts in</span>
+ {yearKey}
+ </h2>
+ <ul class="mt-5 mb-16 space-y-6 text-start">
+ {groupedByYear[yearKey]?.map((p) => (
+ <li class="grid gap-2 sm:grid-cols-[auto_1fr] sm:[&_q]:col-start-2">
+ <PostPreview post={p} />
+ </li>
+ ))}
+ </ul>
+ </section>
+ ))
+ }
+ <Pagination {...paginationProps} />
+ </div>
+ {
+ !!uniqueTags.length && (
+ <aside>
+ <h2 class="title mb-4 flex items-center gap-2 text-lg">
+ Tags
+ <svg
+ aria-hidden="true"
+ class="h-6 w-6"
+ fill="none"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="1.5"
+ viewBox="0 0 24 24"
+ xmlns="http://www.w3.org/2000/svg"
+ >
+ <path d="M0 0h24v24H0z" fill="none" stroke="none" />
+ <path d="M7.859 6h-2.834a2.025 2.025 0 0 0 -2.025 2.025v2.834c0 .537 .213 1.052 .593 1.432l6.116 6.116a2.025 2.025 0 0 0 2.864 0l2.834 -2.834a2.025 2.025 0 0 0 0 -2.864l-6.117 -6.116a2.025 2.025 0 0 0 -1.431 -.593z" />
+ <path d="M17.573 18.407l2.834 -2.834a2.025 2.025 0 0 0 0 -2.864l-7.117 -7.116" />
+ <path d="M6 9h-.01" />
+ </svg>
+ </h2>
+ <ul class="flex flex-wrap gap-2">
+ {uniqueTags.map((tag) => (
+ <li>
+ <a class="cactus-link flex items-center justify-center" href={`/tags/${tag}/`}>
+ <span aria-hidden="true">#</span>
+ <span class="sr-only">View all posts with the tag</span>
+ {tag}
+ </a>
+ </li>
+ ))}
+ </ul>
+ <span class="mt-4 block sm:text-end">
+ <a class="hover:text-link" href="/tags/">
+ View all <span aria-hidden="true">→</span>
+ <span class="sr-only">blog tags</span>
+ </a>
+ </span>
+ </aside>
+ )
+ }
+ </div>
+</PageLayout>
diff --git a/src/pages/posts/[...slug].astro b/src/pages/posts/[...slug].astro
new file mode 100644
index 0000000..ca9c491
--- /dev/null
+++ b/src/pages/posts/[...slug].astro
@@ -0,0 +1,24 @@
+---
+import { render } from "astro:content";
+import { getAllPosts } from "@/data/post";
+import PostLayout from "@/layouts/BlogPost.astro";
+import type { GetStaticPaths, InferGetStaticPropsType } from "astro";
+
+// if you're using an adaptor in SSR mode, getStaticPaths wont work -> https://docs.astro.build/en/guides/routing/#modifying-the-slug-example-for-ssr
+export const getStaticPaths = (async () => {
+ const blogEntries = await getAllPosts();
+ return blogEntries.map((post) => ({
+ params: { slug: post.id },
+ props: { post },
+ }));
+}) satisfies GetStaticPaths;
+
+type Props = InferGetStaticPropsType<typeof getStaticPaths>;
+
+const { post } = Astro.props;
+const { Content } = await render(post);
+---
+
+<PostLayout post={post}>
+ <Content />
+</PostLayout>