feat(all): first init

This commit is contained in:
z0x 2025-01-08 22:06:02 -05:00
commit 67c6e47f58
34 changed files with 2155 additions and 0 deletions

13
src/pages/404.astro Normal file
View file

@ -0,0 +1,13 @@
---
import Layout from "@layouts/Layout.astro";
import Container from "@components/Container.astro";
import { SITE } from "@consts";
---
<Layout title="404" description={SITE.DESCRIPTION}>
<Container>
<div class="text-center">
<h4 class="animate text-2xl font-semibold text-black dark:text-white">404: Page not found</h4>
</div>
</Container>
</Layout>

68
src/pages/[...id].astro Normal file
View file

@ -0,0 +1,68 @@
---
import { type CollectionEntry, getCollection, render } from "astro:content";
import Layout from "@layouts/Layout.astro";
import Container from "@components/Container.astro";
import FormattedDate from "@components/FormattedDate.astro";
import { readingTime } from "@lib/utils";
import PostNavigation from "@components/PostNavigation.astro";
import TableOfContents from "@components/TableOfContents.astro";
export async function getStaticPaths() {
const posts = (await getCollection("blog")).filter((post) => !post.data.draft).sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
return posts.map((post) => ({
params: { id: post.id },
props: post,
}));
}
type Props = CollectionEntry<"blog">;
const posts = (await getCollection("blog")).filter((post) => !post.data.draft).sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
function getNextPost() {
let postIndex;
for (const post of posts) {
if (post.id === Astro.params.id) {
postIndex = posts.indexOf(post);
return posts[postIndex + 1];
}
}
}
function getPrevPost() {
let postIndex;
for (const post of posts) {
if (post.id === Astro.params.id) {
postIndex = posts.indexOf(post);
return posts[postIndex - 1];
}
}
}
const nextPost = getNextPost();
const prevPost = getPrevPost();
const post = Astro.props;
const { Content, headings } = await render(post);
---
<Layout title={post.data.title} description={post.data.description}>
<Container>
<div class="my-10 space-y-1">
<div class="animate flex items-center gap-1.5">
<div class="font-base text-sm">
<FormattedDate date={post.data.date} />
</div>
&bull;
{post.body && <div class="font-base text-sm">{readingTime(post.body)}</div>}
</div>
<h1 class="animate text-3xl font-semibold text-black dark:text-white">
{post.data.title}
</h1>
</div>
{headings.length > 0 && <TableOfContents headings={headings} />}
<article class="animate">
<Content />
<PostNavigation prevPost={prevPost} nextPost={nextPost} />
</article>
</Container>
</Layout>

52
src/pages/index.astro Normal file
View file

@ -0,0 +1,52 @@
---
import { type CollectionEntry, getCollection } from "astro:content";
import Layout from "@layouts/Layout.astro";
import Container from "@components/Container.astro";
import ArrowCard from "@components/ArrowCard.astro";
import { SITE } from "@consts";
import { HOME } from "@consts";
const data = (await getCollection("blog")).filter((post) => !post.data.draft).sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
type Acc = {
[year: string]: CollectionEntry<"blog">[];
};
const posts = data.reduce((acc: Acc, post) => {
const year = post.data.date.getFullYear().toString();
if (!acc[year]) {
acc[year] = [];
}
acc[year].push(post);
return acc;
}, {});
const years = Object.keys(posts).sort((a, b) => parseInt(b) - parseInt(a));
---
<Layout title={HOME.TITLE} description={SITE.DESCRIPTION}>
<Container>
<aside>
<div class="space-y-10">
<div class="space-y-4">
{
years.map((year) => (
<section class="animate space-y-4">
<div class="font-semibold text-black dark:text-white">{year}</div>
<div>
<ul class="not-prose flex flex-col gap-4">
{posts[year].map((post) => (
<li>
<ArrowCard entry={post} />
</li>
))}
</ul>
</div>
</section>
))
}
</div>
</div>
</aside>
</Container>
</Layout>

24
src/pages/rss.xml.js Normal file
View file

@ -0,0 +1,24 @@
import rss from "@astrojs/rss";
import { SITE } from "@consts";
import { getCollection } from "astro:content";
export async function GET(context) {
const blog = (await getCollection("blog")).filter((post) => !post.data.draft);
const items = [...blog].sort(
(a, b) => new Date(b.data.date).valueOf() - new Date(a.data.date).valueOf(),
);
return rss({
title: SITE.TITLE,
description: SITE.DESCRIPTION,
site: context.site,
items: items.map((item) => ({
title: item.data.title,
description: item.data.description,
pubDate: item.data.date,
link: `/${item.id}/`,
})),
});
}