110 lines
2.9 KiB
TypeScript
110 lines
2.9 KiB
TypeScript
import fs from 'fs';
|
|
import path from 'path';
|
|
import matter from 'gray-matter';
|
|
import readingTime from 'reading-time';
|
|
import { notFound } from 'next/navigation';
|
|
|
|
const postsDirectory = path.join(process.cwd(), 'posts');
|
|
|
|
export interface Heading {
|
|
level: number;
|
|
text: string;
|
|
slug: string;
|
|
}
|
|
|
|
export interface PostData {
|
|
id: string;
|
|
date: string;
|
|
title: string;
|
|
description: string;
|
|
content: string;
|
|
readingTime: string;
|
|
headings: Heading[];
|
|
wip: boolean;
|
|
}
|
|
|
|
export interface PostMeta {
|
|
id: string;
|
|
date: string;
|
|
title: string;
|
|
description: string;
|
|
readingTime: string;
|
|
wip: boolean;
|
|
}
|
|
|
|
function extractHeadings(content: string): Heading[] {
|
|
const regex = /^(#{2,3})\s+(.+)$/gm;
|
|
const headings: Heading[] = [];
|
|
let match;
|
|
while ((match = regex.exec(content)) !== null) {
|
|
const text = match[2].trim();
|
|
const slug = text
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9]+/g, '-')
|
|
.replace(/(^-|-$)/g, '');
|
|
headings.push({ level: match[1].length, text, slug });
|
|
}
|
|
return headings;
|
|
}
|
|
|
|
export function getSortedPostsData(): PostMeta[] {
|
|
try {
|
|
const fileNames = fs.readdirSync(postsDirectory);
|
|
const allPostsData = fileNames
|
|
.filter(fileName => fileName.endsWith('.mdx'))
|
|
.map(fileName => {
|
|
const id = fileName.replace(/\.mdx$/, '');
|
|
const fullPath = path.join(postsDirectory, fileName);
|
|
const fileContents = fs.readFileSync(fullPath, 'utf8');
|
|
const matterResult = matter(fileContents);
|
|
const stats = readingTime(matterResult.content);
|
|
|
|
return {
|
|
id,
|
|
date: matterResult.data.date as string,
|
|
title: matterResult.data.title as string,
|
|
description: matterResult.data.description as string,
|
|
readingTime: stats.text,
|
|
wip: matterResult.data.wip ?? false,
|
|
};
|
|
});
|
|
|
|
return allPostsData.sort((a, b) => (a.date < b.date ? 1 : -1));
|
|
} catch (error) {
|
|
console.log("No 'posts' directory found, returning empty array.");
|
|
return [];
|
|
}
|
|
}
|
|
|
|
export function getAllPostIds() {
|
|
try {
|
|
const fileNames = fs.readdirSync(postsDirectory);
|
|
return fileNames.map(fileName => ({
|
|
params: {
|
|
slug: fileName.replace(/\.mdx$/, ''),
|
|
},
|
|
}));
|
|
} catch (error) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
export async function getPostData(id: string): Promise<PostData> {
|
|
const fullPath = path.join(postsDirectory, `${id}.mdx`);
|
|
if (!fs.existsSync(fullPath)) notFound();
|
|
const fileContents = fs.readFileSync(fullPath, 'utf8');
|
|
const matterResult = matter(fileContents);
|
|
const stats = readingTime(matterResult.content);
|
|
|
|
return {
|
|
id,
|
|
content: matterResult.content,
|
|
date: matterResult.data.date,
|
|
title: matterResult.data.title,
|
|
description: matterResult.data.description,
|
|
readingTime: stats.text,
|
|
headings: extractHeadings(matterResult.content),
|
|
wip: matterResult.data.wip ?? false,
|
|
};
|
|
}
|