import { format } from "date-fns"; import { marked } from "marked"; export type NewsArticle = { title: string; date: string; summary: string; image?: string; slug: string; body: string; html: string; }; type Frontmatter = Partial>; const newsModules = import.meta.glob("/src/content/news/*.md", { eager: true, as: "raw", }); const parseFrontmatter = (raw: string): { frontmatter: Frontmatter; body: string } => { const frontmatterMatch = raw.match(/^---\s*([\s\S]*?)\s*---\s*([\s\S]*)$/); if (!frontmatterMatch) { return { frontmatter: {}, body: raw.trim() }; } const [, frontmatterBlock, body] = frontmatterMatch; const frontmatter: Frontmatter = {}; frontmatterBlock.split("\n").forEach((line) => { const trimmed = line.trim(); if (!trimmed || trimmed.startsWith("#")) return; const [key, ...rest] = trimmed.split(":"); if (!key || rest.length === 0) return; const value = rest.join(":").trim().replace(/^["']|["']$/g, ""); if (key in frontmatter) return; (frontmatter as Record)[key.trim()] = value; }); return { frontmatter, body: body.trim() }; }; export const newsArticles: NewsArticle[] = Object.entries(newsModules) .map(([path, raw]) => { const { frontmatter, body } = parseFrontmatter(raw); const slug = frontmatter.slug || path.split("/").pop()?.replace(/\.md$/, "") || ""; return { title: frontmatter.title || slug, date: frontmatter.date || "", summary: frontmatter.summary || "", image: frontmatter.image, slug, body, html: marked.parse(body), }; }) .sort((a, b) => { const aDate = Date.parse(a.date); const bDate = Date.parse(b.date); if (Number.isNaN(aDate) || Number.isNaN(bDate)) { return b.title.localeCompare(a.title); } return bDate - aDate; }); export const getNewsArticle = (slug: string): NewsArticle | undefined => newsArticles.find((article) => article.slug === slug); export const formatNewsDate = (date: string): string => { const parsed = Date.parse(date); if (Number.isNaN(parsed)) return date; return format(new Date(parsed), "MMM yyyy"); };