This commit is contained in:
2025-08-18 13:50:03 -05:00
parent 2725a26899
commit 5e8d7355d4
8 changed files with 12820 additions and 238 deletions
+128 -85
View File
@@ -1,3 +1,4 @@
import fs from 'fs';
import path from 'path';
import matter from 'gray-matter';
@@ -9,111 +10,153 @@ import { PostData, PostMetadata } from '@/types';
const postsDirectory = path.join(process.cwd(), 'data/posts');
export function getSortedPostsData(): PostMetadata[] {
// Ensure we only run this on the server
if (typeof window === 'undefined') {
// Get file names under /posts
const fileNames = fs.readdirSync(postsDirectory);
const allPostsData = fileNames.map((fileName) => {
// Remove ".md" from file name to get id
const id = fileName.replace(/\.md$/, '');
// Ensure we only run this on the server
if (typeof window === 'undefined') {
try {
// Get file names under /posts
const fileNames = fs.readdirSync(postsDirectory);
const allPostsData = fileNames
.filter(fileName => fileName.endsWith('.md')) // Only process .md files
.map((fileName) => {
// Remove ".md" from file name to get id
const id = fileName.replace(/\.md$/, '');
// Read markdown file as string
const fullPath = path.join(postsDirectory, fileName);
const fileContents = fs.readFileSync(fullPath, 'utf8');
// Skip if id is empty or undefined
if (!id || id === 'undefined') {
console.warn(`Skipping invalid filename: ${fileName}`);
return null;
}
// Use gray-matter to parse the post metadata section
const matterResult = matter(fileContents);
// Read markdown file as string
const fullPath = path.join(postsDirectory, fileName);
const fileContents = fs.readFileSync(fullPath, 'utf8');
// Combine the data with the id
return {
id,
title: matterResult.data.title || '',
date: matterResult.data.date || '',
excerpt: matterResult.data.excerpt || '',
author: matterResult.data.author || '',
tags: matterResult.data.tags || [],
coverImage: matterResult.data.coverImage || undefined,
} as PostMetadata;
});
// Use gray-matter to parse the post metadata section
const matterResult = matter(fileContents);
// Sort posts by date
return allPostsData.sort((a, b) => {
if (a.date < b.date) {
return 1;
} else {
return -1;
}
});
}
// Return empty array if running on client side
return [];
// Combine the data with the id
return {
id,
title: matterResult.data.title || '',
date: matterResult.data.date || '',
excerpt: matterResult.data.excerpt || '',
author: matterResult.data.author || '',
tags: matterResult.data.tags || [],
coverImage: matterResult.data.coverImage || undefined,
} as PostMetadata;
})
.filter((post): post is PostMetadata => post !== null); // Filter out null values
// Sort posts by date
return allPostsData.sort((a, b) => {
if (a.date < b.date) {
return 1;
} else {
return -1;
}
});
} catch (error) {
console.error('Error reading posts directory:', error);
return [];
}
}
// Return empty array if running on client side
return [];
}
export function getAllPostIds() {
// Ensure we only run this on the server
if (typeof window === 'undefined') {
const fileNames = fs.readdirSync(postsDirectory);
// Ensure we only run this on the server
if (typeof window === 'undefined') {
try {
const fileNames = fs.readdirSync(postsDirectory);
return fileNames.map((fileName) => {
return {
params: {
id: fileName.replace(/\.md$/, ''),
},
};
});
}
// Return empty array if running on client side
return [];
return fileNames
.filter(fileName => fileName.endsWith('.md'))
.map((fileName) => {
const id = fileName.replace(/\.md$/, '');
if (!id || id === 'undefined') {
return null;
}
return {
params: {
id,
},
};
})
.filter((item): item is { params: { id: string } } => item !== null);
} catch (error) {
console.error('Error reading posts directory:', error);
return [];
}
}
// Return empty array if running on client side
return [];
}
export async function getPostData(id: string): Promise<PostData> {
// Ensure we only run this on the server
if (typeof window === 'undefined') {
const fullPath = path.join(postsDirectory, `${id}.md`);
const fileContents = fs.readFileSync(fullPath, 'utf8');
// Ensure we only run this on the server
if (typeof window === 'undefined') {
try {
// Validate id
if (!id || id === 'undefined') {
throw new Error(`Invalid post id: ${id}`);
}
// Use gray-matter to parse the post metadata section
const matterResult = matter(fileContents);
const fullPath = path.join(postsDirectory, `${id}.md`);
// Use remark to convert markdown into HTML string
const processedContent = await remark()
.use(html, { sanitize: false })
.process(matterResult.content);
const contentHtml = processedContent.toString();
// Check if file exists
if (!fs.existsSync(fullPath)) {
throw new Error(`Post file not found: ${fullPath}`);
}
// Combine the data with the id and contentHtml
const fileContents = fs.readFileSync(fullPath, 'utf8');
// Use gray-matter to parse the post metadata section
const matterResult = matter(fileContents);
// Use remark to convert markdown into HTML string
const processedContent = await remark()
.use(html, { sanitize: false })
.process(matterResult.content);
const contentHtml = processedContent.toString();
// Combine the data with the id and contentHtml
return {
id,
content: contentHtml,
title: matterResult.data.title || '',
date: matterResult.data.date || '',
excerpt: matterResult.data.excerpt || '',
author: matterResult.data.author || '',
tags: matterResult.data.tags || [],
coverImage: matterResult.data.coverImage || undefined,
};
} catch (error) {
console.error(`Error loading post ${id}:`, error);
throw error;
}
}
// Return empty object if running on client side (should never happen in practice)
return {
id,
content: contentHtml,
title: matterResult.data.title || '',
date: matterResult.data.date || '',
excerpt: matterResult.data.excerpt || '',
author: matterResult.data.author || '',
tags: matterResult.data.tags || [],
coverImage: matterResult.data.coverImage || undefined,
id: '',
content: '',
title: '',
date: '',
excerpt: '',
author: '',
tags: [],
};
}
// Return empty object if running on client side (should never happen in practice)
return {
id: '',
content: '',
title: '',
date: '',
excerpt: '',
author: '',
tags: [],
};
}
export function getPostsByTag(tag: string): PostMetadata[] {
const allPosts = getSortedPostsData();
return allPosts.filter(post => post.tags.includes(tag));
const allPosts = getSortedPostsData();
return allPosts.filter(post => post.tags.includes(tag));
}
export function getPostsByAuthor(author: string): PostMetadata[] {
const allPosts = getSortedPostsData();
return allPosts.filter(post => post.author.includes(author));
const allPosts = getSortedPostsData();
return allPosts.filter(post => post.author.includes(author));
}