@@ -3,22 +3,82 @@ import Layout from '../../layouts/Layout.astro';
33import { getCollection , render } from ' astro:content' ;
44
55export async function getStaticPaths() {
6- const posts = await getCollection (' blog' );
6+ const posts = (await getCollection (' blog' )).sort (
7+ (a , b ) => b .data .date .valueOf () - a .data .date .valueOf ()
8+ );
9+
710 return posts .map ((post ) => ({
811 params: { slug: post .id },
9- props: { post },
12+ props: {
13+ post ,
14+ relatedPosts: posts
15+ .filter (candidate => candidate .id !== post .id )
16+ .sort ((a , b ) => {
17+ const aSharedTags = a .data .tags .filter (tag => post .data .tags .includes (tag )).length ;
18+ const bSharedTags = b .data .tags .filter (tag => post .data .tags .includes (tag )).length ;
19+ return bSharedTags - aSharedTags || b .data .date .valueOf () - a .data .date .valueOf ();
20+ })
21+ .slice (0 , 3 ),
22+ },
1023 }));
1124}
1225
13- const { post } = Astro .props ;
26+ const { post, relatedPosts } = Astro .props ;
1427const { Content } = await render (post );
1528
1629// Estimate reading time (~200 words per minute)
1730const wordCount = post .body ?.split (/ \s + / ).length ?? 0 ;
1831const readingTime = Math .max (1 , Math .ceil (wordCount / 200 ));
32+ const siteURL = Astro .site ?? new URL (' https://devproxy.net' );
33+ const postURL = new URL (Astro .url .pathname , siteURL ).href ;
34+ const blogURL = new URL (` ${import .meta .env .BASE_URL }blog/ ` , siteURL ).href ;
35+ const structuredData = [
36+ {
37+ ' @context' : ' https://schema.org' ,
38+ ' @type' : ' BlogPosting' ,
39+ headline: post .data .title ,
40+ description: post .data .description ,
41+ datePublished: post .data .date .toISOString (),
42+ author: {
43+ ' @type' : ' Person' ,
44+ name: post .data .author ,
45+ },
46+ image: post .data .image ? new URL (post .data .image , siteURL ).href : undefined ,
47+ mainEntityOfPage: postURL ,
48+ publisher: {
49+ ' @type' : ' Organization' ,
50+ name: ' Dev Proxy' ,
51+ url: new URL (import .meta .env .BASE_URL , siteURL ).href ,
52+ },
53+ },
54+ {
55+ ' @context' : ' https://schema.org' ,
56+ ' @type' : ' BreadcrumbList' ,
57+ itemListElement: [
58+ {
59+ ' @type' : ' ListItem' ,
60+ position: 1 ,
61+ name: ' Blog' ,
62+ item: blogURL ,
63+ },
64+ {
65+ ' @type' : ' ListItem' ,
66+ position: 2 ,
67+ name: post .data .title ,
68+ item: postURL ,
69+ },
70+ ],
71+ },
72+ ];
1973---
2074
21- <Layout title ={ post .data .title } description ={ post .data .description } image ={ post .data .image } >
75+ <Layout
76+ title ={ post .data .title }
77+ description ={ post .data .description }
78+ image ={ post .data .image }
79+ ogType =" article"
80+ structuredData ={ structuredData }
81+ >
2282 <article class =" pt-16 pb-24 px-4" >
2383 <div class =" max-w-3xl mx-auto" >
2484
@@ -62,6 +122,26 @@ const readingTime = Math.max(1, Math.ceil(wordCount / 200));
62122 <Content />
63123 </div >
64124
125+ <aside class =" mt-16 pt-8 border-t" style =" border-color: var(--border-primary);" aria-labelledby =" related-posts-heading" >
126+ <h2 id =" related-posts-heading" class =" text-xl font-bold mb-6" >Related posts</h2 >
127+ <div class =" grid md:grid-cols-3 gap-4" >
128+ { relatedPosts .map (relatedPost => (
129+ <a
130+ href = { ` ${import .meta .env .BASE_URL }blog/${relatedPost .id }/ ` }
131+ class = " group block rounded-2xl border p-5 transition-all duration-300 hover:border-purple-500/50"
132+ style = " background: var(--bg-secondary); border-color: var(--border-primary);"
133+ >
134+ <h3 class = " font-semibold leading-snug group-hover:text-purple-400 transition-colors" >
135+ { relatedPost .data .title }
136+ </h3 >
137+ <time class = " block text-xs mt-3" style = " color: var(--text-faint);" datetime = { relatedPost .data .date .toISOString ()} >
138+ { relatedPost .data .date .toLocaleDateString (' en-GB' , { year: ' numeric' , month: ' long' , day: ' numeric' })}
139+ </time >
140+ </a >
141+ ))}
142+ </div >
143+ </aside >
144+
65145 <!-- Post footer -->
66146 <footer class =" mt-16 pt-8 border-t" style =" border-color: var(--border-primary);" >
67147 <div class =" flex items-center justify-between flex-wrap gap-4" >
0 commit comments