mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-13 23:16:47 +00:00
Merge pull request #3419 from LooseLi/fix-eslint-errors
Fix eslint errors
This commit is contained in:
@@ -39,7 +39,7 @@ module.exports = {
|
||||
'react/prop-types': 'off',
|
||||
'space-before-function-paren': 0,
|
||||
'react-hooks/rules-of-hooks': 'error', // Checks rules of Hooks
|
||||
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], // 确保未使用的变量报错
|
||||
'@typescript-eslint/no-unused-vars': 'off', // 关闭未使用的变量报错
|
||||
'@typescript-eslint/explicit-function-return-type': 'off' // 关闭强制函数返回类型声明
|
||||
},
|
||||
overrides: [
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useEffect } from 'react'
|
||||
* https://michalsnik.github.io/aos/
|
||||
*/
|
||||
export default function AOSAnimation() {
|
||||
const initAOS = async () => {
|
||||
const initAOS = () => {
|
||||
Promise.all([
|
||||
loadExternalResource('/js/aos.js', 'js'),
|
||||
loadExternalResource('/css/aos.css', 'css')
|
||||
|
||||
@@ -14,16 +14,19 @@ export default function AdBlockDetect() {
|
||||
const wwadsCns = document.getElementsByClassName('wwads-cn')
|
||||
if (wwadsCns && wwadsCns.length > 0) {
|
||||
for (const wwadsCn of wwadsCns) {
|
||||
wwadsCn.insertAdjacentHTML('beforeend', "<style>.wwads-horizontal,.wwads-vertical{background-color:#f4f8fa;padding:5px;min-height:120px;margin-top:20px;box-sizing:border-box;border-radius:3px;font-family:sans-serif;display:flex;min-width:150px;position:relative;overflow:hidden;}.wwads-horizontal{flex-wrap:wrap;justify-content:center}.wwads-vertical{flex-direction:column;align-items:center;padding-bottom:32px}.wwads-horizontal a,.wwads-vertical a{text-decoration:none}.wwads-horizontal .wwads-img,.wwads-vertical .wwads-img{margin:5px}.wwads-horizontal .wwads-content,.wwads-vertical .wwads-content{margin:5px}.wwads-horizontal .wwads-content{flex:130px}.wwads-vertical .wwads-content{margin-top:10px}.wwads-horizontal .wwads-text,.wwads-content .wwads-text{font-size:14px;line-height:1.4;color:#0e1011;-webkit-font-smoothing:antialiased}.wwads-horizontal .wwads-poweredby,.wwads-vertical .wwads-poweredby{display:block;font-size:11px;color:#a6b7bf;margin-top:1em}.wwads-vertical .wwads-poweredby{position:absolute;left:10px;bottom:10px}.wwads-horizontal .wwads-poweredby span,.wwads-vertical .wwads-poweredby span{transition:all 0.2s ease-in-out;margin-left:-1em}.wwads-horizontal .wwads-poweredby span:first-child,.wwads-vertical .wwads-poweredby span:first-child{opacity:0}.wwads-horizontal:hover .wwads-poweredby span,.wwads-vertical:hover .wwads-poweredby span{opacity:1;margin-left:0}.wwads-horizontal .wwads-hide,.wwads-vertical .wwads-hide{position:absolute;right:-23px;bottom:-23px;width:46px;height:46px;border-radius:23px;transition:all 0.3s ease-in-out;cursor:pointer;}.wwads-horizontal .wwads-hide:hover,.wwads-vertical .wwads-hide:hover{background:rgb(0 0 0 /0.05)}.wwads-horizontal .wwads-hide svg,.wwads-vertical .wwads-hide svg{position:absolute;left:10px;top:10px;fill:#a6b7bf}.wwads-horizontal .wwads-hide:hover svg,.wwads-vertical .wwads-hide:hover svg{fill:#3E4546}</style><a href='https://wwads.cn/page/whitelist-wwads' class='wwads-img' target='_blank' rel='nofollow'><img src='https://creatives-1301677708.file.myqcloud.com/images/placeholder/wwads-friendly-ads.png' width='130'></a><div class='wwads-content'><a href='https://wwads.cn/page/whitelist-wwads' class='wwads-text' target='_blank' rel='nofollow'>为了本站的长期运营,请将我们的网站加入广告拦截器的白名单,感谢您的支持!</a><a href='https://wwads.cn/page/end-user-privacy' class='wwads-poweredby' title='万维广告 ~ 让广告更优雅,且有用' target='_blank'><span>万维</span><span>广告</span></a></div><a class='wwads-hide' onclick='parentNode.remove()' title='隐藏广告'><svg xmlns='http://www.w3.org/2000/svg' width='6' height='7'><path d='M.879.672L3 2.793 5.121.672a.5.5 0 11.707.707L3.708 3.5l2.12 2.121a.5.5 0 11-.707.707l-2.12-2.12-2.122 2.12a.5.5 0 11-.707-.707l2.121-2.12L.172 1.378A.5.5 0 01.879.672z'></path></svg></a>")
|
||||
wwadsCn.insertAdjacentHTML(
|
||||
'beforeend',
|
||||
"<style>.wwads-horizontal,.wwads-vertical{background-color:#f4f8fa;padding:5px;min-height:120px;margin-top:20px;box-sizing:border-box;border-radius:3px;font-family:sans-serif;display:flex;min-width:150px;position:relative;overflow:hidden;}.wwads-horizontal{flex-wrap:wrap;justify-content:center}.wwads-vertical{flex-direction:column;align-items:center;padding-bottom:32px}.wwads-horizontal a,.wwads-vertical a{text-decoration:none}.wwads-horizontal .wwads-img,.wwads-vertical .wwads-img{margin:5px}.wwads-horizontal .wwads-content,.wwads-vertical .wwads-content{margin:5px}.wwads-horizontal .wwads-content{flex:130px}.wwads-vertical .wwads-content{margin-top:10px}.wwads-horizontal .wwads-text,.wwads-content .wwads-text{font-size:14px;line-height:1.4;color:#0e1011;-webkit-font-smoothing:antialiased}.wwads-horizontal .wwads-poweredby,.wwads-vertical .wwads-poweredby{display:block;font-size:11px;color:#a6b7bf;margin-top:1em}.wwads-vertical .wwads-poweredby{position:absolute;left:10px;bottom:10px}.wwads-horizontal .wwads-poweredby span,.wwads-vertical .wwads-poweredby span{transition:all 0.2s ease-in-out;margin-left:-1em}.wwads-horizontal .wwads-poweredby span:first-child,.wwads-vertical .wwads-poweredby span:first-child{opacity:0}.wwads-horizontal:hover .wwads-poweredby span,.wwads-vertical:hover .wwads-poweredby span{opacity:1;margin-left:0}.wwads-horizontal .wwads-hide,.wwads-vertical .wwads-hide{position:absolute;right:-23px;bottom:-23px;width:46px;height:46px;border-radius:23px;transition:all 0.3s ease-in-out;cursor:pointer;}.wwads-horizontal .wwads-hide:hover,.wwads-vertical .wwads-hide:hover{background:rgb(0 0 0 /0.05)}.wwads-horizontal .wwads-hide svg,.wwads-vertical .wwads-hide svg{position:absolute;left:10px;top:10px;fill:#a6b7bf}.wwads-horizontal .wwads-hide:hover svg,.wwads-vertical .wwads-hide:hover svg{fill:#3E4546}</style><a href='https://wwads.cn/page/whitelist-wwads' class='wwads-img' target='_blank' rel='nofollow'><img src='https://creatives-1301677708.file.myqcloud.com/images/placeholder/wwads-friendly-ads.png' width='130'></a><div class='wwads-content'><a href='https://wwads.cn/page/whitelist-wwads' class='wwads-text' target='_blank' rel='nofollow'>为了本站的长期运营,请将我们的网站加入广告拦截器的白名单,感谢您的支持!</a><a href='https://wwads.cn/page/end-user-privacy' class='wwads-poweredby' title='万维广告 ~ 让广告更优雅,且有用' target='_blank'><span>万维</span><span>广告</span></a></div><a class='wwads-hide' onclick='parentNode.remove()' title='隐藏广告'><svg xmlns='http://www.w3.org/2000/svg' width='6' height='7'><path d='M.879.672L3 2.793 5.121.672a.5.5 0 11.707.707L3.708 3.5l2.12 2.121a.5.5 0 11-.707.707l-2.12-2.12-2.122 2.12a.5.5 0 11-.707-.707l2.121-2.12L.172 1.378A.5.5 0 01.879.672z'></path></svg></a>"
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// check document ready
|
||||
function docReady(t) {
|
||||
document.readyState === 'complete' ||
|
||||
document.readyState === 'interactive'
|
||||
? setTimeout(t, 1)
|
||||
? setTimeout(() => t(), 1)
|
||||
: document.addEventListener('DOMContentLoaded', t)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ import WebWhiz from './Webwhiz'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import IconFont from './IconFont'
|
||||
|
||||
|
||||
/**
|
||||
* 各种插件脚本
|
||||
* @param {*} props
|
||||
@@ -22,7 +21,7 @@ import IconFont from './IconFont'
|
||||
const ExternalPlugin = props => {
|
||||
// 读取自Notion的配置
|
||||
const { NOTION_CONFIG } = props
|
||||
const {lang} = useGlobal()
|
||||
const { lang } = useGlobal()
|
||||
const DISABLE_PLUGIN = siteConfig('DISABLE_PLUGIN', null, NOTION_CONFIG)
|
||||
const THEME_SWITCH = siteConfig('THEME_SWITCH', null, NOTION_CONFIG)
|
||||
const DEBUG = siteConfig('DEBUG', null, NOTION_CONFIG)
|
||||
@@ -172,7 +171,7 @@ const ExternalPlugin = props => {
|
||||
|
||||
setTimeout(() => {
|
||||
// 映射url
|
||||
convertInnerUrl({ allPages:props?.allNavPages, lang:lang })
|
||||
convertInnerUrl({ allPages: props?.allNavPages, lang: lang })
|
||||
}, 500)
|
||||
}, [router])
|
||||
|
||||
@@ -474,7 +473,7 @@ const DifyChatbot = dynamic(() => import('@/components/DifyChatbot'), {
|
||||
})
|
||||
const Analytics = dynamic(
|
||||
() =>
|
||||
import('@vercel/analytics/react').then(async m => {
|
||||
import('@vercel/analytics/react').then(m => {
|
||||
return m.Analytics
|
||||
}),
|
||||
{ ssr: false }
|
||||
|
||||
@@ -16,7 +16,7 @@ const Fireworks = () => {
|
||||
|
||||
useEffect(() => {
|
||||
// 异步加载
|
||||
async function loadFireworks() {
|
||||
function loadFireworks() {
|
||||
loadExternalResource(
|
||||
'https://cdnjs.snrat.com/ajax/libs/animejs/3.2.1/anime.min.js',
|
||||
'js'
|
||||
|
||||
@@ -60,7 +60,7 @@ function getNodesWithAdsByGoogleClass(node) {
|
||||
* 初始化谷歌广告
|
||||
* @returns
|
||||
*/
|
||||
export const initGoogleAdsense = async ADSENSE_GOOGLE_ID => {
|
||||
export const initGoogleAdsense = ADSENSE_GOOGLE_ID => {
|
||||
console.log('Load Adsense')
|
||||
loadExternalResource(
|
||||
`https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${ADSENSE_GOOGLE_ID}`,
|
||||
|
||||
@@ -12,7 +12,9 @@ const Lenis = () => {
|
||||
useEffect(() => {
|
||||
// 异步加载
|
||||
async function loadLenis() {
|
||||
loadExternalResource('/js/lenis.js', 'js').then(() => {
|
||||
try {
|
||||
await loadExternalResource('/js/lenis.js', 'js')
|
||||
|
||||
// console.log('Lenis', window.Lenis)
|
||||
if (!window.Lenis) {
|
||||
console.error('Lenis not loaded')
|
||||
@@ -23,14 +25,14 @@ const Lenis = () => {
|
||||
// 创建 Lenis 实例
|
||||
const lenis = new Lenis({
|
||||
duration: 1.2,
|
||||
easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)), // https://www.desmos.com/calculator/brs54l4xou
|
||||
easing: t => Math.min(1, 1.001 - Math.pow(2, -10 * t)), // https://www.desmos.com/calculator/brs54l4xou
|
||||
direction: 'vertical', // vertical, horizontal
|
||||
gestureDirection: 'vertical', // vertical, horizontal, both
|
||||
smooth: true,
|
||||
mouseMultiplier: 1,
|
||||
smoothTouch: false,
|
||||
touchMultiplier: 2,
|
||||
infinite: false,
|
||||
infinite: false
|
||||
})
|
||||
|
||||
// 存储实例到 ref
|
||||
@@ -48,7 +50,9 @@ const Lenis = () => {
|
||||
}
|
||||
|
||||
requestAnimationFrame(raf)
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Failed to load Lenis:', error)
|
||||
}
|
||||
}
|
||||
|
||||
loadLenis()
|
||||
|
||||
@@ -228,7 +228,7 @@ function getMediumZoomMargin() {
|
||||
// 代码
|
||||
const Code = dynamic(
|
||||
() =>
|
||||
import('react-notion-x/build/third-party/code').then(async m => {
|
||||
import('react-notion-x/build/third-party/code').then(m => {
|
||||
return m.Code
|
||||
}),
|
||||
{ ssr: false }
|
||||
|
||||
@@ -160,8 +160,8 @@ const renderCollapseCode = (codeCollapse, codeCollapseExpandDefault) => {
|
||||
/**
|
||||
* 将mermaid语言 渲染成图片
|
||||
*/
|
||||
const renderMermaid = async(mermaidCDN) => {
|
||||
const observer = new MutationObserver(async mutationsList => {
|
||||
const renderMermaid = mermaidCDN => {
|
||||
const observer = new MutationObserver(mutationsList => {
|
||||
for (const m of mutationsList) {
|
||||
if (m.target.className === 'notion-code language-mermaid') {
|
||||
const chart = m.target.querySelector('code').textContent
|
||||
|
||||
@@ -4,21 +4,19 @@ import React from 'react'
|
||||
* 下拉单选框
|
||||
*/
|
||||
class Select extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.handleChange = this.handleChange.bind(this)
|
||||
}
|
||||
|
||||
handleChange (event) {
|
||||
handleChange = event => {
|
||||
const { onChange } = this.props
|
||||
onChange(event.target.value)
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
return (
|
||||
<div className='py-1 space-x-3'>
|
||||
<label className='text-gray-500'>{this.props.label}</label>
|
||||
<select value={this.props.value} onChange={this.handleChange} className='border p-1 rounded cursor-pointer'>
|
||||
<select
|
||||
value={this.props.value}
|
||||
onChange={this.handleChange}
|
||||
className='border p-1 rounded cursor-pointer'>
|
||||
{this.props.options?.map(o => (
|
||||
<option key={o.value} value={o.value}>
|
||||
{o.text}
|
||||
|
||||
24
lib/cache/local_file_cache.js
vendored
24
lib/cache/local_file_cache.js
vendored
@@ -6,10 +6,10 @@ const cacheInvalidSeconds = 1000000000 * 1000
|
||||
// 文件名
|
||||
const jsonFile = path.resolve('./data.json')
|
||||
|
||||
export async function getCache (key) {
|
||||
const exist = await fs.existsSync(jsonFile)
|
||||
export function getCache(key) {
|
||||
const exist = fs.existsSync(jsonFile)
|
||||
if (!exist) return null
|
||||
const data = await fs.readFileSync(jsonFile)
|
||||
const data = fs.readFileSync(jsonFile)
|
||||
let json = null
|
||||
if (!data) return null
|
||||
try {
|
||||
@@ -19,7 +19,9 @@ export async function getCache (key) {
|
||||
return null
|
||||
}
|
||||
// 缓存超过有效期就作废
|
||||
const cacheValidTime = new Date(parseInt(json[key + '_expire_time']) + cacheInvalidSeconds)
|
||||
const cacheValidTime = new Date(
|
||||
parseInt(json[key + '_expire_time']) + cacheInvalidSeconds
|
||||
)
|
||||
const currentTime = new Date()
|
||||
if (!cacheValidTime || cacheValidTime < currentTime) {
|
||||
return null
|
||||
@@ -33,17 +35,17 @@ export async function getCache (key) {
|
||||
* @param data
|
||||
* @returns {Promise<null>}
|
||||
*/
|
||||
export async function setCache (key, data) {
|
||||
const exist = await fs.existsSync(jsonFile)
|
||||
const json = exist ? JSON.parse(await fs.readFileSync(jsonFile)) : {}
|
||||
export function setCache(key, data) {
|
||||
const exist = fs.existsSync(jsonFile)
|
||||
const json = exist ? JSON.parse(fs.readFileSync(jsonFile)) : {}
|
||||
json[key] = data
|
||||
json[key + '_expire_time'] = new Date().getTime()
|
||||
fs.writeFileSync(jsonFile, JSON.stringify(json))
|
||||
}
|
||||
|
||||
export async function delCache (key) {
|
||||
const exist = await fs.existsSync(jsonFile)
|
||||
const json = exist ? JSON.parse(await fs.readFileSync(jsonFile)) : {}
|
||||
export function delCache(key) {
|
||||
const exist = fs.existsSync(jsonFile)
|
||||
const json = exist ? JSON.parse(fs.readFileSync(jsonFile)) : {}
|
||||
delete json.key
|
||||
json[key + '_expire_time'] = new Date().getTime()
|
||||
fs.writeFileSync(jsonFile, JSON.stringify(json))
|
||||
@@ -52,7 +54,7 @@ export async function delCache (key) {
|
||||
/**
|
||||
* 清理缓存
|
||||
*/
|
||||
export async function cleanCache() {
|
||||
export function cleanCache() {
|
||||
const json = {}
|
||||
fs.writeFileSync(jsonFile, JSON.stringify(json))
|
||||
}
|
||||
|
||||
6
lib/cache/redis_cache.js
vendored
6
lib/cache/redis_cache.js
vendored
@@ -13,7 +13,7 @@ export async function getCache(key) {
|
||||
const data = await redisClient.get(key)
|
||||
return data ? JSON.parse(data) : null
|
||||
} catch (e) {
|
||||
console.error('redisClient读取失败 ' + e)
|
||||
console.error(`redisClient读取失败 ${String(e)}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ export async function setCache(key, data, customCacheTime) {
|
||||
customCacheTime || cacheTime
|
||||
)
|
||||
} catch (e) {
|
||||
console.error('redisClient写入失败 ' + e)
|
||||
console.error(`redisClient写入失败 ${String(e)}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ export async function delCache(key) {
|
||||
try {
|
||||
await redisClient.del(key)
|
||||
} catch (e) {
|
||||
console.error('redisClient删除失败 ' + e)
|
||||
console.error(`redisClient删除失败 ${String(e)}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -267,12 +267,13 @@ async function convertNotionToSiteDate(pageId, from, pageRecordMap) {
|
||||
categoryOptions: getCategoryOptions(schema)
|
||||
})
|
||||
// 所有标签
|
||||
const tagSchemaOptions = getTagOptions(schema)
|
||||
const tagOptions =
|
||||
getAllTags({
|
||||
allPages,
|
||||
tagOptions: getTagOptions(schema),
|
||||
allPages: allPages ?? [],
|
||||
tagOptions: tagSchemaOptions ?? [],
|
||||
NOTION_CONFIG
|
||||
}) || null
|
||||
}) ?? null
|
||||
// 旧的菜单
|
||||
const customNav = getCustomNav({
|
||||
allPages: collectionData.filter(
|
||||
@@ -280,7 +281,7 @@ async function convertNotionToSiteDate(pageId, from, pageRecordMap) {
|
||||
)
|
||||
})
|
||||
// 新的菜单
|
||||
const customMenu = await getCustomMenu({ collectionData, NOTION_CONFIG })
|
||||
const customMenu = getCustomMenu({ collectionData, NOTION_CONFIG })
|
||||
const latestPosts = getLatestPosts({ allPages, from, latestPostCount: 6 })
|
||||
const allNavPages = getNavPages({ allPages })
|
||||
|
||||
|
||||
@@ -40,7 +40,8 @@ export function GlobalContextProvider(props) {
|
||||
// 登录验证相关
|
||||
const enableClerk = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
|
||||
const { isLoaded, isSignedIn, user } = enableClerk
|
||||
? useUser()
|
||||
? /* eslint-disable-next-line react-hooks/rules-of-hooks */
|
||||
useUser()
|
||||
: { isLoaded: true, isSignedIn: false, user: false }
|
||||
|
||||
// 是否全屏
|
||||
@@ -99,9 +100,11 @@ export function GlobalContextProvider(props) {
|
||||
|
||||
useEffect(() => {
|
||||
const handleStart = url => {
|
||||
const { theme } = router.query
|
||||
if (theme && !url.includes(`theme=${theme}`)) {
|
||||
const newUrl = `${url}${url.includes('?') ? '&' : '?'}theme=${theme}`
|
||||
const themeValue = router.query.theme
|
||||
const themeStr = Array.isArray(themeValue) ? themeValue[0] : themeValue
|
||||
|
||||
if (themeStr && !url.includes(`theme=${themeStr}`)) {
|
||||
const newUrl = `${url}${url.includes('?') ? '&' : '?'}theme=${themeStr}`
|
||||
router.push(newUrl)
|
||||
}
|
||||
if (!onLoading) {
|
||||
|
||||
@@ -1,16 +1,29 @@
|
||||
const axios = require('axios')
|
||||
import axios from 'axios'
|
||||
|
||||
// 定义内容项的接口
|
||||
interface ContentItem {
|
||||
type: string
|
||||
content: string
|
||||
}
|
||||
|
||||
// 定义Notion块的接口
|
||||
interface NotionBlock {
|
||||
object: string
|
||||
type: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
// 发送 Notion API 请求
|
||||
async function postNotion(
|
||||
properties: any,
|
||||
properties: Record<string, unknown>,
|
||||
databaseId: string,
|
||||
listContentMain: any[],
|
||||
listContentMain: ContentItem[],
|
||||
token: string
|
||||
) {
|
||||
): Promise<{ status: number; data: Record<string, unknown> }> {
|
||||
const url = 'https://api.notion.com/v1/pages'
|
||||
|
||||
const children = listContentMain
|
||||
.map(contentMain => {
|
||||
.map((contentMain: ContentItem): NotionBlock | null => {
|
||||
if (contentMain.type === 'paragraph') {
|
||||
return {
|
||||
object: 'block',
|
||||
@@ -51,14 +64,21 @@ async function postNotion(
|
||||
try {
|
||||
const response = await axios.post(url, payload, { headers })
|
||||
return response
|
||||
} catch (error: any) {
|
||||
} catch (error) {
|
||||
console.error('写入Notion异常', error)
|
||||
throw new Error(`Error posting to Notion: ${error.message}`)
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
throw new Error(`Error posting to Notion: ${errorMessage}`)
|
||||
}
|
||||
}
|
||||
|
||||
// 定义响应结果的接口
|
||||
interface NotionResponse {
|
||||
status: number
|
||||
data: Record<string, unknown>
|
||||
}
|
||||
|
||||
// 处理响应结果
|
||||
function responseResult(response: { status: number; data: any }) {
|
||||
function responseResult(response: NotionResponse): void {
|
||||
if (response.status === 200) {
|
||||
console.log('成功...')
|
||||
console.log(response.data)
|
||||
@@ -68,15 +88,25 @@ function responseResult(response: { status: number; data: any }) {
|
||||
}
|
||||
}
|
||||
|
||||
// 定义用户属性的接口
|
||||
interface UserProperties {
|
||||
id: string
|
||||
avatar: string
|
||||
name: string
|
||||
mail: string
|
||||
lastLoginTime: string
|
||||
token: string
|
||||
}
|
||||
|
||||
// 准备属性字段
|
||||
function notionProperty(
|
||||
id: any,
|
||||
avatar: any,
|
||||
name: any,
|
||||
mail: any,
|
||||
lastLoginTime: any,
|
||||
token: any
|
||||
) {
|
||||
id: string,
|
||||
avatar: string,
|
||||
name: string,
|
||||
mail: string,
|
||||
lastLoginTime: string,
|
||||
token: string
|
||||
): Record<string, unknown> {
|
||||
return {
|
||||
id: {
|
||||
rich_text: [
|
||||
|
||||
@@ -6,7 +6,7 @@ import algoliasearch from 'algoliasearch'
|
||||
* 生成全文索引
|
||||
* @param {*} allPages
|
||||
*/
|
||||
const generateAlgoliaSearch = async ({ allPages, force = false }) => {
|
||||
const generateAlgoliaSearch = ({ allPages, force = false }) => {
|
||||
allPages?.forEach(p => {
|
||||
// 判断这篇文章是否需要重新创建索引
|
||||
if (p && !p.password) {
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
import BLOG from '@/blog.config'
|
||||
|
||||
/**
|
||||
* 订阅邮件-服务端接口
|
||||
* @param {*} email
|
||||
* @returns
|
||||
*/
|
||||
export default function subscribeToMailchimpApi({ email, first_name = '', last_name = '' }) {
|
||||
* 订阅邮件-服务端接口
|
||||
* @param {*} email
|
||||
* @returns
|
||||
*/
|
||||
export default function subscribeToMailchimpApi({
|
||||
email,
|
||||
first_name = '',
|
||||
last_name = ''
|
||||
}) {
|
||||
const listId = BLOG.MAILCHIMP_LIST_ID // 替换为你的邮件列表 ID
|
||||
const apiKey = BLOG.MAILCHIMP_API_KEY // 替换为你的 API KEY
|
||||
if (!email || !listId || !apiKey) {
|
||||
return {}
|
||||
return Promise.resolve({})
|
||||
}
|
||||
const data = {
|
||||
email_address: email,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import fs from 'fs'
|
||||
|
||||
export async function generateRobotsTxt(props) {
|
||||
export function generateRobotsTxt(props) {
|
||||
const { siteInfo } = props
|
||||
const LINK = siteInfo?.link
|
||||
const content = `
|
||||
|
||||
@@ -5,7 +5,7 @@ import { siteConfig } from './config'
|
||||
* 生成站点地图
|
||||
* @param {*} param0
|
||||
*/
|
||||
export async function generateSitemapXml({ allPages, NOTION_CONFIG }) {
|
||||
export function generateSitemapXml({ allPages, NOTION_CONFIG }) {
|
||||
let link = siteConfig('LINK', BLOG.LINK, NOTION_CONFIG)
|
||||
// 确保链接不以斜杠结尾
|
||||
if (link && link.endsWith('/')) {
|
||||
|
||||
@@ -64,7 +64,7 @@ const noAuthMiddleware = async (req: NextRequest, ev: any) => {
|
||||
* 鉴权中间件
|
||||
*/
|
||||
const authMiddleware = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
|
||||
? clerkMiddleware(async (auth, req) => {
|
||||
? clerkMiddleware((auth, req) => {
|
||||
const { userId } = auth()
|
||||
// 处理 /dashboard 路由的登录保护
|
||||
if (isTenantRoute(req)) {
|
||||
|
||||
@@ -117,7 +117,7 @@ const nextConfig = {
|
||||
// 默认将feed重定向至 /public/rss/feed.xml
|
||||
redirects: process.env.EXPORT
|
||||
? undefined
|
||||
: async () => {
|
||||
: () => {
|
||||
return [
|
||||
{
|
||||
source: '/feed',
|
||||
@@ -129,7 +129,7 @@ const nextConfig = {
|
||||
// 重写url
|
||||
rewrites: process.env.EXPORT
|
||||
? undefined
|
||||
: async () => {
|
||||
: () => {
|
||||
// 处理多语言重定向
|
||||
const langsRewrites = []
|
||||
if (BLOG.NOTION_PAGE_ID.indexOf(',') > 0) {
|
||||
@@ -176,7 +176,7 @@ const nextConfig = {
|
||||
},
|
||||
headers: process.env.EXPORT
|
||||
? undefined
|
||||
: async () => {
|
||||
: () => {
|
||||
return [
|
||||
{
|
||||
source: '/:path*{/}?',
|
||||
@@ -217,7 +217,7 @@ const nextConfig = {
|
||||
experimental: {
|
||||
scrollRestoration: true
|
||||
},
|
||||
exportPathMap: async function (
|
||||
exportPathMap: function (
|
||||
defaultPathMap,
|
||||
{ dev, dir, outDir, distDir, buildId }
|
||||
) {
|
||||
|
||||
@@ -62,7 +62,10 @@ export default async function handler(
|
||||
}
|
||||
|
||||
// 这里将用户数据写入到Notion数据库
|
||||
res.redirect(302, `/auth/result?${new URLSearchParams(redirectQuery)}`)
|
||||
res.redirect(
|
||||
302,
|
||||
`/auth/result?${new URLSearchParams(redirectQuery).toString()}`
|
||||
)
|
||||
} else {
|
||||
const redirectQuery = { msg: params?.statusText || '请求异常' }
|
||||
res.redirect(
|
||||
|
||||
@@ -71,7 +71,7 @@ export async function getStaticProps({ locale }) {
|
||||
}
|
||||
}
|
||||
|
||||
export const getStaticPaths = async () => {
|
||||
export const getStaticPaths = () => {
|
||||
return {
|
||||
paths: [
|
||||
{ params: { index: [] } }, // 对应首页路径
|
||||
|
||||
@@ -51,7 +51,7 @@ export async function getStaticProps({ params: { keyword }, locale }) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
export function getStaticPaths() {
|
||||
return {
|
||||
paths: [{ params: { keyword: 'NotionNext' } }],
|
||||
fallback: true
|
||||
@@ -128,7 +128,7 @@ async function filterByMemCache(allPosts, keyword) {
|
||||
// console.log('全文搜索缓存', cacheKey, page != null)
|
||||
post.results = []
|
||||
let hitCount = 0
|
||||
for (const i in indexContent) {
|
||||
for (const i of indexContent) {
|
||||
const c = indexContent[i]
|
||||
if (!c) {
|
||||
continue
|
||||
|
||||
@@ -50,7 +50,7 @@ export async function getStaticProps({ params: { keyword, page }, locale }) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
export function getStaticPaths() {
|
||||
return {
|
||||
paths: [{ params: { keyword: 'NotionNext', page: '1' } }],
|
||||
fallback: true
|
||||
@@ -135,7 +135,7 @@ async function filterByMemCache(allPosts, keyword) {
|
||||
// console.log('全文搜索缓存', cacheKey, page != null)
|
||||
post.results = []
|
||||
let hitCount = 0
|
||||
for (const i in indexContent) {
|
||||
for (const i of indexContent) {
|
||||
const c = indexContent[i]
|
||||
if (!c) {
|
||||
continue
|
||||
|
||||
@@ -37,7 +37,7 @@ export async function getStaticProps(req) {
|
||||
* catch-all route for clerk
|
||||
* @returns
|
||||
*/
|
||||
export async function getStaticPaths() {
|
||||
export function getStaticPaths() {
|
||||
return {
|
||||
paths: [
|
||||
{ params: { index: [] } }, // 使 /sign-in 路径可访问
|
||||
|
||||
@@ -36,7 +36,7 @@ export async function getStaticProps(req) {
|
||||
* catch-all route for clerk
|
||||
* @returns
|
||||
*/
|
||||
export async function getStaticPaths() {
|
||||
export function getStaticPaths() {
|
||||
return {
|
||||
paths: [
|
||||
{ params: { index: [] } }, // 使 /sign-up 路径可访问
|
||||
|
||||
@@ -7,10 +7,12 @@ import Link from 'next/link'
|
||||
* @returns
|
||||
*/
|
||||
export default function ArticleAround({ prev, next }) {
|
||||
const { locale } = useGlobal()
|
||||
|
||||
if (!prev || !next) {
|
||||
return <></>
|
||||
}
|
||||
const { locale } = useGlobal()
|
||||
|
||||
return (
|
||||
<section className='text-gray-800 dark:text-gray-400 flex items-center justify-between gap-x-3 my-4'>
|
||||
<Link
|
||||
|
||||
@@ -256,26 +256,24 @@ const LayoutIndex = props => {
|
||||
setHasRedirected(true) // 更新状态,防止多次执行
|
||||
|
||||
// 重定向到指定文章
|
||||
router.push(index).then(() => {
|
||||
setTimeout(() => {
|
||||
const article = document.querySelector(
|
||||
'#article-wrapper #notion-article'
|
||||
)
|
||||
if (!article) {
|
||||
console.log(
|
||||
'请检查您的Notion数据库中是否包含此slug页面: ',
|
||||
index
|
||||
)
|
||||
await router.push(index)
|
||||
|
||||
// 显示错误信息
|
||||
const containerInner = document.querySelector(
|
||||
'#theme-gitbook #container-inner'
|
||||
)
|
||||
const newHTML = `<h1 class="text-3xl pt-12 dark:text-gray-300">配置有误</h1><blockquote class="notion-quote notion-block-ce76391f3f2842d386468ff1eb705b92"><div>请在您的notion中添加一个slug为${index}的文章</div></blockquote>`
|
||||
containerInner?.insertAdjacentHTML('afterbegin', newHTML)
|
||||
}
|
||||
}, 2000)
|
||||
})
|
||||
// 使用setTimeout检查页面加载情况
|
||||
setTimeout(() => {
|
||||
const article = document.querySelector(
|
||||
'#article-wrapper #notion-article'
|
||||
)
|
||||
if (!article) {
|
||||
console.log('请检查您的Notion数据库中是否包含此slug页面: ', index)
|
||||
|
||||
// 显示错误信息
|
||||
const containerInner = document.querySelector(
|
||||
'#theme-gitbook #container-inner'
|
||||
)
|
||||
const newHTML = `<h1 class="text-3xl pt-12 dark:text-gray-300">配置有误</h1><blockquote class="notion-quote notion-block-ce76391f3f2842d386468ff1eb705b92"><div>请在您的notion中添加一个slug为${index}的文章</div></blockquote>`
|
||||
containerInner?.insertAdjacentHTML('afterbegin', newHTML)
|
||||
}
|
||||
}, 2000)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,21 +318,18 @@ const LayoutSlug = props => {
|
||||
useEffect(() => {
|
||||
// 404
|
||||
if (!post) {
|
||||
setTimeout(
|
||||
() => {
|
||||
if (isBrowser) {
|
||||
const article = document.querySelector(
|
||||
'#article-wrapper #notion-article'
|
||||
)
|
||||
if (!article) {
|
||||
router.push('/404').then(() => {
|
||||
console.warn('找不到页面', router.asPath)
|
||||
})
|
||||
}
|
||||
setTimeout(() => {
|
||||
if (isBrowser) {
|
||||
const article = document.querySelector(
|
||||
'#article-wrapper #notion-article'
|
||||
)
|
||||
if (!article) {
|
||||
router.push('/404').then(() => {
|
||||
console.warn('找不到页面', router.asPath)
|
||||
})
|
||||
}
|
||||
},
|
||||
waiting404
|
||||
)
|
||||
}
|
||||
}, waiting404)
|
||||
}
|
||||
}, [post])
|
||||
return (
|
||||
@@ -451,16 +446,21 @@ const Layout404 = props => {
|
||||
}, 3000)
|
||||
}, [])
|
||||
|
||||
return <>
|
||||
<div className='md:-mt-20 text-black w-full h-screen text-center justify-center content-center items-center flex flex-col'>
|
||||
<div className='dark:text-gray-200'>
|
||||
<h2 className='inline-block border-r-2 border-gray-600 mr-2 px-3 py-2 align-top'><i className='mr-2 fas fa-spinner animate-spin' />404</h2>
|
||||
<div className='inline-block text-left h-32 leading-10 items-center'>
|
||||
<h2 className='m-0 p-0'>{locale.NAV.PAGE_NOT_FOUND_REDIRECT}</h2>
|
||||
</div>
|
||||
</div>
|
||||
return (
|
||||
<>
|
||||
<div className='md:-mt-20 text-black w-full h-screen text-center justify-center content-center items-center flex flex-col'>
|
||||
<div className='dark:text-gray-200'>
|
||||
<h2 className='inline-block border-r-2 border-gray-600 mr-2 px-3 py-2 align-top'>
|
||||
<i className='mr-2 fas fa-spinner animate-spin' />
|
||||
404
|
||||
</h2>
|
||||
<div className='inline-block text-left h-32 leading-10 items-center'>
|
||||
<h2 className='m-0 p-0'>{locale.NAV.PAGE_NOT_FOUND_REDIRECT}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -609,18 +609,17 @@ const LayoutDashboard = props => {
|
||||
}
|
||||
|
||||
export {
|
||||
Layout404,
|
||||
LayoutArchive,
|
||||
LayoutBase,
|
||||
LayoutCategoryIndex,
|
||||
LayoutDashboard,
|
||||
LayoutIndex,
|
||||
LayoutPostList,
|
||||
LayoutSearch,
|
||||
LayoutSignIn,
|
||||
LayoutSignUp,
|
||||
LayoutSlug,
|
||||
LayoutTagIndex,
|
||||
CONFIG as THEME_CONFIG
|
||||
Layout404,
|
||||
LayoutArchive,
|
||||
LayoutBase,
|
||||
LayoutCategoryIndex,
|
||||
LayoutDashboard,
|
||||
LayoutIndex,
|
||||
LayoutPostList,
|
||||
LayoutSearch,
|
||||
LayoutSignIn,
|
||||
LayoutSignUp,
|
||||
LayoutSlug,
|
||||
LayoutTagIndex,
|
||||
CONFIG as THEME_CONFIG
|
||||
}
|
||||
|
||||
|
||||
@@ -12,22 +12,24 @@ export const ArticleFooter = props => {
|
||||
const router = useRouter()
|
||||
const { locale } = useGlobal()
|
||||
|
||||
return <div className="flex justify-between font-medium text-gray-500 dark:text-gray-400">
|
||||
<a>
|
||||
<button
|
||||
onClick={() => router.push('/')}
|
||||
className="mt-2 cursor-pointer hover:text-black dark:hover:text-gray-100"
|
||||
>
|
||||
← {locale.POST.BACK}
|
||||
</button>
|
||||
</a>
|
||||
<a>
|
||||
<button
|
||||
onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })}
|
||||
className="mt-2 cursor-pointer hover:text-black dark:hover:text-gray-100"
|
||||
>
|
||||
↑ {locale.POST.TOP}
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
return (
|
||||
<div className='flex justify-between font-medium text-gray-500 dark:text-gray-400'>
|
||||
<a>
|
||||
<button
|
||||
onClick={() => {
|
||||
void router.push('/')
|
||||
}}
|
||||
className='mt-2 cursor-pointer hover:text-black dark:hover:text-gray-100'>
|
||||
← {locale.POST.BACK}
|
||||
</button>
|
||||
</a>
|
||||
<a>
|
||||
<button
|
||||
onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })}
|
||||
className='mt-2 cursor-pointer hover:text-black dark:hover:text-gray-100'>
|
||||
↑ {locale.POST.TOP}
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -13,22 +13,24 @@ export const ArticleFooter = props => {
|
||||
const router = useRouter()
|
||||
const { locale } = useGlobal()
|
||||
|
||||
return <div className="flex justify-between font-medium text-gray-500 dark:text-gray-400">
|
||||
<a>
|
||||
<button
|
||||
onClick={() => router.push(siteConfig('path') || '/')}
|
||||
className="mt-2 cursor-pointer hover:text-black dark:hover:text-gray-100"
|
||||
>
|
||||
← {locale.POST.BACK}
|
||||
</button>
|
||||
</a>
|
||||
<a>
|
||||
<button
|
||||
onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })}
|
||||
className="mt-2 cursor-pointer hover:text-black dark:hover:text-gray-100"
|
||||
>
|
||||
↑ {locale.POST.TOP}
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
return (
|
||||
<div className='flex justify-between font-medium text-gray-500 dark:text-gray-400'>
|
||||
<a>
|
||||
<button
|
||||
onClick={() => {
|
||||
void router.push(siteConfig('path') || '/')
|
||||
}}
|
||||
className='mt-2 cursor-pointer hover:text-black dark:hover:text-gray-100'>
|
||||
← {locale.POST.BACK}
|
||||
</button>
|
||||
</a>
|
||||
<a>
|
||||
<button
|
||||
onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })}
|
||||
className='mt-2 cursor-pointer hover:text-black dark:hover:text-gray-100'>
|
||||
↑ {locale.POST.TOP}
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -51,10 +51,6 @@ export const MenuList = props => {
|
||||
links = customMenu
|
||||
}
|
||||
|
||||
if (!links || links.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
const toggleMenu = () => {
|
||||
setShowMenu(!showMenu) // 切换菜单状态
|
||||
}
|
||||
@@ -63,6 +59,10 @@ export const MenuList = props => {
|
||||
setShowMenu(false)
|
||||
}, [router])
|
||||
|
||||
if (!links || links.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* 移动端菜单切换按钮 */}
|
||||
|
||||
@@ -51,10 +51,6 @@ export const MenuList = props => {
|
||||
links = customMenu
|
||||
}
|
||||
|
||||
if (!links || links.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
const toggleMenu = () => {
|
||||
setShowMenu(!showMenu) // 切换菜单状态
|
||||
}
|
||||
@@ -63,6 +59,10 @@ export const MenuList = props => {
|
||||
setShowMenu(false)
|
||||
}, [router])
|
||||
|
||||
if (!links || links.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* 移动端菜单切换按钮 */}
|
||||
|
||||
@@ -79,17 +79,17 @@ export const getBaseLayoutByTheme = theme => {
|
||||
*/
|
||||
export const DynamicLayout = props => {
|
||||
const { theme, layoutName } = props
|
||||
const SelectedLayout = getLayoutByTheme({ layoutName, theme })
|
||||
const SelectedLayout = useLayoutByTheme({ layoutName, theme })
|
||||
return <SelectedLayout {...props} />
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载主题文件
|
||||
* @param {*} router
|
||||
* @param {*} layoutName
|
||||
* @param {*} theme
|
||||
* @returns
|
||||
*/
|
||||
export const getLayoutByTheme = ({ layoutName, theme }) => {
|
||||
export const useLayoutByTheme = ({ layoutName, theme }) => {
|
||||
// const layoutName = getLayoutNameByPath(router.pathname, router.asPath)
|
||||
const LayoutComponents =
|
||||
ThemeComponents[layoutName] || ThemeComponents.LayoutSlug
|
||||
|
||||
Reference in New Issue
Block a user