mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-14 23:16:49 +00:00
@@ -26,6 +26,9 @@ const GiscusComponent = dynamic(
|
||||
)
|
||||
|
||||
const Comment = ({ frontMatter }) => {
|
||||
if (!frontMatter) {
|
||||
return <>Loading...</>
|
||||
}
|
||||
const router = useRouter()
|
||||
const { locale, isDarkMode } = useGlobal()
|
||||
return (
|
||||
|
||||
@@ -2,32 +2,28 @@
|
||||
import BLOG from '@/blog.config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { loadExternalResource } from '@/lib/utils'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
export default function Live2D () {
|
||||
export default function Live2D() {
|
||||
if (!BLOG.WIDGET_PET) {
|
||||
return <></>
|
||||
}
|
||||
const [init, setInit] = useState()
|
||||
const { switchTheme } = useGlobal()
|
||||
|
||||
function handleClick () {
|
||||
function handleClick() {
|
||||
if (BLOG.WIDGET_PET_SWITCH_THEME) {
|
||||
switchTheme()
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!init) {
|
||||
initLive2D()
|
||||
setInit(true)
|
||||
}
|
||||
}, [init])
|
||||
initLive2D()
|
||||
}, [])
|
||||
|
||||
return <canvas id="live2d" className='cursor-pointer' width="280" height="250" onClick={handleClick} alt='切换主题' title='切换主题'/>
|
||||
return <canvas id="live2d" className='cursor-pointer' width="280" height="250" onClick={handleClick} alt='切换主题' title='切换主题' />
|
||||
}
|
||||
|
||||
function initLive2D () {
|
||||
function initLive2D() {
|
||||
// 加载 waifu.css live2d.min.js waifu-tips.js
|
||||
if (screen.width >= 768) {
|
||||
Promise.all([
|
||||
|
||||
@@ -11,6 +11,7 @@ import { NotionRenderer } from 'react-notion-x'
|
||||
import mediumZoom from 'medium-zoom'
|
||||
import { useEffect, useRef } from 'react'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
const Code = dynamic(() =>
|
||||
import('react-notion-x/build/third-party/code').then((m) => m.Code)
|
||||
@@ -36,6 +37,10 @@ const Modal = dynamic(
|
||||
}
|
||||
)
|
||||
const NotionPage = ({ post }) => {
|
||||
if (!post || !post.blockMap) {
|
||||
return <>{post?.summary || ''}</>
|
||||
}
|
||||
|
||||
const zoom = typeof window !== 'undefined' && mediumZoom({
|
||||
container: '.notion-viewport',
|
||||
background: 'rgba(0, 0, 0, 0.2)',
|
||||
@@ -43,6 +48,8 @@ const NotionPage = ({ post }) => {
|
||||
})
|
||||
const zoomRef = useRef(zoom ? zoom.clone() : null)
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
// 将所有container下的所有图片添加medium-zoom
|
||||
const container = document?.getElementById('container')
|
||||
@@ -52,18 +59,20 @@ const NotionPage = ({ post }) => {
|
||||
(zoomRef.current).attach(imgList[i])
|
||||
}
|
||||
}
|
||||
})
|
||||
}, [router.events])
|
||||
|
||||
return <NotionRenderer
|
||||
recordMap={post.blockMap}
|
||||
mapPageUrl={mapPageUrl}
|
||||
components={{
|
||||
Code,
|
||||
Collection,
|
||||
Equation,
|
||||
Modal,
|
||||
Pdf
|
||||
}} />
|
||||
return <div id='container'>
|
||||
<NotionRenderer
|
||||
recordMap={post.blockMap}
|
||||
mapPageUrl={mapPageUrl}
|
||||
components={{
|
||||
Code,
|
||||
Collection,
|
||||
Equation,
|
||||
Modal,
|
||||
Pdf
|
||||
}} />
|
||||
</div>
|
||||
}
|
||||
|
||||
const mapPageUrl = id => {
|
||||
|
||||
8
lib/cache/memory_cache.js
vendored
8
lib/cache/memory_cache.js
vendored
@@ -3,14 +3,14 @@ import BLOG from 'blog.config'
|
||||
|
||||
const cacheTime = BLOG.isProd ? 10 * 60 : 120 * 60 // 120 minutes for dev,10 minutes for prod
|
||||
|
||||
export async function getCacheFromMemory (key, options) {
|
||||
return cache.get(key)
|
||||
export async function getCacheFromMemory(key, options) {
|
||||
return await cache.get(key)
|
||||
}
|
||||
|
||||
export async function setCacheToMemory (key, data) {
|
||||
export async function setCacheToMemory(key, data) {
|
||||
await cache.put(key, data, cacheTime * 1000)
|
||||
}
|
||||
|
||||
export async function delCacheFromMemory (key) {
|
||||
export async function delCacheFromMemory(key) {
|
||||
await cache.del(key)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import { initDarkMode, initTheme, saveThemeToCookies } from '@/lib/theme'
|
||||
import { ALL_THEME } from '@/themes'
|
||||
|
||||
const GlobalContext = createContext()
|
||||
let hasInit = false
|
||||
|
||||
/**
|
||||
* 全局变量Provider,包括语言本地化、样式主题、搜索词
|
||||
@@ -14,7 +13,7 @@ let hasInit = false
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
export function GlobalContextProvider ({ children }) {
|
||||
export function GlobalContextProvider({ children }) {
|
||||
const [locale, updateLocale] = useState(generateLocaleDict('en-US'))
|
||||
const [isDarkMode, updateDarkMode] = useState(false)
|
||||
const [onLoading, changeLoadingState] = useState(false)
|
||||
@@ -27,13 +26,13 @@ export function GlobalContextProvider ({ children }) {
|
||||
changeLoadingState(false)
|
||||
})
|
||||
|
||||
function switchTheme () {
|
||||
function switchTheme() {
|
||||
const currentIndex = ALL_THEME.indexOf(theme)
|
||||
const newIndex = currentIndex < ALL_THEME.length - 1 ? currentIndex + 1 : 0
|
||||
changeTheme(ALL_THEME[newIndex])
|
||||
}
|
||||
|
||||
function changeTheme (theme) {
|
||||
function changeTheme(theme) {
|
||||
Router.query.theme = ''
|
||||
if (ALL_THEME.indexOf(theme) > -1) {
|
||||
setTheme(theme)
|
||||
@@ -44,13 +43,10 @@ export function GlobalContextProvider ({ children }) {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasInit) {
|
||||
initLocale(locale, updateLocale)
|
||||
initDarkMode(isDarkMode, updateDarkMode)
|
||||
initTheme(theme, changeTheme)
|
||||
hasInit = true
|
||||
}
|
||||
})
|
||||
initLocale(locale, updateLocale)
|
||||
initDarkMode(isDarkMode, updateDarkMode)
|
||||
initTheme(theme, changeTheme)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<GlobalContext.Provider value={{ onLoading, locale, updateLocale, isDarkMode, updateDarkMode, theme, setTheme, switchTheme, changeTheme }}>
|
||||
|
||||
@@ -80,7 +80,7 @@ export async function getNotionPageData({ pageId, from }) {
|
||||
const cacheKey = 'page_block_' + pageId
|
||||
const data = await getDataFromCache(cacheKey)
|
||||
if (data) {
|
||||
console.log('[请求缓存]:', `from:${from}`, `id:${pageId}`)
|
||||
console.log('[请求缓存]:', `from:${from}`, `root-page-id:${pageId}`)
|
||||
return data
|
||||
}
|
||||
const pageRecordMap = await getPageRecordMapByNotionAPI({ pageId, from })
|
||||
|
||||
@@ -41,7 +41,7 @@ export async function generateRss(posts) {
|
||||
link: `${BLOG.LINK}/article/${post.slug}`,
|
||||
description: post.summary,
|
||||
content: await createFeedContent(post),
|
||||
date: new Date(post?.date?.start_date || post.createdTime)
|
||||
date: new Date(post?.date?.start_date || post?.createdTime)
|
||||
})
|
||||
}
|
||||
return feed.atom1()
|
||||
|
||||
@@ -42,7 +42,7 @@ export const initTheme = (theme, changeTheme) => {
|
||||
* 是否优先深色模式, 根据系统深色模式以及当前时间判断
|
||||
* @returns {*}
|
||||
*/
|
||||
export function isPreferDark () {
|
||||
export function isPreferDark() {
|
||||
if (BLOG.APPEARANCE === 'dark') {
|
||||
return true
|
||||
}
|
||||
|
||||
10
lib/utils.js
10
lib/utils.js
@@ -6,7 +6,7 @@
|
||||
* @param type js 或 css
|
||||
* @returns {Promise<unknown>}
|
||||
*/
|
||||
export function loadExternalResource (url, type) {
|
||||
export function loadExternalResource(url, type) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let tag
|
||||
|
||||
@@ -31,8 +31,8 @@ export function loadExternalResource (url, type) {
|
||||
* @param {}} variable
|
||||
* @returns
|
||||
*/
|
||||
export function getQueryVariable (variable) {
|
||||
const query = window.location.search.substring(1)
|
||||
export function getQueryVariable(variable) {
|
||||
const query = typeof window !== 'undefined' ? window.location.search.substring(1) : ''
|
||||
const vars = query.split('&')
|
||||
for (let i = 0; i < vars.length; i++) {
|
||||
const pair = vars[i].split('=')
|
||||
@@ -46,7 +46,7 @@ export function getQueryVariable (variable) {
|
||||
* @param target
|
||||
* @param sources
|
||||
*/
|
||||
export function mergeDeep (target, ...sources) {
|
||||
export function mergeDeep(target, ...sources) {
|
||||
if (!sources.length) return target
|
||||
const source = sources.shift()
|
||||
|
||||
@@ -68,6 +68,6 @@ export function mergeDeep (target, ...sources) {
|
||||
* @param item
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isObject (item) {
|
||||
export function isObject(item) {
|
||||
return (item && typeof item === 'object' && !Array.isArray(item))
|
||||
}
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"memory-cache": "^0.2.0",
|
||||
"next": "^12.0.5",
|
||||
"notion-client": "6.5.0",
|
||||
"notion-utils": "6.5.0",
|
||||
"notion-client": "6.10.0",
|
||||
"notion-utils": "6.10.0",
|
||||
"preact": "^10.5.15",
|
||||
"qrcode.react": "^1.0.1",
|
||||
"react": "17.0.2",
|
||||
|
||||
@@ -19,9 +19,9 @@ const Slug = props => {
|
||||
}
|
||||
|
||||
// 文章锁🔐
|
||||
const [lock, setLock] = useState(true)
|
||||
const [lock, setLock] = useState(post.password && post.password !== '')
|
||||
useEffect(() => {
|
||||
if (post && post.password && post.password !== '') {
|
||||
if (post.password && post.password !== '') {
|
||||
setLock(true)
|
||||
} else {
|
||||
setLock(false)
|
||||
|
||||
@@ -24,20 +24,20 @@ const Slug = props => {
|
||||
const article = document.getElementById('container')
|
||||
if (!article) {
|
||||
router.push('/404').then(() => {
|
||||
console.log('找不到页面', router.asPath)
|
||||
console.warn('找不到页面', router.asPath)
|
||||
})
|
||||
}
|
||||
}
|
||||
}, 3000)
|
||||
})
|
||||
|
||||
return <p>Redirecting...</p>
|
||||
const meta = { title: `${props?.siteInfo?.title} | loading` }
|
||||
return <ThemeComponents.LayoutSlug {...props} showArticleInfo={true} meta={meta} />
|
||||
}
|
||||
|
||||
// 文章锁🔐
|
||||
const [lock, setLock] = useState(true)
|
||||
const [lock, setLock] = useState(post.password && post.password !== '')
|
||||
useEffect(() => {
|
||||
if (post && post.password && post.password !== '') {
|
||||
if (post.password && post.password !== '') {
|
||||
setLock(true)
|
||||
} else {
|
||||
setLock(false)
|
||||
|
||||
@@ -2,15 +2,14 @@ import { getGlobalNotionData } from '@/lib/notion/getNotionData'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { getDataFromCache } from '@/lib/cache/cache_manager'
|
||||
import * as ThemeMap from '@/themes'
|
||||
import BLOG from '@/blog.config'
|
||||
|
||||
const Index = props => {
|
||||
const { keyword, siteInfo } = props
|
||||
const { locale } = useGlobal()
|
||||
const meta = {
|
||||
title: `${keyword || ''}${keyword ? ' | ' : ''}${locale.NAV.SEARCH} | ${
|
||||
siteInfo.title
|
||||
}`,
|
||||
description: siteInfo.title,
|
||||
title: `${keyword || ''}${keyword ? ' | ' : ''}${locale.NAV.SEARCH} | ${siteInfo?.title}`,
|
||||
description: siteInfo?.title,
|
||||
slug: 'search/' + (keyword || ''),
|
||||
type: 'website'
|
||||
}
|
||||
@@ -30,7 +29,7 @@ const Index = props => {
|
||||
* @param {*} param0
|
||||
* @returns
|
||||
*/
|
||||
export async function getServerSideProps({ params: { keyword } }) {
|
||||
export async function getStaticProps({ params: { keyword } }) {
|
||||
const props = await getGlobalNotionData({
|
||||
from: 'search-props',
|
||||
pageType: ['Post']
|
||||
@@ -38,7 +37,15 @@ export async function getServerSideProps({ params: { keyword } }) {
|
||||
props.posts = await filterByMemCache(props.allPosts, keyword)
|
||||
props.keyword = keyword
|
||||
return {
|
||||
props
|
||||
props,
|
||||
revalidate: 1
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return {
|
||||
paths: [{ params: { keyword: BLOG.TITLE } }],
|
||||
fallback: true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,9 +101,11 @@ const isIterable = obj =>
|
||||
*/
|
||||
async function filterByMemCache(allPosts, keyword) {
|
||||
const filterPosts = []
|
||||
if (keyword) {
|
||||
keyword = keyword.trim()
|
||||
}
|
||||
for (const post of allPosts) {
|
||||
const cacheKey = 'page_block_' + post.id
|
||||
// const page = await getPostBlocks(post.id, 'search')
|
||||
const page = await getDataFromCache(cacheKey)
|
||||
const tagContent = post.tags ? post.tags.join(' ') : ''
|
||||
const categoryContent = post.category ? post.category.join(' ') : ''
|
||||
@@ -111,7 +120,7 @@ async function filterByMemCache(allPosts, keyword) {
|
||||
indexContent = appendText(indexContent, properties, 'caption')
|
||||
})
|
||||
}
|
||||
// console.log('搜索是否命中缓存', page !== null, indexContent)
|
||||
console.log('全文搜索缓存', cacheKey, page != null)
|
||||
post.results = []
|
||||
let hitCount = 0
|
||||
for (const i in indexContent) {
|
||||
@@ -119,7 +128,7 @@ async function filterByMemCache(allPosts, keyword) {
|
||||
if (!c) {
|
||||
continue
|
||||
}
|
||||
const index = c.toLowerCase().indexOf(keyword.toLowerCase()) || -1
|
||||
const index = c.toLowerCase().indexOf(keyword.toLowerCase())
|
||||
if (index > -1) {
|
||||
hit = true
|
||||
hitCount += 1
|
||||
|
||||
@@ -8,13 +8,18 @@ import formatDate from '@/lib/formatDate'
|
||||
|
||||
export const LayoutSlug = props => {
|
||||
const { post, lock, validPassword } = props
|
||||
|
||||
if (!post) {
|
||||
return <LayoutBase {...props} />
|
||||
}
|
||||
|
||||
if (!lock && post?.blockMap?.block) {
|
||||
post.content = Object.keys(post.blockMap.block)
|
||||
post.toc = getPageTableOfContents(post, post.blockMap)
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
return (
|
||||
<LayoutBase {...props}>
|
||||
@@ -34,7 +39,7 @@ export const LayoutSlug = props => {
|
||||
</Link>
|
||||
<span className='mr-2'>|</span>
|
||||
|
||||
{post.type[0] !== 'Page' && (<>
|
||||
{post?.type[0] !== 'Page' && (<>
|
||||
<Link
|
||||
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`}
|
||||
passHref
|
||||
@@ -60,7 +65,7 @@ export const LayoutSlug = props => {
|
||||
|
||||
</section>
|
||||
|
||||
{post.blockMap && <NotionPage post={post} />}
|
||||
{post && <NotionPage post={post} />}
|
||||
</section>}
|
||||
|
||||
</div>
|
||||
|
||||
@@ -10,11 +10,15 @@ import ArticleAround from './ArticleAround'
|
||||
* @param {*} param0
|
||||
* @returns
|
||||
*/
|
||||
export default function ArticleDetail({ post, recommendPosts, prev, next }) {
|
||||
export default function ArticleDetail(props) {
|
||||
const { post, prev, next } = props
|
||||
if (!post) {
|
||||
return <></>
|
||||
}
|
||||
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)
|
||||
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">
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img alt={post.title} src={post?.page_cover} className='object-center w-full' />
|
||||
@@ -41,7 +45,7 @@ export default function ArticleDetail({ post, recommendPosts, prev, next }) {
|
||||
</Link>
|
||||
<span className='mr-2'>|</span>
|
||||
|
||||
{post.type[0] !== 'Page' && (<>
|
||||
{post?.type[0] !== 'Page' && (<>
|
||||
<Link
|
||||
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`}
|
||||
passHref
|
||||
@@ -69,7 +73,7 @@ export default function ArticleDetail({ post, recommendPosts, prev, next }) {
|
||||
|
||||
{/* Notion文章主体 */}
|
||||
<section id='notion-article' className='px-1'>
|
||||
{post.blockMap && <NotionPage post={post} />}
|
||||
{post && <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">
|
||||
|
||||
@@ -15,6 +15,15 @@ import ArticleRecommend from './components/ArticleRecommend'
|
||||
export const LayoutSlug = props => {
|
||||
const { post, lock, validPassword } = props
|
||||
|
||||
if (!post) {
|
||||
return <LayoutBase
|
||||
headerSlot={<HeaderArticle {...props} />}
|
||||
{...props}
|
||||
showCategory={false}
|
||||
showTag={false}
|
||||
></LayoutBase>
|
||||
}
|
||||
|
||||
if (!lock && post?.blockMap?.block) {
|
||||
post.content = Object.keys(post.blockMap.block)
|
||||
post.toc = getPageTableOfContents(post, post.blockMap)
|
||||
@@ -50,7 +59,7 @@ export const LayoutSlug = props => {
|
||||
<article itemScope itemType="https://schema.org/Movie" className="subpixel-antialiased" >
|
||||
{/* Notion文章主体 */}
|
||||
<section id='notion-article' className='px-5'>
|
||||
{post.blockMap && <NotionPage post={post} />}
|
||||
{post && <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">
|
||||
|
||||
@@ -13,7 +13,7 @@ import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
*/
|
||||
const BlogPostListPage = ({ page = 1, posts = [], postCount }) => {
|
||||
const totalPage = Math.ceil(postCount / BLOG.POSTS_PER_PAGE)
|
||||
const showPagination = posts.length === BLOG.POSTS_PER_PAGE
|
||||
const showPagination = postCount >= BLOG.POSTS_PER_PAGE
|
||||
|
||||
if (!posts || posts.length === 0) {
|
||||
return <BlogPostListEmpty />
|
||||
@@ -26,7 +26,7 @@ const BlogPostListPage = ({ page = 1, posts = [], postCount }) => {
|
||||
<BlogPostCard key={post.id} post={post} />
|
||||
))}
|
||||
</div>
|
||||
{showPagination && <PaginationNumber page={page} totalPage={totalPage} /> }
|
||||
{showPagination && <PaginationNumber page={page} totalPage={totalPage} />}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,12 +4,15 @@ import formatDate from '@/lib/formatDate'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
export default function HeaderArticle({ post, siteInfo }) {
|
||||
if (!post) {
|
||||
return <>loading...</>
|
||||
}
|
||||
const headerImage = post?.page_cover ? `url("${post.page_cover}")` : `url("${siteInfo?.pageCover}")`
|
||||
const { isDarkMode } = useGlobal()
|
||||
|
||||
const { locale } = useGlobal()
|
||||
const date = formatDate(
|
||||
post?.date?.start_date || post.createdTime,
|
||||
post?.date?.start_date || post?.createdTime,
|
||||
locale.LOCALE
|
||||
)
|
||||
|
||||
@@ -71,7 +74,7 @@ export default function HeaderArticle({ post, siteInfo }) {
|
||||
</>}
|
||||
</div>
|
||||
<div className='flex justify-center'>
|
||||
{post.type[0] !== 'Page' && (
|
||||
{post?.type[0] !== 'Page' && (
|
||||
<>
|
||||
<Link
|
||||
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`}
|
||||
|
||||
@@ -9,6 +9,12 @@ import { ArticleLock } from './components/ArticleLock'
|
||||
|
||||
export const LayoutSlug = props => {
|
||||
const { post, lock, validPassword } = props
|
||||
if (!post) {
|
||||
return <LayoutBase
|
||||
{...props}
|
||||
showInfoCard={true}
|
||||
/>
|
||||
}
|
||||
|
||||
if (!lock && post?.blockMap?.block) {
|
||||
post.content = Object.keys(post.blockMap.block)
|
||||
|
||||
@@ -15,7 +15,7 @@ export const ArticleDetail = props => {
|
||||
const { locale } = useGlobal()
|
||||
|
||||
const date = formatDate(
|
||||
post?.date?.start_date || post.createdTime,
|
||||
post?.date?.start_date || post?.createdTime,
|
||||
locale.LOCALE
|
||||
)
|
||||
return <div id='container'>
|
||||
@@ -48,7 +48,7 @@ export const ArticleDetail = props => {
|
||||
</section>
|
||||
{/* Notion文章主体 */}
|
||||
<section id="notion-article" className="px-1 max-w-5xl">
|
||||
{post.blockMap && (<NotionPage post={post} />)}
|
||||
{post && (<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">
|
||||
|
||||
@@ -10,7 +10,6 @@ const Progress = ({ targetRef, showPercent = true }) => {
|
||||
const [percent, changePercent] = useState(0)
|
||||
const scrollListener = () => {
|
||||
const target = currentRef || document.getElementById('container')
|
||||
console.log(target)
|
||||
if (target) {
|
||||
const clientHeight = target.clientHeight
|
||||
const scrollY = window.pageYOffset
|
||||
|
||||
@@ -11,6 +11,14 @@ import { ArticleLock } from './components/ArticleLock'
|
||||
|
||||
export const LayoutSlug = (props) => {
|
||||
const { post, latestPosts, lock, validPassword } = props
|
||||
if (!post) {
|
||||
return <LayoutBase
|
||||
{...props}
|
||||
rightAreaSlot={
|
||||
CONFIG_NEXT.RIGHT_LATEST_POSTS && <Card><LatestPostsGroup posts={latestPosts} /></Card>
|
||||
}
|
||||
/>
|
||||
}
|
||||
|
||||
if (!lock && post?.blockMap?.block) {
|
||||
post.content = Object.keys(post.blockMap.block)
|
||||
|
||||
@@ -21,15 +21,15 @@ export default function ArticleDetail(props) {
|
||||
const { post, recommendPosts, prev, next, showArticleInfo } = props
|
||||
const url = BLOG.LINK + useRouter().asPath
|
||||
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)
|
||||
|
||||
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"
|
||||
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-hexo-black-gray"
|
||||
>
|
||||
|
||||
{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">
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img alt={post.title} src={post?.page_cover} className='object-center w-full' />
|
||||
@@ -51,7 +51,7 @@ export default function ArticleDetail(props) {
|
||||
</Link>
|
||||
<span className='mr-2'>|</span>
|
||||
</>}
|
||||
{post.type[0] !== 'Page' && (<>
|
||||
{post?.type[0] !== 'Page' && (<>
|
||||
<Link
|
||||
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`}
|
||||
passHref
|
||||
@@ -84,7 +84,7 @@ export default function ArticleDetail(props) {
|
||||
|
||||
{/* Notion内容主体 */}
|
||||
<article id='notion-article' className='px-1'>
|
||||
{post.blockMap && (<NotionPage post={post} />)}
|
||||
{post && (<NotionPage post={post} />)}
|
||||
</article>
|
||||
|
||||
<section className="px-1 py-2 my-1 text-sm font-light overflow-auto text-gray-600 dark:text-gray-400">
|
||||
|
||||
@@ -7,17 +7,17 @@ const Footer = ({ title }) => {
|
||||
const startYear = BLOG.SINCE && BLOG.SINCE !== currentYear && BLOG.SINCE + '-'
|
||||
return (
|
||||
<footer
|
||||
className='dark:bg-gray-900 flex-shrink-0 justify-center text-center m-auto w-full leading-6 text-sm p-6'
|
||||
className='dark:bg-gray-900 flex-shrink-0 justify-center text-center m-auto w-full leading-6 text-sm p-6 dark:text-gray-400'
|
||||
>
|
||||
<i className='fas fa-copyright' /> {`${startYear}${currentYear}`} <span><i className='mx-1 animate-pulse fas fas-heart'/> <a href={BLOG.LINK} className='underline font-bold text-gray-500 dark:text-gray-300 '>{BLOG.AUTHOR}</a>.<br/>
|
||||
<i className='fas fa-copyright' /> {`${startYear}${currentYear}`} <span><i className='mx-1 animate-pulse fas fas-heart' /> <a href={BLOG.LINK} className='underline font-bold '>{BLOG.AUTHOR}</a>.<br />
|
||||
|
||||
{BLOG.BEI_AN && <><i className='fas fa-shield-alt' /> <a href='https://beian.miit.gov.cn/' className='mr-2'>{BLOG.BEI_AN}</a><br/></>}
|
||||
{BLOG.BEI_AN && <><i className='fas fa-shield-alt' /> <a href='https://beian.miit.gov.cn/' className='mr-2'>{BLOG.BEI_AN}</a><br /></>}
|
||||
|
||||
<span className='hidden busuanzi_container_site_pv'>
|
||||
<i className='fas fa-eye'/><span className='px-1 busuanzi_value_site_pv'> </span> </span>
|
||||
<span className='pl-2 hidden busuanzi_container_site_uv'>
|
||||
<i className='fas fa-users'/> <span className='px-1 busuanzi_value_site_uv'> </span> </span>
|
||||
<br/>
|
||||
<span className='hidden busuanzi_container_site_pv'>
|
||||
<i className='fas fa-eye' /><span className='px-1 busuanzi_value_site_pv'> </span> </span>
|
||||
<span className='pl-2 hidden busuanzi_container_site_uv'>
|
||||
<i className='fas fa-users' /> <span className='px-1 busuanzi_value_site_uv'> </span> </span>
|
||||
<br />
|
||||
<h1>{title}</h1>
|
||||
<span className='text-xs font-serif text-gray-500 dark:text-gray-300 '>Powered by <a href='https://github.com/tangly1024/NotionNext' className='underline '>NotionNext {BLOG.VERSION}</a>.</span></span>
|
||||
</footer>
|
||||
|
||||
@@ -60,10 +60,10 @@ const Toc = ({ toc }) => {
|
||||
|
||||
return <div className='px-3'>
|
||||
<div className='w-full pb-1'>
|
||||
<Progress/>
|
||||
<Progress />
|
||||
</div>
|
||||
<div className='overflow-y-auto max-h-96 overscroll-none' ref={tRef}>
|
||||
<nav className='h-full font-sans text-black'>
|
||||
<nav className='h-full font-sans text-black dark:text-gray-300'>
|
||||
{toc.map((tocItem) => {
|
||||
const id = uuidToId(tocItem.id)
|
||||
tocIds.push(id)
|
||||
@@ -74,9 +74,9 @@ const Toc = ({ toc }) => {
|
||||
className={`notion-table-of-contents-item duration-300 transform font-light
|
||||
notion-table-of-contents-item-indent-level-${tocItem.indentLevel} `}
|
||||
>
|
||||
<span style={{ display: 'inline-block', marginLeft: tocItem.indentLevel * 16 }} className={`${activeSection === id && ' font-bold text-red-400 underline'}`}>
|
||||
{tocItem.text}
|
||||
</span>
|
||||
<span style={{ display: 'inline-block', marginLeft: tocItem.indentLevel * 16 }} className={`${activeSection === id && ' font-bold text-red-400 underline'}`}>
|
||||
{tocItem.text}
|
||||
</span>
|
||||
</a>
|
||||
)
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user