Merge branch 'main' into feat/new-theme-landing

This commit is contained in:
tangly1024.com
2023-07-05 12:30:45 +08:00
37 changed files with 338 additions and 100 deletions

View File

@@ -1,2 +1,2 @@
# 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables
NEXT_PUBLIC_VERSION=3.16.2
NEXT_PUBLIC_VERSION=3.16.3

View File

@@ -5,7 +5,7 @@ const BLOG = {
process.env.NOTION_PAGE_ID || '02ab3b8678004aa69e9e415905ef32a5',
PSEUDO_STATIC: false, // 伪静态路径开启后所有文章URL都以 .html 结尾。
NEXT_REVALIDATE_SECOND: process.env.NEXT_PUBLIC_REVALIDATE_SECOND || 5, // 更新内容缓存间隔 单位(秒)即每个页面有5秒的纯静态期、此期间无论多少次访问都不会抓取notion数据调大该值有助于节省Vercel资源、同时提升访问速率但也会使文章更新有延迟。
THEME: process.env.NEXT_PUBLIC_THEME || 'fukasawa', // 主题, 支持 ['next','hexo',"fukasawa','medium','example','matery','gitbook','simple'] @see https://preview.tangly1024.com
THEME: process.env.NEXT_PUBLIC_THEME || 'hexo', // 主题, 支持 ['next','hexo',"fukasawa','medium','example','matery','gitbook','simple'] @see https://preview.tangly1024.com
THEME_SWITCH: process.env.NEXT_PUBLIC_THEME_SWITCH || false, // 是否显示切换主题按钮
LANG: process.env.NEXT_PUBLIC_LANG || 'zh-CN', // e.g 'zh-CN','en-US' see /lib/lang.js for more.
SINCE: 2021, // e.g if leave this empty, current year will be used.
@@ -154,7 +154,7 @@ const BLOG = {
WIDGET_PET_LINK:
process.env.NEXT_PUBLIC_WIDGET_PET_LINK ||
'https://cdn.jsdelivr.net/npm/live2d-widget-model-wanko@1.0.5/assets/wanko.model.json', // 挂件模型地址 @see https://github.com/xiazeyu/live2d-widget-models
WIDGET_PET_SWITCH_THEME: true, // 点击宠物挂件切换博客主题
WIDGET_PET_SWITCH_THEME: process.env.NEXT_PUBLIC_WIDGET_PET_SWITCH_THEME || true, // 点击宠物挂件切换博客主题
// 音乐播放插件
MUSIC_PLAYER: process.env.NEXT_PUBLIC_MUSIC_PLAYER || false, // 是否使用音乐播放插件

View File

@@ -56,7 +56,7 @@ const CommonHead = ({ meta, children }) => {
<>
<meta
property="article:published_time"
content={meta.date || meta.createdTime}
content={meta.publishTime}
/>
<meta property="article:author" content={BLOG.AUTHOR} />
<meta property="article:section" content={category} />

View File

@@ -1,4 +1,4 @@
import { useRef, useEffect } from 'react'
import { useRef, useEffect, useState } from 'react'
/**
* 可拖拽组件
*/
@@ -7,6 +7,7 @@ export const Draggable = (props) => {
const { children } = props
const draggableRef = useRef(null)
const rafRef = useRef(null)
const [moving, setMoving] = useState(false)
let currentObj, offsetX, offsetY
useEffect(() => {
@@ -54,6 +55,8 @@ export const Draggable = (props) => {
event.preventDefault() // 阻止默认的滚动行为
document.documentElement.style.overflow = 'hidden' // 防止页面一起滚动
}
setMoving(true)
offsetX = event.mx - currentObj.offsetLeft
offsetY = event.my - currentObj.offsetTop
@@ -73,6 +76,7 @@ export const Draggable = (props) => {
event = e(event)
document.documentElement.style.overflow = 'auto' // 恢复默认的滚动行为
cancelAnimationFrame(rafRef.current)
setMoving(false)
currentObj = document.ontouchmove = document.ontouchend = document.onmousemove = document.onmouseup = null
}
@@ -138,7 +142,7 @@ export const Draggable = (props) => {
}
}, [])
return <div className='draggable cursor-move select-none' ref={draggableRef}>
return <div className={`draggable ${moving ? 'cursor-grabbing' : 'cursor-grab'} select-none`} ref={draggableRef}>
{children}
</div>
}

View File

@@ -26,7 +26,7 @@ export default function Live2D() {
}, [theme])
function handleClick() {
if (BLOG.WIDGET_PET_SWITCH_THEME) {
if (JSON.parse(BLOG.WIDGET_PET_SWITCH_THEME)) {
switchTheme()
}
}
@@ -35,5 +35,9 @@ export default function Live2D() {
return <></>
}
return <canvas id="live2d" className='cursor-pointer' width="280" height="250" onClick={handleClick} alt='切换主题' title='切换主题' />
return <canvas id="live2d" width="280" height="250" onClick={handleClick}
className="cursor-grab"
onMouseDown={(e) => e.target.classList.add('cursor-grabbing')}
onMouseUp={(e) => e.target.classList.remove('cursor-grabbing')}
/>
}

View File

@@ -23,14 +23,13 @@ const ThemeSwitch = () => {
return (<>
<Draggable>
<div id="draggableBox" style={{ left: '10px', top: '85vh' }} className="fixed text-white bg-black z-50 rounded-lg shadow-card">
<div className="py-2 flex items-center text-sm">
<i className='fas fa-arrows cursor-move px-2' />
{/* <div className='uppercase font-sans whitespace-nowrap cursor-pointer ' onClick={switchTheme}> {theme}</div> */}
<div className="py-2 flex items-center text-sm px-2">
<select value={theme} onChange={onSelectChange} name="cars" className='text-white bg-black uppercase cursor-pointer'>
{THEMES.map(t => {
return <option key={t} value={t}>{t}</option>
})}
</select>
<i className='fas fa-palette pl-1' />
</div>
</div>
</Draggable>

View File

@@ -13,7 +13,6 @@ export default function formatDate (date, local) {
? res.replace('年', '-').replace('月', '-').replace('日', '')
: res
}
export function formatDateFmt (timestamp, fmt) {
const date = new Date(timestamp)
const o = {

View File

@@ -45,7 +45,7 @@ export async function getAllPosts({ notionPageData, from, pageType }) {
// Sort by date
if (BLOG.POSTS_SORT_BY === 'date') {
posts.sort((a, b) => {
return b?.sortDate - a?.sortDate
return b?.publishDate - a?.publishDate
})
}
return posts

View File

@@ -20,23 +20,23 @@ import { mapImgUrl, compressImage } from './mapImage'
* @returns
*
*/
export async function getGlobalNotionData({
export async function getGlobalData({
pageId = BLOG.NOTION_PAGE_ID,
from
}) {
// 获取Notion数据
const notionPageData = deepClone(await getNotionPageData({ pageId, from }))
notionPageData.allNavPages = getNavPages({ allPages: notionPageData.allPages })
delete notionPageData.block
delete notionPageData.schema
delete notionPageData.rawMetadata
delete notionPageData.pageIds
delete notionPageData.viewIds
delete notionPageData.collection
delete notionPageData.collectionQuery
delete notionPageData.collectionId
delete notionPageData.collectionView
return notionPageData
// 从notion获取
const db = deepClone(await getNotionPageData({ pageId, from }))
// 不返回的敏感数据
delete db.block
delete db.schema
delete db.rawMetadata
delete db.pageIds
delete db.viewIds
delete db.collection
delete db.collectionQuery
delete db.collectionId
delete db.collectionView
return db
}
/**
@@ -48,8 +48,8 @@ function getLatestPosts({ allPages, from, latestPostCount }) {
const allPosts = allPages?.filter(page => page.type === 'Post' && page.status === 'Published')
const latestPosts = Object.create(allPosts).sort((a, b) => {
const dateA = new Date(a?.lastEditedTime || a?.sortDate)
const dateB = new Date(b?.lastEditedTime || b?.sortDate)
const dateA = new Date(a?.lastEditedTime || a?.publishDate)
const dateB = new Date(b?.lastEditedTime || b?.publishDate)
return dateB - dateA
})
return latestPosts.slice(0, latestPostCount)
@@ -69,12 +69,12 @@ export async function getNotionPageData({ pageId, from }) {
console.log('[缓存]:', `from:${from}`, `root-page-id:${pageId}`)
return data
}
const pageRecordMap = await getDataBaseInfoByNotionAPI({ pageId, from })
const db = await getDataBaseInfoByNotionAPI({ pageId, from })
// 存入缓存
if (pageRecordMap) {
await setDataToCache(cacheKey, pageRecordMap)
if (db) {
await setDataToCache(cacheKey, db)
}
return pageRecordMap
return db
}
/**
@@ -298,7 +298,7 @@ async function getDataBaseInfoByNotionAPI({ pageId, from }) {
// Sort by date
if (BLOG.POSTS_SORT_BY === 'date') {
allPages.sort((a, b) => {
return b?.sortDate - a?.sortDate
return b?.publishDate - a?.publishDate
})
}

View File

@@ -92,11 +92,9 @@ export default async function getPageProperties(id, block, schema, authToken, ta
properties.slug += '.html'
}
}
properties.sortDate = value?.date?.start_date || value.created_time
properties.createdTime = formatDate(new Date(value.created_time).toString(), BLOG.LANG)
properties.publishTime = value?.date?.start_date ? formatDate(new Date(value?.date?.start_date).toString, BLOG.LANG) : properties.createdTime
properties.lastEditedTime = formatDate(new Date(value?.last_edited_time).toString(), BLOG.LANG)
properties.publishDate = new Date(properties?.date?.start_date || value.created_time).getTime()
properties.publishTime = formatDate(properties.publishDate, BLOG.LANG)
properties.lastEditedTime = formatDate(new Date(value?.last_edited_time), BLOG.LANG)
properties.fullWidth = value.format?.page_full_width ?? false
properties.pageIcon = mapImgUrl(block[id].value?.format?.page_icon, block[id].value) ?? ''
properties.pageCover = mapImgUrl(block[id].value?.format?.page_cover, block[id].value) ?? ''

View File

@@ -46,7 +46,7 @@ export async function generateRss(posts) {
link: `${BLOG.LINK}/${post.slug}`,
description: post.summary,
content: await createFeedContent(post),
date: new Date(post?.publishTime || post?.createdTime)
date: new Date(post?.publishTime)
})
}

View File

@@ -24,7 +24,7 @@ export async function generateSitemapXml({ allPages }) {
allPages?.forEach(post => {
urls.push({
loc: `${BLOG.LINK}/${post.slug}`,
lastmod: new Date(post?.publishTime || post?.createdTime).toISOString().split('T')[0],
lastmod: new Date(post?.publishTime).toISOString().split('T')[0],
changefreq: 'daily'
})
})

View File

@@ -94,6 +94,9 @@ module.exports = withBundleAnalyzer({
config.resolve.alias['@theme-components'] = path.resolve(__dirname, 'themes', THEME)
return config
},
experimental: {
scrollRestoration: true
},
publicRuntimeConfig: { // 这里的配置既可以服务端获取到,也可以在浏览器端获取到
NODE_ENV_API: process.env.NODE_ENV_API || 'prod',
THEMES: themes

View File

@@ -1,6 +1,6 @@
{
"name": "notion-next",
"version": "3.16.2",
"version": "3.16.3",
"homepage": "https://github.com/tangly1024/NotionNext.git",
"license": "MIT",
"repository": {

View File

@@ -1,4 +1,4 @@
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
import { getGlobalData } from '@/lib/notion/getNotionData'
import { useGlobal } from '@/lib/global'
import { useRouter } from 'next/router'
import { getLayoutByTheme } from '@/themes/theme'
@@ -21,7 +21,7 @@ const NoFound = props => {
}
export async function getStaticProps () {
const props = (await getGlobalNotionData({ from: '404' })) || {}
const props = (await getGlobalData({ from: '404' })) || {}
return { props }
}

View File

@@ -1,6 +1,6 @@
import BLOG from '@/blog.config'
import { getPostBlocks } from '@/lib/notion'
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
import { getGlobalData } from '@/lib/notion/getNotionData'
import { useEffect, useState } from 'react'
import { idToUuid } from 'notion-utils'
import { useRouter } from 'next/router'
@@ -61,9 +61,6 @@ const Slug = props => {
post.toc = getPageTableOfContents(post, post.blockMap)
}
}
router.events.on('routeChangeComplete', () => {
window.scrollTo({ top: 0, behavior: 'smooth' })
})
}, [post])
const meta = {
@@ -90,7 +87,7 @@ export async function getStaticPaths() {
}
const from = 'slug-paths'
const { allPages } = await getGlobalNotionData({ from })
const { allPages } = await getGlobalData({ from })
return {
paths: allPages?.map(row => ({ params: { slug: [row.slug] } })),
fallback: true
@@ -105,7 +102,7 @@ export async function getStaticProps({ params: { slug } }) {
}
}
const from = `slug-props-${fullSlug}`
const props = await getGlobalNotionData({ from })
const props = await getGlobalData({ from })
// 在列表内查找文章
props.post = props?.allPages?.find((p) => {
return p.slug === fullSlug || p.id === idToUuid(fullSlug)

View File

@@ -1,10 +1,11 @@
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
import React, { useEffect } from 'react'
import { getGlobalData } from '@/lib/notion/getNotionData'
import { useEffect } from 'react'
import { useGlobal } from '@/lib/global'
import BLOG from '@/blog.config'
import { useRouter } from 'next/router'
import { getLayoutByTheme } from '@/themes/theme'
import { isBrowser } from '@/lib/utils'
import { formatDateFmt } from '@/lib/formatDate'
const ArchiveIndex = props => {
const { siteInfo } = props
@@ -41,7 +42,7 @@ const ArchiveIndex = props => {
}
export async function getStaticProps() {
const props = await getGlobalNotionData({ from: 'archive-index' })
const props = await getGlobalData({ from: 'archive-index' })
// 处理分页
props.posts = props.allPages.filter(page => page.type === 'Post' && page.status === 'Published')
delete props.allPages
@@ -49,15 +50,13 @@ export async function getStaticProps() {
const postsSortByDate = Object.create(props.posts)
postsSortByDate.sort((a, b) => {
const dateA = new Date(a?.publishTime || a.createdTime)
const dateB = new Date(b?.publishTime || b.createdTime)
return dateB - dateA
return b?.publishDate - a?.publishDate
})
const archivePosts = {}
postsSortByDate.forEach(post => {
const date = post.date?.start_date?.slice(0, 7) || post.createdTime
const date = formatDateFmt(post.publishDate, 'yyyy-MM')
if (archivePosts[date]) {
archivePosts[date].push(post)
} else {

View File

@@ -1,4 +1,4 @@
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
import { getGlobalData } from '@/lib/notion/getNotionData'
import React from 'react'
import { useGlobal } from '@/lib/global'
import BLOG from '@/blog.config'
@@ -34,7 +34,7 @@ export default function Category(props) {
export async function getStaticProps({ params: { category } }) {
const from = 'category-props'
let props = await getGlobalNotionData({ from })
let props = await getGlobalData({ from })
// 过滤状态
props.posts = props.allPages.filter(page => page.type === 'Post' && page.status === 'Published')
@@ -61,7 +61,7 @@ export async function getStaticProps({ params: { category } }) {
export async function getStaticPaths() {
const from = 'category-paths'
const { categoryOptions } = await getGlobalNotionData({ from })
const { categoryOptions } = await getGlobalData({ from })
return {
paths: Object.keys(categoryOptions).map(category => ({
params: { category: categoryOptions[category]?.name }

View File

@@ -1,4 +1,4 @@
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
import { getGlobalData } from '@/lib/notion/getNotionData'
import React from 'react'
import { useGlobal } from '@/lib/global'
import BLOG from '@/blog.config'
@@ -34,7 +34,7 @@ export default function Category(props) {
export async function getStaticProps({ params: { category, page } }) {
const from = 'category-page-props'
let props = await getGlobalNotionData({ from })
let props = await getGlobalData({ from })
// 过滤状态类型
props.posts = props.allPages.filter(page => page.type === 'Post' && page.status === 'Published').filter(post => post && post.category && post.category.includes(category))
@@ -56,7 +56,7 @@ export async function getStaticProps({ params: { category, page } }) {
export async function getStaticPaths() {
const from = 'category-paths'
const { categoryOptions, allPages } = await getGlobalNotionData({ from })
const { categoryOptions, allPages } = await getGlobalData({ from })
const paths = []
categoryOptions?.forEach(category => {

View File

@@ -1,4 +1,4 @@
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
import { getGlobalData } from '@/lib/notion/getNotionData'
import React from 'react'
import { useGlobal } from '@/lib/global'
import BLOG from '@/blog.config'
@@ -30,7 +30,7 @@ export default function Category(props) {
}
export async function getStaticProps() {
const props = await getGlobalNotionData({ from: 'category-index-props' })
const props = await getGlobalData({ from: 'category-index-props' })
delete props.allPages
return {
props,

View File

@@ -1,6 +1,6 @@
import BLOG from '@/blog.config'
import { getPostBlocks } from '@/lib/notion'
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
import { getGlobalData } from '@/lib/notion/getNotionData'
import { generateRss } from '@/lib/rss'
import { generateRobotsTxt } from '@/lib/robots.txt'
@@ -24,7 +24,7 @@ const Index = props => {
*/
export async function getStaticProps() {
const from = 'index'
const props = await getGlobalNotionData({ from })
const props = await getGlobalData({ from })
const { siteInfo } = props
props.posts = props.allPages.filter(page => page.type === 'Post' && page.status === 'Published')

View File

@@ -1,6 +1,6 @@
import BLOG from '@/blog.config'
import { getPostBlocks } from '@/lib/notion'
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
import { getGlobalData } from '@/lib/notion/getNotionData'
import { useRouter } from 'next/router'
import { getLayoutByTheme } from '@/themes/theme'
@@ -30,7 +30,7 @@ const Page = props => {
export async function getStaticPaths() {
const from = 'page-paths'
const { postCount } = await getGlobalNotionData({ from })
const { postCount } = await getGlobalData({ from })
const totalPages = Math.ceil(postCount / BLOG.POSTS_PER_PAGE)
return {
// remove first page, we 're not gonna handle that.
@@ -43,7 +43,7 @@ export async function getStaticPaths() {
export async function getStaticProps({ params: { page } }) {
const from = `page-${page}`
const props = await getGlobalNotionData({ from })
const props = await getGlobalData({ from })
const { allPages } = props
const allPosts = allPages.filter(page => page.type === 'Post' && page.status === 'Published')
// 处理分页

View File

@@ -1,4 +1,4 @@
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
import { getGlobalData } from '@/lib/notion/getNotionData'
import { useGlobal } from '@/lib/global'
import { getDataFromCache } from '@/lib/cache/cache_manager'
import BLOG from '@/blog.config'
@@ -31,7 +31,7 @@ const Index = props => {
* @returns
*/
export async function getStaticProps({ params: { keyword } }) {
const props = await getGlobalNotionData({
const props = await getGlobalData({
from: 'search-props',
pageType: ['Post']
})

View File

@@ -1,4 +1,4 @@
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
import { getGlobalData } from '@/lib/notion/getNotionData'
import { useGlobal } from '@/lib/global'
import { getDataFromCache } from '@/lib/cache/cache_manager'
import BLOG from '@/blog.config'
@@ -31,7 +31,7 @@ const Index = props => {
* @returns
*/
export async function getStaticProps({ params: { keyword, page } }) {
const props = await getGlobalNotionData({
const props = await getGlobalData({
from: 'search-props',
pageType: ['Post']
})

View File

@@ -1,4 +1,4 @@
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
import { getGlobalData } from '@/lib/notion/getNotionData'
import { useGlobal } from '@/lib/global'
import { useRouter } from 'next/router'
import BLOG from '@/blog.config'
@@ -45,7 +45,7 @@ const Search = props => {
* 浏览器前端搜索
*/
export async function getStaticProps() {
const props = await getGlobalNotionData({
const props = await getGlobalData({
from: 'search-props',
pageType: ['Post']
})

View File

@@ -1,10 +1,10 @@
// pages/sitemap.xml.js
import { getServerSideSitemap } from 'next-sitemap'
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
import { getGlobalData } from '@/lib/notion/getNotionData'
import BLOG from '@/blog.config'
export const getServerSideProps = async (ctx) => {
const { allPages } = await getGlobalNotionData({ from: 'rss' })
const { allPages } = await getGlobalData({ from: 'rss' })
const defaultFields = [
{
loc: `${BLOG.LINK}`,
@@ -41,7 +41,7 @@ export const getServerSideProps = async (ctx) => {
const postFields = allPages?.filter(p => p.status === BLOG.NOTION_PROPERTY_NAME.status_publish)?.map(post => {
return {
loc: `${BLOG.LINK}/${post.slug}`,
lastmod: new Date(post?.publishTime || post?.createdTime).toISOString().split('T')[0],
lastmod: new Date(post?.publishTime).toISOString().split('T')[0],
changefreq: 'daily',
priority: '0.7'
}

View File

@@ -1,5 +1,5 @@
import { useGlobal } from '@/lib/global'
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
import { getGlobalData } from '@/lib/notion/getNotionData'
import BLOG from '@/blog.config'
import { useRouter } from 'next/router'
import { getLayoutByTheme } from '@/themes/theme'
@@ -30,7 +30,7 @@ const Tag = props => {
export async function getStaticProps({ params: { tag } }) {
const from = 'tag-props'
const props = await getGlobalNotionData({ from })
const props = await getGlobalData({ from })
// 过滤状态
props.posts = props.allPages.filter(page => page.type === 'Post' && page.status === 'Published').filter(post => post && post.tags && post.tags.includes(tag))
@@ -68,7 +68,7 @@ function getTagNames(tags) {
export async function getStaticPaths() {
const from = 'tag-static-path'
const { tagOptions } = await getGlobalNotionData({ from })
const { tagOptions } = await getGlobalData({ from })
const tagNames = getTagNames(tagOptions)
return {

View File

@@ -1,5 +1,5 @@
import { useGlobal } from '@/lib/global'
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
import { getGlobalData } from '@/lib/notion/getNotionData'
import BLOG from '@/blog.config'
import { useRouter } from 'next/router'
import { getLayoutByTheme } from '@/themes/theme'
@@ -25,7 +25,7 @@ const Tag = props => {
export async function getStaticProps({ params: { tag, page } }) {
const from = 'tag-page-props'
const props = await getGlobalNotionData({ from })
const props = await getGlobalData({ from })
// 过滤状态、标签
props.posts = props.allPages.filter(page => page.type === 'Post' && page.status === 'Published').filter(post => post && post.tags && post.tags.includes(tag))
// 处理文章数
@@ -44,7 +44,7 @@ export async function getStaticProps({ params: { tag, page } }) {
export async function getStaticPaths() {
const from = 'tag-page-static-path'
const { tagOptions, allPages } = await getGlobalNotionData({ from })
const { tagOptions, allPages } = await getGlobalData({ from })
const paths = []
tagOptions?.forEach(tag => {
// 过滤状态类型

View File

@@ -1,4 +1,4 @@
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
import { getGlobalData } from '@/lib/notion/getNotionData'
import { useGlobal } from '@/lib/global'
import BLOG from '@/blog.config'
import { useRouter } from 'next/router'
@@ -30,7 +30,7 @@ const TagIndex = props => {
export async function getStaticProps() {
const from = 'tag-index-props'
const props = await getGlobalNotionData({ from })
const props = await getGlobalData({ from })
delete props.allPages
return {
props,

View File

@@ -19,7 +19,7 @@ export default function ArticleDetail(props) {
if (!post) {
return <></>
}
const date = formatDate(post?.publishTime || post?.createdTime, locale.LOCALE)
const date = formatDate(post?.publishTime, 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 !== 'Page' && post?.pageCover && (

View File

@@ -0,0 +1,138 @@
import CommonHead from '@/components/CommonHead'
import { useState, createContext, useContext, useEffect } from 'react'
import Footer from './components/Footer'
import InfoCard from './components/InfoCard'
import RevolverMaps from './components/RevolverMaps'
import CONFIG_GITBOOK from './config_gitbook'
import TopNavBar from './components/TopNavBar'
import SearchInput from './components/SearchInput'
import { useGlobal } from '@/lib/global'
import Live2D from '@/components/Live2D'
import BLOG from '@/blog.config'
import NavPostList from './components/NavPostList'
import ArticleInfo from './components/ArticleInfo'
import Catalog from './components/Catalog'
import { useRouter } from 'next/router'
import Announcement from './components/Announcement'
import PageNavDrawer from './components/PageNavDrawer'
import FloatTocButton from './components/FloatTocButton'
import { AdSlot } from '@/components/GoogleAdsense'
import JumpToTopButton from './components/JumpToTopButton'
const ThemeGlobalMedium = createContext()
/**
* 基础布局 采用左右两侧布局,移动端使用顶部导航栏
* @returns {JSX.Element}
* @constructor
*/
const LayoutBase = (props) => {
const { children, meta, post, allNavPages, slotLeft, slotRight, slotTop } = props
const [tocVisible, changeTocVisible] = useState(false)
const [pageNavVisible, changePageNavVisible] = useState(false)
const [filterPosts, setFilterPosts] = useState(allNavPages)
const { onLoading } = useGlobal()
const router = useRouter()
const showTocButton = post?.toc?.length > 1
useEffect(() => {
setFilterPosts(allNavPages)
}, [post])
const LoadingCover = <div id='cover-loading' className={`${onLoading ? 'z-50 opacity-50' : '-z-10 opacity-0'} pointer-events-none transition-all duration-300`}>
<div className='w-full h-screen flex justify-center items-center'>
<i className="fa-solid fa-spinner text-2xl text-black dark:text-white animate-spin"> </i>
</div>
</div>
return (
<ThemeGlobalMedium.Provider value={{ tocVisible, changeTocVisible, filterPosts, setFilterPosts, allNavPages, pageNavVisible, changePageNavVisible }}>
<CommonHead meta={meta} />
<div id='theme-medium' className='bg-white dark:bg-hexo-black-gray w-full h-full min-h-screen justify-center dark:text-gray-300'>
{/* 顶部导航栏 */}
<TopNavBar {...props} />
<main id='wrapper' className={(BLOG.LAYOUT_SIDEBAR_REVERSE ? 'flex-row-reverse' : '') + 'relative flex justify-between w-full h-full mx-auto'}>
{/* 左侧推拉抽屉 */}
<div style={{ width: '32rem' }} className={'font-sans hidden md:block border-r dark:border-transparent relative z-10 '}>
<div className='pt-14 pb-4 px-6 sticky top-0 overflow-y-scroll h-screen flex flex-col justify-between'>
{slotLeft}
<SearchInput className='my-3 rounded-md' />
{/* 所有文章列表 */}
<NavPostList posts={filterPosts} />
<div className='mt-2'>
<Footer {...props} />
</div>
</div>
</div>
<div id='center-wrapper' className='flex flex-col justify-between w-full relative z-10 pt-12 min-h-screen'>
<div id='container-inner' className='w-full px-7 max-w-3xl justify-center mx-auto'>
{slotTop}
<AdSlot type='in-article' />
{onLoading ? LoadingCover : children}
<AdSlot type='in-article' />
{/* 回顶按钮 */}
<JumpToTopButton />
</div>
{/* 底部 */}
<div className='md:hidden'>
<Footer {...props}/>
</div>
<div className='text-center'>
<AdSlot type='native' />
</div>
</div>
{/* 右侧侧推拉抽屉 */}
<div style={{ width: '32rem' }} className={'hidden xl:block dark:border-transparent relative z-10 '}>
<div className='py-14 px-6 sticky top-0'>
<ArticleInfo post={props?.post ? props?.post : props.notice} />
<div className='py-6'>
<Catalog {...props} />
{slotRight}
{router.route === '/' && <>
<InfoCard {...props} />
{CONFIG_GITBOOK.WIDGET_REVOLVER_MAPS === 'true' && <RevolverMaps />}
<Live2D />
</>}
{/* gitbook主题首页只显示公告 */}
<Announcement {...props} />
</div>
<Live2D />
</div>
</div>
</main>
{showTocButton && !tocVisible && <div className='md:hidden fixed right-0 bottom-52 z-30 bg-white border-l border-t border-b dark:border-gray-800 rounded'>
<FloatTocButton {...props} />
</div>}
<PageNavDrawer {...props} />
{/* 移动端底部导航栏 */}
{/* <BottomMenuBar {...props} className='block md:hidden' /> */}
</div>
</ThemeGlobalMedium.Provider>
)
}
export default LayoutBase
export const useGitBookGlobal = () => useContext(ThemeGlobalMedium)

View File

@@ -1,7 +1,7 @@
import React from 'react'
import BLOG from '@/blog.config'
const Footer = ({ title }) => {
const Footer = ({ siteInfo }) => {
const d = new Date()
const currentYear = d.getFullYear()
const copyrightDate = (function () {
@@ -13,23 +13,24 @@ const Footer = ({ title }) => {
return (
<footer
className='max-w-3xl z-10 dark:bg-hexo-black-gray flex-shrink-0 justify-center text-center mx-auto w-full leading-6 text-sm px-6 pb-6 relative'
className='z-10 bg:white dark:bg-hexo-black-gray justify-center text-center w-full text-sm relative'
>
<hr />
<hr className='py-2' />
<div className='flex justify-between'>
<div className='flex'>© {`${copyrightDate}`} <div><i className='mx-1 animate-pulse fas fa-heart' /> <a href={BLOG.LINK} className='underline font-bold text-gray-500 dark:text-gray-300 '>{BLOG.AUTHOR}</a>.<br /></div></div>
<div className='text-xs font-serif'><a href='https://github.com/tangly1024/NotionNext' className='underline text-gray-500 dark:text-gray-300'>NotionNext {BLOG.VERSION}</a></div>
<div className='flex justify-center'>
<div><i className='mx-1 animate-pulse fas fa-heart' /> <a href={BLOG.LINK} className='underline font-bold text-gray-500 dark:text-gray-300 '>{BLOG.AUTHOR}</a>.<br /></div>
© {`${copyrightDate}`}
</div>
<div className='text-xs font-serif'>Powered By <a href='https://github.com/tangly1024/NotionNext' className='underline text-gray-500 dark:text-gray-300'>NotionNext</a></div>
{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 />
<h1>{title}</h1>
<h1 className='pt-1'>{siteInfo?.title}</h1>
</footer>
)

View File

@@ -36,7 +36,7 @@ const NavPostList = (props) => {
if (!filteredPosts || filteredPosts.length === 0) {
return <NavPostListEmpty currentSearch={currentSearch} />
} else {
return <div id='posts-wrapper' className='w-full'>
return <div id='posts-wrapper' className='w-full flex-grow'>
{/* 文章列表 */}
{filteredPosts?.map((group, index) => <NavPostItem key={index} group={group} onHeightChange={props.onHeightChange}/>)}
</div>

View File

@@ -10,7 +10,7 @@ import BLOG from '@/blog.config'
* @returns
*/
export const BlogPostCardInfo = ({ post, showPreview, showPageCover, showSummary }) => {
return <div className={`flex flex-col justify-between lg:p-6 p-4 ${showPageCover && !showPreview ? 'md:w-7/12 w-full h-56 md:max-h-60 ' : 'w-full '}`}>
return <div className={`flex flex-col justify-between lg:p-6 p-4 ${showPageCover && !showPreview ? 'md:w-7/12 w-full md:max-h-60' : 'w-full'}`}>
<div>
{/* 标题 */}
<Link

View File

@@ -14,7 +14,7 @@ export default function HeaderArticle({ post, siteInfo }) {
const headerImage = post?.pageCover ? `url("${post.pageCover}")` : `url("${siteInfo?.pageCover}")`
const date = formatDate(
post?.publishTime || post?.createdTime,
post?.publishTime,
locale.LOCALE
)

View File

@@ -8,7 +8,7 @@ export const ArticleInfo = (props) => {
const { post } = props
const { locale } = useGlobal()
const date = formatDate(post?.publishTime || post?.createdTime, locale.LOCALE)
const date = formatDate(post?.publishTime, locale.LOCALE)
return (
<section className='mb-3 dark:text-gray-200'>

View File

@@ -0,0 +1,96 @@
import LayoutBase from './LayoutBase'
import { useGlobal } from '@/lib/global'
import React from 'react'
import Catalog from './components/Catalog'
import { ArticleLock } from './components/ArticleLock'
import formatDate from '@/lib/formatDate'
import BLOG from '@/blog.config'
import Link from 'next/link'
import NotionPage from '@/components/NotionPage'
import CONFIG_MEDIUM from './config_medium'
import Comment from '@/components/Comment'
import ArticleAround from './components/ArticleAround'
import TocDrawer from './components/TocDrawer'
import CategoryItem from './components/CategoryItem'
import TagItemMini from './components/TagItemMini'
import ShareBar from '@/components/ShareBar'
export const LayoutSlug = props => {
const { post, prev, next, siteInfo, lock, validPassword } = props
const { locale } = useGlobal()
const date = formatDate(
post?.publishTime || post?.createdTime,
locale.LOCALE
)
if (!post) {
return <LayoutBase {...props} showInfoCard={true} />
}
const slotRight = post?.toc && post?.toc?.length >= 3 && (
<div key={locale.COMMON.TABLE_OF_CONTENTS} >
<Catalog toc={post.toc} />
{/* <JumpToTopButton className='text-gray-400 hover:text-green-500 hover:bg-gray-100 py-1 duration-200' /> */}
</div>
)
return (
<LayoutBase showInfoCard={true} slotRight={slotRight} {...props} >
{/* 文章锁 */}
{lock && <ArticleLock validPassword={validPassword} />}
{!lock && <div id='container'>
{/* title */}
<h1 className="text-3xl pt-12 dark:text-gray-300">{post?.title}</h1>
{/* meta */}
<section className="py-2 items-center text-sm px-1">
<div className='flex flex-wrap text-gray-500 py-1 dark:text-gray-600'>
<span className='whitespace-nowrap'> <i className='far fa-calendar mr-2' />{date}</span>
<span className='mx-1'>|</span>
<span className='whitespace-nowrap mr-2'><i className='far fa-calendar-check mr-2' />{post.lastEditedTime}</span>
<div className="hidden busuanzi_container_page_pv font-light mr-2 whitespace-nowrap">
<i className="mr-1 fas fa-eye" /><span className="busuanzi_value_page_pv" />
</div>
</div>
<Link href="/about" passHref legacyBehavior>
<div className='flex pt-2'>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src={siteInfo?.icon} className='rounded-full cursor-pointer' width={22} alt={BLOG.AUTHOR} />
<div className="mr-3 ml-2 my-auto text-green-500 cursor-pointer">
{BLOG.AUTHOR}
</div>
</div>
</Link>
</section>
{/* Notion文章主体 */}
<section id="notion-article" className="px-1 max-w-4xl">
{post && (<NotionPage post={post} />)}
</section>
<section>
{/* 分享 */}
<ShareBar post={post} />
{/* 文章分类和标签信息 */}
<div className='flex justify-between'>
{CONFIG_MEDIUM.POST_DETAIL_CATEGORY && post.category && <CategoryItem category={post.category} />}
<div>
{CONFIG_MEDIUM.POST_DETAIL_TAG && post?.tagItems?.map(tag => <TagItemMini key={tag.name} tag={tag} />)}
</div>
</div>
{post.type === 'Post' && <ArticleAround prev={prev} next={next} />}
<Comment frontMatter={post} />
</section>
<TocDrawer {...props} />
</div>}
</LayoutBase>
)
}
export default LayoutSlug