Merge pull request #40 from tangly1024/theme-hexo

Theme hexo
This commit is contained in:
tangly1024
2022-01-27 15:58:49 +08:00
committed by GitHub
15 changed files with 158 additions and 104 deletions

View File

@@ -1,7 +1,7 @@
import BLOG from '@/blog.config'
import Head from 'next/head'
const CommonHead = ({ meta }) => {
const CommonHead = ({ meta, children }) => {
let url = BLOG?.PATH?.length ? `${BLOG.LINK}/${BLOG.PATH}` : BLOG.LINK
if (meta) {
url = `${url}/${meta.slug}`
@@ -42,6 +42,7 @@ const CommonHead = ({ meta }) => {
)}
{/* 谷歌字体镜像 */}
<link href="https://fonts.loli.net/css2?family=Noto+Serif+SC&display=swap" rel="stylesheet"/>
{children}
</Head>
}

View File

@@ -1,5 +1,5 @@
import { getCacheFromMemory, setCacheToMemory } from '@/lib/cache/memory_cache'
// import { getCacheFromFile, setCacheToFile } from './local_file_cache'
import { getCacheFromMemory, setCacheToMemory, delCacheFromMemory } from '@/lib/cache/memory_cache'
// import { getCacheFromFile, setCacheToFile, delCacheFromFile } from './local_file_cache'
const enableCache = true // 生产环境禁用
/**
@@ -24,3 +24,10 @@ export async function setDataToCache (key, data) {
}
await setCacheToMemory(key, data)
}
export async function delCacheData (key) {
if (!enableCache) {
return
}
await delCacheFromMemory(key)
}

View File

@@ -40,3 +40,11 @@ export async function setCacheToFile (key, data) {
json[key + '_expire_time'] = new Date().getTime()
fs.writeFileSync(jsonFile, JSON.stringify(json))
}
export async function delCacheFromFile (key, data) {
const exist = await fs.existsSync(jsonFile)
const json = exist ? JSON.parse(await fs.readFileSync(jsonFile)) : {}
delete json.key
json[key + '_expire_time'] = new Date().getTime()
fs.writeFileSync(jsonFile, JSON.stringify(json))
}

View File

@@ -10,3 +10,7 @@ export async function getCacheFromMemory (key, options) {
export async function setCacheToMemory (key, data) {
await cache.put(key, data, cacheTime * 1000)
}
export async function delCacheFromMemory (key) {
await cache.del(key)
}

View File

@@ -3,6 +3,7 @@ import getAllPageIds from './getAllPageIds'
import getPageProperties from './getPageProperties'
import { defaultMapImageUrl } from 'react-notion-x'
import { getNotionPageData } from '@/lib/notion/getNotionData'
import { delCacheData } from '@/lib/cache/cache_manager'
/**
* 获取所有文章列表
@@ -61,6 +62,8 @@ export async function getAllPosts ({ notionPageData, from, includePage = false }
if (!posts || posts.length === 0) {
console.warn('文章列表为空')
const cacheKey = 'page_block_' + BLOG.NOTION_PAGE_ID
await delCacheData(cacheKey)
}
// Sort by date
if (BLOG.POSTS_SORT_BY === 'date') {

View File

@@ -59,7 +59,7 @@ export async function getGlobalNotionData ({
*/
export async function getNotionPageData ({ pageId, from }) {
// 尝试从缓存获取
const cacheKey = 'page_record_map_' + pageId
const cacheKey = 'page_block_' + pageId
const data = await getDataFromCache(cacheKey)
if (data) {
console.log('[请求缓存]:', `from:${from}`, `id:${pageId}`)

View File

@@ -6,7 +6,7 @@ export async function getPostBlocks (id, from, slice) {
const cacheKey = 'page_block_' + id
let pageBlock = await getDataFromCache(cacheKey)
if (pageBlock) {
console.log('[请求缓存]:', `from:${from}`, `id:${id}`)
console.log('[请求缓存]:', `from:${from}`, `id:${id}`, cacheKey)
return filterPostBlocks(id, pageBlock, slice)
}
const authToken = BLOG.NOTION_ACCESS_TOKEN || null

View File

@@ -33,14 +33,14 @@
"lodash.throttle": "^4.1.1",
"memory-cache": "^0.2.0",
"next": "^12.0.5",
"notion-client": "4.13.0",
"notion-utils": "4.12.0",
"notion-client": "4.14.1",
"notion-utils": "4.14.1",
"preact": "^10.5.15",
"qrcode.react": "^1.0.1",
"react": "17.0.2",
"react-cookies": "^0.1.1",
"react-dom": "17.0.2",
"react-notion-x": "4.13.0",
"react-notion-x": "4.14.2",
"smoothscroll-polyfill": "^0.4.4",
"typed.js": "^2.0.12",
"use-ackee": "^3.0.0"

View File

@@ -1,3 +1,5 @@
import CONFIG_EMPTY from './config_empty'
export { CONFIG_EMPTY as THEME_CONFIG }
export { LayoutIndex } from './LayoutIndex'
export { LayoutSearch } from './LayoutSearch'
export { LayoutArchive } from './LayoutArchive'

View File

@@ -47,7 +47,7 @@ const LayoutBase = (props) => {
<main id='wrapper' className='mt-12 lg:mt-0 flex w-full justify-center py-8 min-h-screen'>
<div id='container-inner' className='w-full mx-auto flex justify-between space-x-4 max-w-6xl'>
<div className='flex-grow'>{children}</div>
<div className='flex-grow w-full'>{children}</div>
<SideRight {...props}/>
</div>

View File

@@ -1,10 +1,5 @@
import BLOG from '@/blog.config'
import formatDate from '@/lib/formatDate'
import { useGlobal } from '@/lib/global'
import { getPageTableOfContents } from 'notion-utils'
import { faFolderOpen } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import Link from 'next/link'
import 'prismjs'
import 'prismjs/components/prism-bash'
import 'prismjs/components/prism-java'
@@ -12,12 +7,12 @@ import 'prismjs/components/prism-javascript'
import 'prismjs/components/prism-markup'
import 'prismjs/components/prism-python'
import 'prismjs/components/prism-typescript'
import CONFIG_NEXT from '../NEXT/config_next'
import ArticleDetail from './components/ArticleDetail'
import LayoutBase from './LayoutBase'
import TocDrawerButton from './components/TocDrawerButton'
import { useRef } from 'react'
import ArticleDetail from './components/ArticleDetail'
import HeaderArticle from './components/HeaderArticle'
import TocDrawer from './components/TocDrawer'
import TocDrawerButton from './components/TocDrawerButton'
import LayoutBase from './LayoutBase'
export const LayoutSlug = props => {
const { post } = props
@@ -28,64 +23,11 @@ export const LayoutSlug = props => {
tags: post.tags
}
const { locale } = useGlobal()
const date = formatDate(
post?.date?.start_date || post.createdTime,
locale.LOCALE
)
if (post?.blockMap?.block) {
post.content = Object.keys(post.blockMap.block)
post.toc = getPageTableOfContents(post, post.blockMap)
}
const headerImage = post?.page_cover ? `url("${post.page_cover}")` : `url("/${CONFIG_NEXT.HOME_BANNER_IMAGE}")`
const headerSlot = (
<div
className="w-full h-96 relative md:flex-shrink-0 overflow-hidden bg-cover bg-center bg-no-repeat"
style={{ backgroundImage: headerImage }}
>
<header className="animate__slideInDown animate__animated bg-black bg-opacity-70 absolute top-0 w-full h-96 py-10 flex justify-center items-center font-sans">
<div>
{/* 文章Title */}
<div className="font-bold text-3xl shadow-text flex justify-center text-white dark:text-white font-sans">
{post.title}
</div>
<section className="flex-wrap shadow-text flex justify-center mt-2 text-white dark:text-gray-400 font-light leading-8">
<div>
<Link href={`/category/${post.category}`} passHref>
<a className="cursor-pointer text-md mr-2 dark:hover:text-white border-b dark:border-gray-500 border-dashed">
<FontAwesomeIcon icon={faFolderOpen} className="mr-1" />
{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:underline border-b dark:border-gray-500 border-dashed">
{date}
</a>
</Link>
</>
)}
<div className="hidden busuanzi_container_page_pv font-light mr-2">
<span className="mr-2">|</span>
<span className="mr-2 busuanzi_value_page_pv" />
次访问
</div>
</div>
</section>
</div>
</header>
</div>
)
const drawerRight = useRef(null)
const targetRef = typeof window !== 'undefined' ? document.getElementById('container') : null
@@ -104,7 +46,7 @@ export const LayoutSlug = props => {
return (
<LayoutBase
headerSlot={headerSlot}
headerSlot={<HeaderArticle post={post}/>}
{...props}
meta={meta}
showCategory={false}

View File

@@ -1,3 +1,4 @@
import BLOG from '@/blog.config'
import { useGlobal } from '@/lib/global'
import { faAngleDown } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
@@ -15,7 +16,12 @@ let autoScroll = false
*/
export default function Header () {
const [typed, changeType] = useState()
const { theme } = useGlobal()
useEffect(() => {
scrollTrigger()
updateHeaderHeight()
updateTopNav()
if (!typed && window && document.getElementById('typed')) {
changeType(
new Typed('#typed', {
@@ -28,8 +34,13 @@ export default function Header () {
})
)
}
window.addEventListener('scroll', scrollTrigger)
window.addEventListener('resize', updateHeaderHeight)
return () => {
window.removeEventListener('scroll', scrollTrigger)
window.removeEventListener('resize', updateHeaderHeight)
}
})
const { theme } = useGlobal()
const autoScrollEnd = () => {
if (autoScroll) {
@@ -39,25 +50,29 @@ export default function Header () {
}
const scrollTrigger = () => {
if (
(window.scrollY > windowTop) &
(window.scrollY < window.innerHeight) &&
!autoScroll
const scrollS = window.scrollY
const nav = document.querySelector('#sticky-nav')
if (scrollS < 300) {
nav && nav.classList.replace('bg-white', 'bg-none')
nav && nav.classList.replace('text-black', 'text-white')
} else {
nav && nav.classList.replace('bg-none', 'bg-white')
nav && nav.classList.replace('text-white', 'text-black')
}
if ((scrollS > windowTop) & (scrollS < window.innerHeight) && !autoScroll
) {
autoScroll = true
window.scrollTo({ top: wrapperTop, behavior: 'smooth' })
setTimeout(autoScrollEnd, 500)
}
if (
(window.scrollY < windowTop) &
(window.scrollY < window.innerHeight) &&
!autoScroll
) {
if ((scrollS < windowTop) && (scrollS < window.innerHeight) && !autoScroll) {
autoScroll = true
window.scrollTo({ top: 0, behavior: 'smooth' })
setTimeout(autoScrollEnd, 500)
}
windowTop = window.scrollY
windowTop = scrollS
updateTopNav()
}
@@ -82,17 +97,6 @@ export default function Header () {
}, 500)
}
useEffect(() => {
updateHeaderHeight()
updateTopNav()
window.addEventListener('scroll', scrollTrigger)
window.addEventListener('resize', updateHeaderHeight)
return () => {
window.removeEventListener('scroll', scrollTrigger)
window.removeEventListener('resize', updateHeaderHeight)
}
})
return (
<header
id="header"
@@ -102,14 +106,15 @@ export default function Header () {
`linear-gradient(rgba(0, 0, 0, 0.8), rgba(0,0,0,0.2), rgba(0, 0, 0, 0.8) ),url("${CONFIG_HEXO.HOME_BANNER_IMAGE}")`
}}
>
<div className="absolute flex h-full items-center lg:-mt-14 justify-center w-full text-4xl md:text-7xl text-white">
<div id='typed' className='flex text-center font-sans shadow-text'/>
<div className="absolute flex flex-col h-full items-center justify-center w-full font-sans">
<div className='text-4xl md:text-5xl text-white shadow-text'>{BLOG.TITLE}</div>
<div id='typed' className='flex h-10 items-center text-center text-lg shadow-text text-white'/>
</div>
<div
onClick={() => {
window.scrollTo({ top: wrapperTop, behavior: 'smooth' })
}}
className="cursor-pointer w-full text-center py-4 text-5xl absolute bottom-10 text-white"
className="cursor-pointer w-full text-center py-4 text-3xl absolute bottom-10 text-white"
>
<FontAwesomeIcon icon={faAngleDown} className='animate-bounce'/>
</div>

View File

@@ -0,0 +1,83 @@
import { faFolderOpen } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import Link from 'next/link'
import { useGlobal } from '@/lib/global'
import formatDate from '@/lib/formatDate'
import CONFIG_HEXO from '../config_hexo'
import { useEffect } from 'react'
export default function HeaderArticle ({ post }) {
const headerImage = post?.page_cover ? `url("${post.page_cover}")` : `url("/${CONFIG_HEXO.HOME_BANNER_IMAGE}")`
const { locale } = useGlobal()
const date = formatDate(
post?.date?.start_date || post.createdTime,
locale.LOCALE
)
const scrollTrigger = () => {
const scrollS = window.scrollY
const nav = document.querySelector('#sticky-nav')
if (scrollS < 300) {
nav && nav.classList.replace('bg-white', 'bg-none')
nav && nav.classList.replace('text-black', 'text-white')
} else {
nav && nav.classList.replace('bg-none', 'bg-white')
nav && nav.classList.replace('text-white', 'text-black')
}
}
useEffect(() => {
window.addEventListener('scroll', scrollTrigger)
return () => {
window.removeEventListener('scroll', scrollTrigger)
}
})
return (
<div
className="w-full h-96 relative md:flex-shrink-0 overflow-hidden bg-cover bg-center bg-no-repeat"
style={{ backgroundImage: headerImage }}
>
<header className="animate__slideInDown animate__animated bg-black bg-opacity-70 absolute top-0 w-full h-96 py-10 flex justify-center items-center font-sans">
<div>
{/* 文章Title */}
<div className="font-bold text-3xl shadow-text flex justify-center text-white dark:text-white font-sans">
{post.title}
</div>
<section className="flex-wrap shadow-text flex justify-center mt-2 text-white dark:text-gray-400 font-light leading-8">
<div>
<Link href={`/category/${post.category}`} passHref>
<a className="cursor-pointer text-md mr-2 dark:hover:text-white border-b dark:border-gray-500 border-dashed">
<FontAwesomeIcon icon={faFolderOpen} className="mr-1" />
{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:underline border-b dark:border-gray-500 border-dashed">
{date}
</a>
</Link>
</>
)}
<div className="hidden busuanzi_container_page_pv font-light mr-2">
<span className="mr-2">|</span>
<span className="mr-2 busuanzi_value_page_pv" />
次访问
</div>
</div>
</section>
</div>
</header>
</div>
)
}

View File

@@ -4,8 +4,8 @@ import React from 'react'
const Logo = () => {
return <Link href='/' passHref>
<div className='flex flex-col justify-center items-center cursor-pointer space-y-3 font-bold'>
<div className='font-serif text-xl text-white'> {BLOG.TITLE}</div>
<div className='flex flex-col justify-center items-center cursor-pointer space-y-3'>
<div className='font-sans text-xl'> {BLOG.TITLE}</div>
</div>
</Link>
}

View File

@@ -26,12 +26,11 @@ const TopNav = ({ tags, currentTag, categories, currentCategory, postCount }) =>
const scrollTrigger = throttle(() => {
const scrollS = window.scrollY
if (scrollS >= windowTop && scrollS > 10) {
const nav = document.querySelector('#sticky-nav')
const nav = document.querySelector('#sticky-nav')
if (scrollS >= windowTop && scrollS > 20) {
nav && nav.classList.replace('top-0', '-top-16')
windowTop = scrollS
} else {
const nav = document.querySelector('#sticky-nav')
nav && nav.classList.replace('-top-16', 'top-0')
windowTop = scrollS
}
@@ -90,8 +89,8 @@ const TopNav = ({ tags, currentTag, categories, currentCategory, postCount }) =>
<SearchDrawer cRef={searchDrawer} slot={searchDrawerSlot}/>
{/* 导航栏 */}
<div id='sticky-nav' className={`${CONFIG_HEXO.NAV_TYPE !== 'normal' ? 'fixed' : ''} w-full top-0 z-20 transform duration-500`}>
<div className='w-full flex justify-between items-center p-4 bg-black shadow-md bg-opacity-70 text-white'>
<div id='sticky-nav' className={`${CONFIG_HEXO.NAV_TYPE !== 'normal' ? 'fixed' : ''} bg-white bg-opacity-70 text-black w-full top-0 z-20 transform duration-500 font-sans`}>
<div className='w-full flex justify-between items-center p-4 shadow-md'>
<div className='flex'>
<Logo/>
</div>