diff --git a/.env.local b/.env.local
index 5df7065b..48b76dc9 100644
--- a/.env.local
+++ b/.env.local
@@ -1,2 +1,2 @@
# 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables
-NEXT_PUBLIC_VERSION=4.0.16
\ No newline at end of file
+NEXT_PUBLIC_VERSION=4.0.18
\ No newline at end of file
diff --git a/blog.config.js b/blog.config.js
index 65683d0d..ae020dac 100644
--- a/blog.config.js
+++ b/blog.config.js
@@ -114,7 +114,9 @@ const BLOG = {
CODE_MAC_BAR: process.env.NEXT_PUBLIC_CODE_MAC_BAR || true, // 代码左上角显示mac的红黄绿图标
CODE_LINE_NUMBERS: process.env.NEXT_PUBLIC_CODE_LINE_NUMBERS || false, // 是否显示行号
- CODE_COLLAPSE: process.env.NEXT_PUBLIC_CODE_COLLAPSE || true, // 是否折叠代码框
+ CODE_COLLAPSE: process.env.NEXT_PUBLIC_CODE_COLLAPSE || true, // 是否支持折叠代码框
+ CODE_COLLAPSE_EXPAND_DEFAULT: process.env.NEXT_PUBLIC_CODE_COLLAPSE_EXPAND_DEFAULT || true, // 折叠代码默认是展开状态
+
// END********代码相关********
// Mermaid 图表CDN
diff --git a/components/PrismMac.js b/components/PrismMac.js
index 0a69e55e..3e568e9f 100644
--- a/components/PrismMac.js
+++ b/components/PrismMac.js
@@ -105,13 +105,20 @@ const renderCollapseCode = () => {
codeBlock.parentNode.insertBefore(collapseWrapper, codeBlock)
panel.appendChild(codeBlock)
- header.addEventListener('click', () => {
+ function collapseCode() {
panel.classList.toggle('invisible')
panel.classList.toggle('h-0')
panel.classList.toggle('h-auto')
header.querySelector('svg').classList.toggle('rotate-180')
panelWrapper.classList.toggle('border-gray-300')
- })
+ }
+
+ // 点击后折叠展开代码
+ header.addEventListener('click', collapseCode)
+ // 是否自动展开
+ if (JSON.parse(BLOG.CODE_COLLAPSE_EXPAND_DEFAULT)) {
+ header.click()
+ }
}
}
diff --git a/components/StarrySky.js b/components/StarrySky.js
index 5479df93..e0fd3ac4 100644
--- a/components/StarrySky.js
+++ b/components/StarrySky.js
@@ -1,23 +1,24 @@
/* eslint-disable */
-import React from 'react'
+import { useEffect } from 'react'
const StarrySky = () => {
- React.useEffect(() => {
- dark()
+ useEffect(() => {
+ renderStarrySky()
}, [])
return (
-
+
)
}
export default StarrySky
+
/**
* 创建星空雨
* @param config
*/
-function dark() {
+function renderStarrySky() {
window.requestAnimationFrame =
window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
@@ -124,7 +125,7 @@ function dark() {
u()
})(),
(function t() {
- document.getElementsByTagName('html')[0].className == 'dark' && u(),
+ document.getElementsByTagName('html')[0].className.indexOf('dark')>=0 && u(),
window.requestAnimationFrame(t)
})()
}
diff --git a/lib/notion/getPageProperties.js b/lib/notion/getPageProperties.js
index 8d3add33..ddf47f3e 100644
--- a/lib/notion/getPageProperties.js
+++ b/lib/notion/getPageProperties.js
@@ -135,6 +135,8 @@ function mapProperties(properties) {
/**
* 获取自定义URL
+ * 可以根据变量生成URL
+ * 支持:%year%/%month%/%day%/%slug%
* @param {*} postProperties
* @returns
*/
diff --git a/lib/notion/getPostBlocks.js b/lib/notion/getPostBlocks.js
index a9e3a757..809dfe7a 100644
--- a/lib/notion/getPostBlocks.js
+++ b/lib/notion/getPostBlocks.js
@@ -102,7 +102,7 @@ function filterPostBlocks(id, pageBlock, slice) {
}
// 如果是文件,或嵌入式PDF,需要重新加密签名
- if ((b?.value?.type === 'file' || b?.value?.type === 'pdf') && b?.value?.properties?.source?.[0][0]) {
+ if ((b?.value?.type === 'file' || b?.value?.type === 'pdf' || b?.value?.type === 'video') && b?.value?.properties?.source?.[0][0]) {
const oldUrl = b?.value?.properties?.source?.[0][0]
const newUrl = `https://notion.so/signed/${encodeURIComponent(oldUrl)}?table=block&id=${b?.value?.id}`
b.value.properties.source[0][0] = newUrl
diff --git a/lib/notion/mapImage.js b/lib/notion/mapImage.js
index 8d7f9fba..b6da8d87 100644
--- a/lib/notion/mapImage.js
+++ b/lib/notion/mapImage.js
@@ -6,7 +6,7 @@ import BLOG from '@/blog.config'
* 2. UnPlash 图片可以通过api q=50 控制压缩质量 width=400 控制图片尺寸
* @param {*} image
*/
-const compressImage = (image, width = 400, quality = 50, fmt = 'webp') => {
+const compressImage = (image, width = 800, quality = 50, fmt = 'webp') => {
if (!image) {
return null
}
@@ -67,12 +67,11 @@ const mapImgUrl = (img, block, type = 'block', from) => {
ret = BLOG.NOTION_HOST + '/image/' + encodeURIComponent(ret) + '?table=' + type + '&id=' + block.id
}
- // UnSplash 随机图片接口优化
- if (ret.includes('source.unsplash.com/random')) {
- // 检查原始URL是否已经包含参数
+ if (!isEmoji(ret) && ret.indexOf('notion.so/images/page-cover') < 0) {
+ // 随机图片接口优化 防止因url一致而随机结果相同
const separator = ret.includes('?') ? '&' : '?'
// 拼接唯一识别参数,防止请求的图片被缓存
- ret = `${ret}${separator}random=${block.id}`
+ ret = `${ret.trim()}${separator}t=${block.id}`
}
// 文章封面
@@ -83,4 +82,9 @@ const mapImgUrl = (img, block, type = 'block', from) => {
return ret
}
+function isEmoji(str) {
+ const emojiRegex = /[\u{1F300}-\u{1F6FF}\u{1F1E0}-\u{1F1FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}\u{1F900}-\u{1F9FF}\u{1F018}-\u{1F270}]/u;
+ return emojiRegex.test(str);
+}
+
export { mapImgUrl, compressImage }
diff --git a/package.json b/package.json
index 1c24ce6f..6164cbb4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "notion-next",
- "version": "4.0.16",
+ "version": "4.0.18",
"homepage": "https://github.com/tangly1024/NotionNext.git",
"license": "MIT",
"repository": {
diff --git a/pages/[prefix]/[slug]/[...suffix].js b/pages/[prefix]/[slug]/[...suffix].js
new file mode 100644
index 00000000..67f099d7
--- /dev/null
+++ b/pages/[prefix]/[slug]/[...suffix].js
@@ -0,0 +1,113 @@
+import BLOG from '@/blog.config'
+import { getPostBlocks } from '@/lib/notion'
+import { getGlobalData } from '@/lib/notion/getNotionData'
+import { idToUuid } from 'notion-utils'
+import { getNotion } from '@/lib/notion/getNotion'
+import Slug, { getRecommendPost } from '..'
+import { uploadDataToAlgolia } from '@/lib/algolia'
+
+/**
+ * 根据notion的slug访问页面
+ * 解析三级以上目录 /article/2023/10/29/test
+ * @param {*} props
+ * @returns
+ */
+const PrefixSlug = props => {
+ return
+}
+
+/**
+ * 编译渲染页面路径
+ * @returns
+ */
+export async function getStaticPaths() {
+ if (!BLOG.isProd) {
+ return {
+ paths: [],
+ fallback: true
+ }
+ }
+
+ const from = 'slug-paths'
+ const { allPages } = await getGlobalData({ from })
+ return {
+ paths: allPages?.filter(row => hasMultipleSlashes(row.slug) && row.type.indexOf('Menu') < 0).map(row => ({ params: { prefix: row.slug.split('/')[0], slug: row.slug.split('/')[1], suffix: row.slug.split('/').slice(1) } })),
+ fallback: true
+ }
+}
+
+/**
+ * 抓取页面数据
+ * @param {*} param0
+ * @returns
+ */
+export async function getStaticProps({ params: { prefix, slug, suffix } }) {
+ let fullSlug = prefix + '/' + slug + '/' + suffix.join('/')
+ if (JSON.parse(BLOG.PSEUDO_STATIC)) {
+ if (!fullSlug.endsWith('.html')) {
+ fullSlug += '.html'
+ }
+ }
+ const from = `slug-props-${fullSlug}`
+ const props = await getGlobalData({ from })
+ // 在列表内查找文章
+ props.post = props?.allPages?.find((p) => {
+ return p.slug === fullSlug || p.id === idToUuid(fullSlug)
+ })
+
+ // 处理非列表内文章的内信息
+ if (!props?.post) {
+ const pageId = fullSlug.slice(-1)[0]
+ if (pageId.length >= 32) {
+ const post = await getNotion(pageId)
+ props.post = post
+ }
+ }
+
+ // 无法获取文章
+ if (!props?.post) {
+ props.post = null
+ return { props, revalidate: parseInt(BLOG.NEXT_REVALIDATE_SECOND) }
+ }
+
+ // 文章内容加载
+ if (!props?.posts?.blockMap) {
+ props.post.blockMap = await getPostBlocks(props.post.id, from)
+ }
+ // 生成全文索引 && JSON.parse(BLOG.ALGOLIA_RECREATE_DATA)
+ if (BLOG.ALGOLIA_APP_ID) {
+ uploadDataToAlgolia(props?.post)
+ }
+
+ // 推荐关联文章处理
+ const allPosts = props.allPages?.filter(page => page.type === 'Post' && page.status === 'Published')
+ if (allPosts && allPosts.length > 0) {
+ const index = allPosts.indexOf(props.post)
+ props.prev = allPosts.slice(index - 1, index)[0] ?? allPosts.slice(-1)[0]
+ props.next = allPosts.slice(index + 1, index + 2)[0] ?? allPosts[0]
+ props.recommendPosts = getRecommendPost(props.post, allPosts, BLOG.POST_RECOMMEND_COUNT)
+ } else {
+ props.prev = null
+ props.next = null
+ props.recommendPosts = []
+ }
+
+ delete props.allPages
+ return {
+ props,
+ revalidate: parseInt(BLOG.NEXT_REVALIDATE_SECOND)
+ }
+}
+
+/**
+ * 判断是否包含两个以上的 /
+ * @param {*} str
+ * @returns
+ */
+function hasMultipleSlashes(str) {
+ const regex = /\/+/g; // 创建正则表达式,匹配所有的斜杠符号
+ const matches = str.match(regex); // 在字符串中找到所有匹配的斜杠符号
+ return matches && matches.length >= 2; // 判断匹配的斜杠符号数量是否大于等于2
+}
+
+export default PrefixSlug
diff --git a/pages/[prefix]/[slug].js b/pages/[prefix]/[slug]/index.js
similarity index 96%
rename from pages/[prefix]/[slug].js
rename to pages/[prefix]/[slug]/index.js
index 2beae09c..4571b791 100644
--- a/pages/[prefix]/[slug].js
+++ b/pages/[prefix]/[slug]/index.js
@@ -3,11 +3,12 @@ import { getPostBlocks } from '@/lib/notion'
import { getGlobalData } from '@/lib/notion/getNotionData'
import { idToUuid } from 'notion-utils'
import { getNotion } from '@/lib/notion/getNotion'
-import Slug, { getRecommendPost } from '.'
+import Slug, { getRecommendPost } from '..'
import { uploadDataToAlgolia } from '@/lib/algolia'
/**
* 根据notion的slug访问页面
+ * 解析二级目录 /article/about
* @param {*} props
* @returns
*/
diff --git a/pages/[prefix]/index.js b/pages/[prefix]/index.js
index ecfea4e1..6fa5d47b 100644
--- a/pages/[prefix]/index.js
+++ b/pages/[prefix]/index.js
@@ -13,6 +13,7 @@ import { uploadDataToAlgolia } from '@/lib/algolia'
/**
* 根据notion的slug访问页面
+ * 只解析一级目录例如 /about
* @param {*} props
* @returns
*/
diff --git a/themes/heo/components/Hero.js b/themes/heo/components/Hero.js
index 14cad8b0..a0ff3f73 100644
--- a/themes/heo/components/Hero.js
+++ b/themes/heo/components/Hero.js
@@ -253,7 +253,7 @@ function TopGroup(props) {
)
})}
-
+
)
}
@@ -301,7 +301,7 @@ function getTopPosts({ latestPosts, allNavPages }) {
* 英雄区右侧,今日卡牌
* @returns
*/
-function TodayCard({ cRef }) {
+function TodayCard({ cRef, siteInfo }) {
const router = useRouter()
// 卡牌是否盖住下层
const [isCoverUp, setIsCoverUp] = useState(true)
@@ -378,8 +378,7 @@ function TodayCard({ cRef }) {
isCoverUp ? '' : ' pointer-events-none'
} cursor-pointer today-card-cover absolute w-full h-full top-0`}
style={{
- background:
- "url('https://bu.dusays.com/2023/03/12/640dcd3a1b146.png') no-repeat center /cover"
+ background: `url('${siteInfo?.pageCover}') no-repeat center /cover`
}}
>
diff --git a/themes/heo/config.js b/themes/heo/config.js
index f62be177..a979621c 100644
--- a/themes/heo/config.js
+++ b/themes/heo/config.js
@@ -25,6 +25,7 @@ const CONFIG = {
// 英雄区右侧推荐文章标签, 例如 [推荐] , 最多六篇文章; 若留空白'',则推荐最近更新文章
HERO_RECOMMEND_POST_TAG: '推荐',
HERO_RECOMMEND_POST_SORT_BY_UPDATE_TIME: false, // 推荐文章排序,为`true`时将强制按最后修改时间倒序
+ // HERO_RECOMMEND_COVER: 'https://cdn.pixabay.com/photo/2015/10/30/20/13/sunrise-1014712_1280.jpg', // 英雄区右侧图片
// 右侧个人资料卡牌欢迎语,点击可自动切换
INFOCARD_GREETINGS: [
diff --git a/themes/hexo/components/BlogPostCard.js b/themes/hexo/components/BlogPostCard.js
index dc1d9759..f1febbdd 100644
--- a/themes/hexo/components/BlogPostCard.js
+++ b/themes/hexo/components/BlogPostCard.js
@@ -9,7 +9,7 @@ import LazyImage from '@/components/LazyImage'
const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
const showPreview = CONFIG.POST_LIST_PREVIEW && post.blockMap
if (post && !post.pageCoverThumbnail && CONFIG.POST_LIST_COVER_DEFAULT) {
- post.pageCover = siteInfo?.pageCoverThumbnail
+ post.pageCoverThumbnail = siteInfo?.pageCover
}
const showPageCover = CONFIG.POST_LIST_COVER && post?.pageCoverThumbnail && !showPreview
// const delay = (index % 2) * 200
diff --git a/themes/hexo/components/MenuGroupCard.js b/themes/hexo/components/MenuGroupCard.js
index 574a8e5b..5be22e2b 100644
--- a/themes/hexo/components/MenuGroupCard.js
+++ b/themes/hexo/components/MenuGroupCard.js
@@ -16,6 +16,12 @@ const MenuGroupCard = (props) => {
{ name: locale.COMMON.TAGS, to: '/tag', slot: tagSlot, show: CONFIG.MENU_TAG }
]
+ for (let i = 0; i < links.length; i++) {
+ if (links[i].id !== i) {
+ links[i].id = i
+ }
+ }
+
return (