jedmund-svelte/src/lib/posts.ts
Justin Edmund 80d54aaaf0 Admin WIP
Projects and Posts sorta work, need design help
2025-05-27 16:57:51 -07:00

73 lines
1.7 KiB
TypeScript

import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
import { marked } from 'marked'
export interface Post {
title?: string
type: 'note' | 'article' | 'image' | 'link'
date: string
slug: string
published: boolean
content: string
excerpt?: string
images?: string[]
link?:
| {
url: string
title?: string
description?: string
image?: string
favicon?: string
siteName?: string
}
| string
}
const postsDirectory = path.join(process.cwd(), 'src/lib/posts')
export async function getAllPosts(): Promise<Post[]> {
const fileNames = fs.readdirSync(postsDirectory)
const posts = fileNames
.filter((fileName) => fileName.endsWith('.md'))
.map((fileName) => {
const filePath = path.join(postsDirectory, fileName)
const fileContents = fs.readFileSync(filePath, 'utf8')
const { data, content } = matter(fileContents)
const slug = data.slug || fileName.replace(/\.md$/, '')
return {
...data,
slug,
content,
excerpt: getExcerpt(content, data.type)
} as Post
})
.filter((post) => post.published)
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
return posts
}
export async function getPostBySlug(slug: string): Promise<Post | null> {
const posts = await getAllPosts()
const post = posts.find((p) => p.slug === slug)
if (!post) return null
return {
...post,
content: marked(post.content) as string
}
}
function getExcerpt(content: string, type: 'note' | 'article'): string {
const plainText = content.replace(/[#*`\[\]]/g, '').trim()
const maxLength = type === 'note' ? 280 : 160
if (plainText.length <= maxLength) return plainText
return plainText.substring(0, maxLength).trim() + '...'
}