Merge branch 'preview' into feature_last_update_time

This commit is contained in:
tangly1024
2022-04-06 14:49:33 +08:00
14 changed files with 276 additions and 589 deletions

91
components/NotionPage.js Normal file
View File

@@ -0,0 +1,91 @@
import 'prismjs'
import 'prismjs/components/prism-bash'
import 'prismjs/components/prism-javascript'
import 'prismjs/components/prism-markup'
import 'prismjs/components/prism-python'
import 'prismjs/components/prism-typescript'
import 'prismjs/components/prism-java'
import { NotionRenderer } from 'react-notion-x'
import mediumZoom from 'medium-zoom'
import { useEffect, useRef } from 'react'
import dynamic from 'next/dynamic'
const Code = dynamic(() =>
import('react-notion-x/build/third-party/code').then((m) => m.Code)
)
const Collection = dynamic(() =>
import('react-notion-x/build/third-party/collection').then(
(m) => m.Collection
)
)
const Equation = dynamic(() =>
import('react-notion-x/build/third-party/equation').then((m) => m.Equation)
)
const Pdf = dynamic(
() => import('react-notion-x/build/third-party/pdf').then((m) => m.Pdf),
{
ssr: false
}
)
const Modal = dynamic(
() => import('react-notion-x/build/third-party/modal').then((m) => m.Modal),
{
ssr: false
}
)
const NotionPage = ({ post }) => {
const zoom = typeof window !== 'undefined' && mediumZoom({
container: '.notion-viewport',
background: 'rgba(0, 0, 0, 0.2)',
margin: getMediumZoomMargin()
})
const zoomRef = useRef(zoom ? zoom.clone() : null)
useEffect(() => {
// 将所有container下的所有图片添加medium-zoom
const container = document?.getElementById('container')
const imgList = container?.getElementsByTagName('img')
if (imgList && zoomRef.current) {
for (let i = 0; i < imgList.length; i++) {
(zoomRef.current).attach(imgList[i])
}
}
})
return <NotionRenderer
recordMap={post.blockMap}
mapPageUrl={mapPageUrl}
components={{
Code,
Collection,
Equation,
Modal,
Pdf
}} />
}
const mapPageUrl = id => {
return 'https://www.notion.so/' + id.replace(/-/g, '')
}
function getMediumZoomMargin() {
const width = window.innerWidth
if (width < 500) {
return 8
} else if (width < 800) {
return 20
} else if (width < 1280) {
return 30
} else if (width < 1600) {
return 40
} else if (width < 1920) {
return 48
} else {
return 72
}
}
export default NotionPage

View File

@@ -1,16 +1,8 @@
import { Feed } from 'feed' import { Feed } from 'feed'
import BLOG from '@/blog.config' import BLOG from '@/blog.config'
import ReactDOMServer from 'react-dom/server' import ReactDOMServer from 'react-dom/server'
import {
NotionRenderer,
Equation,
Code,
Collection,
CollectionRow
} from 'react-notion-x'
import { getPostBlocks } from './notion' import { getPostBlocks } from './notion'
import NotionPage from '@/components/NotionPage'
const mapPageUrl = id => 'https://www.notion.so/' + id.replace(/-/g, '')
const createFeedContent = async post => { const createFeedContent = async post => {
// 加密的文章内容只返回摘要 // 加密的文章内容只返回摘要
@@ -19,18 +11,7 @@ const createFeedContent = async post => {
} }
const blockMap = await getPostBlocks(post.id, 'rss-content') const blockMap = await getPostBlocks(post.id, 'rss-content')
if (blockMap) { if (blockMap) {
const content = ReactDOMServer.renderToString( const content = ReactDOMServer.renderToString(<NotionPage post={post} />)
<NotionRenderer
recordMap={blockMap}
components={{
equation: Equation,
code: Code,
collection: Collection,
collectionRow: CollectionRow
}}
mapPageUrl={mapPageUrl}
/>
)
const regexExp = const regexExp =
/<div class="notion-collection-row"><div class="notion-collection-row-body"><div class="notion-collection-row-property"><div class="notion-collection-column-title"><svg.*?class="notion-collection-column-title-icon">.*?<\/svg><div class="notion-collection-column-title-body">.*?<\/div><\/div><div class="notion-collection-row-value">.*?<\/div><\/div><\/div><\/div>/g /<div class="notion-collection-row"><div class="notion-collection-row-body"><div class="notion-collection-row-property"><div class="notion-collection-column-title"><svg.*?class="notion-collection-column-title-icon">.*?<\/svg><div class="notion-collection-column-title-body">.*?<\/div><\/div><div class="notion-collection-row-value">.*?<\/div><\/div><\/div><\/div>/g
return content.replace(regexExp, '') return content.replace(regexExp, '')

View File

@@ -32,15 +32,15 @@
"lodash.throttle": "^4.1.1", "lodash.throttle": "^4.1.1",
"memory-cache": "^0.2.0", "memory-cache": "^0.2.0",
"next": "^12.0.5", "next": "^12.0.5",
"notion-client": "4.16.0", "notion-client": "6.5.0",
"notion-utils": "4.16.0", "notion-utils": "6.5.0",
"preact": "^10.5.15", "preact": "^10.5.15",
"qrcode.react": "^1.0.1", "qrcode.react": "^1.0.1",
"react": "17.0.2", "react": "17.0.2",
"react-cookies": "^0.1.1", "react-cookies": "^0.1.1",
"react-cusdis": "^2.1.3", "react-cusdis": "^2.1.3",
"react-dom": "17.0.2", "react-dom": "17.0.2",
"react-notion-x": "4.16.0", "react-notion-x": "6.6.2",
"smoothscroll-polyfill": "^0.4.4", "smoothscroll-polyfill": "^0.4.4",
"typed.js": "^2.0.12", "typed.js": "^2.0.12",
"use-ackee": "^3.0.0" "use-ackee": "^3.0.0"

View File

@@ -7,11 +7,12 @@ import 'react-notion-x/src/styles.css'
import '@/styles/notion.css' // 重写部分样式 import '@/styles/notion.css' // 重写部分样式
// used for collection views (optional) // used for collection views (optional)
import 'rc-dropdown/assets/index.css' // import 'rc-dropdown/assets/index.css'
// used for code syntax highlighting (optional) // used for code syntax highlighting (optional)
import 'prismjs/themes/prism-okaidia.css' import 'prismjs/themes/prism-okaidia.css'
// used for rendering equations (optional) // used for rendering equations (optional)
import 'katex/dist/katex.min.css' import 'react-notion-x/build/third-party/equation.css'
import dynamic from 'next/dynamic' import dynamic from 'next/dynamic'
import { GlobalContextProvider } from '@/lib/global' import { GlobalContextProvider } from '@/lib/global'
import { DebugPanel } from '@/components/DebugPanel' import { DebugPanel } from '@/components/DebugPanel'
@@ -25,15 +26,15 @@ const GoogleAdsense = dynamic(() => import('@/components/GoogleAdsense'), { ssr:
const MyApp = ({ Component, pageProps }) => { const MyApp = ({ Component, pageProps }) => {
return ( return (
<GlobalContextProvider> <GlobalContextProvider>
{BLOG.THEME_SWITCH && <ThemeSwitch/>} {BLOG.THEME_SWITCH && <ThemeSwitch />}
{BLOG.DEBUG && <DebugPanel/>} {BLOG.DEBUG && <DebugPanel />}
{BLOG.ANALYTICS_ACKEE_TRACKER && <Ackee />} {BLOG.ANALYTICS_ACKEE_TRACKER && <Ackee />}
{BLOG.ANALYTICS_GOOGLE_ID && <Gtag />} {BLOG.ANALYTICS_GOOGLE_ID && <Gtag />}
{JSON.parse(BLOG.ANALYTICS_BUSUANZI_ENABLE) && <Busuanzi/>} {JSON.parse(BLOG.ANALYTICS_BUSUANZI_ENABLE) && <Busuanzi />}
{BLOG.ADSENSE_GOOGLE_ID && <GoogleAdsense/>} {BLOG.ADSENSE_GOOGLE_ID && <GoogleAdsense />}
{/* FontawesomeCDN */} {/* FontawesomeCDN */}
<link href={BLOG.FONT_AWESOME_PATH} rel="stylesheet" referrerPolicy="no-referrer" /> <link href={BLOG.FONT_AWESOME_PATH} rel="stylesheet" referrerPolicy="no-referrer" />
<Component {...pageProps} /> <Component {...pageProps} />
</GlobalContextProvider> </GlobalContextProvider>
) )

View File

@@ -1,25 +1,7 @@
import { getPageTableOfContents } from 'notion-utils' import { getPageTableOfContents } from 'notion-utils'
import 'prismjs'
import 'prismjs/components/prism-bash'
import 'prismjs/components/prism-javascript'
import 'prismjs/components/prism-markup'
import 'prismjs/components/prism-python'
import 'prismjs/components/prism-typescript'
import {
Code,
Collection,
CollectionRow,
Equation,
NotionRenderer
} from 'react-notion-x'
import LayoutBase from './LayoutBase' import LayoutBase from './LayoutBase'
import { useRef, useEffect } from 'react'
import { ArticleLock } from './components/ArticleLock' import { ArticleLock } from './components/ArticleLock'
import mediumZoom from 'medium-zoom' import NotionPage from '@/components/NotionPage'
const mapPageUrl = id => {
return 'https://www.notion.so/' + id.replace(/-/g, '')
}
export const LayoutSlug = props => { export const LayoutSlug = props => {
const { post, lock, validPassword } = props const { post, lock, validPassword } = props
@@ -28,24 +10,6 @@ export const LayoutSlug = props => {
post.toc = getPageTableOfContents(post, post.blockMap) post.toc = getPageTableOfContents(post, post.blockMap)
} }
const zoom =
typeof window !== 'undefined' &&
mediumZoom({
container: '.notion-viewport',
background: 'rgba(0, 0, 0, 0.2)',
margin: getMediumZoomMargin()
})
const zoomRef = useRef(zoom ? zoom.clone() : null)
useEffect(() => {
// 将所有container下的所有图片添加medium-zoom
const container = document.getElementById('notion-article')
const imgList = container?.getElementsByTagName('img')
if (imgList && zoomRef.current) {
for (let i = 0; i < imgList.length; i++) {
zoomRef.current.attach(imgList[i])
}
}
})
return ( return (
<LayoutBase {...props}> <LayoutBase {...props}>
<div> <div>
@@ -54,39 +18,10 @@ export const LayoutSlug = props => {
{lock && <ArticleLock password={post.password} validPassword={validPassword} />} {lock && <ArticleLock password={post.password} validPassword={validPassword} />}
{!lock && <section id="notion-article" className="px-1"> {!lock && <section id="notion-article" className="px-1">
{post.blockMap && ( {post.blockMap && <NotionPage post={post} />}
<NotionRenderer </section>}
recordMap={post.blockMap}
mapPageUrl={mapPageUrl}
components={{
equation: Equation,
code: Code,
collectionRow: CollectionRow,
collection: Collection
}}
/>
)}
</section>}
</div> </div>
</LayoutBase> </LayoutBase>
) )
} }
function getMediumZoomMargin () {
const width = window.innerWidth
if (width < 500) {
return 8
} else if (width < 800) {
return 20
} else if (width < 1280) {
return 30
} else if (width < 1600) {
return 40
} else if (width < 1920) {
return 48
} else {
return 72
}
}

View File

@@ -1,16 +1,8 @@
import Comment from '@/components/Comment' import Comment from '@/components/Comment'
import NotionPage from '@/components/NotionPage'
import formatDate from '@/lib/formatDate' import formatDate from '@/lib/formatDate'
import { useGlobal } from '@/lib/global' import { useGlobal } from '@/lib/global'
import mediumZoom from 'medium-zoom'
import Link from 'next/link' import Link from 'next/link'
import 'prismjs'
import 'prismjs/components/prism-bash'
import 'prismjs/components/prism-javascript'
import 'prismjs/components/prism-markup'
import 'prismjs/components/prism-python'
import 'prismjs/components/prism-typescript'
import { useEffect, useRef } from 'react'
import { Code, Collection, CollectionRow, Equation, NotionRenderer } from 'react-notion-x'
import ArticleAround from './ArticleAround' import ArticleAround from './ArticleAround'
/** /**
@@ -18,34 +10,15 @@ import ArticleAround from './ArticleAround'
* @param {*} param0 * @param {*} param0
* @returns * @returns
*/ */
export default function ArticleDetail ({ post, recommendPosts, prev, next }) { export default function ArticleDetail({ post, recommendPosts, prev, next }) {
const { locale } = useGlobal() const { locale } = useGlobal()
const date = formatDate(post?.date?.start_date || post.createdTime, locale.LOCALE) const date = formatDate(post?.date?.start_date || post.createdTime, locale.LOCALE)
const zoom = typeof window !== 'undefined' && mediumZoom({
container: '.notion-viewport',
background: 'rgba(0, 0, 0, 0.2)',
margin: getMediumZoomMargin()
})
const zoomRef = useRef(zoom ? zoom.clone() : null)
useEffect(() => {
// 将所有container下的所有图片添加medium-zoom
const container = document.getElementById('container')
const imgList = container.getElementsByTagName('img')
if (imgList && zoomRef.current) {
for (let i = 0; i < imgList.length; i++) {
(zoomRef.current).attach(imgList[i])
}
}
})
return (<div id="container" className="max-w-5xl overflow-x-auto flex-grow mx-auto w-screen md:w-full "> return (<div id="container" className="max-w-5xl overflow-x-auto flex-grow mx-auto w-screen md:w-full ">
{post.type && !post.type.includes('Page') && post?.page_cover && ( {post.type && !post.type.includes('Page') && post?.page_cover && (
<div className="w-full relative md:flex-shrink-0 overflow-hidden"> <div className="w-full relative md:flex-shrink-0 overflow-hidden">
{/* eslint-disable-next-line @next/next/no-img-element */} {/* eslint-disable-next-line @next/next/no-img-element */}
<img alt={post.title} src={post?.page_cover} className='object-center w-full' /> <img alt={post.title} src={post?.page_cover} className='object-center w-full' />
</div> </div>
)} )}
<article itemScope itemType="https://schema.org/Movie" <article itemScope itemType="https://schema.org/Movie"
className="subpixel-antialiased py-10 px-5 lg:pt-24 md:px-32 dark:border-gray-700 bg-white dark:bg-gray-800" className="subpixel-antialiased py-10 px-5 lg:pt-24 md:px-32 dark:border-gray-700 bg-white dark:bg-gray-800"
@@ -53,59 +26,48 @@ export default function ArticleDetail ({ post, recommendPosts, prev, next }) {
<header className='animate__slideInDown animate__animated'> <header className='animate__slideInDown animate__animated'>
{/* 文章Title */} {/* 文章Title */}
<div className="font-bold text-3xl text-black dark:text-white font-serif pt-10"> <div className="font-bold text-3xl text-black dark:text-white font-serif pt-10">
{post.title} {post.title}
</div> </div>
<section className="flex-wrap flex mt-2 text-gray-400 dark:text-gray-400 font-light leading-8"> <section className="flex-wrap flex mt-2 text-gray-400 dark:text-gray-400 font-light leading-8">
<div> <div>
<Link href={`/category/${post.category}`} passHref> <Link href={`/category/${post.category}`} passHref>
<a className="cursor-pointer text-md mr-2 hover:text-black dark:hover:text-white border-b dark:border-gray-500 border-dashed"> <a className="cursor-pointer text-md mr-2 hover:text-black dark:hover:text-white border-b dark:border-gray-500 border-dashed">
<i className="mr-1 fas fa-folder-open" /> <i className="mr-1 fas fa-folder-open" />
{post.category} {post.category}
</a>
</Link>
<span className='mr-2'>|</span>
{post.type[0] !== 'Page' && (<>
<Link
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`}
passHref
>
<a className="pl-1 mr-2 cursor-pointer hover:text-gray-700 dark:hover:text-gray-200 border-b dark:border-gray-500 border-dashed">
{date}
</a> </a>
</Link> </Link>
<span className='mr-2'>|</span> <span className='mr-2'>|</span>
</>)}
{post.type[0] !== 'Page' && (<> <div className="hidden busuanzi_container_page_pv font-light mr-2">
<Link <i className='mr-1 fas fa-eye' />
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`} &nbsp;
passHref <span className="mr-2 busuanzi_value_page_pv" />
> <span className='mr-2'>|</span>
<a className="pl-1 mr-2 cursor-pointer hover:text-gray-700 dark:hover:text-gray-200 border-b dark:border-gray-500 border-dashed">
{date}
</a>
</Link>
<span className='mr-2'>|</span>
</>)}
<div className="hidden busuanzi_container_page_pv font-light mr-2">
<i className='mr-1 fas fa-eye'/>
&nbsp;
<span className="mr-2 busuanzi_value_page_pv"/>
<span className='mr-2'>|</span>
</div>
</div> </div>
</div>
</section> </section>
</header> </header>
{/* Notion文章主体 */} {/* Notion文章主体 */}
<section id='notion-article' className='px-1'> <section id='notion-article' className='px-1'>
{post.blockMap && ( {post.blockMap && <NotionPage post={post} />}
<NotionRenderer
recordMap={post.blockMap}
mapPageUrl={mapPageUrl}
components={{
equation: Equation,
code: Code,
collectionRow: CollectionRow,
collection: Collection
}}
/>
)}
</section> </section>
<section className="px-1 py-2 my-1 text-sm font-light overflow-auto text-gray-600 dark:text-gray-400"> <section className="px-1 py-2 my-1 text-sm font-light overflow-auto text-gray-600 dark:text-gray-400">
@@ -116,38 +78,16 @@ export default function ArticleDetail ({ post, recommendPosts, prev, next }) {
data-ad-layout="in-article" data-ad-layout="in-article"
data-ad-format="fluid" data-ad-format="fluid"
data-ad-client="ca-pub-2708419466378217" data-ad-client="ca-pub-2708419466378217"
data-ad-slot="3806269138"/> data-ad-slot="3806269138" />
</section> </section>
</article> </article>
<ArticleAround prev={prev} next={next}/> <ArticleAround prev={prev} next={next} />
{/* 评论互动 */} {/* 评论互动 */}
<div className="duration-200 shadow px-12 w-screen md:w-full overflow-x-auto dark:border-gray-700 bg-white dark:bg-gray-800"> <div className="duration-200 shadow px-12 w-screen md:w-full overflow-x-auto dark:border-gray-700 bg-white dark:bg-gray-800">
<Comment frontMatter={post} /> <Comment frontMatter={post} />
</div> </div>
</div>) </div>)
} }
const mapPageUrl = id => {
return 'https://www.notion.so/' + id.replace(/-/g, '')
}
function getMediumZoomMargin () {
const width = window.innerWidth
if (width < 500) {
return 8
} else if (width < 800) {
return 20
} else if (width < 1280) {
return 30
} else if (width < 1600) {
return 40
} else if (width < 1920) {
return 48
} else {
return 72
}
}

View File

@@ -1,19 +1,16 @@
import { getPageTableOfContents } from 'notion-utils' import { getPageTableOfContents } from 'notion-utils'
import 'prismjs'
import 'prismjs/components/prism-bash'
import 'prismjs/components/prism-java'
import 'prismjs/components/prism-javascript'
import 'prismjs/components/prism-markup'
import 'prismjs/components/prism-python'
import 'prismjs/components/prism-typescript'
import { useRef } from 'react' import { useRef } from 'react'
import ArticleDetail from './components/ArticleDetail'
import { ArticleLock } from './components/ArticleLock' import { ArticleLock } from './components/ArticleLock'
import HeaderArticle from './components/HeaderArticle' import HeaderArticle from './components/HeaderArticle'
import JumpToCommentButton from './components/JumpToCommentButton' import JumpToCommentButton from './components/JumpToCommentButton'
import TocDrawer from './components/TocDrawer' import TocDrawer from './components/TocDrawer'
import TocDrawerButton from './components/TocDrawerButton' import TocDrawerButton from './components/TocDrawerButton'
import LayoutBase from './LayoutBase' import LayoutBase from './LayoutBase'
import Comment from '@/components/Comment'
import NotionPage from '@/components/NotionPage'
import ArticleAdjacent from './components/ArticleAdjacent'
import ArticleCopyright from './components/ArticleCopyright'
import ArticleRecommend from './components/ArticleRecommend'
export const LayoutSlug = props => { export const LayoutSlug = props => {
const { post, lock, validPassword } = props const { post, lock, validPassword } = props
@@ -27,27 +24,58 @@ export const LayoutSlug = props => {
const targetRef = typeof window !== 'undefined' ? document.getElementById('container') : null const targetRef = typeof window !== 'undefined' ? document.getElementById('container') : null
const floatSlot = <> const floatSlot = <>
{post?.toc?.length > 1 && <div className="block lg:hidden"> {post?.toc?.length > 1 && <div className="block lg:hidden">
<TocDrawerButton <TocDrawerButton
onClick={() => { onClick={() => {
drawerRight?.current?.handleSwitchVisible() drawerRight?.current?.handleSwitchVisible()
}} }}
/> />
</div>} </div>}
<JumpToCommentButton/> <JumpToCommentButton />
</> </>
return ( return (
<LayoutBase <LayoutBase
headerSlot={<HeaderArticle {...props}/>} headerSlot={<HeaderArticle {...props} />}
{...props} {...props}
showCategory={false} showCategory={false}
showTag={false} showTag={false}
floatSlot={floatSlot} floatSlot={floatSlot}
> >
<div className="w-full lg:shadow-sm lg:hover:shadow lg:border lg:rounded-xl lg:px-2 lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black"> <div className="w-full lg:shadow-sm lg:hover:shadow lg:border lg:rounded-xl lg:px-2 lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black">
{!lock && <ArticleDetail {...props} />}
{lock && <ArticleLock password={post.password} validPassword={validPassword} />} {lock && <ArticleLock password={post.password} validPassword={validPassword} />}
{!lock && <div id="container" className="max-w-5xl overflow-x-auto flex-grow mx-auto md:w-full md:px-5 ">
<article itemScope itemType="https://schema.org/Movie" className="subpixel-antialiased" >
{/* Notion文章主体 */}
<section id='notion-article' className='px-5'>
{post.blockMap && <NotionPage post={post} />}
</section>
<section className="px-1 py-2 my-1 text-sm font-light overflow-auto text-gray-600 dark:text-gray-400">
{/* 文章内嵌广告 */}
<ins className="adsbygoogle"
style={{ display: 'block', textAlign: 'center' }}
data-adtest="on"
data-ad-layout="in-article"
data-ad-format="fluid"
data-ad-client="ca-pub-2708419466378217"
data-ad-slot="3806269138" />
</section>
<ArticleCopyright {...props} />
<ArticleRecommend {...props} />
<ArticleAdjacent {...props} />
</article>
<hr className='border-dashed' />
{/* 评论互动 */}
<div className="duration-200 overflow-x-auto bg-white dark:bg-hexo-black-gray px-3">
<Comment frontMatter={post} />
</div>
</div>}
</div> </div>
<div className='block lg:hidden'> <div className='block lg:hidden'>

View File

@@ -1,105 +0,0 @@
import Comment from '@/components/Comment'
import mediumZoom from 'medium-zoom'
import 'prismjs'
import 'prismjs/components/prism-bash'
import 'prismjs/components/prism-javascript'
import 'prismjs/components/prism-markup'
import 'prismjs/components/prism-python'
import 'prismjs/components/prism-typescript'
import { useEffect, useRef } from 'react'
import { Code, Collection, CollectionRow, Equation, NotionRenderer } from 'react-notion-x'
import ArticleAdjacent from './ArticleAdjacent'
import ArticleCopyright from './ArticleCopyright'
import ArticleRecommend from './ArticleRecommend'
/**
*
* @param {*} param0
* @returns
*/
export default function ArticleDetail (props) {
const { post } = props
const zoom = typeof window !== 'undefined' && mediumZoom({
container: '.notion-viewport',
background: 'rgba(0, 0, 0, 0.2)',
margin: getMediumZoomMargin()
})
const zoomRef = useRef(zoom ? zoom.clone() : null)
useEffect(() => {
// 将所有container下的所有图片添加medium-zoom
const container = document?.getElementById('container')
const imgList = container?.getElementsByTagName('img')
if (imgList && zoomRef.current) {
for (let i = 0; i < imgList.length; i++) {
(zoomRef.current).attach(imgList[i])
}
}
})
return (<div id="container" className="max-w-5xl overflow-x-auto flex-grow mx-auto md:w-full md:px-5 ">
<article itemScope itemType="https://schema.org/Movie" className="subpixel-antialiased" >
{/* Notion文章主体 */}
<section id='notion-article' className='px-5'>
{post.blockMap && (
<NotionRenderer
recordMap={post.blockMap}
mapPageUrl={mapPageUrl}
components={{
equation: Equation,
code: Code,
collectionRow: CollectionRow,
collection: Collection
}}
/>
)}
</section>
<section className="px-1 py-2 my-1 text-sm font-light overflow-auto text-gray-600 dark:text-gray-400">
{/* 文章内嵌广告 */}
<ins className="adsbygoogle"
style={{ display: 'block', textAlign: 'center' }}
data-adtest="on"
data-ad-layout="in-article"
data-ad-format="fluid"
data-ad-client="ca-pub-2708419466378217"
data-ad-slot="3806269138"/>
</section>
<ArticleCopyright {...props}/>
<ArticleRecommend {...props}/>
<ArticleAdjacent {...props}/>
</article>
<hr className='border-dashed'/>
{/* 评论互动 */}
<div className="duration-200 overflow-x-auto bg-white dark:bg-hexo-black-gray px-3">
<Comment frontMatter={post} />
</div>
</div>)
}
const mapPageUrl = id => {
return 'https://www.notion.so/' + id.replace(/-/g, '')
}
function getMediumZoomMargin () {
const width = window.innerWidth
if (width < 500) {
return 8
} else if (width < 800) {
return 20
} else if (width < 1280) {
return 30
} else if (width < 1600) {
return 40
} else if (width < 1920) {
return 48
} else {
return 72
}
}

View File

@@ -1,15 +1,9 @@
import BLOG from '@/blog.config' import BLOG from '@/blog.config'
import Link from 'next/link' import Link from 'next/link'
import React from 'react' import React from 'react'
import {
Code,
Collection,
CollectionRow,
Equation,
NotionRenderer
} from 'react-notion-x'
import TagItemMini from './TagItemMini' import TagItemMini from './TagItemMini'
import CONFIG_HEXO from '../config_hexo' import CONFIG_HEXO from '../config_hexo'
import NotionPage from '@/components/NotionPage'
const BlogPostCard = ({ post, showSummary }) => { const BlogPostCard = ({ post, showSummary }) => {
const showPreview = CONFIG_HEXO.POST_LIST_PREVIEW && post.blockMap const showPreview = CONFIG_HEXO.POST_LIST_PREVIEW && post.blockMap
@@ -22,18 +16,16 @@ const BlogPostCard = ({ post, showSummary }) => {
<div className="lg:p-8 p-4 flex flex-col w-full"> <div className="lg:p-8 p-4 flex flex-col w-full">
<Link href={`${BLOG.SUB_PATH}/article/${post.slug}`} passHref> <Link href={`${BLOG.SUB_PATH}/article/${post.slug}`} passHref>
<a <a
className={`replace cursor-pointer hover:underline text-2xl font-sans ${ className={`replace cursor-pointer hover:underline text-2xl font-sans ${showPreview ? 'text-center' : ''
showPreview ? 'text-center' : '' } leading-tight text-gray-700 dark:text-gray-100 hover:text-indigo-700 dark:hover:text-indigo-400`}
} leading-tight text-gray-700 dark:text-gray-100 hover:text-indigo-700 dark:hover:text-indigo-400`}
> >
{post.title} {post.title}
</a> </a>
</Link> </Link>
<div <div
className={`flex mt-2 items-center ${ className={`flex mt-2 items-center ${showPreview ? 'justify-center' : 'justify-start'
showPreview ? 'justify-center' : 'justify-start' } flex-wrap dark:text-gray-500 text-gray-400 hover:text-indigo-700 dark:hover:text-indigo-400`}
} flex-wrap dark:text-gray-500 text-gray-400 hover:text-indigo-700 dark:hover:text-indigo-400`}
> >
<Link <Link
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`} href={`/archive#${post?.date?.start_date?.substr(0, 7)}`}
@@ -54,17 +46,7 @@ const BlogPostCard = ({ post, showSummary }) => {
{showPreview && ( {showPreview && (
<div className="overflow-ellipsis truncate"> <div className="overflow-ellipsis truncate">
<NotionRenderer <NotionPage post={post} />
bodyClassName="max-h-full"
recordMap={post.blockMap}
mapPageUrl={mapPageUrl}
components={{
equation: Equation,
code: Code,
collectionRow: CollectionRow,
collection: Collection
}}
/>
</div> </div>
)} )}
@@ -104,8 +86,4 @@ const BlogPostCard = ({ post, showSummary }) => {
) )
} }
const mapPageUrl = id => {
return 'https://www.notion.so/' + id.replace(/-/g, '')
}
export default BlogPostCard export default BlogPostCard

View File

@@ -2,8 +2,7 @@ import { getPageTableOfContents } from 'notion-utils'
import LayoutBase from './LayoutBase' import LayoutBase from './LayoutBase'
import { useGlobal } from '@/lib/global' import { useGlobal } from '@/lib/global'
import mediumZoom from 'medium-zoom' import React from 'react'
import React, { useEffect, useRef } from 'react'
import Catalog from './components/Catalog' import Catalog from './components/Catalog'
import { ArticleDetail } from './components/ArticleDetail' import { ArticleDetail } from './components/ArticleDetail'
import { ArticleLock } from './components/ArticleLock' import { ArticleLock } from './components/ArticleLock'
@@ -17,26 +16,6 @@ export const LayoutSlug = props => {
} }
const { locale } = useGlobal() const { locale } = useGlobal()
const zoom =
typeof window !== 'undefined' &&
mediumZoom({
container: '.notion-viewport',
background: 'rgba(0, 0, 0, 0.2)',
margin: getMediumZoomMargin()
})
const zoomRef = useRef(zoom ? zoom.clone() : null)
useEffect(() => {
// 将所有container下的所有图片添加medium-zoom
const container = document.getElementById('notion-article')
const imgList = container?.getElementsByTagName('img')
if (imgList && zoomRef.current) {
for (let i = 0; i < imgList.length; i++) {
zoomRef.current.attach(imgList[i])
}
}
})
const slotRight = post?.toc && post?.toc?.length > 3 && ( const slotRight = post?.toc && post?.toc?.length > 3 && (
<div key={locale.COMMON.TABLE_OF_CONTENTS} > <div key={locale.COMMON.TABLE_OF_CONTENTS} >
<Catalog toc={post.toc} /> <Catalog toc={post.toc} />
@@ -50,27 +29,9 @@ export const LayoutSlug = props => {
slotRight={slotRight} slotRight={slotRight}
> >
{!lock && <ArticleDetail {...props} />} {!lock && <ArticleDetail {...props} />}
{lock && <ArticleLock password={post.password} validPassword={validPassword} />} {lock && <ArticleLock password={post.password} validPassword={validPassword} />}
</LayoutBase> </LayoutBase>
) )
} }
function getMediumZoomMargin () {
const width = window.innerWidth
if (width < 500) {
return 8
} else if (width < 800) {
return 20
} else if (width < 1280) {
return 30
} else if (width < 1600) {
return 40
} else if (width < 1920) {
return 48
} else {
return 72
}
}

View File

@@ -1,10 +1,3 @@
import {
Code,
Collection,
CollectionRow,
Equation,
NotionRenderer
} from 'react-notion-x'
import Comment from '@/components/Comment' import Comment from '@/components/Comment'
import Image from 'next/image' import Image from 'next/image'
import Link from 'next/link' import Link from 'next/link'
@@ -14,18 +7,8 @@ import TagItemMini from './TagItemMini'
import CONFIG_MEDIUM from '../config_medium' import CONFIG_MEDIUM from '../config_medium'
import formatDate from '@/lib/formatDate' import formatDate from '@/lib/formatDate'
import { useGlobal } from '@/lib/global' import { useGlobal } from '@/lib/global'
import 'prismjs'
import 'prismjs/components/prism-bash'
import 'prismjs/components/prism-javascript'
import 'prismjs/components/prism-markup'
import 'prismjs/components/prism-python'
import 'prismjs/components/prism-typescript'
import BLOG from '@/blog.config' import BLOG from '@/blog.config'
import NotionPage from '@/components/NotionPage'
const mapPageUrl = id => {
return 'https://www.notion.so/' + id.replace(/-/g, '')
}
export const ArticleDetail = props => { export const ArticleDetail = props => {
const { post, prev, next } = props const { post, prev, next } = props
@@ -62,18 +45,7 @@ export const ArticleDetail = props => {
</section> </section>
{/* Notion文章主体 */} {/* Notion文章主体 */}
<section id="notion-article" className="px-1 max-w-5xl"> <section id="notion-article" className="px-1 max-w-5xl">
{post.blockMap && ( {post.blockMap && (<NotionPage post={post} />)}
<NotionRenderer
recordMap={post.blockMap}
mapPageUrl={mapPageUrl}
components={{
equation: Equation,
code: Code,
collectionRow: CollectionRow,
collection: Collection
}}
/>
)}
</section> </section>
<section className="px-1 py-2 my-1 text-sm font-light overflow-auto text-gray-600 dark:text-gray-400"> <section className="px-1 py-2 my-1 text-sm font-light overflow-auto text-gray-600 dark:text-gray-400">
@@ -90,10 +62,10 @@ export const ArticleDetail = props => {
</section> </section>
<section> <section>
<div className='flex justify-between'> <div className='flex justify-between'>
{ CONFIG_MEDIUM.POST_DETAIL_CATEGORY && post.category && <CategoryItem category={post.category}/>} {CONFIG_MEDIUM.POST_DETAIL_CATEGORY && post.category && <CategoryItem category={post.category} />}
<div> <div>
{ CONFIG_MEDIUM.POST_DETAIL_TAG && post?.tagItems?.map(tag => <TagItemMini key={tag.name} tag={tag} />)} {CONFIG_MEDIUM.POST_DETAIL_TAG && post?.tagItems?.map(tag => <TagItemMini key={tag.name} tag={tag} />)}
</div> </div>
</div> </div>
<ArticleAround prev={prev} next={next} /> <ArticleAround prev={prev} next={next} />
<Comment frontMatter={post} /> <Comment frontMatter={post} />

View File

@@ -1,8 +1,8 @@
import BLOG from '@/blog.config' import BLOG from '@/blog.config'
import NotionPage from '@/components/NotionPage'
import { useGlobal } from '@/lib/global' import { useGlobal } from '@/lib/global'
import Link from 'next/link' import Link from 'next/link'
import React from 'react' import React from 'react'
import { Code, Collection, Equation, NotionRenderer } from 'react-notion-x'
import CONFIG_MEDIUM from '../config_medium' import CONFIG_MEDIUM from '../config_medium'
import CategoryItem from './CategoryItem' import CategoryItem from './CategoryItem'
import TagItemMini from './TagItemMini' import TagItemMini from './TagItemMini'
@@ -51,16 +51,7 @@ const BlogPostCard = ({ post, showSummary }) => {
{showPreview && ( {showPreview && (
<div className="overflow-ellipsis truncate"> <div className="overflow-ellipsis truncate">
<NotionRenderer <NotionPage post={post} />
bodyClassName="max-h-full"
recordMap={post.blockMap}
mapPageUrl={mapPageUrl}
components={{
equation: Equation,
code: Code,
collection: Collection
}}
/>
<div className="pointer-events-none border-t pt-8 border-dashed"> <div className="pointer-events-none border-t pt-8 border-dashed">
<div className="w-full justify-start flex"> <div className="w-full justify-start flex">
<Link href={`${BLOG.SUB_PATH}/article/${post.slug}`} passHref> <Link href={`${BLOG.SUB_PATH}/article/${post.slug}`} passHref>
@@ -78,8 +69,4 @@ const BlogPostCard = ({ post, showSummary }) => {
) )
} }
const mapPageUrl = id => {
return 'https://www.notion.so/' + id.replace(/-/g, '')
}
export default BlogPostCard export default BlogPostCard

View File

@@ -6,50 +6,23 @@ import ShareBar from './ShareBar'
import TagItem from './TagItem' import TagItem from './TagItem'
import formatDate from '@/lib/formatDate' import formatDate from '@/lib/formatDate'
import { useGlobal } from '@/lib/global' import { useGlobal } from '@/lib/global'
import mediumZoom from 'medium-zoom'
import Link from 'next/link' import Link from 'next/link'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import 'prismjs'
import 'prismjs/components/prism-bash'
import 'prismjs/components/prism-c'
import 'prismjs/components/prism-java'
import 'prismjs/components/prism-markup'
import 'prismjs/components/prism-python'
import 'prismjs/components/prism-typescript'
import { useEffect, useRef } from 'react'
import { Code, Collection, CollectionRow, Equation, NotionRenderer } from 'react-notion-x'
import ArticleCopyright from './ArticleCopyright' import ArticleCopyright from './ArticleCopyright'
import WordCount from './WordCount' import WordCount from './WordCount'
import NotionPage from '@/components/NotionPage'
/** /**
* *
* @param {*} param0 * @param {*} param0
* @returns * @returns
*/ */
export default function ArticleDetail (props) { export default function ArticleDetail(props) {
const { post, recommendPosts, prev, next, showArticleInfo } = props const { post, recommendPosts, prev, next, showArticleInfo } = props
const url = BLOG.LINK + useRouter().asPath const url = BLOG.LINK + useRouter().asPath
const { locale } = useGlobal() const { locale } = useGlobal()
const date = formatDate(post?.date?.start_date || post.createdTime, locale.LOCALE) const date = formatDate(post?.date?.start_date || post.createdTime, locale.LOCALE)
const zoom = typeof window !== 'undefined' && mediumZoom({
container: '.notion-viewport',
background: 'rgba(0, 0, 0, 0.2)',
margin: getMediumZoomMargin()
})
const zoomRef = useRef(zoom ? zoom.clone() : null)
useEffect(() => {
// 将所有container下的所有图片添加medium-zoom
const container = document.getElementById('container')
const imgList = container.getElementsByTagName('img')
if (imgList && zoomRef.current) {
for (let i = 0; i < imgList.length; i++) {
(zoomRef.current).attach(imgList[i])
}
}
})
return (<div id="container" className="shadow md:hover:shadow-2xl overflow-x-auto flex-grow mx-auto w-screen md:w-full "> return (<div id="container" className="shadow md:hover:shadow-2xl overflow-x-auto flex-grow mx-auto w-screen md:w-full ">
<div itemScope itemType="https://schema.org/Movie" <div itemScope itemType="https://schema.org/Movie"
className="subpixel-antialiased py-10 px-5 lg:pt-24 md:px-24 dark:border-gray-700 bg-white dark:bg-gray-800" className="subpixel-antialiased py-10 px-5 lg:pt-24 md:px-24 dark:border-gray-700 bg-white dark:bg-gray-800"
@@ -57,68 +30,57 @@ export default function ArticleDetail (props) {
{showArticleInfo && <header className='animate__slideInDown animate__animated'> {showArticleInfo && <header className='animate__slideInDown animate__animated'>
{post.type && !post.type.includes('Page') && post?.page_cover && ( {post.type && !post.type.includes('Page') && post?.page_cover && (
<div className="w-full relative md:flex-shrink-0 overflow-hidden"> <div className="w-full relative md:flex-shrink-0 overflow-hidden">
{/* eslint-disable-next-line @next/next/no-img-element */} {/* eslint-disable-next-line @next/next/no-img-element */}
<img alt={post.title} src={post?.page_cover} className='object-center w-full' /> <img alt={post.title} src={post?.page_cover} className='object-center w-full' />
</div> </div>
)} )}
{/* 文章Title */} {/* 文章Title */}
<div className="font-bold text-3xl text-black dark:text-white font-serif pt-10"> <div className="font-bold text-3xl text-black dark:text-white font-serif pt-10">
{post.title} {post.title}
</div> </div>
<section className="flex-wrap flex mt-2 text-gray-400 dark:text-gray-400 font-light leading-8"> <section className="flex-wrap flex mt-2 text-gray-400 dark:text-gray-400 font-light leading-8">
<div> <div>
{post.category && <> {post.category && <>
<Link href={`/category/${post.category}`} passHref> <Link href={`/category/${post.category}`} passHref>
<a className="cursor-pointer text-md mr-2 hover:text-black dark:hover:text-white border-b dark:border-gray-500 border-dashed"> <a className="cursor-pointer text-md mr-2 hover:text-black dark:hover:text-white border-b dark:border-gray-500 border-dashed">
<i className="mr-1 far fa-folder-open" /> {post.category} <i className="mr-1 far fa-folder-open" /> {post.category}
</a> </a>
</Link> </Link>
<span className='mr-2'>|</span> <span className='mr-2'>|</span>
</>} </>}
{post.type[0] !== 'Page' && (<> {post.type[0] !== 'Page' && (<>
<Link <Link
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`} href={`/archive#${post?.date?.start_date?.substr(0, 7)}`}
passHref passHref
> >
<a className="pl-1 mr-2 cursor-pointer hover:text-gray-700 dark:hover:text-gray-200 border-b dark:border-gray-500 border-dashed"> <a className="pl-1 mr-2 cursor-pointer hover:text-gray-700 dark:hover:text-gray-200 border-b dark:border-gray-500 border-dashed">
{date} {date}
</a> </a>
</Link> </Link>
<span className='mr-2'>|</span> <span className='mr-2'>|</span>
</>)} </>)}
<div className="hidden busuanzi_container_page_pv font-light mr-2"> <div className="hidden busuanzi_container_page_pv font-light mr-2">
<i className='mr-1 fas fa-eye'/> <i className='mr-1 fas fa-eye' />
&nbsp; &nbsp;
<span className="mr-2 busuanzi_value_page_pv"/> <span className="mr-2 busuanzi_value_page_pv" />
<span className='mr-2'>|</span> <span className='mr-2'>|</span>
</div>
</div> </div>
<div className='flex flex-nowrap whitespace-nowrap items-center font-light text-md'> </div>
<WordCount/> <div className='flex flex-nowrap whitespace-nowrap items-center font-light text-md'>
</div> <WordCount />
</div>
</section> </section>
</header>} </header>}
{/* Notion内容主体 */} {/* Notion内容主体 */}
<article id='notion-article' className='px-1'> <article id='notion-article' className='px-1'>
{post.blockMap && ( {post.blockMap && (<NotionPage post={post} />)}
<NotionRenderer
recordMap={post.blockMap}
mapPageUrl={mapPageUrl}
components={{
equation: Equation,
code: Code,
collectionRow: CollectionRow,
collection: Collection
}}
/>
)}
</article> </article>
<section className="px-1 py-2 my-1 text-sm font-light overflow-auto text-gray-600 dark:text-gray-400"> <section className="px-1 py-2 my-1 text-sm font-light overflow-auto text-gray-600 dark:text-gray-400">
@@ -129,34 +91,34 @@ export default function ArticleDetail (props) {
data-ad-layout="in-article" data-ad-layout="in-article"
data-ad-format="fluid" data-ad-format="fluid"
data-ad-client="ca-pub-2708419466378217" data-ad-client="ca-pub-2708419466378217"
data-ad-slot="3806269138"/> data-ad-slot="3806269138" />
</section> </section>
{showArticleInfo && <> {showArticleInfo && <>
{/* 版权声明 */} {/* 版权声明 */}
<ArticleCopyright author={BLOG.AUTHOR} url={url} /> <ArticleCopyright author={BLOG.AUTHOR} url={url} />
{/* 推荐文章 */} {/* 推荐文章 */}
<RecommendPosts currentPost={post} recommendPosts={recommendPosts} /> <RecommendPosts currentPost={post} recommendPosts={recommendPosts} />
{/* 标签列表 */} {/* 标签列表 */}
<section className="md:flex md:justify-between"> <section className="md:flex md:justify-between">
{post.tagItems && ( {post.tagItems && (
<div className="flex flex-nowrap leading-8 p-1 py-4 overflow-x-auto"> <div className="flex flex-nowrap leading-8 p-1 py-4 overflow-x-auto">
<div className="hidden md:block dark:text-gray-300 whitespace-nowrap"> <div className="hidden md:block dark:text-gray-300 whitespace-nowrap">
{locale.COMMON.TAGS} {locale.COMMON.TAGS}
</div>
{post.tagItems.map(tag => (
<TagItem key={tag.name} tag={tag} />
))}
</div> </div>
{post.tagItems.map(tag => ( )}
<TagItem key={tag.name} tag={tag} /> <div>
))} <ShareBar post={post} />
</div> </div>
)} </section>
<div>
<ShareBar post={post} />
</div>
</section>
<BlogAround prev={prev} next={next} /> <BlogAround prev={prev} next={next} />
</>} </>}
{/* 评论互动 */} {/* 评论互动 */}
@@ -167,25 +129,3 @@ export default function ArticleDetail (props) {
</div>) </div>)
} }
const mapPageUrl = id => {
return 'https://www.notion.so/' + id.replace(/-/g, '')
}
function getMediumZoomMargin () {
const width = window.innerWidth
if (width < 500) {
return 8
} else if (width < 800) {
return 20
} else if (width < 1280) {
return 30
} else if (width < 1600) {
return 40
} else if (width < 1920) {
return 48
} else {
return 72
}
}

View File

@@ -3,16 +3,10 @@ import { useGlobal } from '@/lib/global'
import Image from 'next/image' import Image from 'next/image'
import Link from 'next/link' import Link from 'next/link'
import React from 'react' import React from 'react'
import {
Code,
Collection,
CollectionRow,
Equation,
NotionRenderer
} from 'react-notion-x'
import Card from './Card' import Card from './Card'
import TagItemMini from './TagItemMini' import TagItemMini from './TagItemMini'
import CONFIG_NEXT from '../config_next' import CONFIG_NEXT from '../config_next'
import NotionPage from '@/components/NotionPage'
const BlogPostCard = ({ post, showSummary }) => { const BlogPostCard = ({ post, showSummary }) => {
const { locale } = useGlobal() const { locale } = useGlobal()
@@ -26,18 +20,16 @@ const BlogPostCard = ({ post, showSummary }) => {
<div className="lg:p-8 p-4 flex flex-col w-full"> <div className="lg:p-8 p-4 flex flex-col w-full">
<Link href={`${BLOG.SUB_PATH}/article/${post.slug}`} passHref> <Link href={`${BLOG.SUB_PATH}/article/${post.slug}`} passHref>
<a <a
className={`cursor-pointer font-bold hover:underline text-3xl ${ className={`cursor-pointer font-bold hover:underline text-3xl ${showPreview ? 'text-center' : ''
showPreview ? 'text-center' : '' } leading-tight text-gray-700 dark:text-gray-100 hover:text-blue-500 dark:hover:text-blue-400`}
} leading-tight text-gray-700 dark:text-gray-100 hover:text-blue-500 dark:hover:text-blue-400`}
> >
{post.title} {post.title}
</a> </a>
</Link> </Link>
<div <div
className={`flex mt-2 items-center ${ className={`flex mt-2 items-center ${showPreview ? 'justify-center' : 'justify-start'
showPreview ? 'justify-center' : 'justify-start' } flex-wrap dark:text-gray-500 text-gray-400 hover:text-blue-500 dark:hover:text-blue-400 `}
} flex-wrap dark:text-gray-500 text-gray-400 hover:text-blue-500 dark:hover:text-blue-400 `}
> >
<div> <div>
{post.category && ( {post.category && (
@@ -87,17 +79,7 @@ const BlogPostCard = ({ post, showSummary }) => {
{showPreview && post?.blockMap && ( {showPreview && post?.blockMap && (
<div className="overflow-ellipsis truncate"> <div className="overflow-ellipsis truncate">
<NotionRenderer <NotionPage post={post} />
bodyClassName="max-h-full"
recordMap={post.blockMap}
mapPageUrl={mapPageUrl}
components={{
equation: Equation,
code: Code,
collectionRow: CollectionRow,
collection: Collection
}}
/>
</div> </div>
)} )}
@@ -130,8 +112,4 @@ const BlogPostCard = ({ post, showSummary }) => {
) )
} }
const mapPageUrl = id => {
return 'https://www.notion.so/' + id.replace(/-/g, '')
}
export default BlogPostCard export default BlogPostCard