@@ -18,6 +18,12 @@ import LandingPageGad from '~/components/LandingPageGad'
1818import { MaintainerCard } from '~/components/MaintainerCard'
1919import { coreMaintainers } from '~/libraries/maintainers'
2020import { useToast } from '~/components/ToastProvider'
21+ import { allPosts } from 'content-collections'
22+ import { formatAuthors } from '~/utils/blog'
23+ import { format } from 'date-fns'
24+ import { Markdown } from '~/components/Markdown'
25+ import { createServerFn } from '@tanstack/react-start'
26+ import { setResponseHeaders } from '@tanstack/react-start/server'
2127
2228export const textColors = [
2329 `text-rose-500` ,
@@ -42,12 +48,37 @@ const courses = [
4248 } ,
4349]
4450
51+ const fetchRecentPosts = createServerFn ( { method : 'GET' } ) . handler ( async ( ) => {
52+ setResponseHeaders ( {
53+ 'cache-control' : 'public, max-age=0, must-revalidate' ,
54+ 'cdn-cache-control' : 'max-age=300, stale-while-revalidate=300, durable' ,
55+ 'Netlify-Vary' : 'query=payload' ,
56+ } )
57+
58+ return allPosts
59+ . sort ( ( a , b ) => {
60+ return new Date ( b . published ) . getTime ( ) - new Date ( a . published ) . getTime ( )
61+ } )
62+ . slice ( 0 , 3 )
63+ . map ( ( post ) => {
64+ return {
65+ slug : post . slug ,
66+ title : post . title ,
67+ published : post . published ,
68+ excerpt : post . excerpt ,
69+ authors : post . authors ,
70+ }
71+ } )
72+ } )
73+
4574export const Route = createFileRoute ( '/_libraries/' ) ( {
4675 loader : async ( { context : { queryClient } } ) => {
4776 await queryClient . ensureQueryData ( convexQuery ( api . stats . getStats , { } ) )
77+ const recentPosts = await fetchRecentPosts ( )
4878
4979 return {
5080 randomNumber : Math . random ( ) ,
81+ recentPosts,
5182 }
5283 } ,
5384 component : Index ,
@@ -74,6 +105,7 @@ function Index() {
74105 fn : bytesSignupServerFn ,
75106 } )
76107 const { notify } = useToast ( )
108+ const { recentPosts } = Route . useLoaderData ( )
77109
78110 // sponsorsPromise no longer needed - using lazy loading
79111
@@ -348,6 +380,74 @@ function Index() {
348380 </ div >
349381 </ div >
350382
383+ { recentPosts && recentPosts . length > 0 && (
384+ < div className = "px-4 lg:max-w-(--breakpoint-lg) md:mx-auto" >
385+ < h3 id = "blog" className = { `text-4xl font-light mb-6 scroll-mt-24` } >
386+ < a
387+ href = "#blog"
388+ className = "hover:underline decoration-gray-400 dark:decoration-gray-600"
389+ >
390+ Latest Blog Posts
391+ </ a >
392+ </ h3 >
393+ < div className = "grid grid-cols-1 md:grid-cols-3 gap-4" >
394+ { recentPosts . map ( ( { slug, title, published, excerpt, authors } ) => {
395+ return (
396+ < Link
397+ key = { slug }
398+ to = "/blog/$"
399+ params = { { _splat : slug } }
400+ className = { `flex flex-col gap-3 justify-between
401+ border-2 border-transparent rounded-lg p-4
402+ transition-all bg-white/90 dark:bg-black/40
403+ shadow-md dark:shadow-lg dark:shadow-blue-500/20
404+ hover:border-blue-500 hover:shadow-xl
405+ ` }
406+ >
407+ < div >
408+ < div className = { `text-base font-bold` } > { title } </ div >
409+ < div className = { `text-xs italic font-light mt-1 text-gray-600 dark:text-gray-400` } >
410+ < p >
411+ by { formatAuthors ( authors ) }
412+ { published ? (
413+ < time
414+ dateTime = { published }
415+ title = { format ( new Date ( published ) , 'MMM dd, yyyy' ) }
416+ >
417+ { ' ' }
418+ on { format ( new Date ( published ) , 'MMM dd, yyyy' ) }
419+ </ time >
420+ ) : null }
421+ </ p >
422+ </ div >
423+ { excerpt && (
424+ < div
425+ className = { `text-xs mt-3 text-gray-700 dark:text-gray-300 line-clamp-2 leading-relaxed` }
426+ >
427+ < Markdown rawContent = { excerpt } />
428+ </ div >
429+ ) }
430+ </ div >
431+ < div >
432+ < div className = "text-blue-500 uppercase font-bold text-xs" >
433+ Read More →
434+ </ div >
435+ </ div >
436+ </ Link >
437+ )
438+ } ) }
439+ </ div >
440+ < div className = "text-center mt-6" >
441+ < Link
442+ to = "/blog"
443+ className = "inline-flex items-center text-sm text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 transition-colors"
444+ >
445+ View All Posts →
446+ </ Link >
447+ </ div >
448+ </ div >
449+ ) }
450+
351451 < div className = { `lg:max-w-(--breakpoint-lg) px-4 mx-auto` } >
352452 < h3 id = "courses" className = { `text-4xl font-light mb-6 scroll-mt-24` } >
353453 < a
@@ -430,6 +530,14 @@ function Index() {
430530 < MaintainerCard key = { maintainer . github } maintainer = { maintainer } />
431531 ) ) }
432532 </ div >
533+ < div className = "text-center mt-6" >
534+ < Link
535+ to = "/maintainers"
536+ className = "inline-flex items-center text-sm text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 transition-colors"
537+ >
538+ View All Maintainers →
539+ </ Link >
540+ </ div >
433541 </ div >
434542
435543 < LandingPageGad />
0 commit comments