Don't use tabs in editor
This commit is contained in:
@ -4,81 +4,81 @@ import type { Post } from '~/types';
|
||||
import { cleanSlug } from './permalinks';
|
||||
|
||||
const getNormalizedPost = async (post: CollectionEntry<'blog'>): Promise<Post> => {
|
||||
const { id, slug = '', data } = post;
|
||||
const { Content, injectedFrontmatter } = await post.render();
|
||||
const { id, slug = '', data } = post;
|
||||
const { Content, injectedFrontmatter } = await post.render();
|
||||
|
||||
const { tags = [], category = 'default', author = 'Anonymous', publishDate = new Date(), ...rest } = data;
|
||||
const { tags = [], category = 'default', author = 'Anonymous', publishDate = new Date(), ...rest } = data;
|
||||
|
||||
return {
|
||||
id: id,
|
||||
slug: cleanSlug(slug.split('/').pop() ?? ''),
|
||||
return {
|
||||
id: id,
|
||||
slug: cleanSlug(slug.split('/').pop() ?? ''),
|
||||
|
||||
publishDate: new Date(publishDate),
|
||||
category: cleanSlug(category),
|
||||
tags: tags.map((tag: string) => cleanSlug(tag)),
|
||||
author,
|
||||
publishDate: new Date(publishDate),
|
||||
category: cleanSlug(category),
|
||||
tags: tags.map((tag: string) => cleanSlug(tag)),
|
||||
author,
|
||||
|
||||
...rest,
|
||||
...rest,
|
||||
|
||||
Content: Content,
|
||||
// or 'body' in case you consume from API
|
||||
Content: Content,
|
||||
// or 'body' in case you consume from API
|
||||
|
||||
readingTime: injectedFrontmatter.readingTime,
|
||||
};
|
||||
readingTime: injectedFrontmatter.readingTime,
|
||||
};
|
||||
};
|
||||
|
||||
const load = async function (): Promise<Array<Post>> {
|
||||
const posts = await getCollection('blog');
|
||||
const normalizedPosts = posts.map(async (post) => await getNormalizedPost(post));
|
||||
const posts = await getCollection('blog');
|
||||
const normalizedPosts = posts.map(async (post) => await getNormalizedPost(post));
|
||||
|
||||
const results = (await Promise.all(normalizedPosts))
|
||||
.sort((a, b) => b.publishDate.valueOf() - a.publishDate.valueOf())
|
||||
.filter((post) => !post.draft);
|
||||
const results = (await Promise.all(normalizedPosts))
|
||||
.sort((a, b) => b.publishDate.valueOf() - a.publishDate.valueOf())
|
||||
.filter((post) => !post.draft);
|
||||
|
||||
return results;
|
||||
return results;
|
||||
};
|
||||
|
||||
let _posts: Array<Post>;
|
||||
|
||||
/** */
|
||||
export const fetchPosts = async (): Promise<Array<Post>> => {
|
||||
if (!_posts) {
|
||||
_posts = await load();
|
||||
}
|
||||
if (!_posts) {
|
||||
_posts = await load();
|
||||
}
|
||||
|
||||
return _posts;
|
||||
return _posts;
|
||||
};
|
||||
|
||||
/** */
|
||||
export const findPostsBySlugs = async (slugs: Array<string>): Promise<Array<Post>> => {
|
||||
if (!Array.isArray(slugs)) return [];
|
||||
if (!Array.isArray(slugs)) return [];
|
||||
|
||||
const posts = await fetchPosts();
|
||||
const posts = await fetchPosts();
|
||||
|
||||
return slugs.reduce(function (r: Array<Post>, slug: string) {
|
||||
posts.some(function (post: Post) {
|
||||
return slug === post.slug && r.push(post);
|
||||
});
|
||||
return r;
|
||||
}, []);
|
||||
return slugs.reduce(function (r: Array<Post>, slug: string) {
|
||||
posts.some(function (post: Post) {
|
||||
return slug === post.slug && r.push(post);
|
||||
});
|
||||
return r;
|
||||
}, []);
|
||||
};
|
||||
|
||||
/** */
|
||||
export const findPostsByIds = async (ids: Array<string>): Promise<Array<Post>> => {
|
||||
if (!Array.isArray(ids)) return [];
|
||||
if (!Array.isArray(ids)) return [];
|
||||
|
||||
return await Promise.all(
|
||||
ids.map(async (id: never) => {
|
||||
const post = await getEntry('blog', id);
|
||||
return await getNormalizedPost(post);
|
||||
})
|
||||
);
|
||||
return await Promise.all(
|
||||
ids.map(async (id: never) => {
|
||||
const post = await getEntry('blog', id);
|
||||
return await getNormalizedPost(post);
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
/** */
|
||||
export const findLatestPosts = async ({ count }: { count?: number }): Promise<Array<Post>> => {
|
||||
const _count = count || 4;
|
||||
const posts = await fetchPosts();
|
||||
const _count = count || 4;
|
||||
const posts = await fetchPosts();
|
||||
|
||||
return posts ? posts.slice(_count * -1) : [];
|
||||
return posts ? posts.slice(_count * -1) : [];
|
||||
};
|
||||
|
@ -5,14 +5,14 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
/** */
|
||||
export const getProjectRootDir = (): string => {
|
||||
const mode = import.meta.env.MODE;
|
||||
const mode = import.meta.env.MODE;
|
||||
|
||||
return mode === 'production' ? path.join(__dirname, '../') : path.join(__dirname, '../../');
|
||||
return mode === 'production' ? path.join(__dirname, '../') : path.join(__dirname, '../../');
|
||||
};
|
||||
|
||||
const __srcFolder = path.join(getProjectRootDir(), '/src');
|
||||
|
||||
/** */
|
||||
export const getRelativeUrlByFilePath = (filepath: string): string => {
|
||||
return filepath.replace(__srcFolder, '');
|
||||
return filepath.replace(__srcFolder, '');
|
||||
};
|
||||
|
@ -2,10 +2,10 @@ import getReadingTime from 'reading-time';
|
||||
import { toString } from 'mdast-util-to-string';
|
||||
|
||||
export function remarkReadingTime() {
|
||||
return function (tree, { data }) {
|
||||
const text = toString(tree);
|
||||
const readingTime = Math.ceil(getReadingTime(text).minutes);
|
||||
return function (tree, { data }) {
|
||||
const text = toString(tree);
|
||||
const readingTime = Math.ceil(getReadingTime(text).minutes);
|
||||
|
||||
data.astro.frontmatter.readingTime = readingTime;
|
||||
};
|
||||
data.astro.frontmatter.readingTime = readingTime;
|
||||
};
|
||||
}
|
||||
|
@ -1,37 +1,37 @@
|
||||
const load = async function () {
|
||||
let images: Record<string, () => Promise<unknown>> | undefined = undefined;
|
||||
try {
|
||||
images = import.meta.glob('~/assets/images/**');
|
||||
} catch (e) {
|
||||
// continue regardless of error
|
||||
}
|
||||
return images;
|
||||
let images: Record<string, () => Promise<unknown>> | undefined = undefined;
|
||||
try {
|
||||
images = import.meta.glob('~/assets/images/**');
|
||||
} catch (e) {
|
||||
// continue regardless of error
|
||||
}
|
||||
return images;
|
||||
};
|
||||
|
||||
let _images;
|
||||
|
||||
/** */
|
||||
export const fetchLocalImages = async () => {
|
||||
_images = _images || load();
|
||||
return await _images;
|
||||
_images = _images || load();
|
||||
return await _images;
|
||||
};
|
||||
|
||||
/** */
|
||||
export const findImage = async (imagePath?: string) => {
|
||||
if (typeof imagePath !== 'string') {
|
||||
return null;
|
||||
}
|
||||
if (typeof imagePath !== 'string') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (imagePath.startsWith('http://') || imagePath.startsWith('https://')) {
|
||||
return imagePath;
|
||||
}
|
||||
if (imagePath.startsWith('http://') || imagePath.startsWith('https://')) {
|
||||
return imagePath;
|
||||
}
|
||||
|
||||
if (!imagePath.startsWith('~/assets')) {
|
||||
return null;
|
||||
} // For now only consume images using ~/assets alias (or absolute)
|
||||
if (!imagePath.startsWith('~/assets')) {
|
||||
return null;
|
||||
} // For now only consume images using ~/assets alias (or absolute)
|
||||
|
||||
const images = await fetchLocalImages();
|
||||
const key = imagePath.replace('~/', '/src/');
|
||||
const images = await fetchLocalImages();
|
||||
const key = imagePath.replace('~/', '/src/');
|
||||
|
||||
return typeof images[key] === 'function' ? (await images[key]())['default'] : null;
|
||||
return typeof images[key] === 'function' ? (await images[key]())['default'] : null;
|
||||
};
|
||||
|
@ -5,20 +5,20 @@ import { trim } from '~/utils/utils';
|
||||
|
||||
const trimSlash = (s: string) => trim(trim(s, '/'));
|
||||
const createPath = (...params: string[]) => {
|
||||
const paths = params
|
||||
.map((el) => trimSlash(el))
|
||||
.filter((el) => !!el)
|
||||
.join('/');
|
||||
return '/' + paths + (SITE.trailingSlash && paths ? '/' : '');
|
||||
const paths = params
|
||||
.map((el) => trimSlash(el))
|
||||
.filter((el) => !!el)
|
||||
.join('/');
|
||||
return '/' + paths + (SITE.trailingSlash && paths ? '/' : '');
|
||||
};
|
||||
|
||||
const BASE_PATHNAME = SITE.basePathname;
|
||||
|
||||
export const cleanSlug = (text: string) =>
|
||||
trimSlash(text)
|
||||
.split('/')
|
||||
.map((slug) => slugify(slug))
|
||||
.join('/');
|
||||
trimSlash(text)
|
||||
.split('/')
|
||||
.map((slug) => slugify(slug))
|
||||
.join('/');
|
||||
|
||||
export const BLOG_BASE = cleanSlug(BLOG?.list?.pathname);
|
||||
export const POST_BASE = cleanSlug(BLOG?.post?.pathname);
|
||||
@ -30,28 +30,28 @@ export const getCanonical = (path = ''): string | URL => new URL(path, SITE.orig
|
||||
|
||||
/** */
|
||||
export const getPermalink = (slug = '', type = 'page'): string => {
|
||||
let permalink: string;
|
||||
let permalink: string;
|
||||
|
||||
switch (type) {
|
||||
case 'category':
|
||||
permalink = createPath(CATEGORY_BASE, cleanSlug(slug));
|
||||
break;
|
||||
switch (type) {
|
||||
case 'category':
|
||||
permalink = createPath(CATEGORY_BASE, cleanSlug(slug));
|
||||
break;
|
||||
|
||||
case 'tag':
|
||||
permalink = createPath(TAG_BASE, cleanSlug(slug));
|
||||
break;
|
||||
case 'tag':
|
||||
permalink = createPath(TAG_BASE, cleanSlug(slug));
|
||||
break;
|
||||
|
||||
case 'post':
|
||||
permalink = createPath(POST_BASE, cleanSlug(slug));
|
||||
break;
|
||||
case 'post':
|
||||
permalink = createPath(POST_BASE, cleanSlug(slug));
|
||||
break;
|
||||
|
||||
case 'page':
|
||||
default:
|
||||
permalink = createPath(slug);
|
||||
break;
|
||||
}
|
||||
case 'page':
|
||||
default:
|
||||
permalink = createPath(slug);
|
||||
break;
|
||||
}
|
||||
|
||||
return definitivePermalink(permalink);
|
||||
return definitivePermalink(permalink);
|
||||
};
|
||||
|
||||
/** */
|
||||
|
@ -1,21 +1,21 @@
|
||||
import { DATE_FORMATTER } from '~/config.mjs';
|
||||
|
||||
const formatter =
|
||||
DATE_FORMATTER ||
|
||||
new Intl.DateTimeFormat('en', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
timeZone: 'UTC'
|
||||
});
|
||||
DATE_FORMATTER ||
|
||||
new Intl.DateTimeFormat('en', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
timeZone: 'UTC',
|
||||
});
|
||||
|
||||
/* eslint-disable no-mixed-spaces-and-tabs */
|
||||
export const getFormattedDate = (date: Date) => (date ? formatter.format(date) : '');
|
||||
|
||||
export const trim = (str = '', ch?: string) => {
|
||||
let start = 0,
|
||||
end = str.length || 0;
|
||||
while (start < end && str[start] === ch) ++start;
|
||||
while (end > start && str[end - 1] === ch) --end;
|
||||
return start > 0 || end < str.length ? str.substring(start, end) : str;
|
||||
let start = 0,
|
||||
end = str.length || 0;
|
||||
while (start < end && str[start] === ch) ++start;
|
||||
while (end > start && str[end - 1] === ch) --end;
|
||||
return start > 0 || end < str.length ? str.substring(start, end) : str;
|
||||
};
|
||||
|
Reference in New Issue
Block a user