import { json } from "remix";
import path from "path";
import fs from "fs/promises";
import parseFrontMatter from "front-matter";
import invariant from "tiny-invariant";
import { marked } from "marked";
export type Post = {
slug: string;
title: string;
html: string;
};
export type PostMarkdownAttributes = {
title: string;
};
type NewPost = {
title: string;
slug: string;
markdown: string;
};
function isValidPostAttributes(
attributes: any
): attributes is PostMarkdownAttributes {
return attributes?.title;
}
const postsPath = path.join(__dirname, "..", "posts");
export async function getPost(slug: string): Promise<Post> {
const filepath = path.join(postsPath, slug + ".md");
const file = await fs.readFile(filepath);
const { attributes, body } = parseFrontMatter(file.toString());
invariant(
isValidPostAttributes(attributes),
`Post ${filepath} is missing attributes`
);
const html = marked(body);
return { slug, html, title: attributes.title };
}
export const action: ActionFunction = async ({ request }) => {
const formData = await request.formData();
await new Promise((res) => setTimeout(res, 1000));
const title = formData.get("title");
const slug = formData.get("slug");
const markdown = formData.get("markdown");
const errors: PostError = {};
if (!title) errors.title = true;
if (!slug) errors.slug = true;
if (!markdown) errors.markdown = true;
if (Object.keys(errors).length) {
return json(errors);
}
invariant(typeof title === "string");
invariant(typeof slug === "string");
invariant(typeof markdown === "string");
await createPost({ title, slug, markdown });
return redirect("/admin");
};
