71 lines
1.8 KiB
TypeScript
71 lines
1.8 KiB
TypeScript
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import matter from "gray-matter";
|
|
|
|
export type DevblogPost = {
|
|
slug: string;
|
|
title: string;
|
|
date: string;
|
|
excerpt: string;
|
|
author?: string;
|
|
tags?: string[];
|
|
game?: string;
|
|
content: string;
|
|
};
|
|
|
|
const POSTS_DIR = path.join(process.cwd(), "content", "devblog");
|
|
|
|
function ensureDir() {
|
|
if (!fs.existsSync(POSTS_DIR)) {
|
|
fs.mkdirSync(POSTS_DIR, { recursive: true });
|
|
}
|
|
}
|
|
|
|
export function getAllPosts(): DevblogPost[] {
|
|
ensureDir();
|
|
const files = fs
|
|
.readdirSync(POSTS_DIR)
|
|
.filter((f) => f.endsWith(".mdx") || f.endsWith(".md"));
|
|
|
|
const posts = files.map((file) => {
|
|
const slug = file.replace(/\.(mdx|md)$/, "");
|
|
const raw = fs.readFileSync(path.join(POSTS_DIR, file), "utf8");
|
|
const { data, content } = matter(raw);
|
|
return {
|
|
slug,
|
|
title: data.title ?? slug,
|
|
date: data.date ?? new Date().toISOString().slice(0, 10),
|
|
excerpt: data.excerpt ?? "",
|
|
author: data.author,
|
|
tags: data.tags ?? [],
|
|
game: data.game,
|
|
content,
|
|
} as DevblogPost;
|
|
});
|
|
|
|
return posts.sort((a, b) => (a.date < b.date ? 1 : -1));
|
|
}
|
|
|
|
export function getPost(slug: string): DevblogPost | undefined {
|
|
return getAllPosts().find((p) => p.slug === slug);
|
|
}
|
|
|
|
export function getPostsByGame(gameSlug: string): DevblogPost[] {
|
|
return getAllPosts().filter(
|
|
(p) => p.game === gameSlug || p.tags?.includes(gameSlug),
|
|
);
|
|
}
|
|
|
|
export function getAdjacentPosts(slug: string): {
|
|
newer?: DevblogPost;
|
|
older?: DevblogPost;
|
|
} {
|
|
const posts = getAllPosts();
|
|
const idx = posts.findIndex((p) => p.slug === slug);
|
|
if (idx === -1) return {};
|
|
return {
|
|
newer: idx > 0 ? posts[idx - 1] : undefined,
|
|
older: idx < posts.length - 1 ? posts[idx + 1] : undefined,
|
|
};
|
|
}
|