mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-18 23:16:49 +00:00
Merge branch 'main' into main
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
# 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables
|
||||
NEXT_PUBLIC_VERSION=4.0.16
|
||||
NEXT_PUBLIC_VERSION=4.0.18
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
/* eslint-disable */
|
||||
import React from 'react'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
const StarrySky = () => {
|
||||
React.useEffect(() => {
|
||||
dark()
|
||||
useEffect(() => {
|
||||
renderStarrySky()
|
||||
}, [])
|
||||
return (
|
||||
<div className="relative">
|
||||
<canvas id="starry-sky-vixcity" style={{zIndex:1}} className="top-0 fixed pointer-events-none"></canvas>
|
||||
<canvas id="starry-sky-vixcity" style={{zIndex:5}} className="top-0 fixed pointer-events-none"></canvas>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
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)
|
||||
})()
|
||||
}
|
||||
|
||||
@@ -135,6 +135,8 @@ function mapProperties(properties) {
|
||||
|
||||
/**
|
||||
* 获取自定义URL
|
||||
* 可以根据变量生成URL
|
||||
* 支持:%year%/%month%/%day%/%slug%
|
||||
* @param {*} postProperties
|
||||
* @returns
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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": {
|
||||
|
||||
113
pages/[prefix]/[slug]/[...suffix].js
Normal file
113
pages/[prefix]/[slug]/[...suffix].js
Normal file
@@ -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 <Slug {...props}/>
|
||||
}
|
||||
|
||||
/**
|
||||
* 编译渲染页面路径
|
||||
* @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
|
||||
@@ -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
|
||||
*/
|
||||
@@ -13,6 +13,7 @@ import { uploadDataToAlgolia } from '@/lib/algolia'
|
||||
|
||||
/**
|
||||
* 根据notion的slug访问页面
|
||||
* 只解析一级目录例如 /about
|
||||
* @param {*} props
|
||||
* @returns
|
||||
*/
|
||||
|
||||
@@ -253,7 +253,7 @@ function TopGroup(props) {
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<TodayCard cRef={todayCardRef} />
|
||||
<TodayCard cRef={todayCardRef} siteInfo={siteInfo}/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -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`
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 (
|
||||
<nav id='nav' className='leading-8 flex justify-center dark:text-gray-200 w-full'>
|
||||
{links.map(link => {
|
||||
|
||||
@@ -18,6 +18,12 @@ export const MenuListSide = (props) => {
|
||||
if (customNav) {
|
||||
links = customNav.concat(links)
|
||||
}
|
||||
|
||||
for (let i = 0; i < links.length; i++) {
|
||||
if (links[i].id !== i) {
|
||||
links[i].id = i
|
||||
}
|
||||
}
|
||||
|
||||
// 如果 开启自定义菜单,则覆盖Page生成的菜单
|
||||
if (BLOG.CUSTOM_MENU) {
|
||||
|
||||
@@ -20,6 +20,12 @@ export const MenuListTop = (props) => {
|
||||
links = links.concat(customNav)
|
||||
}
|
||||
|
||||
for (let i = 0; i < links.length; i++) {
|
||||
if (links[i].id !== i) {
|
||||
links[i].id = i
|
||||
}
|
||||
}
|
||||
|
||||
// 如果 开启自定义菜单,则覆盖Page生成的菜单
|
||||
if (BLOG.CUSTOM_MENU) {
|
||||
links = customMenu
|
||||
|
||||
@@ -133,8 +133,6 @@ export default function Features() {
|
||||
unmount={false}
|
||||
>
|
||||
<div className="relative inline-flex flex-col">
|
||||
{/* <Image className="md:max-w-none mx-auto rounded" src={FeaturesBg} width={500} height="462" alt="Features bg" />
|
||||
<Image className="md:max-w-none absolute w-full left-0 transform animate-float" src={FeaturesElement} width={500} height="44" alt="Element" style={{ top: '30%' }} /> */}
|
||||
<LazyImage src='/images/feature-2.webp'/>
|
||||
</div>
|
||||
</Transition>
|
||||
@@ -153,8 +151,6 @@ export default function Features() {
|
||||
unmount={false}
|
||||
>
|
||||
<div className="relative inline-flex flex-col">
|
||||
{/* <Image className="md:max-w-none mx-auto rounded" src={FeaturesBg} width={500} height="462" alt="Features bg" />
|
||||
<Image className="md:max-w-none absolute w-full left-0 transform animate-float" src={FeaturesElement} width={500} height="44" alt="Element" style={{ top: '30%' }} /> */}
|
||||
<LazyImage src='/images/feature-3.webp'/>
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
@@ -22,7 +22,7 @@ const CONFIG = {
|
||||
FEATURES_HEADER_1: '探索的过程',
|
||||
FEATURES_HEADER_1_P: "如何搭建自己的门户网站,塑造一个品牌展示中心?<br/>曾经,它是系统<strong class='font-bold text-red-500'>繁重</strong>的Wordpress、是操作<strong class='font-bold text-red-500'>复杂</strong>的Hexo、是<strong class='font-bold text-red-500'>昂贵</strong>且<strong class='font-bold text-red-500'>不稳定</strong>的技术团队;<br/>现在,只要一个Notion笔记就够了",
|
||||
FEATURES_HEADER_2: 'Notion+NextJs组合方案',
|
||||
FEATURES_HEADER_2_P: 'Notion作为CMS管理您的站点配置和网页数据,NextJs作为渲染博客的脚本,借助第三方的Vercel等托管平台提供网络服务。',
|
||||
FEATURES_HEADER_2_P: '在Notion笔记中管理文章数据,NextJs将其渲染成网页排版,通过Vercel等第三方平台将您的网站发布到全球。',
|
||||
FEATURES_CARD_1_TITLE: '简单快速的系统',
|
||||
FEATURES_CARD_1_P: '在Notion中写下一篇文章,内容立刻在您的网站首页中呈现给互联网',
|
||||
FEATURES_CARD_2_TITLE: '高效传播的媒介',
|
||||
@@ -47,7 +47,7 @@ const CONFIG = {
|
||||
FEATURES_BLOCK_6_P: 'NotionNext,助您轻松开始写作',
|
||||
|
||||
// 感言
|
||||
TESTIMONIALS_HEADER: '已搭建超4000个网站、浏览量突破 100,000,000+',
|
||||
TESTIMONIALS_HEADER: '已搭建超5300个网站、总浏览量突破100,000,000+',
|
||||
TESTIMONIALS_P: '网站内容涵盖地产、教育、建筑、医学、机械、IT、电子、软件、自媒体、数位游民、短视频、电商、学生、摄影爱好者、旅行爱好者等等各行各业',
|
||||
|
||||
TESTIMONIALS_AVATAR: 'https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F22de3fcb-d90d-4271-bc01-f815f476122b%2F4FE0A0C0-E487-4C74-BF8E-6F01A27461B8-14186-000008094BC289A6.jpg?table=collection&id=a320a2cc-6ebe-4a8d-95cc-ea94e63bced9&width=200',
|
||||
|
||||
@@ -31,7 +31,7 @@ const BlogPostCard = ({ post, showSummary }) => {
|
||||
}>
|
||||
<div>
|
||||
{CONFIG.POST_LIST_COVER && <div className='w-full max-h-96 object-cover overflow-hidden mb-2'>
|
||||
<LazyImage src={post.pageCoverThumbnail} className='w-full max-h-96 object-cover hover:scale-125 duration-150' />
|
||||
<LazyImage src={post.pageCoverThumbnail} style={post.pageCoverThumbnail ? {} : { height: '0px' }} className='w-full max-h-96 object-cover hover:scale-125 duration-150' />
|
||||
</div>}
|
||||
{post.title}
|
||||
</div>
|
||||
|
||||
@@ -87,11 +87,13 @@ const LayoutBase = (props) => {
|
||||
|
||||
{/* 左侧推拉抽屉 */}
|
||||
<div className={'font-sans hidden md:block dark:border-transparent relative z-10 mx-4 w-52 max-h-full pb-44'}>
|
||||
|
||||
{/* 图标Logo */}
|
||||
<div className='hidden md:block w-full top-0 left-5 md:left-4 z-40 pt-3 md:pt-4'>
|
||||
<LogoBar {...props} />
|
||||
</div>
|
||||
<div className='main-menu z-20 pl-9 pr-7 pb-5 sticky pt-1 top-20 overflow-y-scroll h-fit max-h-full scroll-hidden bg-white dark:bg-neutral-800 rounded-xl '>
|
||||
|
||||
{/* 嵌入 */}
|
||||
{slotLeft}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user