mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-06-04 15:10:23 +00:00
Merge branch 'preview' into feature_last_update_time
This commit is contained in:
91
components/NotionPage.js
Normal file
91
components/NotionPage.js
Normal 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
|
||||||
23
lib/rss.js
23
lib/rss.js
@@ -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, '')
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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)}`}
|
|
||||||
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'/>
|
|
||||||
|
|
||||||
<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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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'>
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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} />
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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' />
|
||||||
|
|
||||||
<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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user