diff --git a/.env.local b/.env.local index 5df7065b34d..48b76dc9300 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 6747c7b09e4..051db1e6cd7 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 0a69e55e58f..3e568e9f97d 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/lib/notion/getPageProperties.js b/lib/notion/getPageProperties.js index 8d3add33ee0..ddf47f3e678 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 a9e3a757ca9..809dfe7ae6e 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 8d7f9fba7a7..b6da8d8744a 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 1c24ce6fc10..6164cbb42a7 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 00000000000..67f099d7e84 --- /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 2beae09cdbc..4571b791adf 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 ecfea4e1f39..6fa5d47b377 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 14cad8b086f..a0ff3f738d3 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 f62be177ec9..a979621c06b 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 dc1d9759c0e..f1febbddf81 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 574a8e5b6d7..5be22e2bbfd 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 (