mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-10-01 23:58:36 -05:00
Move app to apps/web-react in pnpm workspace layout
This commit is contained in:
56
apps/web-react/app/features/articles/core/bySlug.server.ts
Normal file
56
apps/web-react/app/features/articles/core/bySlug.server.ts
Normal 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];
|
||||
}
|
||||
35
apps/web-react/app/features/articles/core/list.server.ts
Normal file
35
apps/web-react/app/features/articles/core/list.server.ts
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user