Skip to content

Commit e62dc41

Browse files
committed
refactor: post metadata handling and remove image preview features
1 parent 1ef8e99 commit e62dc41

21 files changed

+130
-389
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"lodash": "^4.17.21",
1818
"next": "^13.4.4",
1919
"notion-to-jsx": "^1.2.7",
20-
"notion-to-utils": "^1.0.2",
20+
"notion-to-utils": "^1.1.0",
2121
"p-map": "^7.0.2",
2222
"prismjs": "^1.30.0",
2323
"react": "^18.2.0",

pages/index.tsx

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,16 @@ import { GetStaticProps } from 'next';
44
import { categoriesAtom } from '@/atoms/categories';
55
import { postsAtom } from '@/atoms/posts';
66
import Home from '@/features/home';
7-
import { Category, Post } from '@/interfaces';
8-
import { parsePosts, getNotionPosts, getCategories } from '@/utils';
9-
import { getPreviewImages } from '@/utils';
7+
import { Category, PostMeta } from '@/interfaces';
8+
import { getPostsMeta, fetchNotionPostsMeta, getCategories } from '@/utils';
109
import { siteConfig } from 'site.config';
1110

1211
import PageHead from '@/components/common/PageHead';
1312

1413
import { REVALIDATE_TIME } from '@/assets/constants';
1514

1615
interface Props {
17-
posts: Post[];
16+
posts: PostMeta[];
1817
categories: Category[];
1918
}
2019
const HomePage = ({ posts, categories }: Props) => {
@@ -37,15 +36,13 @@ export const getStaticProps: GetStaticProps<Props> = async () => {
3736
if (!process.env.NOTION_POST_DATABASE_ID)
3837
throw new Error('NOTION_POST_DATABASE_ID is not defined');
3938

40-
const notionPostsResponse = await getNotionPosts(process.env.NOTION_POST_DATABASE_ID);
41-
const posts = parsePosts(notionPostsResponse);
42-
const postsWithPreview = await getPreviewImages(posts);
43-
39+
const notionPostsResponse = await fetchNotionPostsMeta(process.env.NOTION_POST_DATABASE_ID);
40+
const posts = getPostsMeta(notionPostsResponse);
4441
const categories = getCategories(notionPostsResponse);
4542

4643
return {
4744
props: {
48-
posts: postsWithPreview,
45+
posts,
4946
categories,
5047
},
5148
revalidate: REVALIDATE_TIME,

pages/posts/[slug].tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { ParsedUrlQuery } from 'querystring';
33
import { GetStaticPaths, GetStaticProps } from 'next';
44
import { NotionBlock, Renderer } from 'notion-to-jsx';
55

6-
import { getIdBySlug, getNotionPosts, getSlugs, notionClient } from '@/utils';
6+
import { fetchIdBySlug, fetchNotionPostsMeta, getSlugs, notionClient } from '@/utils';
77

88
import Giscus from '@/components/common/Giscus';
99
import PageHead from '@/components/common/PageHead';
@@ -50,7 +50,7 @@ interface PostParams extends ParsedUrlQuery {
5050

5151
export const getStaticProps: GetStaticProps<Props, PostParams> = async ({ params }) => {
5252
const { slug } = params as PostParams;
53-
const id = await getIdBySlug(slug as string, process.env.NOTION_POST_DATABASE_ID as string);
53+
const id = await fetchIdBySlug(slug as string, process.env.NOTION_POST_DATABASE_ID as string);
5454
const blocks = (await notionClient.getPageBlocks(id)) as NotionBlock[];
5555
const properties = await notionClient.getPageProperties(id);
5656

@@ -71,7 +71,7 @@ export const getStaticProps: GetStaticProps<Props, PostParams> = async ({ params
7171
export const getStaticPaths: GetStaticPaths = async () => {
7272
if (!process.env.NOTION_POST_DATABASE_ID)
7373
throw new Error('NOTION_POST_DATABASE_ID is not defined');
74-
const databaseItems = await getNotionPosts(process.env.NOTION_POST_DATABASE_ID);
74+
const databaseItems = await fetchNotionPostsMeta(process.env.NOTION_POST_DATABASE_ID);
7575
const slugs = getSlugs(databaseItems);
7676

7777
const paths = slugs.map((slug) => ({

pages/rss.xml.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { GetServerSideProps } from 'next';
2+
import RSS from 'rss';
23

3-
import { generateRssFeed, getNotionPosts } from '@/utils';
4+
import { GetPageResponse } from '@/interfaces';
5+
import { fetchNotionPostsMeta, getPostsMeta } from '@/utils';
6+
import { siteConfig } from 'site.config';
47

58
const Rss = () => {
69
return null;
@@ -9,7 +12,7 @@ const Rss = () => {
912
export const getServerSideProps: GetServerSideProps = async ({ res }) => {
1013
if (!process.env.NOTION_POST_DATABASE_ID)
1114
throw new Error('NOTION_POST_DATABASE_ID is not defined');
12-
const databaseItems = await getNotionPosts(process.env.NOTION_POST_DATABASE_ID);
15+
const databaseItems = await fetchNotionPostsMeta(process.env.NOTION_POST_DATABASE_ID);
1316

1417
res.setHeader('Content-Type', 'text/xml');
1518
res.write(generateRssFeed(databaseItems));
@@ -21,3 +24,26 @@ export const getServerSideProps: GetServerSideProps = async ({ res }) => {
2124
};
2225

2326
export default Rss;
27+
28+
const generateRssFeed = (notionPostsResponse: GetPageResponse[]) => {
29+
const feedOptions = {
30+
title: `${siteConfig.homeTitle} | ${siteConfig.blogName}`,
31+
description: siteConfig.seoDefaultDesc,
32+
site_url: siteConfig.url,
33+
feed_url: `${siteConfig.url}/rss.xml`,
34+
pubDate: new Date(),
35+
copyright: `All rights reserved ${new Date().getFullYear()}, Jinsoo`,
36+
};
37+
38+
const feed = new RSS(feedOptions);
39+
getPostsMeta(notionPostsResponse).forEach(({ title, description, slug, published }) => {
40+
feed.item({
41+
title,
42+
description,
43+
url: `${siteConfig.url}/posts/${slug}`,
44+
date: new Date(published),
45+
});
46+
});
47+
48+
return feed.xml();
49+
};

pages/sitemap.xml.ts

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1+
import dayjs from 'dayjs';
12
import { GetServerSideProps } from 'next';
3+
import { GetPageResponse } from 'notion-to-utils';
24

3-
import { generateSitemap, getNotionPosts } from '@/utils';
5+
import { PostMeta } from '@/interfaces';
6+
import { getPostsMeta, fetchNotionPostsMeta } from '@/utils';
7+
8+
type PostIdentifier = Pick<PostMeta, 'slug' | 'published'>;
49

510
const Sitemap = () => {
611
return null;
@@ -9,7 +14,7 @@ const Sitemap = () => {
914
export const getServerSideProps: GetServerSideProps = async ({ res }) => {
1015
if (!process.env.NOTION_POST_DATABASE_ID)
1116
throw new Error('NOTION_POST_DATABASE_ID is not defined');
12-
const databaseItems = await getNotionPosts(process.env.NOTION_POST_DATABASE_ID);
17+
const databaseItems = await fetchNotionPostsMeta(process.env.NOTION_POST_DATABASE_ID);
1318
res.setHeader('Content-Type', 'text/xml');
1419
res.write(generateSitemap(databaseItems));
1520
res.end();
@@ -20,3 +25,55 @@ export const getServerSideProps: GetServerSideProps = async ({ res }) => {
2025
};
2126

2227
export default Sitemap;
28+
29+
const generateSitemap = (notionPostsResponse: GetPageResponse[]) => {
30+
const paths: PostIdentifier[] = getSitemapPostIdentifiers(notionPostsResponse);
31+
32+
const urlSet = paths
33+
.map((path) => {
34+
return `
35+
<url>
36+
<loc>${process.env.BLOG_URL}/posts/${path.slug}</loc>
37+
<changefreq>daily</changefreq>
38+
<priority>1</priority>
39+
<lastmod>${path.published}</lastmod>
40+
</url>
41+
`;
42+
})
43+
.join('');
44+
45+
const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
46+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
47+
<url>
48+
<loc>${process.env.BLOG_URL}</loc>
49+
<changefreq>daily</changefreq>
50+
<priority>1</priority>
51+
<lastmod>${new Date().toISOString()}</lastmod>
52+
</url>
53+
<url>
54+
<loc>${process.env.BLOG_URL}/about</loc>
55+
<changefreq>daily</changefreq>
56+
<priority>1</priority>
57+
<lastmod>${new Date().toISOString()}</lastmod>
58+
</url>
59+
${urlSet}
60+
</urlset>
61+
`;
62+
63+
return sitemap;
64+
};
65+
66+
const getSitemapPostIdentifiers = (notionPostsResponse: GetPageResponse[]) => {
67+
const posts = getPostsMeta(notionPostsResponse);
68+
const postsMeta = posts
69+
.map((post) => {
70+
const { slug, published } = post;
71+
const formattedPublished = published ? dayjs(published).format('YYYY-MM-DD') : '';
72+
return { slug, published: formattedPublished };
73+
})
74+
.filter((postMeta: PostIdentifier | null): postMeta is PostIdentifier =>
75+
postMeta ? 'slug' in postMeta : false,
76+
);
77+
78+
return postsMeta;
79+
};

src/assets/constants.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,5 @@ export const INITIAL_CATEGORY = 'All';
1717

1818
export const DEFAULT_CATEGORY_COLOR: SelectColor = 'default';
1919

20-
export const DEFAULT_BLUR_BASE64 =
21-
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkqAcAAIUAgUW0RjgAAAAASUVORK5CYII=';
22-
2320
export const REVALIDATE_TIME = 60;
2421
export const IMAGE_MAX_AGE = 60 * 60;

src/atoms/posts/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ import { atom } from 'jotai';
22
import { atomWithReset } from 'jotai/utils';
33

44
import { selectedCategoryAtom } from '@/atoms/categories';
5-
import { Post } from '@/interfaces';
5+
import { PostMeta } from '@/interfaces';
66

77
import { INITIAL_CATEGORY } from '@/assets/constants';
88

9-
export const postsAtom = atom<Post[]>([]);
9+
export const postsAtom = atom<PostMeta[]>([]);
1010

11-
export const postsFilterByCategoryAtom = atom<Post[]>((get) => {
11+
export const postsFilterByCategoryAtom = atom<PostMeta[]>((get) => {
1212
const posts = get(postsAtom);
1313
const selectedCategory = get(selectedCategoryAtom);
1414

src/features/home/Intro/index.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import { HiMail } from 'react-icons/hi';
77

88
import { siteConfig } from 'site.config';
99

10-
import { DEFAULT_BLUR_BASE64 } from '@/assets/constants';
11-
1210
const profileImage = `/api/profile-image`;
1311

1412
const Intro = () => {
@@ -21,8 +19,6 @@ const Intro = () => {
2119
width={110}
2220
height={110}
2321
alt={'Intro Picture'}
24-
placeholder="blur"
25-
blurDataURL={DEFAULT_BLUR_BASE64}
2622
/>
2723
<section className="flex flex-col justify-around gap-1">
2824
<section className="flex flex-col gap-2">

src/features/home/PostList/Post/index.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import Image from 'next/image';
44
import Link from 'next/link';
55

66
import { calculate } from '@/features/home/PostList/Post/util';
7-
import { Post as Item } from '@/interfaces';
7+
import { PostMeta as Item } from '@/interfaces';
88
import { siteConfig } from 'site.config';
99

10-
import { COLOR_TABLE, DEFAULT_BLUR_BASE64 } from '@/assets/constants';
10+
import { COLOR_TABLE } from '@/assets/constants';
1111

1212
interface Props {
1313
item: Item;
@@ -16,7 +16,7 @@ interface Props {
1616
const Post = ({ item }: Props) => {
1717
const ref = useRef<HTMLDivElement>(null);
1818
const [onError, setOnError] = useState<boolean>(false);
19-
const { cover, description, published, category, title, slug, previewImage } = item;
19+
const { cover, description, published, category, title, slug } = item;
2020

2121
useEffect(() => {
2222
if (!ref.current) return;
@@ -58,8 +58,6 @@ const Post = ({ item }: Props) => {
5858
src={cover}
5959
alt={title}
6060
fill
61-
placeholder="blur"
62-
blurDataURL={previewImage?.dataURIBase64 || DEFAULT_BLUR_BASE64}
6361
onError={() => setOnError(true)}
6462
/>
6563
) : (

src/hooks/useInfiniteScroll.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { useMemo } from 'react';
22

33
import { useIntersectionObserver } from '@/hooks';
4-
import { Post } from '@/interfaces';
4+
import { PostMeta } from '@/interfaces';
55

66
interface Props {
7-
data: Post[];
7+
data: PostMeta[];
88
page: number;
99
pageSize?: number;
1010
intersectCb?: () => void;

0 commit comments

Comments
 (0)