1
+ import type { Metadata } from 'next' ;
2
+ import { Suspense } from 'react' ;
3
+ import { notFound } from 'next/navigation' ;
4
+ // import { CustomMDX } from 'app/components/mdx';
5
+ import MarkdownRenderer from '@/components/markdown/markdown-renderer' ;
6
+ import { getBlogPosts } from '../../db/blog' ;
7
+ import { unstable_noStore as noStore } from 'next/cache' ;
8
+ import Header from '@/components/markdown/header' ;
9
+
10
+ export async function generateMetadata ( {
11
+ params,
12
+ } : {
13
+ params : { slug : string } ;
14
+ } ) : Promise < Metadata | undefined > {
15
+ let post = getBlogPosts ( ) . find ( ( post ) => post . slug === params . slug ) ;
16
+ if ( ! post ) {
17
+ return ;
18
+ }
19
+
20
+ let {
21
+ title,
22
+ publishedAt : publishedTime ,
23
+ summary : description ,
24
+ image,
25
+ } = post . metadata ;
26
+ let ogImage = image
27
+ ? `https://leerob.io${ image } `
28
+ : `https://leerob.io/og?title=${ title } ` ;
29
+
30
+ return {
31
+ title,
32
+ description,
33
+ openGraph : {
34
+ title,
35
+ description,
36
+ type : 'article' ,
37
+ publishedTime,
38
+ url : `https://leerob.io/blog/${ post . slug } ` ,
39
+ images : [
40
+ {
41
+ url : ogImage ,
42
+ } ,
43
+ ] ,
44
+ } ,
45
+ twitter : {
46
+ card : 'summary_large_image' ,
47
+ title,
48
+ description,
49
+ images : [ ogImage ] ,
50
+ } ,
51
+ } ;
52
+ }
53
+
54
+ function formatDate ( date : string ) {
55
+ noStore ( ) ;
56
+ let currentDate = new Date ( ) . getTime ( ) ;
57
+ if ( ! date . includes ( 'T' ) ) {
58
+ date = `${ date } T00:00:00` ;
59
+ }
60
+ let targetDate = new Date ( date ) . getTime ( ) ;
61
+ let timeDifference = Math . abs ( currentDate - targetDate ) ;
62
+ let daysAgo = Math . floor ( timeDifference / ( 1000 * 60 * 60 * 24 ) ) ;
63
+
64
+ let fullDate = new Date ( date ) . toLocaleString ( 'en-us' , {
65
+ month : 'long' ,
66
+ day : 'numeric' ,
67
+ year : 'numeric' ,
68
+ } ) ;
69
+
70
+ if ( daysAgo < 1 ) {
71
+ return 'Today' ;
72
+ } else if ( daysAgo < 7 ) {
73
+ return `${ fullDate } (${ daysAgo } d ago)` ;
74
+ } else if ( daysAgo < 30 ) {
75
+ const weeksAgo = Math . floor ( daysAgo / 7 )
76
+ return `${ fullDate } (${ weeksAgo } w ago)` ;
77
+ } else if ( daysAgo < 365 ) {
78
+ const monthsAgo = Math . floor ( daysAgo / 30 )
79
+ return `${ fullDate } (${ monthsAgo } mo ago)` ;
80
+ } else {
81
+ const yearsAgo = Math . floor ( daysAgo / 365 )
82
+ return `${ fullDate } (${ yearsAgo } y ago)` ;
83
+ }
84
+ }
85
+
86
+ export default function Blog ( { params } : { params : { slug : string } } ) {
87
+ let post = getBlogPosts ( ) . find ( ( post ) => post . slug === params . slug ) ;
88
+
89
+ if ( ! post ) {
90
+ notFound ( ) ;
91
+ }
92
+
93
+ return (
94
+ < article >
95
+ < section >
96
+ { /* <script
97
+ type="application/ld+json"
98
+ suppressHydrationWarning
99
+ dangerouslySetInnerHTML={{
100
+ __html: JSON.stringify({
101
+ '@context ': 'https://schema.org',
102
+ '@type': 'BlogPosting',
103
+ headline: post.metadata.title,
104
+ datePublished: post.metadata.publishedAt,
105
+ dateModified: post.metadata.publishedAt,
106
+ description: post.metadata.summary,
107
+ image: post.metadata.image
108
+ ? `https://leerob.io${post.metadata.image}`
109
+ : `https://leerob.io/og?title=${post.metadata.title}`,
110
+ url: `https://leerob.io/blog/${post.slug}`,
111
+ author: {
112
+ '@type ': 'Person',
113
+ name: 'Lee Robinson',
114
+ },
115
+ }),
116
+ }}
117
+ /> */ }
118
+ < Header title = "Hugo's Blog" />
119
+ < h1 className = "title font-medium text-2xl tracking-tighter max-w-[650px]" >
120
+ { post . metadata . title }
121
+ </ h1 >
122
+ < div className = "flex justify-between items-center mt-2 mb-8 text-sm max-w-[650px]" >
123
+ < Suspense fallback = { < p className = "h-5" /> } >
124
+ < p className = "text-sm text-neutral-600 dark:text-neutral-400" >
125
+ { formatDate ( post . metadata . publishedAt ) }
126
+ </ p >
127
+ </ Suspense >
128
+ { /* <Suspense fallback={<p className="h-5" />}>
129
+ <Views slug={post.slug} />
130
+ </Suspense> */ }
131
+ </ div >
132
+ < div className = "prose prose-quoteless prose-neutral dark:prose-invert" >
133
+ < MarkdownRenderer content = { post . content } />
134
+ </ div >
135
+ </ section >
136
+ </ article >
137
+ ) ;
138
+ }
139
+
140
+ // let incrementViews = cache(increment);
141
+
142
+ // async function Views({ slug }: { slug: string }) {
143
+ // let views = await getViewsCount();
144
+ // incrementViews(slug);
145
+ // return <ViewCounter allViews={views} slug={slug} />;
146
+ // }
0 commit comments