at main 73 lines 1.9 kB view raw
1--- 2import { getCollection } from "astro:content"; 3import PrettyDate from "./PrettyDate.astro"; 4// import Tags from "./Tags.astro"; 5import type { CollectionEntry } from "astro:content"; 6 7interface Props { 8 limit?: number; 9} 10 11const { limit = Infinity } = Astro.props; 12 13const posts = (await getCollection("blog")) 14 .sort((a, b) => b.data.publish_date.valueOf() - a.data.publish_date.valueOf()) 15 .slice(0, limit); 16 17type Post = CollectionEntry<"blog">; 18 19const postsByYear = Object.entries( 20 posts.reduce( 21 (acc, post) => { 22 const year = post.data.publish_date.getFullYear().toString(); 23 acc[year] ??= []; 24 acc[year].push(post); 25 return acc; 26 }, 27 {} as Record<string, Post[]>, 28 ), 29).sort(([year1], [year2]) => year2.localeCompare(year1)); 30--- 31 32<div class="posts"> 33 { 34 postsByYear.map(([year, posts]) => { 35 if (!posts) return null; 36 37 return ( 38 <> 39 <h3>{year}</h3> 40 <ul> 41 {posts.map( 42 ({ 43 id, 44 data: { 45 title, 46 description: snippet, 47 publish_date, 48 hero_image, 49 // tags, 50 }, 51 }) => ( 52 <li> 53 <div class="flex gap-2 items-center"> 54 <a 55 href={`/blog/${id}`} 56 class="leading-tight inline-block" 57 transition:name={`post-title-${id}`} 58 > 59 {title} 60 </a> 61 <div class="border-b border-dashed self-center flex-1" /> 62 <PrettyDate date={publish_date ?? new Date()} /> 63 </div> 64 <p transition:name={`post-snippet-${id}`}>{snippet}</p> 65 </li> 66 ), 67 )} 68 </ul> 69 </> 70 ); 71 }) 72 } 73</div>