Files
nextjs-notion-starter-kit/components/NotionPage.tsx
2021-01-28 02:01:20 -05:00

225 lines
6.2 KiB
TypeScript

import * as React from 'react'
import Head from 'next/head'
import Link from 'next/link'
import cs from 'classnames'
import { useRouter } from 'next/router'
import { useLocalStorage, useSearchParam } from 'react-use'
import BodyClassName from 'react-body-classname'
// core notion renderer
import { NotionRenderer } from 'react-notion-x'
// utils
import { getBlockTitle } from 'notion-utils'
import { mapPageUrl, getCanonicalPageUrl } from 'lib/map-page-url'
import { mapNotionImageUrl } from 'lib/map-image-url'
import { getPageDescription } from 'lib/get-page-description'
import { getPageTweet } from 'lib/get-page-tweet'
import { searchNotion } from 'lib/search-notion'
import * as types from 'lib/types'
import * as config from 'lib/config'
// components
import { CustomFont } from './CustomFont'
import { CustomHtml } from './CustomHtml'
import { Loading } from './Loading'
import { Page404 } from './Page404'
import { PageHead } from './PageHead'
import { PageActions } from './PageActions'
import { Footer } from './Footer'
import { ReactUtterances } from './ReactUtterances'
import styles from './styles.module.css'
export const NotionPage: React.FC<types.PageProps> = ({
site,
recordMap,
error,
pageId
}) => {
const router = useRouter()
const dark = useSearchParam('dark')
const lite = useSearchParam('lite')
const params: any = {}
if (dark) params.dark = dark
if (lite) params.lite = lite
const searchParams = new URLSearchParams(params)
// TODO: add ability to toggle dark mode
const [isDarkMode, setDarkMode] = useLocalStorage(
'notionx-dark-mode',
dark !== null ? dark === 'true' : !!site?.darkMode
)
const isLiteMode = lite === 'true'
if (router.isFallback) {
return <Loading />
}
const keys = Object.keys(recordMap?.block || {})
const block = recordMap?.block?.[keys[0]]?.value
if (error || !site || !keys.length || !block) {
return <Page404 site={site} pageId={pageId} error={error} />
}
const title = getBlockTitle(block, recordMap) || site.name
console.log('notion page', {
isDev: config.isDev,
title,
pageId,
rootNotionPageId: site.rootNotionPageId,
recordMap
})
if (!config.isServer) {
// add important objects global window for easy debugging
const g = window as any
g.recordMap = recordMap
g.block = block
}
const siteMapPageUrl = mapPageUrl(site, recordMap, searchParams)
const canonicalPageUrl =
!config.isDev && getCanonicalPageUrl(site, recordMap)(pageId)
const isBlogPost =
block.type === 'page' && block.parent_table === 'collection'
const showTableOfContents = !!isBlogPost
const minTableOfContentsItems = 3
const socialImage = config.api.renderSocialImage(pageId)
const socialDescription =
getPageDescription(block, recordMap) ?? config.description
let comments: React.ReactNode = null
let pageAside: React.ReactChild = null
// only display comments and page actions on blog post pages
if (isBlogPost) {
if (config.utterancesGitHubRepo) {
comments = (
<ReactUtterances
repo={config.utterancesGitHubRepo}
issueMap='issue-term'
issueTerm='title'
theme={isDarkMode ? 'photon-dark' : 'github-light'}
/>
)
}
const tweet = getPageTweet(block, recordMap)
if (tweet) {
pageAside = <PageActions tweet={tweet} />
}
}
return (
<>
<PageHead site={site} />
<Head>
<meta property='og:title' content={title} />
<meta property='og:site_name' content={site.name} />
<meta name='twitter:title' content={title} />
<meta property='twitter:domain' content={site.domain} />
{config.twitter && (
<meta name='twitter:creator' content={`@${config.twitter}`} />
)}
{socialDescription && (
<>
<meta name='description' content={socialDescription} />
<meta property='og:description' content={socialDescription} />
<meta name='twitter:description' content={socialDescription} />
</>
)}
{socialImage ? (
<>
<meta name='twitter:card' content='summary_large_image' />
<meta name='twitter:image' content={socialImage} />
<meta property='og:image' content={socialImage} />
</>
) : (
<meta name='twitter:card' content='summary' />
)}
{canonicalPageUrl && (
<>
<link rel='canonical' href={canonicalPageUrl} />
<meta property='og:url' content={canonicalPageUrl} />
<meta property='twitter:url' content={canonicalPageUrl} />
</>
)}
<title>{title}</title>
</Head>
<CustomFont site={site} />
{isLiteMode && <BodyClassName className='notion-lite' />}
<NotionRenderer
bodyClassName={cs(
styles.notion,
pageId === site.rootNotionPageId && 'index-page'
)}
components={{
pageLink: ({
href,
as,
passHref,
prefetch,
replace,
scroll,
shallow,
locale,
...props
}) => (
<Link
href={href}
as={as}
passHref={passHref}
prefetch={prefetch}
replace={replace}
scroll={scroll}
shallow={shallow}
locale={locale}
>
<a {...props} />
</Link>
)
}}
recordMap={recordMap}
rootPageId={site.rootNotionPageId}
fullPage={!isLiteMode}
darkMode={isDarkMode}
previewImages={site.previewImages !== false}
showCollectionViewDropdown={false}
showTableOfContents={showTableOfContents}
minTableOfContentsItems={minTableOfContentsItems}
defaultPageIcon={config.defaultPageIcon}
defaultPageCover={config.defaultPageCover}
defaultPageCoverPosition={config.defaultPageCoverPosition}
mapPageUrl={siteMapPageUrl}
mapImageUrl={mapNotionImageUrl}
searchNotion={searchNotion}
pageFooter={comments}
pageAside={pageAside}
footer={<Footer isDarkMode={isDarkMode} setDarkMode={setDarkMode} />}
/>
<CustomHtml site={site} />
</>
)
}