mirror of
https://github.com/d0zingcat/nextjs-notion-starter-kit.git
synced 2026-05-13 15:09:47 +00:00
Merge pull request #641 from transitive-bullshit/feature/maintenance-fall-2024
This commit is contained in:
@@ -1,27 +1,17 @@
|
||||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": ["@typescript-eslint", "react", "react-hooks"],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:react/recommended",
|
||||
"plugin:react-hooks/recommended",
|
||||
"prettier"
|
||||
],
|
||||
"settings": {
|
||||
"react": {
|
||||
"version": "detect"
|
||||
}
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": ["@fisch0920/eslint-config"],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-explicit-any": 0,
|
||||
"@typescript-eslint/no-non-null-assertion": 0,
|
||||
"@typescript-eslint/no-unused-vars": 2,
|
||||
"react/prop-types": 0
|
||||
"react/prop-types": "off",
|
||||
"unicorn/no-array-reduce": "off",
|
||||
"unicorn/filename-case": "off",
|
||||
"no-process-env": "off",
|
||||
"array-callback-return": "off",
|
||||
"jsx-a11y/click-events-have-key-events": "off",
|
||||
"jsx-a11y/no-static-element-interactions": "off",
|
||||
"jsx-a11y/media-has-caption": "off",
|
||||
"jsx-a11y/interactive-supports-focus": "off",
|
||||
"jsx-a11y/anchor-is-valid": "off",
|
||||
"@typescript-eslint/naming-convention": "off"
|
||||
}
|
||||
}
|
||||
|
||||
48
.github/workflows/build.yml
vendored
48
.github/workflows/build.yml
vendored
@@ -1,22 +1,44 @@
|
||||
name: Build
|
||||
name: CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
Build:
|
||||
test:
|
||||
name: Test Node.js ${{ matrix.node-version }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
node-version:
|
||||
- 18
|
||||
- 22
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
id: pnpm-install
|
||||
with:
|
||||
node-version: 16
|
||||
cache: yarn
|
||||
version: 9.12.2
|
||||
run_install: false
|
||||
|
||||
- run: yarn install --frozen-lockfile
|
||||
- name: build
|
||||
# TODO Enable those lines below if you use a Redis cache, you'll also need to configure GitHub Repository Secrets
|
||||
# env:
|
||||
# REDIS_HOST: ${{ secrets.REDIS_HOST }}
|
||||
# REDIS_PASSWORD: ${{ secrets.REDIS_PASSWORD }}
|
||||
run: yarn build
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile --strict-peer-dependencies
|
||||
|
||||
- name: Run test
|
||||
run: pnpm test
|
||||
|
||||
# TODO Enable those lines below if you use a Redis cache, you'll also need to configure GitHub Repository Secrets
|
||||
# env:
|
||||
# REDIS_HOST: ${{ secrets.REDIS_HOST }}
|
||||
# REDIS_PASSWORD: ${{ secrets.REDIS_PASSWORD }}
|
||||
# - name: Build
|
||||
# run: pnpm build
|
||||
|
||||
11
.prettierrc
11
.prettierrc
@@ -7,14 +7,5 @@
|
||||
"bracketSpacing": true,
|
||||
"bracketSameLine": false,
|
||||
"arrowParens": "always",
|
||||
"trailingComma": "none",
|
||||
"importOrder": [
|
||||
"^(react/(.*)$)|^(react$)|^(next/(.*)$)|^(next$)",
|
||||
"<THIRD_PARTY_MODULES>",
|
||||
"^(@/lib/(.*)$)|^(@/components/(.*)$)|^(@/styles/(.*)$)",
|
||||
"^[./]"
|
||||
],
|
||||
"importOrderSeparation": true,
|
||||
"importOrderSortSpecifiers": true,
|
||||
"importOrderGroupNamespaceSpecifiers": true
|
||||
"trailingComma": "none"
|
||||
}
|
||||
|
||||
1
.vscode/launch.json
vendored
1
.vscode/launch.json
vendored
@@ -8,7 +8,6 @@
|
||||
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/next",
|
||||
"runtimeArgs": ["dev"],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"port": 9229,
|
||||
"smartStep": true,
|
||||
"console": "integratedTerminal",
|
||||
"skipFiles": ["<node_internals>/**"],
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import { PageHead } from './PageHead'
|
||||
import styles from './styles.module.css'
|
||||
|
||||
export const ErrorPage: React.FC<{ statusCode: number }> = ({ statusCode }) => {
|
||||
export function ErrorPage({ statusCode }: { statusCode: number }) {
|
||||
const title = 'Error'
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import { FaEnvelopeOpenText } from '@react-icons/all-files/fa/FaEnvelopeOpenText'
|
||||
import { FaGithub } from '@react-icons/all-files/fa/FaGithub'
|
||||
import { FaLinkedin } from '@react-icons/all-files/fa/FaLinkedin'
|
||||
@@ -9,6 +7,7 @@ import { FaYoutube } from '@react-icons/all-files/fa/FaYoutube'
|
||||
import { FaZhihu } from '@react-icons/all-files/fa/FaZhihu'
|
||||
import { IoMoonSharp } from '@react-icons/all-files/io5/IoMoonSharp'
|
||||
import { IoSunnyOutline } from '@react-icons/all-files/io5/IoSunnyOutline'
|
||||
import * as React from 'react'
|
||||
|
||||
import * as config from '@/lib/config'
|
||||
import { useDarkMode } from '@/lib/use-dark-mode'
|
||||
@@ -17,7 +16,7 @@ import styles from './styles.module.css'
|
||||
|
||||
// TODO: merge the data and icons from PageSocial with the social links in Footer
|
||||
|
||||
export const FooterImpl: React.FC = () => {
|
||||
export function FooterImpl() {
|
||||
const [hasMounted, setHasMounted] = React.useState(false)
|
||||
const { isDarkMode, toggleDarkMode } = useDarkMode()
|
||||
const currentYear = new Date().getFullYear()
|
||||
@@ -36,7 +35,9 @@ export const FooterImpl: React.FC = () => {
|
||||
|
||||
return (
|
||||
<footer className={styles.footer}>
|
||||
<div className={styles.copyright}>Copyright {currentYear} {config.author}</div>
|
||||
<div className={styles.copyright}>
|
||||
Copyright {currentYear} {config.author}
|
||||
</div>
|
||||
|
||||
<div className={styles.settings}>
|
||||
{hasMounted && (
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import styles from './styles.module.css'
|
||||
|
||||
export const GitHubShareButton: React.FC = () => {
|
||||
export function GitHubShareButton() {
|
||||
return (
|
||||
<a
|
||||
href='https://github.com/transitive-bullshit/nextjs-notion-starter-kit'
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import { LoadingIcon } from './LoadingIcon'
|
||||
import styles from './styles.module.css'
|
||||
|
||||
export const Loading: React.FC = () => (
|
||||
<div className={styles.container}>
|
||||
<LoadingIcon />
|
||||
</div>
|
||||
)
|
||||
export function Loading() {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<LoadingIcon />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import cs from 'classnames'
|
||||
|
||||
import styles from './styles.module.css'
|
||||
|
||||
export const LoadingIcon = (props) => {
|
||||
export function LoadingIcon(props: any) {
|
||||
const { className, ...rest } = props
|
||||
return (
|
||||
<svg
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import * as React from 'react'
|
||||
import cs from 'classnames'
|
||||
import dynamic from 'next/dynamic'
|
||||
import Image from 'next/image'
|
||||
import Image from 'next/legacy/image'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
import cs from 'classnames'
|
||||
import { PageBlock } from 'notion-types'
|
||||
import { type PageBlock } from 'notion-types'
|
||||
import { formatDate, getBlockTitle, getPageProperty } from 'notion-utils'
|
||||
import * as React from 'react'
|
||||
import BodyClassName from 'react-body-classname'
|
||||
import { NotionRenderer } from 'react-notion-x'
|
||||
import TweetEmbed from 'react-tweet-embed'
|
||||
import { useSearchParam } from 'react-use'
|
||||
|
||||
import type * as types from '@/lib/types'
|
||||
import * as config from '@/lib/config'
|
||||
import * as types from '@/lib/types'
|
||||
import { mapImageUrl } from '@/lib/map-image-url'
|
||||
import { getCanonicalPageUrl, mapPageUrl } from '@/lib/map-page-url'
|
||||
import { searchNotion } from '@/lib/search-notion'
|
||||
@@ -97,7 +96,7 @@ const Modal = dynamic(
|
||||
}
|
||||
)
|
||||
|
||||
const Tweet = ({ id }: { id: string }) => {
|
||||
function Tweet({ id }: { id: string }) {
|
||||
return <TweetEmbed tweetId={id} />
|
||||
}
|
||||
|
||||
@@ -142,12 +141,12 @@ const propertyTextValue = (
|
||||
return defaultFn()
|
||||
}
|
||||
|
||||
export const NotionPage: React.FC<types.PageProps> = ({
|
||||
export function NotionPage({
|
||||
site,
|
||||
recordMap,
|
||||
error,
|
||||
pageId
|
||||
}) => {
|
||||
}: types.PageProps) {
|
||||
const router = useRouter()
|
||||
const lite = useSearchParam('lite')
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import * as types from 'notion-types'
|
||||
import type * as types from 'notion-types'
|
||||
import { IoMoonSharp } from '@react-icons/all-files/io5/IoMoonSharp'
|
||||
import { IoSunnyOutline } from '@react-icons/all-files/io5/IoSunnyOutline'
|
||||
import cs from 'classnames'
|
||||
import * as React from 'react'
|
||||
import { Breadcrumbs, Header, Search, useNotionContext } from 'react-notion-x'
|
||||
|
||||
import { isSearchEnabled, navigationLinks, navigationStyle } from '@/lib/config'
|
||||
@@ -11,7 +10,7 @@ import { useDarkMode } from '@/lib/use-dark-mode'
|
||||
|
||||
import styles from './styles.module.css'
|
||||
|
||||
const ToggleThemeButton = () => {
|
||||
function ToggleThemeButton() {
|
||||
const [hasMounted, setHasMounted] = React.useState(false)
|
||||
const { isDarkMode, toggleDarkMode } = useDarkMode()
|
||||
|
||||
@@ -33,9 +32,11 @@ const ToggleThemeButton = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export const NotionPageHeader: React.FC<{
|
||||
export function NotionPageHeader({
|
||||
block
|
||||
}: {
|
||||
block: types.CollectionViewPageBlock | types.PageBlock
|
||||
}> = ({ block }) => {
|
||||
}) {
|
||||
const { components, mapPageUrl } = useNotionContext()
|
||||
|
||||
if (navigationStyle === 'default') {
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import * as types from '@/lib/types'
|
||||
import type * as types from '@/lib/types'
|
||||
|
||||
import { PageHead } from './PageHead'
|
||||
import styles from './styles.module.css'
|
||||
|
||||
export const Page404: React.FC<types.PageProps> = ({ site, pageId, error }) => {
|
||||
export function Page404({ site, pageId, error }: types.PageProps) {
|
||||
const title = site?.name || 'Notion Page Not Found'
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import { AiOutlineRetweet } from '@react-icons/all-files/ai/AiOutlineRetweet'
|
||||
import { IoHeartOutline } from '@react-icons/all-files/io5/IoHeartOutline'
|
||||
|
||||
@@ -8,7 +6,7 @@ import styles from './styles.module.css'
|
||||
/**
|
||||
* @see https://developer.twitter.com/en/docs/twitter-for-websites/web-intents/overview
|
||||
*/
|
||||
export const PageActions: React.FC<{ tweet: string }> = ({ tweet }) => {
|
||||
export function PageActions({ tweet }: { tweet: string }) {
|
||||
return (
|
||||
<div className={styles.pageActions}>
|
||||
<a
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import { Block, ExtendedRecordMap } from 'notion-types'
|
||||
import { type Block, type ExtendedRecordMap } from 'notion-types'
|
||||
|
||||
import { getPageTweet } from '@/lib/get-page-tweet'
|
||||
|
||||
import { PageActions } from './PageActions'
|
||||
import { PageSocial } from './PageSocial'
|
||||
|
||||
export const PageAside: React.FC<{
|
||||
export function PageAside({
|
||||
block,
|
||||
recordMap,
|
||||
isBlogPost
|
||||
}: {
|
||||
block: Block
|
||||
recordMap: ExtendedRecordMap
|
||||
isBlogPost: boolean
|
||||
}> = ({ block, recordMap, isBlogPost }) => {
|
||||
}) {
|
||||
if (!block) {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
import * as React from 'react'
|
||||
import Head from 'next/head'
|
||||
|
||||
import type * as types from '@/lib/types'
|
||||
import * as config from '@/lib/config'
|
||||
import * as types from '@/lib/types'
|
||||
import { getSocialImageUrl } from '@/lib/get-social-image-url'
|
||||
|
||||
export const PageHead: React.FC<
|
||||
types.PageProps & {
|
||||
title?: string
|
||||
description?: string
|
||||
image?: string
|
||||
url?: string
|
||||
}
|
||||
> = ({ site, title, description, pageId, image, url }) => {
|
||||
export function PageHead({
|
||||
site,
|
||||
title,
|
||||
description,
|
||||
pageId,
|
||||
image,
|
||||
url
|
||||
}: types.PageProps & {
|
||||
title?: string
|
||||
description?: string
|
||||
image?: string
|
||||
url?: string
|
||||
}) {
|
||||
const rssFeedUrl = `${config.host}/feed`
|
||||
|
||||
title = title ?? site?.name
|
||||
@@ -30,13 +34,20 @@ export const PageHead: React.FC<
|
||||
/>
|
||||
|
||||
<meta name='apple-mobile-web-app-capable' content='yes' />
|
||||
<meta
|
||||
name='apple-mobile-web-app-status-bar-style'
|
||||
content='black'
|
||||
/>
|
||||
<meta name='apple-mobile-web-app-status-bar-style' content='black' />
|
||||
|
||||
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#fefffe" key="theme-color-light"/>
|
||||
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#2d3439" key="theme-color-dark"/>
|
||||
<meta
|
||||
name='theme-color'
|
||||
media='(prefers-color-scheme: light)'
|
||||
content='#fefffe'
|
||||
key='theme-color-light'
|
||||
/>
|
||||
<meta
|
||||
name='theme-color'
|
||||
media='(prefers-color-scheme: dark)'
|
||||
content='#2d3439'
|
||||
key='theme-color-dark'
|
||||
/>
|
||||
|
||||
<meta name='robots' content='index,follow' />
|
||||
<meta property='og:type' content='website' />
|
||||
|
||||
@@ -101,10 +101,10 @@
|
||||
}
|
||||
|
||||
.youtube .actionBgPane {
|
||||
background: #FF0000;
|
||||
background: #ff0000;
|
||||
}
|
||||
.youtube:hover {
|
||||
border-color: #FF0000;
|
||||
border-color: #ff0000;
|
||||
}
|
||||
|
||||
.medium .actionBgPane {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import type * as React from 'react'
|
||||
import cs from 'classnames'
|
||||
|
||||
import * as config from '@/lib/config'
|
||||
@@ -70,7 +69,7 @@ const socialLinks: SocialLink[] = [
|
||||
}
|
||||
].filter(Boolean)
|
||||
|
||||
export const PageSocial: React.FC = () => {
|
||||
export function PageSocial() {
|
||||
return (
|
||||
<div className={styles.pageSocial}>
|
||||
{socialLinks.map((action) => (
|
||||
|
||||
@@ -4,20 +4,20 @@ Suggestions and pull requests are highly encouraged. Have a look at the [open is
|
||||
|
||||
## Development
|
||||
|
||||
To develop the project locally, you'll need a recent version of Node.js and `yarn` v1 installed globally.
|
||||
To develop the project locally, you'll need a recent version of Node.js and `pnpm` installed globally.
|
||||
|
||||
To get started, clone the repo and run `yarn` from the root directory:
|
||||
To get started, clone the repo and run `pnpm` from the root directory:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/transitive-bullshit/nextjs-notion-starter-kit
|
||||
cd nextjs-notion-starter-kit
|
||||
yarn
|
||||
pnpm
|
||||
```
|
||||
|
||||
Now that your dependencies are installed, you can run the local Next.js dev server:
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
You should now be able to open `http://localhost:3000` to view the webapp.
|
||||
@@ -27,7 +27,7 @@ You should now be able to open `http://localhost:3000` to view the webapp.
|
||||
To build for production, you can run:
|
||||
|
||||
```bash
|
||||
yarn build
|
||||
pnpm build
|
||||
```
|
||||
|
||||
Which just runs `next build` under the hood.
|
||||
@@ -36,48 +36,18 @@ Which just runs `next build` under the hood.
|
||||
|
||||
If you are making changes to `react-notion-x` and want to test them out with `nextjs-notion-starter-kit`, you'll first need to [set up and build `react-notion-x` locally](https://github.com/NotionX/react-notion-x/blob/master/contributing.md).
|
||||
|
||||
Once you have `react-notion-x` set up locally, run `yarn link` from each `react-notion-x` package:
|
||||
Once you have `react-notion-x` set up and built locally, you can link these local deps into `nextjs-notion-starter-kit`:
|
||||
|
||||
```bash
|
||||
# from react-notion-x clone
|
||||
cd packages/react-notion-x
|
||||
yarn link
|
||||
cd ../packages/notion-utils
|
||||
yarn link
|
||||
cd ../packages/notion-types
|
||||
yarn link
|
||||
cd ../packages/notion-client
|
||||
yarn link
|
||||
pnpm deps:link
|
||||
```
|
||||
|
||||
Now you can link these local deps into `nextjs-notion-starter-kit`:
|
||||
|
||||
```bash
|
||||
# from nextjs-notion-starter-kit
|
||||
yarn deps:link
|
||||
```
|
||||
|
||||
The last step is to make sure that the Next.js project and these local dependencies are all pointing to the same versions of `react` and `react-dom`.
|
||||
|
||||
```bash
|
||||
# from react-notion-x clone
|
||||
cd node_modules/react
|
||||
yarn link
|
||||
cd ../react-dom
|
||||
yarn link
|
||||
```
|
||||
|
||||
```bash
|
||||
# from nextjs-notion-starter-kit
|
||||
yarn link react react-dom
|
||||
```
|
||||
|
||||
With this setup, in one tab, you can run `yarn dev` to keep `react-notion-x` up-to-date, and in another tab, you can run `yarn dev` to keep `nextjs-notion-starter-kit` up-to-date.
|
||||
With this setup, in one tab, you can run `pnpm dev` to keep `react-notion-x` up-to-date, and in another tab, you can run `pnpm dev` to keep `nextjs-notion-starter-kit` up-to-date.
|
||||
|
||||
### Gotchas
|
||||
|
||||
Whenever you make a change to one of the `react-notion-x` packages, it will automatically be recompiled into its respective `build` folder, and the `yarn dev` from `nextjs-notion-starter-kit` should hot-reload it in the browser.
|
||||
Whenever you make a change to one of the `react-notion-x` packages, it will automatically be recompiled into its respective `build` folder, and the `pnpm dev` from `nextjs-notion-starter-kit` should hot-reload it in the browser.
|
||||
|
||||
Sometimes, this process gets a little out of whack, and if you're not sure what's going on, I usually just quit one or both of the `yarn dev` commands and restart them.
|
||||
Sometimes, this process gets a little out of whack, and if you're not sure what's going on, I usually just quit one or both of the `pnpm dev` commands and restart them.
|
||||
|
||||
If you're seeing something unexpected while debugging with Next.js, try running `rm -rf .next` to refresh the Next.js cache before running `yarn dev` again.
|
||||
If you're seeing something unexpected while debugging with Next.js, try running `rm -rf .next` to refresh the Next.js cache before running `pnpm dev` again.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PageProps } from './types'
|
||||
import { type PageProps } from './types'
|
||||
|
||||
export async function pageAcl({
|
||||
site,
|
||||
|
||||
@@ -7,7 +7,7 @@ export function bootstrap() {
|
||||
██║ ██╔══██╗██╔══██║██║╚██╗██║╚════██║██║ ██║ ██║╚██╗ ██╔╝██╔══╝ ██╔══██╗╚════██║
|
||||
██║ ██║ ██║██║ ██║██║ ╚████║███████║██║ ██║ ██║ ╚████╔╝ ███████╗ ██████╔╝███████║
|
||||
╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═══╝ ╚══════╝ ╚═════╝ ╚══════╝
|
||||
|
||||
|
||||
This site is built using Notion, Next.js, and https://github.com/NotionX/react-notion-x.
|
||||
`)
|
||||
}
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
* for optional depenencies.
|
||||
*/
|
||||
import { parsePageId } from 'notion-utils'
|
||||
import { PostHogConfig } from 'posthog-js'
|
||||
import { type PostHogConfig } from 'posthog-js'
|
||||
|
||||
import { getEnv, getSiteConfig } from './get-config-value'
|
||||
import { NavigationLink } from './site-config'
|
||||
import { type NavigationLink } from './site-config'
|
||||
import {
|
||||
NavigationStyle,
|
||||
PageUrlOverridesInverseMap,
|
||||
PageUrlOverridesMap,
|
||||
Site
|
||||
type NavigationStyle,
|
||||
type PageUrlOverridesInverseMap,
|
||||
type PageUrlOverridesMap,
|
||||
type Site
|
||||
} from './types'
|
||||
|
||||
export const rootNotionPageId: string = parsePageId(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ExtendedRecordMap } from 'notion-types'
|
||||
import { type ExtendedRecordMap } from 'notion-types'
|
||||
import {
|
||||
getCanonicalPageId as getCanonicalPageIdImpl,
|
||||
parsePageId
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import rawSiteConfig from '../site.config'
|
||||
import { SiteConfig } from './site-config'
|
||||
import { type SiteConfig } from './site-config'
|
||||
|
||||
if (!rawSiteConfig) {
|
||||
throw new Error(`Config error: invalid site.config.ts`)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { getPageProperty } from 'notion-utils'
|
||||
|
||||
import * as types from './types'
|
||||
import type * as types from './types'
|
||||
|
||||
export function getPageTweet(
|
||||
block: types.Block,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { getAllPagesInSpace, uuidToId, getPageProperty } from 'notion-utils'
|
||||
import { getAllPagesInSpace, getPageProperty, uuidToId } from 'notion-utils'
|
||||
import pMemoize from 'p-memoize'
|
||||
|
||||
import type * as types from './types'
|
||||
import * as config from './config'
|
||||
import * as types from './types'
|
||||
import { includeNotionIdInUrls } from './config'
|
||||
import { getCanonicalPageId } from './get-canonical-page-id'
|
||||
import { notion } from './notion-api'
|
||||
@@ -25,15 +25,15 @@ const getAllPages = pMemoize(getAllPagesImpl, {
|
||||
cacheKey: (...args) => JSON.stringify(args)
|
||||
})
|
||||
|
||||
const getPage = async (pageId: string, ...args) => {
|
||||
console.log('\nnotion getPage', uuidToId(pageId))
|
||||
return notion.getPage(pageId, ...args)
|
||||
}
|
||||
|
||||
async function getAllPagesImpl(
|
||||
rootNotionPageId: string,
|
||||
rootNotionSpaceId: string
|
||||
): Promise<Partial<types.SiteMap>> {
|
||||
const getPage = async (pageId: string, ...args) => {
|
||||
console.log('\nnotion getPage', uuidToId(pageId))
|
||||
return notion.getPage(pageId, ...args)
|
||||
}
|
||||
|
||||
const pageMap = await getAllPagesInSpace(
|
||||
rootNotionPageId,
|
||||
rootNotionSpaceId,
|
||||
@@ -48,7 +48,9 @@ async function getAllPagesImpl(
|
||||
}
|
||||
|
||||
const block = recordMap.block[pageId]?.value
|
||||
if (!(getPageProperty<boolean|null>('Public', block, recordMap) ?? true)) {
|
||||
if (
|
||||
!(getPageProperty<boolean | null>('Public', block, recordMap) ?? true)
|
||||
) {
|
||||
return map
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Block } from 'notion-types'
|
||||
import { type Block } from 'notion-types'
|
||||
import { defaultMapImageUrl } from 'react-notion-x'
|
||||
|
||||
import { defaultPageCover, defaultPageIcon } from './config'
|
||||
|
||||
export const mapImageUrl = (url: string, block: Block) => {
|
||||
export const mapImageUrl = (url: string | undefined, block: Block) => {
|
||||
if (url === defaultPageCover || url === defaultPageIcon) {
|
||||
return url
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { ExtendedRecordMap } from 'notion-types'
|
||||
import { type ExtendedRecordMap } from 'notion-types'
|
||||
import { parsePageId, uuidToId } from 'notion-utils'
|
||||
|
||||
import { includeNotionIdInUrls } from './config'
|
||||
import { getCanonicalPageId } from './get-canonical-page-id'
|
||||
import { Site } from './types'
|
||||
import { type Site } from './types'
|
||||
|
||||
// include UUIDs in page URLs during local development but not in production
|
||||
// (they're nice for debugging and speed up local dev)
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { ExtendedRecordMap, SearchParams, SearchResults } from 'notion-types'
|
||||
import {
|
||||
type ExtendedRecordMap,
|
||||
type SearchParams,
|
||||
type SearchResults
|
||||
} from 'notion-types'
|
||||
import { mergeRecordMaps } from 'notion-utils'
|
||||
import pMap from 'p-map'
|
||||
import pMemoize from 'p-memoize'
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import got from 'got'
|
||||
import ky from 'ky'
|
||||
import lqip from 'lqip-modern'
|
||||
import { ExtendedRecordMap, PreviewImage, PreviewImageMap } from 'notion-types'
|
||||
import {
|
||||
type ExtendedRecordMap,
|
||||
type PreviewImage,
|
||||
type PreviewImageMap
|
||||
} from 'notion-types'
|
||||
import { getPageImageUrls, normalizeUrl } from 'notion-utils'
|
||||
import pMap from 'p-map'
|
||||
import pMemoize from 'p-memoize'
|
||||
@@ -49,7 +53,7 @@ async function createPreviewImage(
|
||||
console.warn(`redis error get "${cacheKey}"`, err.message)
|
||||
}
|
||||
|
||||
const { body } = await got(url, { responseType: 'buffer' })
|
||||
const body = await ky(url).arrayBuffer()
|
||||
const result = await lqip(body)
|
||||
console.log('lqip', { ...result.metadata, url, cacheKey })
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ExtendedRecordMap } from 'notion-types'
|
||||
import { type ExtendedRecordMap } from 'notion-types'
|
||||
import { parsePageId } from 'notion-utils'
|
||||
|
||||
import * as acl from './acl'
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
// import ky from 'ky'
|
||||
import ExpiryMap from 'expiry-map'
|
||||
import fetch from 'isomorphic-unfetch'
|
||||
import pMemoize from 'p-memoize'
|
||||
|
||||
import * as types from './types'
|
||||
import type * as types from './types'
|
||||
import { api } from './config'
|
||||
|
||||
export const searchNotion = pMemoize(searchNotionImpl, {
|
||||
cacheKey: (args) => args[0]?.query,
|
||||
cache: new ExpiryMap(10000)
|
||||
cache: new ExpiryMap(10_000)
|
||||
})
|
||||
|
||||
async function searchNotionImpl(
|
||||
@@ -29,7 +27,7 @@ async function searchNotionImpl(
|
||||
// convert non-2xx HTTP responses into errors
|
||||
const error: any = new Error(res.statusText)
|
||||
error.response = res
|
||||
return Promise.reject(error)
|
||||
throw error
|
||||
})
|
||||
.then((res) => res.json())
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as types from './types'
|
||||
import type * as types from './types'
|
||||
|
||||
export interface SiteConfig {
|
||||
rootNotionPageId: string
|
||||
@@ -16,7 +16,7 @@ export interface SiteConfig {
|
||||
newsletter?: string
|
||||
youtube?: string
|
||||
zhihu?: string
|
||||
mastodon?: string;
|
||||
mastodon?: string
|
||||
|
||||
defaultPageIcon?: string | null
|
||||
defaultPageCover?: string | null
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { ExtendedRecordMap, PageMap } from 'notion-types'
|
||||
import { ParsedUrlQuery } from 'querystring'
|
||||
import { type ParsedUrlQuery } from 'node:querystring'
|
||||
|
||||
import { type ExtendedRecordMap, type PageMap } from 'notion-types'
|
||||
|
||||
export * from 'notion-types'
|
||||
|
||||
|
||||
2
license
2
license
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Travis Fischer
|
||||
Copyright (c) 2024 Travis Fischer
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
2
next-env.d.ts
vendored
2
next-env.d.ts
vendored
@@ -2,4 +2,4 @@
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information.
|
||||
|
||||
@@ -1,22 +1,66 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const withBundleAnalyzer = require('@next/bundle-analyzer')({
|
||||
import bundleAnalyzer from '@next/bundle-analyzer'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const withBundleAnalyzer = bundleAnalyzer({
|
||||
enabled: process.env.ANALYZE === 'true'
|
||||
})
|
||||
|
||||
module.exports = withBundleAnalyzer({
|
||||
export default withBundleAnalyzer({
|
||||
staticPageGenerationTimeout: 300,
|
||||
images: {
|
||||
domains: [
|
||||
'www.notion.so',
|
||||
'notion.so',
|
||||
'images.unsplash.com',
|
||||
'pbs.twimg.com',
|
||||
'abs.twimg.com',
|
||||
's3.us-west-2.amazonaws.com',
|
||||
'transitivebullsh.it'
|
||||
remotePatterns: [
|
||||
{
|
||||
protocol: 'https',
|
||||
hostname: 'www.notion.so',
|
||||
pathname: '**'
|
||||
},
|
||||
{
|
||||
protocol: 'https',
|
||||
hostname: 'notion.so',
|
||||
pathname: '**'
|
||||
},
|
||||
{
|
||||
protocol: 'https',
|
||||
hostname: 'images.unsplash.com',
|
||||
pathname: '**'
|
||||
},
|
||||
{
|
||||
protocol: 'https',
|
||||
hostname: 'pbs.twimg.com',
|
||||
pathname: '**'
|
||||
},
|
||||
{
|
||||
protocol: 'https',
|
||||
hostname: 'abs.twimg.com',
|
||||
pathname: '**'
|
||||
},
|
||||
{
|
||||
protocol: 'https',
|
||||
hostname: 's3.us-west-2.amazonaws.com',
|
||||
pathname: '**'
|
||||
},
|
||||
{
|
||||
protocol: 'https',
|
||||
hostname: 'transitivebullsh.it',
|
||||
pathname: '**'
|
||||
}
|
||||
],
|
||||
formats: ['image/avif', 'image/webp'],
|
||||
dangerouslyAllowSVG: true,
|
||||
contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;"
|
||||
},
|
||||
|
||||
webpack: (config, _context) => {
|
||||
// Workaround for ensuring that `react` and `react-dom` resolve correctly
|
||||
// when using a locally-linked version of `react-notion-x`.
|
||||
// @see https://github.com/vercel/next.js/issues/50391
|
||||
const dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
config.resolve.alias.react = path.resolve(dirname, 'node_modules/react')
|
||||
config.resolve.alias['react-dom'] = path.resolve(
|
||||
dirname,
|
||||
'node_modules/react-dom'
|
||||
)
|
||||
return config
|
||||
}
|
||||
})
|
||||
|
||||
60
package.json
60
package.json
@@ -7,21 +7,26 @@
|
||||
"repository": "transitive-bullshit/nextjs-notion-starter-kit",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
"node": ">=18"
|
||||
},
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"deploy": "vercel deploy",
|
||||
"deps": "run-s deps:*",
|
||||
"deps:update": "[ -z $GITHUB_ACTIONS ] && yarn add notion-client notion-types notion-utils react-notion-x || echo 'Skipping deps:update on CI'",
|
||||
"deps:link": "[ -z $GITHUB_ACTIONS ] && yarn link notion-client notion-types notion-utils react-notion-x || echo 'Skipping deps:link on CI'",
|
||||
"deps:update": "[ -z $GITHUB_ACTIONS ] && pnpm up -L notion-client notion-types notion-utils react-notion-x || echo 'Skipping deps:update on CI'",
|
||||
"deps:link": "[ -z $GITHUB_ACTIONS ] && run-s deps:link:* || echo 'Skipping deps:update on CI'",
|
||||
"deps:unlink": "[ -z $GITHUB_ACTIONS ] && pnpm add notion-client notion-types notion-utils react-notion-x || echo 'Skipping deps:update on CI'",
|
||||
"deps:link:notion-types": "pnpm link ../react-notion-x/packages/notion-types",
|
||||
"deps:link:notion-utils": "pnpm link ../react-notion-x/packages/notion-utils",
|
||||
"deps:link:notion-client": "pnpm link ../react-notion-x/packages/notion-client",
|
||||
"deps:link:react-notion-x": "pnpm link ../react-notion-x/packages/react-notion-x",
|
||||
"analyze": "cross-env ANALYZE=true next build",
|
||||
"analyze:server": "cross-env BUNDLE_ANALYZE=server next build",
|
||||
"analyze:browser": "cross-env BUNDLE_ANALYZE=browser next build",
|
||||
"test": "run-p test:*",
|
||||
"test:lint": "eslint '**/*.{ts,tsx}'",
|
||||
"test:lint": "eslint .",
|
||||
"test:prettier": "prettier '**/*.{js,jsx,ts,tsx}' --check"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -29,44 +34,39 @@
|
||||
"@keyvhq/core": "^1.6.9",
|
||||
"@keyvhq/redis": "^1.6.10",
|
||||
"@react-icons/all-files": "^4.1.0",
|
||||
"@vercel/og": "^0.0.19",
|
||||
"classnames": "^2.3.1",
|
||||
"date-fns": "^2.28.0",
|
||||
"@vercel/og": "^0.6.3",
|
||||
"classnames": "^2.5.1",
|
||||
"date-fns": "^2.30.0",
|
||||
"expiry-map": "^2.0.0",
|
||||
"fathom-client": "^3.4.1",
|
||||
"got": "^12.0.3",
|
||||
"isomorphic-unfetch": "^3.1.0",
|
||||
"lqip-modern": "^2.0.0",
|
||||
"next": "12",
|
||||
"notion-client": "^6.15.6",
|
||||
"notion-types": "^6.15.6",
|
||||
"notion-utils": "^6.15.6",
|
||||
"p-map": "^5.3.0",
|
||||
"p-memoize": "^6.0.1",
|
||||
"ky": "^1.7.2",
|
||||
"lqip-modern": "^2.1.0",
|
||||
"next": "^15.0.2",
|
||||
"notion-client": "^7.0.1",
|
||||
"notion-types": "^7.0.1",
|
||||
"notion-utils": "^7.0.1",
|
||||
"p-map": "^7.0.2",
|
||||
"p-memoize": "^7.1.1",
|
||||
"posthog-js": "^1.20.2",
|
||||
"prismjs": "^1.29.0",
|
||||
"react": "^18.2.0",
|
||||
"react-body-classname": "^1.3.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-notion-x": "^6.15.6",
|
||||
"react-notion-x": "^7.0.1",
|
||||
"react-tweet-embed": "^2.0.0",
|
||||
"react-use": "^17.4.2",
|
||||
"rss": "^1.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next/bundle-analyzer": "^12.3.1",
|
||||
"@trivago/prettier-plugin-sort-imports": "^3.3.1",
|
||||
"@types/node": "^18.8.5",
|
||||
"@fisch0920/eslint-config": "^1.4.0",
|
||||
"@next/bundle-analyzer": "^15.0.2",
|
||||
"@types/node": "^22.8.6",
|
||||
"@types/react": "^18.0.21",
|
||||
"@typescript-eslint/eslint-plugin": "^5.40.0",
|
||||
"@typescript-eslint/parser": "^5.40.0",
|
||||
"cross-env": "^7.0.2",
|
||||
"eslint": "^8.25.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-react": "^7.31.10",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^2.7.1",
|
||||
"typescript": "^4.8.4"
|
||||
"eslint": "^8.57.1",
|
||||
"npm-run-all2": "^7.0.1",
|
||||
"prettier": "^3.3.3",
|
||||
"typescript": "^5.6.3"
|
||||
},
|
||||
"overrides": {
|
||||
"cacheable-request": {
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
import { Page404 } from '@/components/Page404'
|
||||
|
||||
export default Page404
|
||||
export { Page404 as default } from '@/components/Page404'
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import * as React from 'react'
|
||||
import { GetStaticProps } from 'next'
|
||||
import { type GetStaticProps } from 'next'
|
||||
|
||||
import { NotionPage } from '@/components/NotionPage'
|
||||
import { domain, isDev } from '@/lib/config'
|
||||
import { getSiteMap } from '@/lib/get-site-map'
|
||||
import { resolveNotionPage } from '@/lib/resolve-notion-page'
|
||||
import { PageProps, Params } from '@/lib/types'
|
||||
import { type PageProps, type Params } from '@/lib/types'
|
||||
|
||||
export const getStaticProps: GetStaticProps<PageProps, Params> = async (
|
||||
context
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
// global styles shared across the entire site
|
||||
import * as React from 'react'
|
||||
import type { AppProps } from 'next/app'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
import * as Fathom from 'fathom-client'
|
||||
// used for rendering equations (optional)
|
||||
import 'katex/dist/katex.min.css'
|
||||
import posthog from 'posthog-js'
|
||||
// used for code syntax highlighting (optional)
|
||||
import 'prismjs/themes/prism-coy.css'
|
||||
// core styles shared by all of react-notion-x (required)
|
||||
import 'react-notion-x/src/styles.css'
|
||||
// global styles shared across the entire site
|
||||
import 'styles/global.css'
|
||||
// this might be better for dark mode
|
||||
// import 'prismjs/themes/prism-okaidia.css'
|
||||
@@ -19,6 +13,12 @@ import 'styles/notion.css'
|
||||
// global style overrides for prism theme (optional)
|
||||
import 'styles/prism-theme.css'
|
||||
|
||||
import type { AppProps } from 'next/app'
|
||||
import * as Fathom from 'fathom-client'
|
||||
import { useRouter } from 'next/router'
|
||||
import posthog from 'posthog-js'
|
||||
import * as React from 'react'
|
||||
|
||||
import { bootstrap } from '@/lib/bootstrap-client'
|
||||
import {
|
||||
fathomConfig,
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import * as React from 'react'
|
||||
import Document, { Head, Html, Main, NextScript } from 'next/document'
|
||||
|
||||
import { IconContext } from '@react-icons/all-files'
|
||||
import Document, { Head, Html, Main, NextScript } from 'next/document'
|
||||
|
||||
export default class MyDocument extends Document {
|
||||
render() {
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
import { ErrorPage } from '@/components/ErrorPage'
|
||||
|
||||
export default ErrorPage
|
||||
export { ErrorPage as default } from '@/components/ErrorPage'
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
import got from 'got'
|
||||
import { PageBlock } from 'notion-types'
|
||||
import ky from 'ky'
|
||||
import { type NextApiRequest, type NextApiResponse } from 'next'
|
||||
import { type PageBlock } from 'notion-types'
|
||||
import {
|
||||
getBlockIcon,
|
||||
getBlockTitle,
|
||||
@@ -13,9 +12,12 @@ import {
|
||||
import * as libConfig from '@/lib/config'
|
||||
import { mapImageUrl } from '@/lib/map-image-url'
|
||||
import { notion } from '@/lib/notion-api'
|
||||
import { NotionPageInfo } from '@/lib/types'
|
||||
import { type NotionPageInfo } from '@/lib/types'
|
||||
|
||||
export default async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
export default async function notionPageInfo(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
if (req.method !== 'POST') {
|
||||
return res.status(405).send({ error: 'method not allowed' })
|
||||
}
|
||||
@@ -125,9 +127,9 @@ async function isUrlReachable(url: string | null): Promise<boolean> {
|
||||
}
|
||||
|
||||
try {
|
||||
await got.head(url)
|
||||
await ky.head(url)
|
||||
return true
|
||||
} catch (err) {
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
import { type NextApiRequest, type NextApiResponse } from 'next'
|
||||
|
||||
import * as types from '../../lib/types'
|
||||
import type * as types from '../../lib/types'
|
||||
import { search } from '../../lib/notion'
|
||||
|
||||
export default async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
export default async function searchNotion(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
if (req.method !== 'POST') {
|
||||
return res.status(405).send({ error: 'method not allowed' })
|
||||
}
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
import * as React from 'react'
|
||||
import { NextRequest } from 'next/server'
|
||||
|
||||
import { ImageResponse } from '@vercel/og'
|
||||
import ky from 'ky'
|
||||
import { type NextRequest } from 'next/server'
|
||||
|
||||
import { api, apiHost, rootNotionPageId } from '@/lib/config'
|
||||
import { NotionPageInfo } from '@/lib/types'
|
||||
import { type NotionPageInfo } from '@/lib/types'
|
||||
|
||||
const interRegularFontP = fetch(
|
||||
const interRegularFontP = ky(
|
||||
new URL('../../public/fonts/Inter-Regular.ttf', import.meta.url)
|
||||
).then((res) => res.arrayBuffer())
|
||||
).arrayBuffer()
|
||||
|
||||
const interBoldFontP = fetch(
|
||||
const interBoldFontP = ky(
|
||||
new URL('../../public/fonts/Inter-SemiBold.ttf', import.meta.url)
|
||||
).then((res) => res.arrayBuffer())
|
||||
).arrayBuffer()
|
||||
|
||||
export const config = {
|
||||
runtime: 'experimental-edge'
|
||||
runtime: 'edge'
|
||||
}
|
||||
|
||||
export default async function OGImage(req: NextRequest) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { GetServerSideProps } from 'next'
|
||||
|
||||
import { ExtendedRecordMap } from 'notion-types'
|
||||
import { type ExtendedRecordMap } from 'notion-types'
|
||||
import {
|
||||
getBlockParentPage,
|
||||
getBlockTitle,
|
||||
@@ -67,8 +66,8 @@ export const getServerSideProps: GetServerSideProps = async ({ req, res }) => {
|
||||
const date = lastUpdatedTime
|
||||
? new Date(lastUpdatedTime)
|
||||
: publishedTime
|
||||
? new Date(publishedTime)
|
||||
: undefined
|
||||
? new Date(publishedTime)
|
||||
: undefined
|
||||
const socialImageUrl = getSocialImageUrl(pageId)
|
||||
|
||||
feed.item({
|
||||
@@ -98,4 +97,6 @@ export const getServerSideProps: GetServerSideProps = async ({ req, res }) => {
|
||||
return { props: {} }
|
||||
}
|
||||
|
||||
export default () => null
|
||||
export default function noop() {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import { NotionPage } from '@/components/NotionPage'
|
||||
import { domain } from '@/lib/config'
|
||||
import { resolveNotionPage } from '@/lib/resolve-notion-page'
|
||||
|
||||
@@ -42,4 +42,6 @@ Sitemap: ${host}/sitemap.xml
|
||||
}
|
||||
}
|
||||
|
||||
export default () => null
|
||||
export default function noop() {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { GetServerSideProps } from 'next'
|
||||
|
||||
import type { SiteMap } from '@/lib/types'
|
||||
import { host } from '@/lib/config'
|
||||
import { getSiteMap } from '@/lib/get-site-map'
|
||||
import type { SiteMap } from '@/lib/types'
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async ({ req, res }) => {
|
||||
if (req.method !== 'GET') {
|
||||
@@ -54,4 +54,6 @@ const createSitemap = (siteMap: SiteMap) =>
|
||||
</urlset>
|
||||
`
|
||||
|
||||
export default () => null
|
||||
export default function noop() {
|
||||
return null
|
||||
}
|
||||
|
||||
5144
pnpm-lock.yaml
generated
Normal file
5144
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2016",
|
||||
"target": "es2017",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": false,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"experimentalDecorators": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"moduleResolution": "bundler",
|
||||
"moduleDetection": "force",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
|
||||
Reference in New Issue
Block a user