rda-v3/client/src/lib/news.ts
2025-12-21 19:53:04 +00:00

77 lines
2.4 KiB
TypeScript

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<Pick<NewsArticle, "title" | "date" | "summary" | "image" | "slug">>;
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<string, string>)[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");
};