|
import dynamic from 'next/dynamic' |
|
import mediumZoom from '@fisch0920/medium-zoom' |
|
import { useEffect, useRef } from 'react' |
|
import 'katex/dist/katex.min.css' |
|
import { compressImage, mapImgUrl } from '@/lib/notion/mapImage' |
|
import { isBrowser } from '@/lib/utils' |
|
import { siteConfig } from '@/lib/config' |
|
import { NotionRenderer } from 'react-notion-x' |
|
|
|
const Code = dynamic(() => |
|
import('react-notion-x/build/third-party/code').then(async (m) => { |
|
return m.Code |
|
}), { ssr: false } |
|
) |
|
|
|
|
|
const Equation = dynamic(() => |
|
import('@/components/Equation').then(async (m) => { |
|
|
|
await import('@/lib/mhchem') |
|
return m.Equation |
|
}), { ssr: false } |
|
) |
|
|
|
const Pdf = dynamic( |
|
() => import('react-notion-x/build/third-party/pdf').then((m) => m.Pdf), |
|
{ |
|
ssr: false |
|
} |
|
) |
|
|
|
|
|
|
|
const PrismMac = dynamic(() => import('@/components/PrismMac'), { |
|
ssr: false |
|
}) |
|
|
|
|
|
|
|
|
|
const TweetEmbed = dynamic(() => import('react-tweet-embed'), { |
|
ssr: false |
|
}) |
|
|
|
const Collection = dynamic(() => |
|
import('react-notion-x/build/third-party/collection').then((m) => m.Collection), { ssr: true } |
|
) |
|
|
|
const Modal = dynamic( |
|
() => import('react-notion-x/build/third-party/modal').then((m) => m.Modal), { ssr: false } |
|
) |
|
|
|
const Tweet = ({ id }) => { |
|
return <TweetEmbed tweetId={id} /> |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
const NotionPage = ({ post, className }) => { |
|
useEffect(() => { |
|
autoScrollToTarget() |
|
}, []) |
|
|
|
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(() => { |
|
if (!isBrowser) return; |
|
|
|
|
|
if (siteConfig('POST_DISABLE_GALLERY_CLICK')) { |
|
setTimeout(() => { |
|
if (isBrowser) { |
|
const imgList = document?.querySelectorAll('.notion-collection-card-cover img') |
|
if (imgList && zoomRef.current) { |
|
for (let i = 0; i < imgList.length; i++) { |
|
(zoomRef.current).attach(imgList[i]) |
|
} |
|
} |
|
|
|
const cards = document.getElementsByClassName('notion-collection-card') |
|
for (const e of cards) { |
|
e.removeAttribute('href') |
|
} |
|
} |
|
}, 800) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (isBrowser) { |
|
const currentURL = window.location.origin + window.location.pathname |
|
const allAnchorTags = document.getElementsByTagName('a') |
|
for (const anchorTag of allAnchorTags) { |
|
if (anchorTag?.target === '_blank') { |
|
const hrefWithoutQueryHash = anchorTag.href.split('?')[0].split('#')[0] |
|
const hrefWithRelativeHash = currentURL.split('#')[0] + anchorTag.href.split('#')[1] |
|
|
|
if (currentURL === hrefWithoutQueryHash || currentURL === hrefWithRelativeHash) { |
|
anchorTag.target = '_self' |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
const observer = new MutationObserver((mutationsList, observer) => { |
|
mutationsList.forEach(mutation => { |
|
if (mutation.type === 'attributes' && mutation.attributeName === 'class') { |
|
if (mutation.target.classList.contains('medium-zoom-image--opened')) { |
|
|
|
setTimeout(() => { |
|
|
|
const src = mutation?.target?.getAttribute('src'); |
|
|
|
mutation?.target?.setAttribute('src', compressImage(src, siteConfig('IMAGE_ZOOM_IN_WIDTH', 1200))); |
|
}, 800); |
|
} |
|
} |
|
}); |
|
}); |
|
|
|
|
|
observer.observe(document.body, { attributes: true, subtree: true, attributeFilter: ['class'] }); |
|
|
|
return () => { |
|
observer.disconnect(); |
|
}; |
|
}, []) |
|
|
|
if (!post || !post.blockMap) { |
|
return <>{post?.summary || ''}</> |
|
} |
|
|
|
return <div id='notion-article' className={`mx-auto overflow-hidden ${className || ''}`}> |
|
<NotionRenderer |
|
recordMap={post.blockMap} |
|
mapPageUrl={mapPageUrl} |
|
mapImageUrl={mapImgUrl} |
|
components={{ |
|
Code, |
|
Collection, |
|
Equation, |
|
Modal, |
|
Pdf, |
|
Tweet |
|
}} /> |
|
|
|
<PrismMac/> |
|
|
|
</div> |
|
} |
|
|
|
|
|
|
|
|
|
const autoScrollToTarget = () => { |
|
setTimeout(() => { |
|
|
|
const needToJumpToTitle = window.location.hash |
|
if (needToJumpToTitle) { |
|
const tocNode = document.getElementById(window.location.hash.substring(1)) |
|
if (tocNode && tocNode?.className?.indexOf('notion') > -1) { |
|
tocNode.scrollIntoView({ block: 'start', behavior: 'smooth' }) |
|
} |
|
} |
|
}, 180) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
const mapPageUrl = id => { |
|
|
|
return '/' + 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 |
|
|