81 lines
2.6 KiB
TypeScript
81 lines
2.6 KiB
TypeScript
export const THUMBNAIL_DEFAULT = "https://teasanctuary.ru/common/background-day.webp";
|
||
export const BLOG_POST_FRESHNESS_MILLIS = 3 * 24 * 60 * 60 * 1000; // 3 дня
|
||
|
||
export type PostComparer = (a: App.BlogPost, b: App.BlogPost) => number;
|
||
|
||
export const sortPostsByPostDate: PostComparer = (a, b) => new Date(b.date!).valueOf() - new Date(a.date!).valueOf();
|
||
|
||
function laterDate(a: string, b?: string): number {
|
||
const dateA = new Date(a).valueOf();
|
||
if (!b) return dateA;
|
||
|
||
const dateB = new Date(b).valueOf();
|
||
return Math.max(dateA, dateB);
|
||
}
|
||
|
||
export const sortPostsByPostAndUpdateDate: PostComparer = (a, b) => laterDate(b.date!, b.dateChanged) - laterDate(a.date!, a.dateChanged);
|
||
|
||
export async function fetchPostsSorted(postComparer?: PostComparer) {
|
||
const allPosts = await fetchPosts();
|
||
|
||
const sortedPosts = allPosts
|
||
// Для списка постов оставляем только те, у которых объявлена дата публикации
|
||
.filter((a) => !!a.date)
|
||
.sort(postComparer ?? sortPostsByPostDate);
|
||
|
||
return sortedPosts;
|
||
};
|
||
|
||
// rndtrash: пришлось заменить `path.parse`, так как на стороне клиента его больше не реализуют
|
||
function getFilenameFromPath(path: string) {
|
||
const file = path.split("/").pop();
|
||
const dot = file?.lastIndexOf('.') ?? -1;
|
||
return dot === -1 ? file : file?.substring(0, file.lastIndexOf('.'));
|
||
}
|
||
|
||
export async function fetchPosts() {
|
||
const allPostFiles = import.meta.glob('/src/blogs/*.md');
|
||
const iterablePostFiles = Object.entries(allPostFiles);
|
||
|
||
const allPosts: App.BlogPost[] = await Promise.all(
|
||
iterablePostFiles.map(async ([filePath, resolver]) => {
|
||
const { metadata }: any = await resolver();
|
||
const name = getFilenameFromPath(filePath);
|
||
|
||
return {
|
||
slug: name,
|
||
...metadata
|
||
};
|
||
})
|
||
);
|
||
|
||
return allPosts;
|
||
};
|
||
|
||
export function resolveBlogPath(slug?: string, src?: string) {
|
||
if (!src) return null;
|
||
|
||
return src.startsWith('http://') || src.startsWith('https://')
|
||
? src
|
||
: `/blog/${slug}/${src}`;
|
||
}
|
||
|
||
const bptToString: Record<App.BlogPostType, string> = {
|
||
'article': 'Заметка',
|
||
'event': 'Событие',
|
||
'update': 'Обновление'
|
||
};
|
||
|
||
const bptToIcon: Record<App.BlogPostType, string> = {
|
||
'article': 'material-symbols:article',
|
||
'event': 'material-symbols:event',
|
||
'update': 'material-symbols:autorenew'
|
||
};
|
||
|
||
export function blogPostTypeToString(type: App.BlogPostType): string {
|
||
return bptToString[type] ?? bptToString['article'];
|
||
}
|
||
|
||
export function blogPostTypeToIcon(type: App.BlogPostType): string {
|
||
return bptToIcon[type] ?? bptToIcon['article'];
|
||
}
|