@@ -3,7 +3,7 @@ import { GetStaticProps } from "next";
3
3
import { useRouter } from "next/router" ;
4
4
import Head from "next/head" ;
5
5
import TagIcon from "@heroicons/react/24/solid/TagIcon" ;
6
- import { motion , AnimatePresence } from "framer-motion" ;
6
+ import { motion , AnimatePresence , Variants } from "framer-motion" ;
7
7
import { useForm , useWatch } from "react-hook-form" ;
8
8
import { zodResolver } from "@hookform/resolvers/zod" ;
9
9
import { z } from "zod" ;
@@ -29,16 +29,16 @@ interface BlogPageProps {
29
29
30
30
const SORT_OPTIONS = [
31
31
{
32
- " direction" : "new" ,
33
- " name" : "Newest" ,
34
- " func" : ( a : IArticleBrief , b : IArticleBrief ) => {
32
+ direction : 1 ,
33
+ name : "Newest" ,
34
+ func : ( a : IArticleBrief , b : IArticleBrief ) => {
35
35
return new Date ( b . date ) . getTime ( ) - new Date ( a . date ) . getTime ( ) ;
36
36
}
37
37
} ,
38
38
{
39
- " direction" : "old" ,
40
- " name" : "Oldest" ,
41
- " func" : ( a : IArticleBrief , b : IArticleBrief ) => {
39
+ direction : 2 ,
40
+ name : "Oldest" ,
41
+ func : ( a : IArticleBrief , b : IArticleBrief ) => {
42
42
return new Date ( a . date ) . getTime ( ) - new Date ( b . date ) . getTime ( ) ;
43
43
}
44
44
}
@@ -47,12 +47,30 @@ const SORT_OPTIONS = [
47
47
const filterSchema = z . object ( {
48
48
search : z . string ( ) ,
49
49
sort : z . object ( {
50
- direction : z . union ( [ z . literal ( "new" ) , z . literal ( "old" ) ] ) ,
50
+ direction : z . union ( [ z . literal ( 1 ) , z . literal ( 2 ) ] ) ,
51
51
name : z . string ( ) ,
52
52
func : z . function ( z . tuple ( [ z . object ( { } ) , z . object ( { } ) ] ) , z . number ( ) )
53
53
} )
54
54
} ) ;
55
55
56
+ const NO_RESULTS_ANIM = {
57
+ in : {
58
+ opacity : 0
59
+ } ,
60
+ anim : {
61
+ opacity : 1 ,
62
+ transition : {
63
+ duration : 0.25
64
+ }
65
+ } ,
66
+ exit : {
67
+ opacity : 0 ,
68
+ transition : {
69
+ duration : 0.25
70
+ }
71
+ }
72
+ } as Variants ;
73
+
56
74
const filterSchemaResolver = zodResolver ( filterSchema ) ;
57
75
58
76
type FilterSchema = z . infer < typeof filterSchema > ;
@@ -99,7 +117,7 @@ const BlogPage: Page<BlogPageProps> = ({ articles, pathname }) => {
99
117
< Heading . H1 id = "blog" className = "text-center text-secondary" >
100
118
Blog
101
119
</ Heading . H1 >
102
- { computedArticles . length > 0 && < >
120
+ { articles . length > 0 && < >
103
121
< div className = "mx-0 sm:mx-16 md:mx-0 motion-safe:transition-[margin-inline] motion-safe:duration-500 flex gap-2 items-end" >
104
122
< div >
105
123
< Label htmlFor = "search-input" className = "text-secondary" >
@@ -149,13 +167,25 @@ const BlogPage: Page<BlogPageProps> = ({ articles, pathname }) => {
149
167
</ motion . div > }
150
168
</ AnimatePresence >
151
169
</ div >
152
- < ul className = "grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3" aria-label = "blog articles" >
170
+ < AnimatePresence >
171
+ { computedArticles . length <= 0 && < motion . p
172
+ role = "note"
173
+ className = "w-full text-2xl font-semibold text-center"
174
+ variants = { NO_RESULTS_ANIM }
175
+ initial = "in"
176
+ animate = "anim"
177
+ exit = "exit"
178
+ >
179
+ There are no blog posts that fit this criteria
180
+ </ motion . p > }
181
+ </ AnimatePresence >
182
+ < ul className = "grid w-full grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3" aria-label = "blog articles" >
153
183
< AnimatePresence >
154
184
{ computedArticles . map ( ( brief , i ) => < ArticleBrief key = { brief . url } { ...brief } imgLoading = { i > 3 ? "lazy" : "eager" } /> ) }
155
185
</ AnimatePresence >
156
186
</ ul >
157
187
</ > }
158
- { computedArticles . length < 1 && < p role = "note" className = "text-3xl font-semibold text-center" >
188
+ { articles . length <= 0 && < p role = "note" className = "text-2xl font-semibold text-center" >
159
189
There are no blog posts yet! Stay tuned!
160
190
</ p > }
161
191
</ main >
0 commit comments