Skip to content

Commit 756e950

Browse files
committed
separate path for archived posts
The previous approach (tabs) doesn't preserve URL path for archived posts and therefore doesn't provide basic web browsing experiences such as history-back. While improving this, it also removes various duplications used to filter posts. Also, this makes the blog page faster because less initial data is loaded for entry.
1 parent 3987e81 commit 756e950

File tree

6 files changed

+97
-57
lines changed

6 files changed

+97
-57
lines changed

pages/blog.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import BlogRes from "src/Blog.mjs";
22

3-
export { getStaticProps } from "src/Blog.mjs";
3+
export { getStaticProps_All as getStaticProps } from "src/Blog.mjs";
44

55
export default function Blog(props) {
66
return <BlogRes {...props} />

pages/blog/archived.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import BlogRes from "src/Blog.mjs";
2+
3+
export { getStaticProps_Archived as getStaticProps } from "src/Blog.mjs";
4+
5+
export default function Blog(props) {
6+
return <BlogRes {...props} />
7+
}

src/Blog.res

Lines changed: 36 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -39,44 +39,34 @@ module Badge = {
3939
</div>
4040
}
4141
}
42-
module CategorySelector = {
43-
type selection =
44-
| All
45-
| Archived
4642

47-
let renderTab = (~text: string, ~isActive: bool, ~onClick) => {
48-
let active = "bg-gray-20 text-gray-80 rounded py-1"
49-
<div
50-
key=text
51-
onClick
52-
className={(
53-
isActive ? active : "hover:cursor-pointer bg-white hover:text-gray-80"
54-
) ++ " px-4 inline-block"}>
55-
{React.string(text)}
56-
</div>
57-
}
43+
type category =
44+
| /** Actually only unarchived */ All
45+
| Archived
5846

47+
module CategorySelector = {
5948
@react.component
60-
let make = (~selected: selection, ~onSelected: selection => unit) => {
49+
let make = (~selected: category) => {
6150
let tabs = [All, Archived]
6251

6352
<div className="text-16 w-full flex items-center justify-between text-gray-60">
64-
{Belt.Array.map(tabs, tab => {
65-
let onClick = evt => {
66-
evt->ReactEvent.Mouse.preventDefault
67-
onSelected(tab)
68-
}
69-
53+
{tabs
54+
->Belt.Array.map(tab => {
7055
// Deep comparison here!
7156
let isActive = selected == tab
72-
73-
let text = switch tab {
74-
| All => "All"
75-
| Archived => "Archived"
57+
let text = (tab :> string)
58+
let href = switch tab {
59+
| All => "/blog"
60+
| Archived => "/blog/archived"
7661
}
77-
78-
renderTab(~isActive, ~text, ~onClick)
79-
})->React.array}
62+
let className =
63+
switch isActive {
64+
| true => "bg-gray-20 text-gray-80 rounded py-1"
65+
| false => "hover:cursor-pointer bg-white hover:text-gray-80"
66+
} ++ " px-4 inline-block"
67+
<Link key=text href className> {React.string(text)} </Link>
68+
})
69+
->React.array}
8070
</div>
8171
}
8272
}
@@ -209,15 +199,10 @@ module FeatureCard = {
209199

210200
type params = {slug: string}
211201

212-
type props = {
213-
posts: array<BlogApi.post>,
214-
archived: array<BlogApi.post>,
215-
}
202+
type props = {posts: array<BlogApi.post>, category: category}
216203

217204
let default = (props: props): React.element => {
218-
let {posts, archived} = props
219-
220-
let (currentSelection, setSelection) = React.useState(() => CategorySelector.All)
205+
let {posts, category} = props
221206

222207
let content = if Belt.Array.length(posts) === 0 {
223208
/* <div> {React.string("Currently no posts available")} </div>; */
@@ -226,16 +211,11 @@ let default = (props: props): React.element => {
226211
<Markdown.Warn> {React.string("This blog is currently in the works.")} </Markdown.Warn>
227212
</div>
228213
} else {
229-
let filtered = switch currentSelection {
230-
| All => posts
231-
| Archived => archived
232-
}
233-
234-
let result = switch Belt.Array.length(filtered) {
214+
let result = switch Belt.Array.length(posts) {
235215
| 0 => <div> {React.string("No posts for this category available...")} </div>
236216
| _ =>
237-
let first = Belt.Array.getExn(filtered, 0)
238-
let rest = Js.Array2.sliceFrom(filtered, 1)
217+
let first = Belt.Array.getExn(posts, 0)
218+
let rest = Js.Array2.sliceFrom(posts, 1)
239219

240220
let featureBox =
241221
<div className="w-full mb-24 lg:px-8 xl:px-0">
@@ -280,9 +260,7 @@ let default = (props: props): React.element => {
280260
<>
281261
<div className="hidden sm:flex justify-center ">
282262
<div className="my-16 w-full" style={ReactDOMStyle.make(~maxWidth="12rem", ())}>
283-
<CategorySelector
284-
onSelected={selection => setSelection(_ => selection)} selected=currentSelection
285-
/>
263+
<CategorySelector selected=category />
286264
</div>
287265
</div>
288266
result
@@ -316,12 +294,19 @@ let default = (props: props): React.element => {
316294
</>
317295
}
318296

319-
let getStaticProps: Next.GetStaticProps.t<props, params> = async _ctx => {
320-
let (archived, nonArchived) = BlogApi.getAllPosts()->Belt.Array.partition(data => data.archived)
297+
let getStaticProps_All: Next.GetStaticProps.t<props, params> = async _ctx => {
298+
let props = {
299+
posts: BlogApi.getLivePosts(),
300+
category: All,
301+
}
302+
303+
{"props": props}
304+
}
321305

306+
let getStaticProps_Archived: Next.GetStaticProps.t<props, params> = async _ctx => {
322307
let props = {
323-
posts: nonArchived,
324-
archived,
308+
posts: BlogApi.getArchivedPosts(),
309+
category: Archived,
325310
}
326311

327312
{"props": props}

src/Blog.resi

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ let defaultPreviewImg: string
33
type params
44
type props
55

6+
type category = All | Archived
7+
68
let default: props => React.element
79

8-
let getStaticProps: Next.GetStaticProps.t<props, params>
10+
let getStaticProps_All: Next.GetStaticProps.t<props, params>
11+
let getStaticProps_Archived: Next.GetStaticProps.t<props, params>

src/common/BlogApi.res

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,14 @@ let blogPathToSlug = path => {
4242
path->Js.String2.replaceByRe(%re(`/^(archive\/)?\d\d\d\d-\d\d-\d\d-(.+)\.mdx$/`), "$2")
4343
}
4444

45+
let mdxFiles = dir => {
46+
Node.Fs.readdirSync(dir)->Js.Array2.filter(path => Node.Path.extname(path) === ".mdx")
47+
}
48+
4549
let getAllPosts = () => {
4650
let postsDirectory = Node.Path.join2(Node.Process.cwd(), "_blogposts")
4751
let archivedPostsDirectory = Node.Path.join2(postsDirectory, "archive")
4852

49-
let mdxFiles = dir => {
50-
Node.Fs.readdirSync(dir)->Js.Array2.filter(path => Node.Path.extname(path) === ".mdx")
51-
}
52-
5353
let nonArchivedPosts = mdxFiles(postsDirectory)->Js.Array2.map(path => {
5454
let {GrayMatter.data: data} =
5555
Node.Path.join2(postsDirectory, path)->Node.Fs.readFileSync->GrayMatter.matter
@@ -81,6 +81,49 @@ let getAllPosts = () => {
8181
})
8282
}
8383

84+
let getLivePosts = () => {
85+
let postsDirectory = Node.Path.join2(Node.Process.cwd(), "_blogposts")
86+
87+
let livePosts = mdxFiles(postsDirectory)->Js.Array2.map(path => {
88+
let {GrayMatter.data: data} =
89+
Node.Path.join2(postsDirectory, path)->Node.Fs.readFileSync->GrayMatter.matter
90+
switch BlogFrontmatter.decode(data) {
91+
| Error(msg) => Js.Exn.raiseError(msg)
92+
| Ok(d) => {
93+
path,
94+
frontmatter: d,
95+
archived: false,
96+
}
97+
}
98+
})
99+
100+
livePosts->Js.Array2.sortInPlaceWith((a, b) => {
101+
String.compare(Node.Path.basename(b.path), Node.Path.basename(a.path))
102+
})
103+
}
104+
105+
let getArchivedPosts = () => {
106+
let postsDirectory = Node.Path.join2(Node.Process.cwd(), "_blogposts")
107+
let archivedPostsDirectory = Node.Path.join2(postsDirectory, "archive")
108+
109+
let archivedPosts = mdxFiles(archivedPostsDirectory)->Js.Array2.map(path => {
110+
let {GrayMatter.data: data} =
111+
Node.Path.join2(archivedPostsDirectory, path)->Node.Fs.readFileSync->GrayMatter.matter
112+
switch BlogFrontmatter.decode(data) {
113+
| Error(msg) => Js.Exn.raiseError(msg)
114+
| Ok(d) => {
115+
path: Node.Path.join2("archive", path),
116+
frontmatter: d,
117+
archived: true,
118+
}
119+
}
120+
})
121+
122+
archivedPosts->Js.Array2.sortInPlaceWith((a, b) => {
123+
String.compare(Node.Path.basename(b.path), Node.Path.basename(a.path))
124+
})
125+
}
126+
84127
module RssFeed = {
85128
// Module inspired by
86129
// https://gist.github.com/fredrikbergqvist/36704828353ebf5379a5c08c7583fe2d

src/common/BlogApi.resi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ type post = {
55
}
66

77
let getAllPosts: unit => array<post>
8+
let getLivePosts: unit => array<post>
9+
let getArchivedPosts: unit => array<post>
810
let blogPathToSlug: string => string
911

1012
module RssFeed: {

0 commit comments

Comments
 (0)