memorium/lib/resource/articles.ts

107 lines
2.4 KiB
TypeScript
Raw Normal View History

2023-08-05 21:52:43 +02:00
import { parseDocument } from "@lib/documents.ts";
2023-08-01 21:35:21 +02:00
import { parse } from "yaml";
import { createCrud } from "@lib/crud.ts";
2023-08-05 21:52:43 +02:00
import { stringify } from "$std/yaml/stringify.ts";
2023-08-02 01:58:03 +02:00
import { extractHashTags, formatDate } from "@lib/string.ts";
2023-08-01 21:35:21 +02:00
import { fixRenderedMarkdown } from "@lib/helpers.ts";
import { getThumbhash } from "@lib/cache/image.ts";
2023-08-01 21:35:21 +02:00
export type Article = {
id: string;
2023-08-02 18:13:31 +02:00
type: "article";
2023-08-01 21:35:21 +02:00
content: string;
name: string;
tags: string[];
meta: {
done?: boolean;
2023-08-01 21:35:21 +02:00
date: Date;
link: string;
thumbnail?: string;
2023-08-12 18:32:56 +02:00
average?: string;
2023-08-04 22:35:25 +02:00
image?: string;
2023-08-01 21:35:21 +02:00
author?: string;
rating?: number;
};
};
function renderArticle(article: Article) {
const meta = article.meta;
if ("date" in meta) {
meta.date = formatDate(meta.date);
}
return fixRenderedMarkdown(`${
meta
? `---
${stringify(meta)}
---`
: `---
---`
}
# ${article.name}
${article.tags.map((t) => `#${t}`).join(" ")}
${article.content}
`);
}
function parseArticle(original: string, id: string): Article {
const doc = parseDocument(original);
let meta = {} as Article["meta"];
let name = "";
const range = [Infinity, -Infinity];
for (const child of doc.children) {
if (child.type === "yaml") {
meta = parse(child.value) as Article["meta"];
if (meta["rating"] && typeof meta["rating"] === "string") {
meta.rating = [...meta.rating?.matchAll("⭐")].length;
}
continue;
}
if (
child.type === "heading" && child.depth === 1 && !name &&
child.children.length === 1 && child.children[0].type === "text"
) {
name = child.children[0].value;
continue;
}
if (name) {
const start = child.position?.start.offset || Infinity;
const end = child.position?.end.offset || -Infinity;
if (start < range[0]) range[0] = start;
if (end > range[1]) range[1] = end;
}
}
let content = original.slice(range[0], range[1]);
2023-08-02 01:58:03 +02:00
const tags = extractHashTags(content);
for (const tag of tags) {
content = content.replace("#" + tag, "");
2023-08-01 21:35:21 +02:00
}
return {
2023-08-02 18:13:31 +02:00
type: "article",
2023-08-01 21:35:21 +02:00
id,
name,
tags,
2023-08-05 21:52:43 +02:00
content,
2023-08-01 21:35:21 +02:00
meta,
};
}
2023-08-12 18:32:56 +02:00
const crud = createCrud<Article>({
prefix: "Media/articles/",
parse: parseArticle,
render: renderArticle,
hasThumbnails: true,
});
2023-08-01 21:35:21 +02:00
export const getAllArticles = crud.readAll;
export const getArticle = crud.read;
2023-08-12 18:32:56 +02:00
export const createArticle = crud.create;