mirror of
https://github.com/prdlk/prdlk.git
synced 2026-11-04 14:07:47 +00:00
feat(pages): add new site pages, routes, and OG image generation
This commit is contained in:
1 parent
8a191f65cc
commit
01eac43ecf
19 files changed
+1206
No files matched your search
@@ -0,0 +1,140 @@
|
||||
---
|
||||
import type { CollectionEntry } from "astro:content";
|
||||
import type { GetStaticPaths, Page } from "astro";
|
||||
import { Icon } from "astro-icon/components";
|
||||
import PostPreview from "@/components/blog/PostPreview.astro";
|
||||
import Pagination from "@/components/Paginator.astro";
|
||||
import { getAllExperience } from "@/data/experience";
|
||||
import { getAllPosts, groupPostsByYear } from "@/data/post";
|
||||
import PageLayout from "@/layouts/Base.astro";
|
||||
import { collectionDateSort } from "@/utils/date";
|
||||
import { breadcrumbList, collectionPageSchema } from "@/utils/seo";
|
||||
|
||||
export const getStaticPaths = (async ({ paginate }) => {
|
||||
const MAX_POSTS_PER_PAGE = 10;
|
||||
const MAX_PINNED_POSTS = 3;
|
||||
const allPosts = await getAllPosts();
|
||||
const allPostsByDate = allPosts.sort(collectionDateSort);
|
||||
const experiences = await getAllExperience();
|
||||
const pinnedPosts = allPostsByDate
|
||||
.values()
|
||||
.filter((p) => p.data.pinned)
|
||||
.take(MAX_PINNED_POSTS)
|
||||
.toArray();
|
||||
return paginate(allPostsByDate, {
|
||||
pageSize: MAX_POSTS_PER_PAGE,
|
||||
props: { experiences, pinnedPosts },
|
||||
});
|
||||
}) satisfies GetStaticPaths;
|
||||
|
||||
interface Props {
|
||||
page: Page<CollectionEntry<"writing">>;
|
||||
experiences: CollectionEntry<"experience">[];
|
||||
pinnedPosts: CollectionEntry<"writing">[];
|
||||
}
|
||||
|
||||
const { page, experiences, pinnedPosts } = Astro.props;
|
||||
|
||||
const meta = {
|
||||
description: "Essays, notes and articles I've written",
|
||||
schema: [
|
||||
breadcrumbList([
|
||||
{ name: "Home", path: "/" },
|
||||
{ name: "Writing", path: "/writing/" },
|
||||
]),
|
||||
collectionPageSchema({
|
||||
name: "Writing",
|
||||
description: "Essays, notes and articles I've written",
|
||||
path: page.url.current,
|
||||
items: page.data.map((p) => ({ name: p.data.title, path: `/writing/${p.id}/` })),
|
||||
}),
|
||||
],
|
||||
title: "Writing",
|
||||
};
|
||||
|
||||
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-12 flex items-center gap-3">
|
||||
<h1 class="title">Writing</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="lucide:rss" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="grid sm:grid-cols-[3fr_1fr] sm:gap-x-8 sm:gap-y-16">
|
||||
<div>
|
||||
{
|
||||
pinnedPosts.length > 0 && (
|
||||
<section class="mb-16">
|
||||
<h2 class="title mb-6 text-xl">Pinned</h2>
|
||||
<ul class="space-y-4" role="list">
|
||||
{pinnedPosts.map((p) => (
|
||||
<li class="grid gap-1 sm:grid-cols-[auto_1fr]">
|
||||
<PostPreview post={p} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
{
|
||||
descYearKeys.map((yearKey) => (
|
||||
<section class="mb-16">
|
||||
<h2 id={`year-${yearKey}`} class="title text-lg">
|
||||
<span class="sr-only">Posts in</span>
|
||||
{yearKey}
|
||||
</h2>
|
||||
<ul class="mt-5 space-y-4 text-start">
|
||||
{groupedByYear[yearKey]?.map((p) => (
|
||||
<li class="grid gap-1 sm:grid-cols-[auto_1fr] sm:[&_q]:col-start-2">
|
||||
<PostPreview post={p} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
))
|
||||
}
|
||||
<Pagination {...paginationProps} />
|
||||
</div>
|
||||
{
|
||||
!!experiences.length && (
|
||||
<aside>
|
||||
<h2 class="title mb-4 text-lg">Experience</h2>
|
||||
<ul class="flex flex-col gap-2">
|
||||
{experiences.map((exp) => (
|
||||
<li>
|
||||
<a class="cactus-link" href={`/experience/${exp.id}/`}>
|
||||
{exp.data.title}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<span class="mt-4 block sm:text-end">
|
||||
<a class="hover:text-link" href="/experience/">
|
||||
View all <span aria-hidden="true">→</span>
|
||||
<span class="sr-only">experience</span>
|
||||
</a>
|
||||
</span>
|
||||
</aside>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</PageLayout>
|
||||
Reference in new issue
Block a user