diff --git a/.env.example b/.env.example index 04dfc9a..bca6ff5 100644 --- a/.env.example +++ b/.env.example @@ -18,7 +18,7 @@ # Optional (for persisting preview images to redis) # NOTE: if you want to enable redis, only REDIS_HOST and REDIS_PASSWORD are required -# NOTE: don't forget to set isRedisEnabled to true in the site.config.js file +# NOTE: don't forget to set isRedisEnabled to true in the site.config.ts file #REDIS_HOST= #REDIS_PASSWORD= #REDIS_USER='default' diff --git a/components/Footer.tsx b/components/Footer.tsx index 2e30556..f5fcffe 100644 --- a/components/Footer.tsx +++ b/components/Footer.tsx @@ -1,4 +1,5 @@ import React from 'react' +import useDarkMode from '@fisch0920/use-dark-mode' import { FaTwitter } from '@react-icons/all-files/fa/FaTwitter' import { FaZhihu } from '@react-icons/all-files/fa/FaZhihu' import { FaGithub } from '@react-icons/all-files/fa/FaGithub' @@ -13,17 +14,16 @@ import styles from './styles.module.css' const year = new Date().getFullYear() -export const Footer: React.FC<{ - isDarkMode: boolean - toggleDarkMode: () => void -}> = ({ isDarkMode, toggleDarkMode }) => { +export const FooterImpl: React.FC = () => { const [hasMounted, setHasMounted] = React.useState(false) - const toggleDarkModeCb = React.useCallback( + const darkMode = useDarkMode(false, { classNameDark: 'dark-mode' }) + + const onToggleDarkMode = React.useCallback( (e) => { e.preventDefault() - toggleDarkMode() + darkMode.toggle() }, - [toggleDarkMode] + [darkMode] ) React.useEffect(() => { @@ -34,18 +34,18 @@ export const Footer: React.FC<{ ) } + +export const Footer = React.memo(FooterImpl) diff --git a/components/NotionPage.tsx b/components/NotionPage.tsx index 2f118d0..90be33d 100644 --- a/components/NotionPage.tsx +++ b/components/NotionPage.tsx @@ -15,12 +15,7 @@ import { Tweet, TwitterContextProvider } from 'react-static-tweets' import { NotionRenderer } from 'react-notion-x' // utils -import { - getBlockTitle, - getBlockIcon, - getPageProperty, - isUrl -} from 'notion-utils' +import { getBlockTitle, getPageProperty } from 'notion-utils' import { mapPageUrl, getCanonicalPageUrl } from 'lib/map-page-url' import { mapImageUrl } from 'lib/map-image-url' import { getPageTweet } from 'lib/get-page-tweet' @@ -37,6 +32,8 @@ import { PageActions } from './PageActions' import { Footer } from './Footer' import { PageSocial } from './PageSocial' const ReactGiscus = dynamic(() => import('./ReactGiscus')) +import { NotionPageHeader } from './NotionPageHeader' +import { GitHubShareButton } from './GitHubShareButton' import styles from './styles.module.css' @@ -62,7 +59,11 @@ const Pdf = dynamic( } ) const Modal = dynamic( - () => import('react-notion-x/build/third-party/modal').then((m) => m.Modal), + () => + import('react-notion-x/build/third-party/modal').then((m) => { + m.Modal.setAppElement('.notion-viewport') + return m.Modal + }), { ssr: false } @@ -77,15 +78,48 @@ export const NotionPage: React.FC = ({ const router = useRouter() const lite = useSearchParam('lite') - const params: any = {} - if (lite) params.lite = lite + const components = React.useMemo( + () => ({ + nextImage: Image, + nextLink: Link, + Code, + Collection, + Equation, + Pdf, + Modal, + Tweet, + Header: NotionPageHeader + }), + [] + ) + + const twitterContextValue = React.useMemo(() => { + if (!recordMap) { + return null + } + + return { + tweetAstMap: (recordMap as any).tweetAstMap || {}, + swrOptions: { + fetcher: (id: string) => + fetch(`/api/get-tweet-ast/${id}`).then((r) => r.json()) + } + } + }, [recordMap]) // lite mode is for oembed const isLiteMode = lite === 'true' - const searchParams = new URLSearchParams(params) const darkMode = useDarkMode(false, { classNameDark: 'dark-mode' }) + const siteMapPageUrl = React.useMemo(() => { + const params: any = {} + if (lite) params.lite = lite + + const searchParams = new URLSearchParams(params) + return mapPageUrl(site, recordMap, searchParams) + }, [site, recordMap, lite]) + if (router.isFallback) { return } @@ -107,8 +141,6 @@ export const NotionPage: React.FC = ({ g.block = block } - const siteMapPageUrl = mapPageUrl(site, recordMap, searchParams) - const canonicalPageUrl = !config.isDev && getCanonicalPageUrl(site, recordMap)(pageId) @@ -121,41 +153,15 @@ export const NotionPage: React.FC = ({ const socialImage = mapImageUrl( getPageProperty('Social Image', block, recordMap) || - (block as PageBlock).format?.page_cover || - config.defaultPageCover, + (block as PageBlock).format?.page_cover || + config.defaultPageCover, block ) - const socialImageCoverPosition = - (block as PageBlock).format?.page_cover_position ?? - config.defaultPageCoverPosition - const socialImageObjectPosition = socialImageCoverPosition - ? `center ${(1 - socialImageCoverPosition) * 100}%` - : null - - const blockIcon = getBlockIcon(block, recordMap) - const socialAuthorImage = mapImageUrl( - blockIcon && isUrl(blockIcon) ? blockIcon : config.defaultPageIcon, - block - ) - - const socialAuthor = - getPageProperty('Author', block, recordMap) || config.author - const socialDescription = getPageProperty('Description', block, recordMap) || config.description - const timePublished = getPageProperty('Published', block, recordMap) - const datePublished = timePublished ? new Date(timePublished) : undefined - const socialDate = - isBlogPost && datePublished - ? `${datePublished.toLocaleString('en-US', { - month: 'long' - })} ${datePublished.getFullYear()}` - : undefined - const socialDetail = socialDate || site.domain - let comments: React.ReactNode = null let pageAside: React.ReactNode = null @@ -165,7 +171,7 @@ export const NotionPage: React.FC = ({ comments = ( ) - } + } const tweet = getPageTweet(block, recordMap) if (tweet) { pageAside = @@ -175,24 +181,13 @@ export const NotionPage: React.FC = ({ } return ( - - fetch(`/api/get-tweet-ast/${id}`).then((r) => r.json()) - } - }} - > + @@ -205,16 +200,7 @@ export const NotionPage: React.FC = ({ styles.notion, pageId === site.rootNotionPageId && 'index-page' )} - components={{ - nextImage: Image, - nextLink: Link, - Code, - Collection, - Equation, - Pdf, - Modal, - Tweet - }} + components={components} recordMap={recordMap} rootPageId={site.rootNotionPageId} rootDomain={site.domain} @@ -229,15 +215,10 @@ export const NotionPage: React.FC = ({ defaultPageCoverPosition={config.defaultPageCoverPosition} mapPageUrl={siteMapPageUrl} mapImageUrl={mapImageUrl} - searchNotion={searchNotion} pageFooter={comments} + searchNotion={config.isSearchEnabled ? searchNotion : null} pageAside={pageAside} - footer={ -