Move app to apps/web-react in pnpm workspace layout

This commit is contained in:
Kalle
2026-08-16 09:20:33 +03:00
parent 7e365ccfcf
commit bbc8ea57af
2913 changed files with 227 additions and 250 deletions

View File

@@ -0,0 +1,56 @@
import fs from "node:fs";
import path from "node:path";
import matter from "gray-matter";
import { ZodError, type z } from "zod";
import { ARTICLES_FOLDER_PATH } from "../articles-constants";
import { articleDataSchema } from "../articles-schemas.server";
const RESOLVED_ARTICLES_DIR = path.resolve(ARTICLES_FOLDER_PATH);
export function articleBySlug(slug: string) {
const validFiles = fs.globSync("*.md", { cwd: RESOLVED_ARTICLES_DIR });
if (!validFiles.includes(`${slug}.md`)) return null;
try {
const rawMarkdown = fs.readFileSync(
path.join(RESOLVED_ARTICLES_DIR, `${slug}.md`),
"utf8",
);
const { content, data } = matter(rawMarkdown);
const { date, ...restParsed } = articleDataSchema.parse(data);
return {
content,
date,
authors: normalizeAuthors(restParsed.author),
title: restParsed.title,
};
} catch (e) {
if (!(e instanceof Error)) throw e;
if (e.message.includes("ENOENT") || e instanceof ZodError) {
return null;
}
throw e;
}
}
export function normalizeAuthors(
authors: z.infer<typeof articleDataSchema>["author"],
): Array<{ name: string; link: string | null }> {
if (Array.isArray(authors)) {
return authors.map((author) => {
if (typeof author === "string") {
return { name: author, link: null };
}
return author;
});
}
if (typeof authors === "string") {
return [{ name: authors, link: null }];
}
return [authors];
}

View File

@@ -0,0 +1,35 @@
import fs from "node:fs";
import path from "node:path";
import matter from "gray-matter";
import { ARTICLES_FOLDER_PATH } from "../articles-constants";
import { articleDataSchema } from "../articles-schemas.server";
import { type articleBySlug, normalizeAuthors } from "./bySlug.server";
export async function mostRecentArticles(count: number) {
const files = await fs.promises.readdir(ARTICLES_FOLDER_PATH);
const articles: Array<
Omit<NonNullable<ReturnType<typeof articleBySlug>>, "content"> & {
slug: string;
}
> = [];
for (const file of files) {
const rawMarkdown = fs.readFileSync(
path.join(ARTICLES_FOLDER_PATH, file),
"utf8",
);
const { data } = matter(rawMarkdown);
const { date, ...restParsed } = articleDataSchema.parse(data);
articles.push({
date,
slug: file.replace(".md", ""),
authors: normalizeAuthors(restParsed.author),
title: restParsed.title,
});
}
return articles
.sort((a, b) => b.date.getTime() - a.date.getTime())
.slice(0, count);
}