Skip to content

Commit

Permalink
feat: ini notion hq
Browse files Browse the repository at this point in the history
  • Loading branch information
shunkakinoki committed Nov 7, 2021
1 parent 48fd042 commit 8468c8e
Show file tree
Hide file tree
Showing 11 changed files with 169 additions and 78 deletions.
1 change: 0 additions & 1 deletion .ncurc.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
upgrade: true
reject:
- "@notionhq/client"
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
4 changes: 2 additions & 2 deletions src/components/Blog/Blog.tsx
Original file line number Diff line number Diff line change
@@ -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;
};

Expand Down
27 changes: 14 additions & 13 deletions src/components/Notion/Notion.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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<TextProps> = ({ text }) => {
Expand Down Expand Up @@ -64,42 +64,42 @@ export const Text: FC<TextProps> = ({ text }) => {
);
};

const renderBlock = (block: Block, theme: string) => {
const renderBlock = (block: blockWithChildren, theme: string) => {
switch (block.type) {
case "paragraph":
return (
<p>
<Text text={block["paragraph"].text} />
<Text text={block["paragraph"].text as richText[]} />
</p>
);
case "heading_1":
return (
<h1>
<Text text={block["heading_1"].text} />
<Text text={block["heading_1"].text as richText[]} />
</h1>
);
case "heading_2":
return (
<h2>
<Text text={block["heading_2"].text} />
<Text text={block["heading_2"].text as richText[]} />
</h2>
);
case "heading_3":
return (
<h3>
<Text text={block["heading_3"].text} />
<Text text={block["heading_3"].text as richText[]} />
</h3>
);
case "bulleted_list_item":
return (
<li>
<Text text={block["bulleted_list_item"].text} />
<Text text={block["bulleted_list_item"].text as richText[]} />
</li>
);
case "numbered_list_item":
return (
<li>
<Text text={block["numbered_list_item"].text} />
<Text text={block["numbered_list_item"].text as richText[]} />
</li>
);
case "to_do":
Expand All @@ -112,7 +112,7 @@ const renderBlock = (block: Block, theme: string) => {
id={block.id}
defaultChecked={block["to_do"].checked}
/>{" "}
<Text text={block["to_do"].text} />
<Text text={block["to_do"].text as richText[]} />
</label>
</div>
);
Expand All @@ -136,6 +136,7 @@ const renderBlock = (block: Block, theme: string) => {
<Tweet
tweetId={
/twitter.com\/.*\/status(?:es)?\/([^/?]+)/.exec(
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
block["embed"].url,
)[1]
}
Expand Down
117 changes: 103 additions & 14 deletions src/lib/notion.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,125 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */

import { Client } from "@notionhq/client";
import type { Filter, Sort } from "@notionhq/client/build/src/api-types";
import { Client, isNotionClientError } from "@notionhq/client";
import type {
QueryDatabaseParameters,
QueryDatabaseResponse,
ListBlockChildrenResponse,
} from "@notionhq/client/build/src/api-endpoints.d";

declare type NotionPage = QueryDatabaseResponse["results"][number];
declare type NotionProperty =
QueryDatabaseResponse["results"][number]["properties"];

export type blockWithChildren = ListBlockChildrenResponse["results"][number] & {
children?: blockWithChildren[];
};
export type richText = {
type: "text";
text: {
content: string;
link: {
url: string;
} | null;
};
annotations: {
bold: boolean;
italic: boolean;
strikethrough: boolean;
underline: boolean;
code: boolean;
color:
| "default"
| "gray"
| "brown"
| "orange"
| "yellow"
| "green"
| "blue"
| "purple"
| "pink"
| "red"
| "gray_background"
| "brown_background"
| "orange_background"
| "yellow_background"
| "green_background"
| "blue_background"
| "purple_background"
| "pink_background"
| "red_background";
};
plain_text: string;
href: string | null;
};

const notion = new Client({
auth: process.env.NOTION_API_KEY,
});

export const getDatabase = async (databaseId: 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) => {
const response = await notion.pages.retrieve({ page_id: pageId });
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,
});
Expand Down
49 changes: 26 additions & 23 deletions src/pages/[...slug].tsx
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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";
Expand Down Expand Up @@ -52,19 +53,22 @@ export const getStaticProps: GetStaticProps<Props> = 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 {
Expand Down Expand Up @@ -134,18 +138,17 @@ export const getStaticProps: GetStaticProps<Props> = 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;
});
Expand Down Expand Up @@ -188,8 +191,8 @@ export const PageId = ({
if (content && blocks && pageId) {
return (
<NotionScreen
blocks={JSON.parse(blocks) as Block[]}
content={JSON.parse(content) as PagesRetrieveResponse}
blocks={JSON.parse(blocks) as blockWithChildren[]}
content={JSON.parse(content) as GetPageResponse}
locale={locale}
pageId={pageId}
/>
Expand Down
4 changes: 2 additions & 2 deletions src/pages/blog.tsx
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -9,7 +9,7 @@ import { getDatabase } from "@/lib/notion";
import { BlogScreen } from "@/screens/BlogScreen";

export type Props = {
database: Page[];
database: GetPageResponse[];
locale?: string;
};

Expand Down
4 changes: 2 additions & 2 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -12,7 +12,7 @@ import { getDatabase } from "@/lib/notion";
import { LandingScreen } from "@/screens/LandingScreen";

export interface Props {
database: Page[];
database: GetPageResponse[];
source: string;
}

Expand Down
Loading

0 comments on commit 8468c8e

Please sign in to comment.