Skip to content

Commit 97dab01

Browse files
authored
Migration to app router (#51)
* migrate to app router - .env.example * migrate to app router - lib/notion.js * migrate to app router - package.json * migrate to app router - pages/[id].js * migrate to app router - pages/_app.js * migrate to app router - pages/index.js * migrate to app router - pages/index.module.css * migrate to app router - pages/post.module.css * migrate to app router - yarn.lock * migrate to app router - .eslintrc.js * migrate to app router - .github/ * migrate to app router - app/ * migrate to app router - components/ * migrate to app router - styles/post.module.css * migrate to app router - .github/workflows/deploy-gh-pages.yml * migrate to app router - .github/workflows/deploy-vercel.yml * migrate to app router - README.md * migrate to app router - .github/workflows/deploy-gh-pages.yml.txt * migrate to app router - .github/workflows/deploy-vercel.yml.txt * refactoring * refactoring * lint
1 parent 8a9f204 commit 97dab01

18 files changed

+2514
-440
lines changed

.env.example

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
NOTION_TOKEN=
2-
NOTION_DATABASE_ID=
1+
NOTION_TOKEN=""
2+
NOTION_DATABASE_ID=""

.eslintrc.js

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
module.exports = {
2+
env: {
3+
browser: true,
4+
es2021: true,
5+
node: true,
6+
},
7+
extends: [
8+
'airbnb',
9+
'eslint:recommended',
10+
'plugin:react/recommended',
11+
'plugin:react/jsx-runtime',
12+
'plugin:@next/next/recommended',
13+
],
14+
overrides: [
15+
{
16+
env: {
17+
node: true,
18+
},
19+
files: [
20+
'.eslintrc.{js,cjs}',
21+
],
22+
parserOptions: {
23+
sourceType: 'script',
24+
},
25+
},
26+
],
27+
parserOptions: {
28+
ecmaVersion: 'latest',
29+
sourceType: 'module',
30+
},
31+
rules: {
32+
'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }],
33+
'react/jsx-props-no-spreading': [1, {
34+
custom: 'ignore',
35+
}],
36+
'react/prop-types': [0],
37+
},
38+
};
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
2+
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3+
4+
name: GitHub Pages deploy
5+
6+
on:
7+
push:
8+
branches: [main]
9+
10+
jobs:
11+
build:
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- name: Checkout 🛎️
16+
uses: actions/[email protected]
17+
- name: Use Node.js 14.x
18+
uses: actions/setup-node@v1
19+
with:
20+
node-version: "14.x"
21+
cache: "yarn"
22+
23+
- name: Installing my packages
24+
run: yarn install --frozen-lockfile
25+
26+
- name: Build my App
27+
run: yarn build && yarn export && touch ./out/.nojekyll
28+
29+
- name: Deploy 🚀
30+
uses: JamesIves/[email protected]
31+
with:
32+
GITHUB_TOKEN: "token"
33+
BRANCH: gh-pages # The branch the action should deploy to.
34+
FOLDER: out # The folder the action should deploy.
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: deploy website
2+
"on":
3+
push:
4+
branches:
5+
- master
6+
pull_request:
7+
branches:
8+
- master
9+
jobs:
10+
deploy:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v2
14+
- uses: actions/setup-node@v2
15+
cache: "yarn"
16+
- run: yarn build
17+
- uses: amondnet/vercel-action@v20 #deploy
18+
with:
19+
vercel-token: ${{ secrets.VERCEL_TOKEN }} # Required
20+
github-token: ${{ secrets.GH_TOKEN }} #Optional
21+
vercel-args: "--prod" #Optional
22+
vercel-org-id: ${{ secrets.ORG_ID}} #Required
23+
vercel-project-id: ${{ secrets.PROJECT_ID}} #Required
24+
# working-directory: ./

README.md

+11
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,14 @@ Open [http://localhost:3000](http://localhost:3000) with your browser to see the
3636
#### Deploy to vercel
3737

3838
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https%3A%2F%2Fgithub.com%2Fsamuelkraft%2Fnotion-blog-nextjs&env=NOTION_TOKEN,NOTION_DATABASE_ID&envDescription=Please%20add%20NOTION_TOKEN%20and%20NOTION_DATABASE_ID%20that%20is%20required%20to%20connect%20the%20blog%20to%20your%20notion%20account.&envLink=https%3A%2F%2Fdevelopers.notion.com%2Fdocs%2Fgetting-started&project-name=notion-blog-nextjs&repo-name=notion-blog-nextjs&demo-title=Notion%20Blog%20Next%20JS&demo-description=%20This%20is%20a%20Next.js%20blog%20using%20Notions%20Public%20API.&demo-url=notion-blog-nextjs-coral.vercel.app)
39+
40+
#### GitHub Actions
41+
- Deployment workflows are located under `.github/workflows/` in this repository.
42+
- To use the actions, rename them to remove the `.txt` extensions
43+
44+
45+
To be able to deploy on both vercel and gh pages through GitHub actions when merging/pushing to master, add the following as your GitHub Action Secrets (Settings->Secrets->Actions).
46+
1. ORG_ID - Vercel account ID found in account Settings.
47+
1. PROJECT_ID - Vercel project ID found in project Settings.
48+
1. VERCEL_TOKEN - Vercel token created in Settings -> Tokens.
49+
1. GH_TOKEN - GitHub token usually readily available for each account (optional).

app/[id]/page.js

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { Fragment } from 'react';
2+
import Head from 'next/head';
3+
import Link from 'next/link';
4+
5+
import {
6+
getDatabase, getPage, getBlocks,
7+
} from '../../lib/notion';
8+
import Text from '../../components/text';
9+
import { renderBlock } from '../../components/notion/renderer';
10+
import styles from '../../styles/post.module.css';
11+
12+
// Return a list of `params` to populate the [id] dynamic segment
13+
export async function generateStaticParams() {
14+
const database = await getDatabase();
15+
return database?.map((page) => ({ id: page.id }));
16+
}
17+
18+
async function getPost(params) {
19+
const { id } = params;
20+
const page = await getPage(id);
21+
const blocks = await getBlocks(id);
22+
23+
return {
24+
page,
25+
blocks,
26+
};
27+
}
28+
29+
export default async function Page({ params }) {
30+
const { page, blocks } = await getPost(params);
31+
32+
if (!page || !blocks) {
33+
return <div />;
34+
}
35+
36+
return (
37+
<div>
38+
{/* TODO: use generate metadata function */}
39+
<Head>
40+
<title>{page.properties.Title?.title[0].plain_text}</title>
41+
<link rel="icon" href="/favicon.ico" />
42+
</Head>
43+
44+
<article className={styles.container}>
45+
<h1 className={styles.name}>
46+
<Text title={page.properties.Title?.title} />
47+
</h1>
48+
<section>
49+
{blocks.map((block) => (
50+
<Fragment key={block.id}>{renderBlock(block)}</Fragment>
51+
))}
52+
<Link href="/" className={styles.back}>
53+
← Go home
54+
</Link>
55+
</section>
56+
</article>
57+
</div>
58+
);
59+
}
60+
61+
// export const getStaticPaths = async () => {
62+
// const database = await getDatabase(databaseId);
63+
// return {
64+
// paths: database.map((page) => {
65+
// return ({ params: { id: page.id } });
66+
// }),
67+
// fallback: true,
68+
// };
69+
// };
70+
71+
// export const getStaticProps = async (context) => {
72+
// const { id } = context.params;
73+
// const page = await getPage(id);
74+
// const blocks = await getBlocks(id);
75+
76+
// return {
77+
// props: {
78+
// page,
79+
// blocks,
80+
// },
81+
// revalidate: 1,
82+
// };
83+
// };

app/article/[slug]/page.js

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { Fragment } from 'react';
2+
import Head from 'next/head';
3+
import Link from 'next/link';
4+
5+
import {
6+
getDatabase, getBlocks, getPageFromSlug,
7+
} from '../../../lib/notion';
8+
import Text from '../../../components/text';
9+
import { renderBlock } from '../../../components/notion/renderer';
10+
import styles from '../../../styles/post.module.css';
11+
12+
// Return a list of `params` to populate the [slug] dynamic segment
13+
export async function generateStaticParams() {
14+
const database = await getDatabase();
15+
return database?.map((page) => {
16+
const slug = page.properties.Slug?.formula?.string;
17+
return ({ id: page.id, slug });
18+
});
19+
}
20+
21+
export default async function Page({ params }) {
22+
const page = await getPageFromSlug(params?.slug);
23+
const blocks = await getBlocks(page?.id);
24+
25+
if (!page || !blocks) {
26+
return <div />;
27+
}
28+
29+
return (
30+
<div>
31+
<Head>
32+
<title>{page.properties.Title?.title[0].plain_text}</title>
33+
<link rel="icon" href="/favicon.ico" />
34+
</Head>
35+
36+
<article className={styles.container}>
37+
<h1 className={styles.name}>
38+
<Text title={page.properties.Title?.title} />
39+
</h1>
40+
<section>
41+
{blocks.map((block) => (
42+
<Fragment key={block.id}>{renderBlock(block)}</Fragment>
43+
))}
44+
<Link href="/" className={styles.back}>
45+
← Go home
46+
</Link>
47+
</section>
48+
</article>
49+
</div>
50+
);
51+
}
52+
53+
// export const getStaticPaths = async () => {
54+
// const database = await getDatabase(databaseId);
55+
// return {
56+
// paths: database.map((page) => {
57+
// const slug = page.properties.Slug?.formula?.string;
58+
// return ({ params: { id: page.id, slug } });
59+
// }),
60+
// fallback: true,
61+
// };
62+
// };
63+
64+
// export const getStaticProps = async (context) => {
65+
// const { slug } = context.params;
66+
// const page = await getPage(id);
67+
// const blocks = await getBlocks(id);
68+
69+
// return {
70+
// props: {
71+
// page,
72+
// blocks,
73+
// },
74+
// revalidate: 1,
75+
// };
76+
// };
File renamed without changes.

app/layout.js

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import '../styles/globals.css';
2+
3+
import { Inter } from 'next/font/google';
4+
5+
const inter = Inter({ subsets: ['latin'] });
6+
7+
export const metadata = {
8+
title: 'Notion Next.js blog',
9+
description: 'Notion Next.js blog',
10+
};
11+
12+
export default function RootLayout({ children }) {
13+
return (
14+
<html lang="en">
15+
<body className={inter.className}>
16+
{children}
17+
</body>
18+
</html>
19+
);
20+
}

0 commit comments

Comments
 (0)