feat: add related blog posts component
This commit is contained in:
28
src/components/blog/RelatedPosts.astro
Normal file
28
src/components/blog/RelatedPosts.astro
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
import { APP_BLOG } from "~/utils/config";
|
||||||
|
|
||||||
|
import { fetchPosts, getRelatedPosts } from "~/utils/blog";
|
||||||
|
import BlogHighlightedPosts from "../widgets/BlogHighlightedPosts.astro";
|
||||||
|
import type { Post } from "~/types";
|
||||||
|
import { getBlogPermalink } from "~/utils/permalinks";
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
post: Post;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { post } = Astro.props;
|
||||||
|
const fetchedPosts = await fetchPosts();
|
||||||
|
const relatedPosts = post.tags ? getRelatedPosts(fetchedPosts, post.slug, post.tags) : [];
|
||||||
|
---
|
||||||
|
|
||||||
|
{
|
||||||
|
APP_BLOG.isRelatedPostsEnabled ? (
|
||||||
|
<BlogHighlightedPosts
|
||||||
|
classes={{ container: "pt-0 lg:pt-0 md:pt-0" }}
|
||||||
|
title="Related Posts"
|
||||||
|
linkText="View All Posts"
|
||||||
|
linkUrl={getBlogPermalink()}
|
||||||
|
postIds={relatedPosts.map((post) => post.id)}
|
||||||
|
/>
|
||||||
|
) : null
|
||||||
|
}
|
@ -35,6 +35,8 @@ apps:
|
|||||||
blog:
|
blog:
|
||||||
isEnabled: true
|
isEnabled: true
|
||||||
postsPerPage: 6
|
postsPerPage: 6
|
||||||
|
isRelatedPostsEnabled: true
|
||||||
|
relatedPostsCount: 4
|
||||||
|
|
||||||
post:
|
post:
|
||||||
isEnabled: true
|
isEnabled: true
|
||||||
|
@ -11,6 +11,7 @@ import { getCanonical, getPermalink } from '~/utils/permalinks';
|
|||||||
import { getStaticPathsBlogPost, blogPostRobots } from '~/utils/blog';
|
import { getStaticPathsBlogPost, blogPostRobots } from '~/utils/blog';
|
||||||
import { findImage } from '~/utils/images';
|
import { findImage } from '~/utils/images';
|
||||||
import type { MetaData } from '~/types';
|
import type { MetaData } from '~/types';
|
||||||
|
import RelatedPosts from '~/components/blog/RelatedPosts.astro';
|
||||||
|
|
||||||
export const prerender = true;
|
export const prerender = true;
|
||||||
|
|
||||||
@ -45,4 +46,5 @@ const metadata = merge(
|
|||||||
<Layout metadata={metadata}>
|
<Layout metadata={metadata}>
|
||||||
<SinglePost post={{ ...post, image: image }} url={url} />
|
<SinglePost post={{ ...post, image: image }} url={url} />
|
||||||
<ToBlogLink />
|
<ToBlogLink />
|
||||||
|
<RelatedPosts post={post} />
|
||||||
</Layout>
|
</Layout>
|
||||||
|
@ -90,6 +90,18 @@ const getNormalizedPost = async (post: CollectionEntry<'post'>): Promise<Post> =
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getRandomizedPosts = (array: Post[], num: number) => {
|
||||||
|
const newArray: Post[] = [];
|
||||||
|
|
||||||
|
while (newArray.length < num && array.length > 0) {
|
||||||
|
const randomIndex = Math.floor(Math.random() * array.length);
|
||||||
|
newArray.push(array[randomIndex]);
|
||||||
|
array.splice(randomIndex, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newArray;
|
||||||
|
};
|
||||||
|
|
||||||
const load = async function (): Promise<Array<Post>> {
|
const load = async function (): Promise<Array<Post>> {
|
||||||
const posts = await getCollection('post');
|
const posts = await getCollection('post');
|
||||||
const normalizedPosts = posts.map(async (post) => await getNormalizedPost(post));
|
const normalizedPosts = posts.map(async (post) => await getNormalizedPost(post));
|
||||||
@ -105,6 +117,7 @@ let _posts: Array<Post>;
|
|||||||
|
|
||||||
/** */
|
/** */
|
||||||
export const isBlogEnabled = APP_BLOG.isEnabled;
|
export const isBlogEnabled = APP_BLOG.isEnabled;
|
||||||
|
export const isRelatedPostsEnabled = APP_BLOG.isRelatedPostsEnabled;
|
||||||
export const isBlogListRouteEnabled = APP_BLOG.list.isEnabled;
|
export const isBlogListRouteEnabled = APP_BLOG.list.isEnabled;
|
||||||
export const isBlogPostRouteEnabled = APP_BLOG.post.isEnabled;
|
export const isBlogPostRouteEnabled = APP_BLOG.post.isEnabled;
|
||||||
export const isBlogCategoryRouteEnabled = APP_BLOG.category.isEnabled;
|
export const isBlogCategoryRouteEnabled = APP_BLOG.category.isEnabled;
|
||||||
@ -225,3 +238,23 @@ export const getStaticPathsBlogTag = async ({ paginate }: { paginate: PaginateFu
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** */
|
||||||
|
export function getRelatedPosts(allPosts: Post[], currentSlug: string, currentTags: string[]) {
|
||||||
|
if (!isBlogEnabled || !isRelatedPostsEnabled) return [];
|
||||||
|
|
||||||
|
const relatedPosts = getRandomizedPosts(
|
||||||
|
allPosts.filter((post) => post.slug !== currentSlug && post.tags?.some((tag) => currentTags.includes(tag))),
|
||||||
|
APP_BLOG.relatedPostsCount
|
||||||
|
);
|
||||||
|
|
||||||
|
if (relatedPosts.length < APP_BLOG.relatedPostsCount) {
|
||||||
|
const morePosts = getRandomizedPosts(
|
||||||
|
allPosts.filter((post) => post.slug !== currentSlug && !post.tags?.some((tag) => currentTags.includes(tag))),
|
||||||
|
APP_BLOG.relatedPostsCount - relatedPosts.length
|
||||||
|
);
|
||||||
|
relatedPosts.push(...morePosts);
|
||||||
|
}
|
||||||
|
|
||||||
|
return relatedPosts;
|
||||||
|
}
|
||||||
|
@ -25,6 +25,8 @@ export interface I18NConfig {
|
|||||||
export interface AppBlogConfig {
|
export interface AppBlogConfig {
|
||||||
isEnabled: boolean;
|
isEnabled: boolean;
|
||||||
postsPerPage: number;
|
postsPerPage: number;
|
||||||
|
isRelatedPostsEnabled: boolean;
|
||||||
|
relatedPostsCount: number;
|
||||||
post: {
|
post: {
|
||||||
isEnabled: boolean;
|
isEnabled: boolean;
|
||||||
permalink: string;
|
permalink: string;
|
||||||
|
Reference in New Issue
Block a user