Files
website/lib/posts.ts
Steffen Illium 0444067c2d
Some checks failed
Next.js App CI / docker (push) Failing after 3m19s
refined design
2025-09-14 22:49:23 +02:00

114 lines
3.1 KiB
TypeScript

import fs from "fs";
import path from "path";
import matter from "gray-matter";
const postsDirectory = path.join(process.cwd(), "content");
const tagsFilePath = path.join(postsDirectory, "tags.json");
type PostData = {
id: string;
href: string;
venue: string;
date: string;
tags: string[];
image: string | undefined;
title?: string;
excerpt?: string;
video?: string;
[key: string]: string | string[] | null | undefined;
};
function getPostFilePaths(dir: string, fileList: string[] = []) {
const files = fs.readdirSync(dir);
files.forEach((file) => {
const filePath = path.join(dir, file);
if (fs.statSync(filePath).isDirectory()) {
getPostFilePaths(filePath, fileList);
} else if (filePath.endsWith(".mdx")) {
fileList.push(filePath);
}
});
return fileList;
}
export function getSortedPostsData(category?: string): PostData[] {
const directory = category ? path.join(postsDirectory, category) : postsDirectory;
const filePaths = getPostFilePaths(directory);
const allPostsData = filePaths.map((filePath) => {
const id = path.basename(filePath).replace(/\.mdx$/, "").replace(/^\d{4}-\d{2}-\d{2}-/, '');
const relativePath = path.relative(postsDirectory, filePath).replace(/\.mdx$/, "");
const pathParts = relativePath.split(path.sep);
pathParts.pop(); // remove the old filename
pathParts.push(id);
const href = pathParts.join('/'); // use forward slashes for URLs
const fileContents = fs.readFileSync(filePath, "utf8");
const matterResult = matter(fileContents);
const dateFromFileName = path.basename(filePath).substring(0, 10);
const tags = matterResult.data.tags
? Array.isArray(matterResult.data.tags)
? matterResult.data.tags
: matterResult.data.tags.split(/, ?/)
: [];
const venue = matterResult.data.venue ? matterResult.data.venue: "arxive";
const image = matterResult.data.teaser || matterResult.data.image || null;
return {
id,
href,
venue,
date: matterResult.data.date ?? dateFromFileName,
...matterResult.data,
tags,
image,
};
});
return allPostsData.sort((a, b) => {
if (!a.date || a.date < b.date) {
return 1;
} else {
return -1;
}
});
}
export function getAllTags(minCount: number = 1, category?: "experience" | "research") {
const allPosts = getSortedPostsData(category);
const tags: { [tag: string]: number } = {};
allPosts.forEach((post) => {
post.tags.forEach((tag: string) => {
if (tag in tags) {
tags[tag]++;
} else {
tags[tag] = 1;
}
});
});
return Object.entries(tags)
.map(([name, count]) => ({ name, count }))
.filter(tag => tag.count >= minCount);
}
export function getPostsByTag(tag: string) {
const allPosts = getSortedPostsData();
return allPosts.filter((post) => post.tags.includes(tag));
}
export function getTagData(tag: string) {
if (!fs.existsSync(tagsFilePath)) {
return null;
}
const tagsFile = fs.readFileSync(tagsFilePath, "utf8");
const tagsData = JSON.parse(tagsFile);
return tagsData[tag] || null;
}