1
- 'use client' ;
2
-
3
- import React , { useEffect } from 'react' ;
4
- import { usePathname } from 'next/navigation' ;
5
- import PageContent from ' @/components/page-content' ;
6
- import Projects from ' @/components/portfolio/projects' ;
7
- import { initializeCustomSelect , filterItemsByCategory } from ' @/lib/utils/dom-utils' ;
8
- import config from ' @/config' ;
9
-
10
- const { title } = config ;
1
+ import Link from "next/link" ;
2
+ import Image from "next/image" ;
3
+ import PageHeader from "@/components/page-header" ;
4
+ import FilterSelectBox from "@/components/portfolio/v2/filter-select-box" ;
5
+ import FilterList from " @/components/portfolio/v2/filter-list" ;
6
+ import MarkdownRenderer from " @/components/markdown/markdown-renderer" ;
7
+ import { getPortfolioPosts } from " @/lib/db/portfolio" ;
8
+ import config from " @/config" ;
9
+ import { LuEye } from "react-icons/lu" ;
10
+ import "react-loading-skeleton/dist/skeleton.css" ;
11
11
12
12
/**
13
13
* TODO: #257
@@ -17,28 +17,104 @@ const { title } = config;
17
17
* };
18
18
*/
19
19
20
- const Portfolio = ( ) => {
21
- const pathname = usePathname ( ) ;
20
+ const { title } = config ;
21
+ const POSTS_PER_PAGE = 9 ;
22
+
23
+ export const metadata = {
24
+ title : `Portfolio | ${ title } ` ,
25
+ description : "Read my thoughts on software development, design, and more." ,
26
+ } ;
27
+
28
+ export default function Portfolio ( {
29
+ searchParams,
30
+ } : {
31
+ searchParams : { tag ?: string ; page ?: string } ;
32
+ } ) {
33
+ let allBlogs = getPortfolioPosts ( ) ;
34
+ const blogTags = [
35
+ "All" ,
36
+ ...Array . from (
37
+ new Set ( allBlogs . map ( ( post ) => post . metadata . category ?? "" ) )
38
+ ) ,
39
+ ] ;
40
+ const selectedTag = searchParams . tag || "All" ;
41
+ const currentPage = parseInt ( searchParams . page || "1" , 10 ) ;
22
42
23
- useEffect ( ( ) => {
24
- initializeCustomSelect ( filterItemsByCategory ) ;
25
- } , [ ] ) ;
43
+ // Filter blogs based on the selected tag
44
+ const filteredBlogs =
45
+ selectedTag === "All"
46
+ ? allBlogs
47
+ : allBlogs . filter ( ( post ) => post . metadata . category === selectedTag ) ;
48
+
49
+ // Sort blogs by date
50
+ const sortedBlogs = filteredBlogs . sort ( ( a , b ) => {
51
+ if ( new Date ( a . metadata . publishedAt ) > new Date ( b . metadata . publishedAt ) ) {
52
+ return - 1 ;
53
+ }
54
+ return 1 ;
55
+ } ) ;
56
+
57
+ // Calculate total pages
58
+ const totalPages = Math . ceil ( sortedBlogs . length / POSTS_PER_PAGE ) ;
59
+
60
+ // Get blogs for current page
61
+ const paginatedBlogs = sortedBlogs . slice (
62
+ ( currentPage - 1 ) * POSTS_PER_PAGE ,
63
+ currentPage * POSTS_PER_PAGE
64
+ ) ;
26
65
27
66
return (
28
- /**
29
- * TODO: #257
30
- * update the document title see (#341)
31
- */
32
- < PageContent
33
- documentTitle = 'Portfolio'
34
- title = { title }
35
- header = "Hugo's Portfolio"
36
- page = "portfolio"
37
- pathName = { pathname }
38
- >
39
- < Projects />
40
- </ PageContent >
67
+ < article >
68
+ < PageHeader header = "Hugo's Portfolio" />
69
+ < section className = "projects" >
70
+ < FilterList selectedTag = { selectedTag } blogTags = { blogTags } />
71
+ < FilterSelectBox selectedTag = { selectedTag } blogTags = { blogTags } />
72
+ < ul className = "project-list" >
73
+ { paginatedBlogs . map ( ( post , index ) => (
74
+ < li
75
+ key = { index }
76
+ className = "project-item active"
77
+ data-category = { post . metadata . category }
78
+ >
79
+ < Link href = { `/portfolio/${ post . slug } ` } rel = "noopener noreferrer" >
80
+ < figure className = "project-img" >
81
+ < div className = "project-item-icon-box" >
82
+ < LuEye />
83
+ </ div >
84
+ < Image
85
+ src = { post . metadata . banner }
86
+ alt = { post . metadata . alt || "Portfolio post image" }
87
+ width = { 1600 }
88
+ height = { 900 }
89
+ priority = { true }
90
+ placeholder = "empty"
91
+ loading = "eager"
92
+ />
93
+ </ figure >
94
+ < h3 className = "project-title" > < MarkdownRenderer content = { post . metadata . title } /> </ h3 >
95
+ < p className = "project-category" > { post . metadata . category } </ p >
96
+ </ Link >
97
+ </ li >
98
+ ) ) }
99
+ </ ul >
100
+ < div className = "pagination" >
101
+ { Array . from ( { length : totalPages } , ( _ , i ) => i + 1 ) . map (
102
+ ( pageNum ) => (
103
+ < Link
104
+ key = { pageNum }
105
+ href = { {
106
+ pathname : "/portfolio" ,
107
+ query : { ...searchParams , page : pageNum . toString ( ) } ,
108
+ } }
109
+ className = { `pagination-btn ${ pageNum === currentPage ? "active" : ""
110
+ } `}
111
+ >
112
+ { pageNum }
113
+ </ Link >
114
+ )
115
+ ) }
116
+ </ div >
117
+ </ section >
118
+ </ article >
41
119
) ;
42
120
}
43
-
44
- export default Portfolio ;
0 commit comments