@@ -34,7 +34,9 @@ const authors = post.data.authors
3434
3535// Get related posts
3636const allPosts = await getCollection (' blog' );
37- const relatedPosts = post .data .relatedPosts
37+
38+ // First, get manually selected related posts
39+ let relatedPosts = post .data .relatedPosts
3840 ? post .data .relatedPosts
3941 .filter (permalink => permalink !== post .data .permalink ) // Don't show current post
4042 .map ((permalink ) => {
@@ -59,6 +61,49 @@ const relatedPosts = post.data.relatedPosts
5961 .filter ((post ): post is NonNullable <typeof post > => post !== null )
6062 : [];
6163
64+ // If we have less than 3 related posts, dynamically add more based on tag matching and recency
65+ if (relatedPosts .length < 3 ) {
66+ const currentTags = new Set (post .data .tags );
67+ const manuallySelectedPermalinks = new Set (relatedPosts .map (p => p .data .permalink ));
68+
69+ // Calculate tag matches for all other posts
70+ const candidatePosts = allPosts
71+ .filter (p =>
72+ p .data .permalink !== post .data .permalink && // Not the current post
73+ ! manuallySelectedPermalinks .has (p .data .permalink ) && // Not already manually selected
74+ (isDev || p .data .published === ' published' ) // Only published posts (except in dev)
75+ )
76+ .map (p => {
77+ // Count matching tags
78+ const matchingTags = p .data .tags .filter (tag => currentTags .has (tag )).length ;
79+
80+ // Resolve authors
81+ const resolvedAuthors = p .data .authors
82+ .map ((id ) => peopleMap .get (id ))
83+ .filter (Boolean );
84+
85+ return {
86+ ... p ,
87+ resolvedAuthors ,
88+ matchingTags
89+ };
90+ })
91+ .sort ((a , b ) => {
92+ // First sort by number of matching tags (descending)
93+ if (b .matchingTags !== a .matchingTags ) {
94+ return b .matchingTags - a .matchingTags ;
95+ }
96+ // Then sort by publish date (most recent first)
97+ return b .data .publishedDate .getTime () - a .data .publishedDate .getTime ();
98+ });
99+
100+ // Add posts to fill up to 3 total
101+ const postsNeeded = 3 - relatedPosts .length ;
102+ const dynamicPosts = candidatePosts .slice (0 , postsNeeded );
103+
104+ relatedPosts = [... relatedPosts , ... dynamicPosts ];
105+ }
106+
62107// Format date
63108const formatDate = (date : Date ) => {
64109 return new Intl .DateTimeFormat (' en-US' , {
0 commit comments