82 lines
2.7 KiB
TypeScript
82 lines
2.7 KiB
TypeScript
import { readdir } from "node:fs/promises";
|
|
import { YAML } from "bun";
|
|
import metadata from "./metadata.json";
|
|
import templateRaw from "./templates/post.html" with { type: "text" };
|
|
import homeRaw from "./templates/home.html" with { type: "text" };
|
|
|
|
const year = new Date().getFullYear().toString();
|
|
const applyVars = (raw: unknown) => (raw as string)
|
|
.replaceAll("[[SITE]]", metadata.title)
|
|
.replaceAll("[[NAME]]", metadata.name)
|
|
.replaceAll("[[TIMEZONE]]", metadata.timezone)
|
|
.replaceAll("[[YEAR]]", year);
|
|
|
|
const template = applyVars(templateRaw);
|
|
const home = applyVars(homeRaw);
|
|
|
|
const posts = await readdir("./posts");
|
|
const postLinks: {
|
|
title: string;
|
|
date: Date;
|
|
link: string;
|
|
}[] = [];
|
|
const defaultFrontmatter = {
|
|
title: "Untitled",
|
|
desc: "",
|
|
date: "0000-00-00", // YYYY-MM-DD
|
|
draft: true,
|
|
};
|
|
|
|
function fetchFrontmatter(raw?: string) {
|
|
try {
|
|
if (!raw) throw new Error("No frontmatter found.");
|
|
const parsed = { ...defaultFrontmatter, ...(YAML.parse(raw) as typeof defaultFrontmatter) };
|
|
return { ...parsed, date: new Date(parsed.date) };
|
|
} catch {
|
|
console.warn("Failed to parse frontmatter. Using default values.");
|
|
return { ...defaultFrontmatter, date: new Date(NaN) };
|
|
}
|
|
}
|
|
|
|
await Promise.all(posts.map(async (post) => {
|
|
const raw = (await Bun.file(`./posts/${post}`).text()).split("^---");
|
|
|
|
const content = raw.at(-1) || "_No content_";
|
|
const frontmatter = fetchFrontmatter(raw.at(0));
|
|
|
|
const html = Bun.markdown.html(content, {
|
|
autolinks: true,
|
|
headings: true,
|
|
underline: true,
|
|
tagFilter: true,
|
|
});
|
|
const render = template
|
|
.replaceAll("[[TITLE]]", `${metadata.title} - ${frontmatter.title}`)
|
|
.replaceAll("[[POST_TITLE]]", frontmatter.title)
|
|
.replaceAll("[[DATE]]", frontmatter.date.toDateString())
|
|
.replaceAll("[[REVISIONS]]", `${metadata.revisions}/${post}`)
|
|
.replaceAll("[[DESC]]", frontmatter.desc)
|
|
.replace("[[CONTENT]]", html);
|
|
|
|
await Bun.write(`./dist/posts/${post.replace(".md", ".html")}`, render);
|
|
|
|
if (!frontmatter.draft) postLinks.push({
|
|
title: frontmatter.title,
|
|
date: frontmatter.date,
|
|
link: `/posts/${post.replace(".md", ".html")}`,
|
|
});
|
|
|
|
console.log(`Built page for ${frontmatter.draft ? 'draft' : 'post'}: ${frontmatter.title}`);
|
|
// TODO: table of contents generation
|
|
}));
|
|
|
|
const parsedPosts = postLinks
|
|
.sort((a, b) => b.date.getTime() - a.date.getTime())
|
|
.map((post) => `<li><a href="${post.link}">${post.title}</a> - <i>${post.date.toDateString()}</i></li>`)
|
|
.join("\n");
|
|
const render = home
|
|
.replace("[[ABOUT]]", Bun.markdown.html(metadata.description))
|
|
.replace("[[MAIN]]", metadata.main)
|
|
.replace("[[POSTS]]", parsedPosts);
|
|
|
|
await Bun.write("./dist/index.html", render);
|