105 lines
3.4 KiB
TypeScript
105 lines
3.4 KiB
TypeScript
import fs from "node:fs/promises";
|
|
import { GLOBAL } from "./variables";
|
|
|
|
type MarkdownData<T extends object> = {
|
|
frontmatter: T;
|
|
file: string;
|
|
url: string;
|
|
};
|
|
|
|
|
|
/**
|
|
* This function processes the content of a directory and returns an array of processed content.
|
|
* It takes a content type, a function to process the content, and an optional directory.
|
|
* If no directory is provided, it defaults to the current working directory.
|
|
*
|
|
* @param contentType the type of content to process
|
|
* @param processFn the function to process the content
|
|
* @param dir the directory to process the content from
|
|
* @returns a promise that resolves to an array of processed content
|
|
*/
|
|
export const processContentInDir = async <T extends object, K>(
|
|
contentType: "projects" | "blog",
|
|
processFn: (data: MarkdownData<T>) => K,
|
|
dir: string = process.cwd(),
|
|
) => {
|
|
const files = await fs.readdir(dir + `/src/pages/${contentType}`);
|
|
const markdownFiles = files
|
|
.filter((file: string) => file.endsWith(".md"))
|
|
.map((file) => file.split(".")[0]);
|
|
const readMdFileContent = async (file: string) => {
|
|
if (contentType === "projects") {
|
|
const content = import.meta
|
|
.glob(`/src/pages/projects/*.md`)
|
|
[`/src/pages/projects/${file}.md`]();
|
|
const data = (await content) as {
|
|
frontmatter: T;
|
|
file: string;
|
|
url: string;
|
|
};
|
|
return processFn(data);
|
|
} else {
|
|
const content = import.meta
|
|
.glob(`/src/pages/blog/*.md`)
|
|
[`/src/pages/blog/${file}.md`]();
|
|
const data = (await content) as {
|
|
frontmatter: T;
|
|
file: string;
|
|
url: string;
|
|
};
|
|
return processFn(data);
|
|
}
|
|
};
|
|
return await Promise.all(markdownFiles.map(readMdFileContent));
|
|
};
|
|
|
|
/**
|
|
* Shortens a string by removing words at the end until it fits within a certain length.
|
|
* @param content the content to shorten
|
|
* @param maxLength the maximum length of the shortened content (default is 20)
|
|
* @returns a shortened version of the content
|
|
*/
|
|
export const getShortDescription = (content: string, maxLength = 20) => {
|
|
const splitByWord = content.split(" ");
|
|
const length = splitByWord.length;
|
|
return length > maxLength ? splitByWord.slice(0, maxLength).join(" ") + "..." : content;
|
|
};
|
|
|
|
/**
|
|
* Processes the date of an article and returns a string representing the processed date.
|
|
* @param timestamp the timestamp to process
|
|
* @returns a string representing the processed timestamp
|
|
*/
|
|
export const processArticleDate = (timestamp: string) => {
|
|
const date = new Date(timestamp);
|
|
const monthSmall = date.toLocaleString("default", { month: "short" });
|
|
const day = date.getDate();
|
|
const year = date.getFullYear();
|
|
return `${monthSmall} ${day}, ${year}`;
|
|
};
|
|
|
|
/**
|
|
* Generates a source URL for a content item. The URL is used in meta tags and social media cards.
|
|
* @param sourceUrl the source URL of the content
|
|
* @param contentType the type of content (either "projects" or "blog")
|
|
* @returns a string representing the source URL with the appropriate domain
|
|
*/
|
|
export const generateSourceUrl = (
|
|
sourceUrl: string,
|
|
contentType: "projects" | "blog",
|
|
) => {
|
|
return `${GLOBAL.rootUrl}/${contentType}/${sourceUrl}`;
|
|
};
|
|
|
|
export const countTags = (tags: string[]) => {
|
|
const tagCount: Record<string, number> = {};
|
|
tags.forEach((tag) => {
|
|
if (tagCount[tag]) {
|
|
tagCount[tag]++;
|
|
} else {
|
|
tagCount[tag] = 1;
|
|
}
|
|
});
|
|
return tagCount;
|
|
}
|