Skip to content

Commit 5a1d73a

Browse files
committed
Link library from the homepage
1 parent 751fc32 commit 5a1d73a

File tree

6 files changed

+115
-60
lines changed

6 files changed

+115
-60
lines changed

components/Book/Book.module.css

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
.Details {
2+
display: flex;
3+
flex-direction: column;
4+
gap: 0.25rem;
5+
}
6+
7+
.Title {
8+
font-weight: 500;
9+
}
10+
11+
.Author {
12+
color: var(--c-gray-11);
13+
}
14+
15+
.Date {
16+
font-size: var(--fs-s);
17+
18+
color: var(--c-gray-11);
19+
}

components/Book/index.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import Image from "next/image";
2+
import React, { useState } from "react";
3+
4+
import { Book as BookData } from "@/cms/models/Book";
5+
6+
import styles from "./Book.module.css";
7+
8+
export type BookProps = {
9+
as?: keyof React.JSX.IntrinsicElements;
10+
book: BookData;
11+
};
12+
13+
export function Book({ as = "div", book }: Readonly<BookProps>) {
14+
const Komponent = as;
15+
16+
const [now] = useState(() => Date.now());
17+
18+
const yearsAgo = (date: Date) => {
19+
return new Intl.RelativeTimeFormat("en", { numeric: "auto" }).format(
20+
-Math.floor((now - date.getTime()) / (1000 * 60 * 60 * 24 * 30 * 12)),
21+
"year",
22+
);
23+
};
24+
25+
return (
26+
<Komponent>
27+
<Image
28+
src={book.image}
29+
alt={`Cover of the book ${book.title}`}
30+
width={230}
31+
height={345}
32+
style={{ objectFit: "contain" }}
33+
/>
34+
35+
<dl className={styles.Details}>
36+
<dt className="sr-only">Title</dt>
37+
<dd className={styles.Title}>{book.title}</dd>
38+
39+
<dt className="sr-only">Author</dt>
40+
<dd className={styles.Author}>{book.author}</dd>
41+
42+
<dt className="sr-only">Read At</dt>
43+
<dd className={styles.Date}>last read {yearsAgo(new Date(book.readAt))}</dd>
44+
</dl>
45+
</Komponent>
46+
);
47+
}

pages/index.tsx

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ import { GetStaticProps } from "next";
33
import Image from "next/image";
44

55
import { ApiArticle } from "@/cms/api/ApiArticle";
6-
import { getBlogpostRepository, getNotesRepository } from "@/cms/repositories";
6+
import { Book } from "@/cms/models/Book";
7+
import { getBlogpostRepository, getBookRepository, getNotesRepository } from "@/cms/repositories";
8+
import { Book as BookThumbnail } from "@/components/Book";
79
import { Heading } from "@/components/Heading";
810
import { Link } from "@/components/Link";
911
import { PostThumbnail } from "@/components/PostThumbnail";
@@ -13,9 +15,10 @@ import { isDevelopment } from "@/lib/env";
1315

1416
type HomepageProps = {
1517
publications: ApiArticle[];
18+
books: Book[];
1619
};
1720

18-
export default function Homepage({ publications }: HomepageProps) {
21+
export default function Homepage({ publications, books }: Readonly<HomepageProps>) {
1922
return (
2023
<Application hideBackLink>
2124
<section className="Homepage">
@@ -39,7 +42,7 @@ export default function Homepage({ publications }: HomepageProps) {
3942
</Text>
4043

4144
<Heading el="h2" size="xl" className="Homepage__Heading">
42-
Latest publications
45+
Recent writing
4346
</Heading>
4447

4548
{publications.map((pub) => (
@@ -50,6 +53,30 @@ export default function Homepage({ publications }: HomepageProps) {
5053
Fancy reading more? Don’t miss either the <Link href="/blog">blog</Link> or the{" "}
5154
<Link href="/notes">notes</Link>!
5255
</Text>
56+
57+
<Heading el="h2" size="xl" className="Homepage__Heading">
58+
My library
59+
</Heading>
60+
61+
<Text size="m">
62+
I love reading, and over time I’ve built a collection of books that have shaped my thinking on software
63+
development in meaningful ways.
64+
</Text>
65+
66+
<Text size="m">
67+
<Link href="/library">My library</Link> spans technical foundations, craft practices, and broader
68+
perspectives, and it’s always growing!
69+
</Text>
70+
71+
<div className="Homepage__Books">
72+
{books.map((book) => (
73+
<BookThumbnail book={book} key={book.title} />
74+
))}
75+
</div>
76+
77+
<Text className="Homepage__ReadMore">
78+
Don’t forget to check out <Link href="/library">the full library!</Link>
79+
</Text>
5380
</div>
5481
</section>
5582
</Application>
@@ -59,12 +86,18 @@ export default function Homepage({ publications }: HomepageProps) {
5986
export const getStaticProps: GetStaticProps<HomepageProps> = async () => {
6087
const blogposts = await getBlogpostRepository().all({ drafts: isDevelopment() });
6188
const notes = await getNotesRepository().all({ drafts: isDevelopment() });
89+
const books = getBookRepository().all();
6290

6391
const publications = orderBy([...blogposts, ...notes], (article) => article.getDate(), "desc").slice(0, 5);
92+
const foundationalBooks = books.filter((book) => book.category === "foundational");
93+
const craftBooks = books.filter((book) => book.category === "craft");
6494

6595
return {
6696
props: {
6797
publications: publications.map((pub) => pub.toApiArticle()),
98+
99+
// Prioritize foundational books, then craft books
100+
books: [...foundationalBooks, ...craftBooks].slice(0, 6),
68101
},
69102
};
70103
};

pages/library.tsx

Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { GetStaticProps } from "next";
2-
import Image from "next/image";
3-
import { useState } from "react";
42

53
import { Book } from "@/cms/models/Book";
64
import { getBookRepository } from "@/cms/repositories";
5+
import { Book as BookThumbnail } from "@/components/Book";
76
import { Heading } from "@/components/Heading";
87
import { Link } from "@/components/Link";
98
import { Text } from "@/components/Text";
@@ -26,41 +25,11 @@ export function LibrarySectionDescription(props: Readonly<React.PropsWithChildre
2625
}
2726

2827
export function LibrarySectionBooks(props: Readonly<{ books: Book[] }>) {
29-
const [now] = useState(() => Date.now());
30-
31-
const yearsAgo = (date: Date) => {
32-
return new Intl.RelativeTimeFormat("en", { numeric: "auto" }).format(
33-
-Math.floor((now - date.getTime()) / (1000 * 60 * 60 * 24 * 30 * 12)),
34-
"year",
35-
);
36-
};
37-
3828
return (
3929
<ul className="LibrarySection__Books">
40-
{props.books.map((book) => {
41-
return (
42-
<li key={book.title}>
43-
<Image
44-
src={book.image}
45-
alt={`Cover of the book ${book.title}`}
46-
width={230}
47-
height={345}
48-
style={{ objectFit: "contain" }}
49-
/>
50-
51-
<dl className="LibrarySection__Books__Details">
52-
<dt className="sr-only">Title</dt>
53-
<dd className="LibrarySection__Book__Title">{book.title}</dd>
54-
55-
<dt className="sr-only">Author</dt>
56-
<dd className="LibrarySection__Book__Author">{book.author}</dd>
57-
58-
<dt className="sr-only">Read At</dt>
59-
<dd className="LibrarySection__Book__Date">last read {yearsAgo(new Date(book.readAt))}</dd>
60-
</dl>
61-
</li>
62-
);
63-
})}
30+
{props.books.map((book) => (
31+
<BookThumbnail as="li" book={book} key={book.title} />
32+
))}
6433
</ul>
6534
);
6635
}

styles/pages/index.css

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,21 @@
1212
}
1313

1414
.Homepage__Heading {
15-
margin-bottom: 1em;
16-
margin-top: 1.5em;
15+
margin-bottom: 1rem;
16+
margin-top: 2rem;
1717
}
1818

1919
.Homepage__Publication:not(:first-of-type) {
2020
margin-top: 1rem;
2121
}
2222

23+
.Homepage__Books {
24+
display: grid;
25+
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
26+
gap: 1.5rem;
27+
margin-top: 1.5rem;
28+
}
29+
2330
.Homepage__ReadMore {
2431
margin-top: 2em;
2532
}

styles/pages/library.css

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,6 @@
1010
list-style-type: none;
1111
}
1212

13-
.LibrarySection__Books__Details {
14-
display: flex;
15-
flex-direction: column;
16-
gap: 0.25rem;
17-
}
18-
19-
.LibrarySection__Book__Title {
20-
font-weight: 500;
21-
}
22-
23-
.LibrarySection__Book__Author {
24-
color: var(--c-gray-11);
25-
}
26-
27-
.LibrarySection__Book__Date {
28-
font-size: var(--fs-s);
29-
30-
color: var(--c-gray-11);
31-
}
32-
3313
.Library__Footer::before {
3414
content: "--";
3515

0 commit comments

Comments
 (0)