11import dayjs from 'dayjs' ;
2- import { motion } from 'framer-motion' ;
2+ import { AnimatePresence , motion } from 'framer-motion' ;
33import fs from 'fs' ;
44import matter from 'gray-matter' ;
55import { GetStaticPaths , GetStaticProps } from 'next' ;
6+ import Image from 'next/image' ;
67import Link from 'next/link' ;
78import { useRouter } from 'next/router' ;
89import wordsCount from 'words-count' ;
@@ -38,109 +39,122 @@ interface BlogProps {
3839 } ;
3940}
4041
41- // The Author Page Content
4242const Author : React . FC < BlogProps > = ( { filteredBlogList, authorInfo } ) => {
4343 const router = useRouter ( ) ;
4444 const { author } = router . query ;
4545
4646 return (
47- < section className = "relative mx-auto mt-20 flex h-full w-full max-w-screen-lg flex-col overflow-hidden px-5 sm:px-10 sm:py-10 " >
47+ < div className = "relative pt-24 " >
4848 < Seo
4949 templateTitle = { `${ authorInfo . name } - Authors` }
5050 templateUrl = { `https://fairdataihub.org/authors/${ author } ` }
5151 templateDescription = { `Blog posts by ${ authorInfo . name } at FAIR Data Innovations Hub.` }
5252 templateImage = "https://fairdataihub.org/thumbnails/index.png"
5353 />
5454
55- < div className = "mb-5 px-2 pt-5 sm:pt-0 md:px-7" >
56- < h1 className = "mb-2 text-left text-4xl font-bold sm:text-4xl" >
57- { filteredBlogList . length }
58- { ` ` }
59- { filteredBlogList . length === 1 ? `post` : `posts` } { ` ` }
60- { `written by` } { ` ` }
61- { authorInfo . name }
62- </ h1 >
63- < Link
64- href = { authorInfo . href }
65- passHref
66- className = "text-url cursor-pointer hover:underline"
67- target = { authorInfo . external ? `_blank` : `_self` }
68- rel = { authorInfo . external ? `noopener noreferrer` : undefined }
69- >
70- < h2 className = "text-url cursor-pointer text-left hover:underline" >
71- View profile
72- </ h2 >
73- </ Link >
55+ < div aria-hidden className = "pointer-events-none fixed inset-0 -z-10" >
56+ < div className = "absolute top-0 left-1/2 h-180 w-250 -translate-x-1/2 bg-[radial-gradient(ellipse_at_center,rgba(211,75,171,0.30),rgba(211,75,171,0.12)_40%,transparent_75%)] blur-3xl" />
7457 </ div >
7558
76- < hr className = "mx-6 my-2 border-dashed border-slate-200" />
77-
78- { filteredBlogList . map ( ( post , idx ) => {
79- const { slug, frontMatter, timeToRead } = post ;
80-
81- return (
82- < motion . div
83- key = { slug }
84- layout
85- className = "my-2"
86- initial = { { opacity : 0 , y : 20 , scale : 0.95 } }
87- whileInView = { {
88- opacity : 1 ,
89- y : 0 ,
90- scale : 1 ,
91- transition : {
92- duration : 0.2 ,
93- delay : idx * 0.02 ,
94- ease : `easeOut` ,
95- } ,
96- } }
97- viewport = { {
98- once : true ,
99- amount : 0.1 ,
100- margin : `0px 0px 150px 0px` ,
101- } }
102- exit = { { opacity : 0 , y : 10 , scale : 0.98 } }
103- >
104- < BlogListItem
105- slug = { slug }
106- title = { frontMatter . title }
107- subtitle = { frontMatter . subtitle }
108- date = { frontMatter . date }
109- timeToRead = { timeToRead }
110- heroImage = { frontMatter . heroImage }
111- imageAuthor = { frontMatter . imageAuthor }
112- tags = { frontMatter . tags }
113- category = { frontMatter . category }
114- />
115- </ motion . div >
116- ) ;
117- } ) }
118- </ section >
59+ < section className = "container mx-auto max-w-7xl px-4 pt-8 pb-16" >
60+ < motion . header
61+ initial = { { opacity : 0 , y : 10 } }
62+ animate = { { opacity : 1 , y : 0 } }
63+ transition = { { duration : 0.4 , ease : `easeOut` } }
64+ className = "mb-8 sm:mb-10"
65+ >
66+ < div className = "flex items-center gap-4 sm:gap-5" >
67+ < div className = "relative h-16 w-16 shrink-0 overflow-hidden rounded-full ring-2 ring-slate-200 sm:h-20 sm:w-20" >
68+ < Image
69+ src = { authorInfo . avatar }
70+ alt = { authorInfo . name }
71+ fill
72+ sizes = "(min-width:640px) 80px, 64px"
73+ className = "object-cover"
74+ />
75+ </ div >
76+
77+ < div >
78+ < h1 className = "text-3xl font-black tracking-tight text-stone-900 sm:text-4xl dark:text-stone-100" >
79+ { filteredBlogList . length }
80+ { ` ` }
81+ { filteredBlogList . length === 1 ? `post` : `posts` } by{ ` ` }
82+ { authorInfo . name }
83+ </ h1 >
84+ < Link
85+ href = { authorInfo . href }
86+ passHref
87+ className = "text-url cursor-pointer text-sm hover:underline"
88+ target = { authorInfo . external ? `_blank` : `_self` }
89+ rel = { authorInfo . external ? `noopener noreferrer` : undefined }
90+ >
91+ View profile
92+ </ Link >
93+ </ div >
94+ </ div >
95+
96+ < div className = "via-primary/60 mt-6 h-px w-full bg-linear-to-r from-transparent to-transparent" />
97+ </ motion . header >
98+
99+ < AnimatePresence mode = "popLayout" >
100+ < motion . ul layout initial = { false } className = "list-none space-y-4" >
101+ { filteredBlogList . map ( ( { slug, frontMatter, timeToRead } , idx ) => (
102+ < motion . div
103+ key = { slug }
104+ layout
105+ initial = { { opacity : 0 , y : 20 , scale : 0.95 } }
106+ whileInView = { {
107+ opacity : 1 ,
108+ y : 0 ,
109+ scale : 1 ,
110+ transition : {
111+ duration : 0.2 ,
112+ delay : idx * 0.02 ,
113+ ease : `easeOut` ,
114+ } ,
115+ } }
116+ viewport = { {
117+ once : true ,
118+ amount : 0.1 ,
119+ margin : `0px 0px 150px 0px` ,
120+ } }
121+ exit = { { opacity : 0 , y : 10 , scale : 0.98 } }
122+ >
123+ < BlogListItem
124+ slug = { slug }
125+ title = { frontMatter . title }
126+ subtitle = { frontMatter . subtitle }
127+ date = { frontMatter . date }
128+ timeToRead = { timeToRead }
129+ heroImage = { frontMatter . heroImage }
130+ imageAuthor = { frontMatter . imageAuthor }
131+ tags = { frontMatter . tags }
132+ category = { frontMatter . category }
133+ authors = { frontMatter . authors }
134+ />
135+ </ motion . div >
136+ ) ) }
137+ </ motion . ul >
138+ </ AnimatePresence >
139+ </ section >
140+ </ div >
119141 ) ;
120142} ;
121143
122144export const getStaticPaths : GetStaticPaths = async ( ) => {
123- // Get the posts from the `blog` directory
124145 const files = fs . readdirSync ( `./blog` ) ;
125146
126147 const blogList = files . map ( ( fileName ) => {
127- // Read the raw content of the file and parse the frontMatter
128148 const rawFileContent = fs . readFileSync ( `blog/${ fileName } ` , `utf-8` ) ;
129-
130149 const { data : frontMatter } = matter ( rawFileContent ) ;
131-
132- return {
133- frontMatter,
134- } ;
150+ return { frontMatter } ;
135151 } ) ;
136152
137153 const authorsList : string [ ] = [ ] ;
138154
139155 for ( const post of blogList ) {
140156 const { frontMatter } = post ;
141-
142157 const { authors } = frontMatter ;
143-
144158 if ( authors ) {
145159 authors . forEach ( ( author : string ) => {
146160 if ( ! authorsList . includes ( author ) ) {
@@ -150,67 +164,36 @@ export const getStaticPaths: GetStaticPaths = async () => {
150164 }
151165 }
152166
153- const paths = [ ] ;
154-
155- for ( const author of authorsList ) {
156- paths . push ( {
157- params : {
158- author,
159- } ,
160- } ) ;
161- }
167+ const paths = authorsList . map ( ( author ) => ( { params : { author } } ) ) ;
162168
163- return {
164- paths,
165- fallback : false ,
166- } ;
169+ return { paths, fallback : false } ;
167170} ;
168171
169172export const getStaticProps : GetStaticProps = async ( { params } ) => {
170- // Get the posts from the `blog` directory
171173 const files = fs . readdirSync ( `./blog` ) ;
172174
173175 const blogList = files . map ( ( fileName ) => {
174- // Remove the .md extension and use the file name as the slug
175176 const slug = fileName . replace ( `.md` , `` ) ;
176-
177- // Read the raw content of the file and parse the frontMatter
178177 const rawFileContent = fs . readFileSync ( `blog/${ fileName } ` , `utf-8` ) ;
179178 const timeToRead = Math . ceil ( wordsCount ( rawFileContent ) / 265 ) ;
180-
181179 const { data : frontMatter } = matter ( rawFileContent ) ;
182-
183- return {
184- slug,
185- frontMatter,
186- timeToRead,
187- } ;
180+ return { slug, frontMatter, timeToRead } ;
188181 } ) ;
189182
190- // sort the posts by date in descending order
191183 blogList . sort ( ( a , b ) => {
192184 const a_date : any = dayjs ( a . frontMatter . date , `YYYY-MM-DD` ) ;
193185 const b_date : any = dayjs ( b . frontMatter . date , `YYYY-MM-DD` ) ;
194-
195186 return b_date - a_date ;
196187 } ) ;
197188
198189 const filteredBlogList = blogList . filter ( ( post ) => {
199190 const { authors } = post . frontMatter ;
200-
201191 return authors && authors . includes ( params ?. author as string ) ;
202192 } ) ;
203193
204- // Get author information
205194 const authorInfo = authorsJSON [ params ?. author as string ] ;
206195
207- // Return the posts data to the page as props
208- return {
209- props : {
210- filteredBlogList,
211- authorInfo,
212- } ,
213- } ;
196+ return { props : { filteredBlogList, authorInfo } } ;
214197} ;
215198
216199export default Author ;
0 commit comments