From 48fd042078a97fec3c67f3eaef8b24455b469704 Mon Sep 17 00:00:00 2001 From: Shun Kakinoki Date: Sun, 7 Nov 2021 15:54:02 -0500 Subject: [PATCH 1/5] chore: update --- src/components/Clock/Clock.tsx | 2 +- src/components/Clock/index.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/Clock/Clock.tsx b/src/components/Clock/Clock.tsx index cfc5298e..4024befa 100644 --- a/src/components/Clock/Clock.tsx +++ b/src/components/Clock/Clock.tsx @@ -11,7 +11,7 @@ export const Clock: FC = () => { }, []); return ( -
+
{time.toLocaleString("en", { diff --git a/src/components/Clock/index.ts b/src/components/Clock/index.ts index 12577172..697d1d47 100644 --- a/src/components/Clock/index.ts +++ b/src/components/Clock/index.ts @@ -1,2 +1 @@ export { Clock } from "./Clock"; -export type { Props } from "./Clock"; From 8468c8e4617f73b2159e7f1dfbebd032bf398140 Mon Sep 17 00:00:00 2001 From: Shun Kakinoki Date: Sun, 7 Nov 2021 16:11:02 -0500 Subject: [PATCH 2/5] feat: ini notion hq --- .ncurc.yml | 1 - package.json | 4 +- src/components/Blog/Blog.tsx | 4 +- src/components/Notion/Notion.tsx | 27 ++--- src/lib/notion.ts | 117 +++++++++++++++++--- src/pages/[...slug].tsx | 49 ++++---- src/pages/blog.tsx | 4 +- src/pages/index.tsx | 4 +- src/pages/products.tsx | 13 +-- src/screens/LandingScreen/LandingScreen.tsx | 4 +- yarn.lock | 20 ++-- 11 files changed, 169 insertions(+), 78 deletions(-) diff --git a/.ncurc.yml b/.ncurc.yml index b0f7b04b..9210e00e 100644 --- a/.ncurc.yml +++ b/.ncurc.yml @@ -1,3 +1,2 @@ upgrade: true reject: - - "@notionhq/client" diff --git a/package.json b/package.json index cb8993b0..da619d47 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "@heroicons/react": "^1.0.5", "@next-auth/prisma-adapter": "^0.5.4", "@next/bundle-analyzer": "^12.0.3", - "@notionhq/client": "^0.3.3", + "@notionhq/client": "^0.4.6", "@prisma/client": "^3.4.1", "autoprefixer": "^10.4.0", "chrome-aws-lambda": "^10.1.0", @@ -91,7 +91,7 @@ "@shunkakinoki/commitlint": "^1.0.5", "@shunkakinoki/depcheck": "^1.0.1", "@shunkakinoki/dev": "^1.2.7", - "@shunkakinoki/eslint-config": "^1.1.35", + "@shunkakinoki/eslint-config": "^1.1.36", "@shunkakinoki/husky": "^1.0.6", "@shunkakinoki/lint-staged": "^1.1.9", "@shunkakinoki/npm-check-updates": "^1.0.4", diff --git a/src/components/Blog/Blog.tsx b/src/components/Blog/Blog.tsx index 624de410..eb3f26b2 100644 --- a/src/components/Blog/Blog.tsx +++ b/src/components/Blog/Blog.tsx @@ -1,9 +1,9 @@ -import type { Page } from "@notionhq/client/build/src/api-types"; +import type { GetPageResponse } from "@notionhq/client/build/src/api-endpoints"; import Link from "next/link"; import type { FC } from "react"; export type Props = { - database: Page[]; + database: GetPageResponse[]; locale?: string; }; diff --git a/src/components/Notion/Notion.tsx b/src/components/Notion/Notion.tsx index f00933c2..ebbf5dbe 100644 --- a/src/components/Notion/Notion.tsx +++ b/src/components/Notion/Notion.tsx @@ -1,7 +1,6 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ -import type { PagesRetrieveResponse } from "@notionhq/client/build/src/api-endpoints"; -import type { Block, RichText } from "@notionhq/client/build/src/api-types"; +import type { GetPageResponse } from "@notionhq/client/build/src/api-endpoints"; import clsx from "clsx"; import { useTheme } from "next-themes"; import Image from "next/image"; @@ -13,16 +12,17 @@ import s from "./Notion.module.css"; import { LikeButton } from "@/components/Notion/LikeButton"; import { useViews } from "@/hooks/useViews"; +import type { blockWithChildren, richText } from "@/lib/notion"; export type Props = { - blocks: Block[]; - content: PagesRetrieveResponse; + blocks: blockWithChildren[]; + content: GetPageResponse; pageId: string; locale?: string; }; export type TextProps = { - text: RichText[]; + text: richText[]; }; export const Text: FC = ({ text }) => { @@ -64,42 +64,42 @@ export const Text: FC = ({ text }) => { ); }; -const renderBlock = (block: Block, theme: string) => { +const renderBlock = (block: blockWithChildren, theme: string) => { switch (block.type) { case "paragraph": return (

- +

); case "heading_1": return (

- +

); case "heading_2": return (

- +

); case "heading_3": return (

- +

); case "bulleted_list_item": return (
  • - +
  • ); case "numbered_list_item": return (
  • - +
  • ); case "to_do": @@ -112,7 +112,7 @@ const renderBlock = (block: Block, theme: string) => { id={block.id} defaultChecked={block["to_do"].checked} />{" "} - +
    ); @@ -136,6 +136,7 @@ const renderBlock = (block: Block, theme: string) => { { - const response = await notion.databases.query({ - database_id: databaseId, - }); - return response.results; + try { + const response = await notion.databases.query({ + database_id: databaseId, + }); + return response.results; + } catch (error: unknown) { + if (isNotionClientError(error)) { + console.log(error.message); + } + return []; + } }; export const getPage = async (pageId: string) => { @@ -19,18 +76,50 @@ export const getPage = async (pageId: string) => { return response; }; +export const getPageTitle = (property: NotionProperty) => { + return property.Name.type == "title" ? property.Name.title[0].plain_text : ""; +}; + +export const getPageDate = (page: NotionPage) => { + let dateString = page.last_edited_time; + if ( + page.properties["publish date"].type == "date" && + page.properties["publish date"].date !== null + ) { + dateString = page.properties["publish date"].date.start; + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + return new Date(dateString).toLocaleDateString(); +}; + export const getBlocks = async (blockId: string) => { - const response = await notion.blocks.children.list({ block_id: blockId }); - return response.results; + const blocks: blockWithChildren[] = []; + let cursor: undefined | string = undefined; + + // eslint-disable-next-line no-constant-condition + while (true) { + const blocksList = await notion.blocks.children.list({ + start_cursor: cursor, + block_id: blockId, + }); + blocks.push(...blocksList.results); + + const next_cursor = blocksList.next_cursor; + if (!next_cursor) { + break; + } + cursor = next_cursor; + } + return blocks; }; -export const queryDatabase = async ( - databaseId: string, - filter?: Filter, - sorts?: Sort[], -) => { +export const queryDatabase = async ({ + database_id, + filter, + sorts, +}: QueryDatabaseParameters) => { const response = await notion.databases.query({ - database_id: databaseId, + database_id: database_id, filter: filter, sorts: sorts, }); diff --git a/src/pages/[...slug].tsx b/src/pages/[...slug].tsx index 1ecea060..3a350016 100644 --- a/src/pages/[...slug].tsx +++ b/src/pages/[...slug].tsx @@ -1,5 +1,5 @@ -import type { PagesRetrieveResponse } from "@notionhq/client/build/src/api-endpoints"; -import type { Block } from "@notionhq/client/build/src/api-types"; +import type { GetPageResponse } from "@notionhq/client/build/src/api-endpoints"; + import type { GetStaticProps, InferGetStaticPropsType, @@ -11,6 +11,7 @@ import type { MDXRemoteSerializeResult } from "next-mdx-remote"; import { SocialLinks } from "@/const/SocialLinks"; import { getGithubContent } from "@/lib/github"; +import type { blockWithChildren } from "@/lib/notion"; import { getPage, getBlocks, queryDatabase } from "@/lib/notion"; import { ContentScreen } from "@/screens/ContentScreen"; import { NotionScreen } from "@/screens/NotionScreen"; @@ -52,19 +53,22 @@ export const getStaticProps: GetStaticProps = async ({ if (!process.env.NOTION_BLOG_ID) { throw new Error("process.NOTION_BLOG_ID is not defined"); } - const database = await queryDatabase(process.env.NOTION_BLOG_ID, { - and: [ - { - property: "Category", - select: { equals: "Journal" }, - }, - { - property: "Date", - date: { - equals: date, + const database = await queryDatabase({ + database_id: process.env.NOTION_BLOG_ID, + filter: { + and: [ + { + property: "Category", + select: { equals: "Journal" }, }, - }, - ], + { + property: "Date", + date: { + equals: date, + }, + }, + ], + }, }); if (database.results && database.results[0] && database.results[0]?.id) { return { @@ -134,18 +138,17 @@ export const getStaticProps: GetStaticProps = async ({ .map(async block => { return { id: block.id, + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument children: await getBlocks(block.id), }; }), ); const blocksWithChildren = blocks.map(block => { - if (block.type === "paragraph") { - const typedBlock = block[block.type]; - if (block.has_children) { - typedBlock["children"] = childBlocks.find(x => { - return x.id === block.id; - })?.children; - } + // Add child blocks if the block should contain children but none exists + if (block.has_children) { + block.children = childBlocks.find(x => { + return x.id === block.id; + })?.children; } return block; }); @@ -188,8 +191,8 @@ export const PageId = ({ if (content && blocks && pageId) { return ( diff --git a/src/pages/blog.tsx b/src/pages/blog.tsx index 840c4248..f25a3660 100644 --- a/src/pages/blog.tsx +++ b/src/pages/blog.tsx @@ -1,4 +1,4 @@ -import type { Page } from "@notionhq/client/build/src/api-types"; +import type { GetPageResponse } from "@notionhq/client/build/src/api-endpoints"; import type { InferGetStaticPropsType, GetStaticProps, @@ -9,7 +9,7 @@ import { getDatabase } from "@/lib/notion"; import { BlogScreen } from "@/screens/BlogScreen"; export type Props = { - database: Page[]; + database: GetPageResponse[]; locale?: string; }; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index a0ed51a5..24e68006 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,4 +1,4 @@ -import type { Page } from "@notionhq/client/build/src/api-types"; +import type { GetPageResponse } from "@notionhq/client/build/src/api-endpoints"; import type { GetStaticProps, GetStaticPropsContext, @@ -12,7 +12,7 @@ import { getDatabase } from "@/lib/notion"; import { LandingScreen } from "@/screens/LandingScreen"; export interface Props { - database: Page[]; + database: GetPageResponse[]; source: string; } diff --git a/src/pages/products.tsx b/src/pages/products.tsx index 4c6fa61b..47d171f7 100644 --- a/src/pages/products.tsx +++ b/src/pages/products.tsx @@ -1,27 +1,26 @@ -import type { Page } from "@notionhq/client/build/src/api-types"; +import type { GetPageResponse } from "@notionhq/client/build/src/api-endpoints"; import type { InferGetStaticPropsType, GetStaticProps } from "next"; import { queryDatabase } from "@/lib/notion"; import { ProductScreen } from "@/screens/ProductScreen"; export type Props = { - database: Page[]; + database: GetPageResponse[]; }; export const getStaticProps: GetStaticProps = async () => { if (!process.env.NOTION_PRODUCT_ID) { throw new Error("process.NOTION_PRODUCT_ID is not defined"); } - const dbResult = await queryDatabase( - process.env.NOTION_PRODUCT_ID, - undefined, - [ + const dbResult = await queryDatabase({ + database_id: process.env.NOTION_PRODUCT_ID, + sorts: [ { property: "Name", direction: "ascending", }, ], - ); + }); const database = dbResult.results; if (database) { return { diff --git a/src/screens/LandingScreen/LandingScreen.tsx b/src/screens/LandingScreen/LandingScreen.tsx index 4207c2d6..40471d61 100644 --- a/src/screens/LandingScreen/LandingScreen.tsx +++ b/src/screens/LandingScreen/LandingScreen.tsx @@ -1,4 +1,4 @@ -import type { Page } from "@notionhq/client/build/src/api-types"; +import type { GetPageResponse } from "@notionhq/client/build/src/api-endpoints"; import type { MDXRemoteSerializeResult } from "next-mdx-remote"; import type { FC } from "react"; @@ -16,7 +16,7 @@ import { Social } from "@/components/Social"; export interface Props { source: MDXRemoteSerializeResult; - database: Page[]; + database: GetPageResponse[]; } export const LandingScreen: FC = ({ source, database }) => { diff --git a/yarn.lock b/yarn.lock index c900de71..878f735a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2690,10 +2690,10 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@notionhq/client@^0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@notionhq/client/-/client-0.3.3.tgz#5e296ffae3917751f8f536f565d5e0916d2374b7" - integrity sha512-5YttL0GmW0kwTST88wIfZWwHzD+vbRoiu8e9Q6oJfFJ7vdA+F3+vU3ncMpDOuSWygMGjVzFWUqd0NUaG2nw5zg== +"@notionhq/client@^0.4.6": + version "0.4.6" + resolved "https://registry.yarnpkg.com/@notionhq/client/-/client-0.4.6.tgz#ca4d3de216e711d03719605066b8b32011a559e3" + integrity sha512-P6JLxESipVTilZl/SCnd4TKvfa6O3r4NtUcqNtcZa6tLcQjI2kM8bBLPeORQ9BHVsG922icSD45oHa/NDZ9vnA== dependencies: "@types/node-fetch" "^2.5.10" node-fetch "^2.6.1" @@ -3553,10 +3553,10 @@ scripty "^2.0.0" sort-package-json "^1.52.0" -"@shunkakinoki/eslint-config@^1.1.35": - version "1.1.35" - resolved "https://registry.yarnpkg.com/@shunkakinoki/eslint-config/-/eslint-config-1.1.35.tgz#ccfb83b82fc586097acad025f91953acae1dad79" - integrity sha512-8/sHKBKl/+pFQ9EB4U/G6qrVGcwWvrhQ55N6a9zQhipET/yB98uXzxBWWZXe8Hn1/XslWif6lYN/isbXu2x8tA== +"@shunkakinoki/eslint-config@^1.1.36": + version "1.1.36" + resolved "https://registry.yarnpkg.com/@shunkakinoki/eslint-config/-/eslint-config-1.1.36.tgz#fb99f7114f5d336c4e725f1e4cacdfb128b546fe" + integrity sha512-t0kZGWDNC9LHJfdosiM+Cyi88yciWb9g8hf3ofS4g8PGXYa1iEM7dFk+n6S3krDA1RlzWzj2pSGh4th05on7SQ== dependencies: "@next/eslint-plugin-next" "^12.0.3" "@typescript-eslint/eslint-plugin" "^5.3.0" @@ -3569,7 +3569,7 @@ eslint-plugin-jsx-a11y "^6.4.1" eslint-plugin-prettier "^4.0.0" eslint-plugin-react "^7.26.1" - eslint-plugin-react-hooks "^4.2.1-alpha-ee069065d-20211105" + eslint-plugin-react-hooks "^4.2.1-alpha-fd5e01c2e-20210913" eslint-plugin-tailwindcss "^1.17.0" "@shunkakinoki/husky@^1.0.6": @@ -9857,7 +9857,7 @@ eslint-plugin-prettier@^4.0.0: dependencies: prettier-linter-helpers "^1.0.0" -eslint-plugin-react-hooks@^4.2.1-alpha-ee069065d-20211105: +eslint-plugin-react-hooks@^4.2.1-alpha-fd5e01c2e-20210913: version "4.2.1-alpha-fd5e01c2e-20210913" resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.1-alpha-fd5e01c2e-20210913.tgz#79a153d00b1d86f267e68c53c6360e19981c3534" integrity sha512-m1fAodKUB/xYFhEuzcZwN063p8fPLeQTTTrmihl5AYEtH+b/2DtAgemAxYuxtZz60R6txmWeH21Xz+W0QRJx/g== From 37eac0e0a24ba7d7cbe73185e2795bfce454a3fa Mon Sep 17 00:00:00 2001 From: Shun Kakinoki Date: Sun, 7 Nov 2021 16:12:56 -0500 Subject: [PATCH 3/5] chore: update --- src/lib/notion.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/notion.ts b/src/lib/notion.ts index ba9f1934..2e05a18c 100644 --- a/src/lib/notion.ts +++ b/src/lib/notion.ts @@ -8,8 +8,8 @@ import type { } from "@notionhq/client/build/src/api-endpoints.d"; declare type NotionPage = QueryDatabaseResponse["results"][number]; -declare type NotionProperty = - QueryDatabaseResponse["results"][number]["properties"]; +// prettier-ignore +declare type NotionProperty = QueryDatabaseResponse["results"][number]["properties"]; export type blockWithChildren = ListBlockChildrenResponse["results"][number] & { children?: blockWithChildren[]; From 572c2834bd20b48eb97797156ef8f4f2075fca5b Mon Sep 17 00:00:00 2001 From: Shun Kakinoki Date: Sun, 7 Nov 2021 16:14:17 -0500 Subject: [PATCH 4/5] chore: update --- src/lib/notion.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/notion.ts b/src/lib/notion.ts index 2e05a18c..4c92122e 100644 --- a/src/lib/notion.ts +++ b/src/lib/notion.ts @@ -102,6 +102,7 @@ export const getBlocks = async (blockId: string) => { start_cursor: cursor, block_id: blockId, }); + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument blocks.push(...blocksList.results); const next_cursor = blocksList.next_cursor; From 8bc6ba65fe548fc4f821c4b92a9e71c83031a32c Mon Sep 17 00:00:00 2001 From: Shun Kakinoki Date: Sun, 7 Nov 2021 16:19:55 -0500 Subject: [PATCH 5/5] chore: update --- src/components/Product/Product.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Product/Product.tsx b/src/components/Product/Product.tsx index 3a262dd6..c261cc8d 100644 --- a/src/components/Product/Product.tsx +++ b/src/components/Product/Product.tsx @@ -1,4 +1,4 @@ -import type { Page } from "@notionhq/client/build/src/api-types"; +import type { GetPageResponse } from "@notionhq/client/build/src/api-endpoints"; import clsx from "clsx"; import Image from "next/image"; import type { FC } from "react"; @@ -9,7 +9,7 @@ import { ProductCard } from "@/components/Product/ProductCard"; export type Props = { isPartial?: boolean; - database: Page[]; + database: GetPageResponse[]; }; export const Product: FC = ({ isPartial = false, database }) => {