https://github.com/proxima812/astro-ts-mastery
🚀 utils and libs for Astro.js projects.
https://github.com/proxima812/astro-ts-mastery
astro-content astro-js en getcollection js ru slug slugify ts zod
Last synced: about 2 months ago
JSON representation
🚀 utils and libs for Astro.js projects.
- Host: GitHub
- URL: https://github.com/proxima812/astro-ts-mastery
- Owner: proxima812
- Created: 2023-11-10T10:38:17.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2023-11-10T14:37:08.000Z (over 2 years ago)
- Last Synced: 2025-06-25T03:46:08.091Z (12 months ago)
- Topics: astro-content, astro-js, en, getcollection, js, ru, slug, slugify, ts, zod
- Homepage:
- Size: 6.84 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
import { getCollection, type CollectionEntry } from "astro:content";
import GithubSlugger from "github-slugger";
import slugify from "slugify";
import { marked } from "marked";
/* --------------------------------- slug --------------------------------- */
const RU_REGEX = /[а-яё]/i;
const slugger = new GithubSlugger();
export const customSlugify = (value = ""): string => {
if (!value) return "";
if (RU_REGEX.test(value)) {
return slugify(value, {
lower: true,
strict: true,
locale: "ru",
trim: true,
});
}
return slugger.slug(value);
};
/* ------------------------------ collections ------------------------------ */
export const getSinglePage = async (
collection: string
): Promise[]> => {
const pages = await getCollection(collection);
return pages.filter(
(p) => !p.data?.draft && !p.id.startsWith("-")
);
};
export const getTaxonomy = async (
collection: string,
field: string
): Promise => {
const pages = await getSinglePage(collection);
return [
...new Set(
pages
.flatMap((p) => p.data?.[field] ?? [])
.filter(Boolean)
.map(customSlugify)
),
];
};
/* -------------------------------- markdown ------------------------------- */
export const markdownify = (content = ""): string => {
if (!content) return "";
return marked.parseInline(content);
};
/* -------------------------------- humanize ------------------------------- */
export const humanize = (value = ""): string => {
if (!value) return "";
const cleaned = value
.trim()
.replace(/[_\s]+/g, " ");
return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
};
/* -------------------------------- plainify ------------------------------- */
export const plainify = (html = ""): string => {
if (!html) return "";
const text = html
.replace(/<\/?[^>]+>/g, "")
.replace(/\s+/g, " ")
.trim();
return decodeHTMLEntities(text);
};
const decodeHTMLEntities = (str: string): string =>
str.replace(
/&(nbsp|amp|lt|gt|quot|#39);/g,
(m) =>
({
" ": " ",
"&": "&",
"<": "<",
">": ">",
""": '"',
"'": "'",
} as Record)[m] ?? m
);
/* ------------------------------ reading time ------------------------------ */
const WORDS_PER_MINUTE = 275;
const readingTime = (content = "", locale: "en" | "ru" = "en"): string => {
if (!content) return "0 min";
const words = content.match(/\p{L}+/gu)?.length ?? 0;
const images = (content.match(/![]()