mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-06-01 15:10:14 +00:00
Merge branch 'main' of https://github.com/tangly1024/NotionNext
This commit is contained in:
@@ -173,3 +173,4 @@
|
|||||||
# ENABLE_CACHE=
|
# ENABLE_CACHE=
|
||||||
# VERCEL_ENV=
|
# VERCEL_ENV=
|
||||||
# NEXT_PUBLIC_VERSION=
|
# NEXT_PUBLIC_VERSION=
|
||||||
|
# NEXT_BUILD_STANDALONE=
|
||||||
|
|||||||
31
Dockerfile
31
Dockerfile
@@ -1,23 +1,42 @@
|
|||||||
ARG NOTION_PAGE_ID
|
ARG NOTION_PAGE_ID
|
||||||
ARG NEXT_PUBLIC_THEME
|
ARG NEXT_PUBLIC_THEME
|
||||||
|
|
||||||
# Install dependencies only when needed
|
FROM node:18-alpine3.18 AS base
|
||||||
FROM node:18-alpine3.18 AS deps
|
|
||||||
|
# 1. Install dependencies only when needed
|
||||||
|
FROM base AS deps
|
||||||
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
||||||
RUN apk add --no-cache libc6-compat
|
RUN apk add --no-cache libc6-compat
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY package.json ./
|
COPY package.json ./
|
||||||
RUN yarn install --frozen-lockfile
|
RUN yarn install --frozen-lockfile
|
||||||
|
|
||||||
# Rebuild the source code only when needed
|
# 2. Rebuild the source code only when needed
|
||||||
FROM node:18-alpine3.18 AS builder
|
FROM base AS builder
|
||||||
ARG NOTION_PAGE_ID
|
ARG NOTION_PAGE_ID
|
||||||
|
ENV NEXT_BUILD_STANDALONE=true
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY --from=deps /app/node_modules ./node_modules
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN yarn build
|
RUN yarn build
|
||||||
|
|
||||||
ENV NODE_ENV production
|
# 3. Production image, copy all the files and run next
|
||||||
|
FROM base AS runner
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY --from=builder /app/public ./public
|
||||||
|
|
||||||
|
# Automatically leverage output traces to reduce image size
|
||||||
|
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||||
|
COPY --from=builder /app/.next/standalone ./
|
||||||
|
COPY --from=builder /app/.next/static ./.next/static
|
||||||
|
|
||||||
|
# 个人仓库把将配置好的.env.local文件放到项目根目录,可自动使用环境变量
|
||||||
|
# COPY --from=builder /app/.env.local ./
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
@@ -26,4 +45,4 @@ EXPOSE 3000
|
|||||||
# Uncomment the following line in case you want to disable telemetry.
|
# Uncomment the following line in case you want to disable telemetry.
|
||||||
# ENV NEXT_TELEMETRY_DISABLED 1
|
# ENV NEXT_TELEMETRY_DISABLED 1
|
||||||
|
|
||||||
CMD ["yarn", "start"]
|
CMD ["node", "server.js"]
|
||||||
@@ -8,6 +8,7 @@ import { GlobalStyle } from './GlobalStyle'
|
|||||||
import { initGoogleAdsense } from './GoogleAdsense'
|
import { initGoogleAdsense } from './GoogleAdsense'
|
||||||
|
|
||||||
import Head from 'next/head'
|
import Head from 'next/head'
|
||||||
|
import ExternalScript from './ExternalScript'
|
||||||
import WebWhiz from './Webwhiz'
|
import WebWhiz from './Webwhiz'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -258,10 +259,10 @@ const ExternalPlugin = props => {
|
|||||||
{/* 提前连接到广告服务器 */}
|
{/* 提前连接到广告服务器 */}
|
||||||
<link rel='preconnect' href='https://cdn.wwads.cn' />
|
<link rel='preconnect' href='https://cdn.wwads.cn' />
|
||||||
</Head>
|
</Head>
|
||||||
<script
|
<ExternalScript
|
||||||
type='text/javascript'
|
type='text/javascript'
|
||||||
src='https://cdn.wwads.cn/js/makemoney.js'
|
src='https://cdn.wwads.cn/js/makemoney.js'
|
||||||
async></script>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { isBrowser } from '@/lib/utils'
|
|||||||
* 传入参数将转为 <script>标签。
|
* 传入参数将转为 <script>标签。
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const ExternalScript = (props) => {
|
const ExternalScript = props => {
|
||||||
const { src } = props
|
const { src } = props
|
||||||
if (!isBrowser || !src) {
|
if (!isBrowser || !src) {
|
||||||
return null
|
return null
|
||||||
@@ -22,7 +22,7 @@ const ExternalScript = (props) => {
|
|||||||
script.setAttribute(key, value)
|
script.setAttribute(key, value)
|
||||||
})
|
})
|
||||||
document.head.appendChild(script)
|
document.head.appendChild(script)
|
||||||
console.log('加载外部脚本', props, script)
|
// console.log('加载外部脚本', props, script)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,32 +57,35 @@ export default function LazyImage({
|
|||||||
} else {
|
} else {
|
||||||
imageRef.current.src = defaultPlaceholderSrc
|
imageRef.current.src = defaultPlaceholderSrc
|
||||||
}
|
}
|
||||||
imageRef.current.classList.remove('lazy-image-placeholder')
|
// 移除占位符类名
|
||||||
|
if (imageRef.current) {
|
||||||
|
imageRef.current.classList.remove('lazy-image-placeholder')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const adjustedImageSrc =
|
const adjustedImageSrc =
|
||||||
adjustImgSize(src, maxWidth) || defaultPlaceholderSrc
|
adjustImgSize(src, maxWidth) || defaultPlaceholderSrc
|
||||||
// 加载原图
|
|
||||||
const img = new Image()
|
|
||||||
img.src = adjustedImageSrc
|
|
||||||
img.onload = () => {
|
|
||||||
setCurrentSrc(adjustedImageSrc)
|
|
||||||
handleImageLoaded(adjustedImageSrc)
|
|
||||||
}
|
|
||||||
img.onerror = handleImageError
|
|
||||||
const observer = new IntersectionObserver(
|
const observer = new IntersectionObserver(
|
||||||
entries => {
|
entries => {
|
||||||
entries.forEach(entry => {
|
entries.forEach(entry => {
|
||||||
if (entry.isIntersecting) {
|
if (entry.isIntersecting) {
|
||||||
const lazyImage = entry.target
|
// 拉取图片
|
||||||
lazyImage.src = adjustedImageSrc
|
const img = new Image()
|
||||||
observer.unobserve(lazyImage)
|
img.src = adjustedImageSrc
|
||||||
|
img.onload = () => {
|
||||||
|
setCurrentSrc(adjustedImageSrc)
|
||||||
|
handleImageLoaded(adjustedImageSrc)
|
||||||
|
}
|
||||||
|
img.onerror = handleImageError
|
||||||
|
|
||||||
|
observer.unobserve(entry.target)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
{ rootMargin: '50px 0px' } // Adjust the rootMargin as needed to trigger the loading earlier or later
|
{ rootMargin: '50px 0px' } // 轻微提前加载
|
||||||
)
|
)
|
||||||
if (imageRef.current) {
|
if (imageRef.current) {
|
||||||
observer.observe(imageRef.current)
|
observer.observe(imageRef.current)
|
||||||
@@ -98,36 +101,19 @@ export default function LazyImage({
|
|||||||
const imgProps = {
|
const imgProps = {
|
||||||
ref: imageRef,
|
ref: imageRef,
|
||||||
src: currentSrc,
|
src: currentSrc,
|
||||||
'data-src': src,
|
'data-src': src, // 存储原始图片地址
|
||||||
alt: alt,
|
alt: alt || 'Lazy loaded image',
|
||||||
onLoad: handleThumbnailLoaded, // 缩略图加载完成
|
onLoad: handleThumbnailLoaded,
|
||||||
onError: handleImageError // 添加onError处理函数
|
onError: handleImageError,
|
||||||
|
className: `${className || ''} lazy-image-placeholder`,
|
||||||
|
style,
|
||||||
|
width: width || 'auto',
|
||||||
|
height: height || 'auto',
|
||||||
|
onClick
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id) {
|
if (id) imgProps.id = id
|
||||||
imgProps.id = id
|
if (title) imgProps.title = title
|
||||||
}
|
|
||||||
|
|
||||||
if (title) {
|
|
||||||
imgProps.title = title
|
|
||||||
}
|
|
||||||
|
|
||||||
if (width && width !== 'auto') {
|
|
||||||
imgProps.width = width
|
|
||||||
}
|
|
||||||
|
|
||||||
if (height && height !== 'auto') {
|
|
||||||
imgProps.height = height
|
|
||||||
}
|
|
||||||
if (className) {
|
|
||||||
imgProps.className = className + ' lazy-image-placeholder'
|
|
||||||
}
|
|
||||||
if (style) {
|
|
||||||
imgProps.style = style
|
|
||||||
}
|
|
||||||
if (onClick) {
|
|
||||||
imgProps.onClick = onClick
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!src) {
|
if (!src) {
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -14,8 +14,7 @@ export default function LoadingCover() {
|
|||||||
if (onLoading) {
|
if (onLoading) {
|
||||||
setIsVisible(true)
|
setIsVisible(true)
|
||||||
} else {
|
} else {
|
||||||
const timeout = setTimeout(() => setIsVisible(false), 1800) // 等待淡出动画结束
|
setIsVisible(false)
|
||||||
return () => clearTimeout(timeout)
|
|
||||||
}
|
}
|
||||||
}, [onLoading])
|
}, [onLoading])
|
||||||
|
|
||||||
|
|||||||
@@ -149,9 +149,11 @@ const processGalleryImg = zoom => {
|
|||||||
const autoScrollToHash = () => {
|
const autoScrollToHash = () => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// 跳转到指定标题
|
// 跳转到指定标题
|
||||||
const needToJumpToTitle = window.location.hash
|
const hash = window?.location?.hash
|
||||||
|
const needToJumpToTitle = hash && hash > 0
|
||||||
if (needToJumpToTitle) {
|
if (needToJumpToTitle) {
|
||||||
const tocNode = document.getElementById(window.location.hash.substring(1))
|
console.log('jump to hash', hash)
|
||||||
|
const tocNode = document.getElementById(hash.substring(1))
|
||||||
if (tocNode && tocNode?.className?.indexOf('notion') > -1) {
|
if (tocNode && tocNode?.className?.indexOf('notion') > -1) {
|
||||||
tocNode.scrollIntoView({ block: 'start', behavior: 'smooth' })
|
tocNode.scrollIntoView({ block: 'start', behavior: 'smooth' })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { siteConfig } from '@/lib/config'
|
|||||||
export default function PoweredBy(props) {
|
export default function PoweredBy(props) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`gap-x-1 flex flex-wrap text-sm font-serif ${props.className}`}>
|
className={`gap-x-1 flex flex-wrap text-sm font-serif ${props.className || ''}`}>
|
||||||
<span>Powered by</span>
|
<span>Powered by</span>
|
||||||
<a
|
<a
|
||||||
href='https://github.com/tangly1024/NotionNext'
|
href='https://github.com/tangly1024/NotionNext'
|
||||||
|
|||||||
@@ -18,6 +18,32 @@ const SEO = props => {
|
|||||||
let image
|
let image
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const meta = getSEOMeta(props, router, useGlobal()?.locale)
|
const meta = getSEOMeta(props, router, useGlobal()?.locale)
|
||||||
|
const webFontUrl = siteConfig('FONT_URL')
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// 使用WebFontLoader字体加载
|
||||||
|
loadExternalResource(
|
||||||
|
'https://cdnjs.cloudflare.com/ajax/libs/webfont/1.6.28/webfontloader.js',
|
||||||
|
'js'
|
||||||
|
).then(url => {
|
||||||
|
const WebFont = window?.WebFont
|
||||||
|
if (WebFont) {
|
||||||
|
// console.log('LoadWebFont', webFontUrl)
|
||||||
|
WebFont.load({
|
||||||
|
custom: {
|
||||||
|
// families: ['"LXGW WenKai"'],
|
||||||
|
urls: webFontUrl
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
// SEO关键词
|
||||||
|
let keywords = meta?.tags || siteConfig('KEYWORDS')
|
||||||
|
if (post?.tags && post?.tags?.length > 0) {
|
||||||
|
keywords = post?.tags?.join(',')
|
||||||
|
}
|
||||||
if (meta) {
|
if (meta) {
|
||||||
url = `${url}/${meta.slug}`
|
url = `${url}/${meta.slug}`
|
||||||
image = meta.image || '/bg_image.jpg'
|
image = meta.image || '/bg_image.jpg'
|
||||||
@@ -28,7 +54,6 @@ const SEO = props => {
|
|||||||
const lang = siteConfig('LANG').replace('-', '_') // Facebook OpenGraph 要 zh_CN 這樣的格式才抓得到語言
|
const lang = siteConfig('LANG').replace('-', '_') // Facebook OpenGraph 要 zh_CN 這樣的格式才抓得到語言
|
||||||
const category = meta?.category || siteConfig('KEYWORDS') // section 主要是像是 category 這樣的分類,Facebook 用這個來抓連結的分類
|
const category = meta?.category || siteConfig('KEYWORDS') // section 主要是像是 category 這樣的分類,Facebook 用這個來抓連結的分類
|
||||||
const favicon = siteConfig('BLOG_FAVICON')
|
const favicon = siteConfig('BLOG_FAVICON')
|
||||||
const webFontUrl = siteConfig('FONT_URL')
|
|
||||||
const BACKGROUND_DARK = siteConfig('BACKGROUND_DARK', '', NOTION_CONFIG)
|
const BACKGROUND_DARK = siteConfig('BACKGROUND_DARK', '', NOTION_CONFIG)
|
||||||
|
|
||||||
const SEO_BAIDU_SITE_VERIFICATION = siteConfig(
|
const SEO_BAIDU_SITE_VERIFICATION = siteConfig(
|
||||||
@@ -68,30 +93,6 @@ const SEO = props => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const FACEBOOK_PAGE = siteConfig('FACEBOOK_PAGE', null, NOTION_CONFIG)
|
const FACEBOOK_PAGE = siteConfig('FACEBOOK_PAGE', null, NOTION_CONFIG)
|
||||||
// SEO关键词
|
|
||||||
let keywords = meta?.tags || siteConfig('KEYWORDS')
|
|
||||||
if (post?.tags && post?.tags?.length > 0) {
|
|
||||||
keywords = post?.tags?.join(',')
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// 使用WebFontLoader字体加载
|
|
||||||
loadExternalResource(
|
|
||||||
'https://cdnjs.cloudflare.com/ajax/libs/webfont/1.6.28/webfontloader.js',
|
|
||||||
'js'
|
|
||||||
).then(url => {
|
|
||||||
const WebFont = window?.WebFont
|
|
||||||
if (WebFont) {
|
|
||||||
console.log('LoadWebFont', webFontUrl)
|
|
||||||
WebFont.load({
|
|
||||||
custom: {
|
|
||||||
// families: ['"LXGW WenKai"'],
|
|
||||||
urls: webFontUrl
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Head>
|
<Head>
|
||||||
|
|||||||
@@ -6,14 +6,23 @@ import { siteConfig } from '@/lib/config'
|
|||||||
* @param {boolean} sticky - 是否粘性定位
|
* @param {boolean} sticky - 是否粘性定位
|
||||||
* @returns {JSX.Element | null} - 返回渲染的 JSX 元素或 null
|
* @returns {JSX.Element | null} - 返回渲染的 JSX 元素或 null
|
||||||
*/
|
*/
|
||||||
export default function WWAds({ orientation = 'vertical', sticky = false, className }) {
|
export default function WWAds({
|
||||||
|
orientation = 'vertical',
|
||||||
|
sticky = false,
|
||||||
|
className
|
||||||
|
}) {
|
||||||
const AD_WWADS_ID = siteConfig('AD_WWADS_ID')
|
const AD_WWADS_ID = siteConfig('AD_WWADS_ID')
|
||||||
|
|
||||||
if (!AD_WWADS_ID) {
|
if (!AD_WWADS_ID) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div data-id={AD_WWADS_ID} className={`wwads-cn
|
return (
|
||||||
|
<div
|
||||||
|
data-id={AD_WWADS_ID}
|
||||||
|
className={`wwads-cn
|
||||||
${orientation === 'vertical' ? 'wwads-vertical' : 'wwads-horizontal'}
|
${orientation === 'vertical' ? 'wwads-vertical' : 'wwads-horizontal'}
|
||||||
${sticky ? 'wwads-sticky' : ''} z-10 ${className || ''}`} />
|
${sticky ? 'wwads-sticky' : ''} z-10 ${className || ''}`}
|
||||||
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,11 +169,11 @@ export function loadExternalResource(url, type = 'js') {
|
|||||||
}
|
}
|
||||||
if (tag) {
|
if (tag) {
|
||||||
tag.onload = () => {
|
tag.onload = () => {
|
||||||
console.log('Load Success', url)
|
// console.log('Load Success', url)
|
||||||
resolve(url)
|
resolve(url)
|
||||||
}
|
}
|
||||||
tag.onerror = () => {
|
tag.onerror = () => {
|
||||||
console.log('Load Error', url)
|
console.warn('Load Error', url)
|
||||||
reject(url)
|
reject(url)
|
||||||
}
|
}
|
||||||
document.head.appendChild(tag)
|
document.head.appendChild(tag)
|
||||||
@@ -204,6 +204,9 @@ export function getQueryVariable(key) {
|
|||||||
* @returns {string|null}
|
* @returns {string|null}
|
||||||
*/
|
*/
|
||||||
export function getQueryParam(url, param) {
|
export function getQueryParam(url, param) {
|
||||||
|
if (!url) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
// 移除哈希部分
|
// 移除哈希部分
|
||||||
const urlWithoutHash = url.split('#')[0]
|
const urlWithoutHash = url.split('#')[0]
|
||||||
const searchParams = new URLSearchParams(urlWithoutHash.split('?')[1])
|
const searchParams = new URLSearchParams(urlWithoutHash.split('?')[1])
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ const nextConfig = {
|
|||||||
eslint: {
|
eslint: {
|
||||||
ignoreDuringBuilds: true
|
ignoreDuringBuilds: true
|
||||||
},
|
},
|
||||||
output: process.env.EXPORT ? 'export' : undefined,
|
output: process.env.EXPORT ? 'export' : process.env.NEXT_BUILD_STANDALONE === 'true' ? 'standalone' : undefined,
|
||||||
staticPageGenerationTimeout: 120,
|
staticPageGenerationTimeout: 120,
|
||||||
// 多语言, 在export时禁用
|
// 多语言, 在export时禁用
|
||||||
i18n: process.env.EXPORT
|
i18n: process.env.EXPORT
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "notion-next",
|
"name": "notion-next",
|
||||||
"version": "4.7.10",
|
"version": "4.7.11",
|
||||||
"homepage": "https://github.com/tangly1024/NotionNext.git",
|
"homepage": "https://github.com/tangly1024/NotionNext.git",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import BLOG from '@/blog.config'
|
|||||||
import { siteConfig } from '@/lib/config'
|
import { siteConfig } from '@/lib/config'
|
||||||
import { getGlobalData } from '@/lib/db/getSiteData'
|
import { getGlobalData } from '@/lib/db/getSiteData'
|
||||||
import { DynamicLayout } from '@/themes/theme'
|
import { DynamicLayout } from '@/themes/theme'
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 404
|
* 404
|
||||||
@@ -10,9 +9,8 @@ import { useRouter } from 'next/router'
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const NoFound = props => {
|
const NoFound = props => {
|
||||||
const router = useRouter()
|
|
||||||
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
||||||
return <DynamicLayout theme={theme} router={router} {...props} />
|
return <DynamicLayout theme={theme} layoutName='Layout404' {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getStaticProps(req) {
|
export async function getStaticProps(req) {
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ const Slug = props => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* 文章布局 */}
|
{/* 文章布局 */}
|
||||||
<DynamicLayout theme={theme} router={router} {...props} />
|
<DynamicLayout theme={theme} layoutName='LayoutSlug' {...props} />
|
||||||
{/* 解锁密码提示框 */}
|
{/* 解锁密码提示框 */}
|
||||||
{post?.password && post?.password !== '' && !lock && <Notification />}
|
{post?.password && post?.password !== '' && !lock && <Notification />}
|
||||||
{/* 导流工具 */}
|
{/* 导流工具 */}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import 'react-notion-x/src/styles.css' // 原版的react-notion-x
|
|||||||
|
|
||||||
import useAdjustStyle from '@/hooks/useAdjustStyle'
|
import useAdjustStyle from '@/hooks/useAdjustStyle'
|
||||||
import { GlobalContextProvider } from '@/lib/global'
|
import { GlobalContextProvider } from '@/lib/global'
|
||||||
import { getGlobalLayoutByTheme } from '@/themes/theme'
|
import { getBaseLayoutByTheme } from '@/themes/theme'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useCallback, useMemo } from 'react'
|
import { useCallback, useMemo } from 'react'
|
||||||
import { getQueryParam } from '../lib/utils'
|
import { getQueryParam } from '../lib/utils'
|
||||||
@@ -34,7 +34,7 @@ const MyApp = ({ Component, pageProps }) => {
|
|||||||
useAdjustStyle()
|
useAdjustStyle()
|
||||||
|
|
||||||
const route = useRouter()
|
const route = useRouter()
|
||||||
const queryParam = useMemo(() => {
|
const theme = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
getQueryParam(route.asPath, 'theme') ||
|
getQueryParam(route.asPath, 'theme') ||
|
||||||
pageProps?.NOTION_CONFIG?.THEME ||
|
pageProps?.NOTION_CONFIG?.THEME ||
|
||||||
@@ -45,10 +45,10 @@ const MyApp = ({ Component, pageProps }) => {
|
|||||||
// 整体布局
|
// 整体布局
|
||||||
const GLayout = useCallback(
|
const GLayout = useCallback(
|
||||||
props => {
|
props => {
|
||||||
const Layout = getGlobalLayoutByTheme(queryParam)
|
const Layout = getBaseLayoutByTheme(theme)
|
||||||
return <Layout {...props} />
|
return <Layout {...props} />
|
||||||
},
|
},
|
||||||
[queryParam]
|
[theme]
|
||||||
)
|
)
|
||||||
|
|
||||||
const enableClerk = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
|
const enableClerk = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { getGlobalData } from '@/lib/db/getSiteData'
|
|||||||
import { isBrowser } from '@/lib/utils'
|
import { isBrowser } from '@/lib/utils'
|
||||||
import { formatDateFmt } from '@/lib/utils/formatDate'
|
import { formatDateFmt } from '@/lib/utils/formatDate'
|
||||||
import { DynamicLayout } from '@/themes/theme'
|
import { DynamicLayout } from '@/themes/theme'
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,9 +26,8 @@ const ArchiveIndex = props => {
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
||||||
return <DynamicLayout theme={theme} router={router} {...props} />
|
return <DynamicLayout theme={theme} layoutName='LayoutArchive' {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getStaticProps({ locale }) {
|
export async function getStaticProps({ locale }) {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import BLOG from '@/blog.config'
|
|||||||
import { siteConfig } from '@/lib/config'
|
import { siteConfig } from '@/lib/config'
|
||||||
import { getGlobalData } from '@/lib/db/getSiteData'
|
import { getGlobalData } from '@/lib/db/getSiteData'
|
||||||
import { DynamicLayout } from '@/themes/theme'
|
import { DynamicLayout } from '@/themes/theme'
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分类页
|
* 分类页
|
||||||
@@ -10,9 +9,8 @@ import { useRouter } from 'next/router'
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export default function Category(props) {
|
export default function Category(props) {
|
||||||
const router = useRouter()
|
|
||||||
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
||||||
return <DynamicLayout theme={theme} router={router} {...props} />
|
return <DynamicLayout theme={theme} layoutName='LayoutPostList' {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getStaticProps({ params: { category }, locale }) {
|
export async function getStaticProps({ params: { category }, locale }) {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import BLOG from '@/blog.config'
|
|||||||
import { siteConfig } from '@/lib/config'
|
import { siteConfig } from '@/lib/config'
|
||||||
import { getGlobalData } from '@/lib/db/getSiteData'
|
import { getGlobalData } from '@/lib/db/getSiteData'
|
||||||
import { DynamicLayout } from '@/themes/theme'
|
import { DynamicLayout } from '@/themes/theme'
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分类页
|
* 分类页
|
||||||
@@ -11,9 +10,8 @@ import { useRouter } from 'next/router'
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export default function Category(props) {
|
export default function Category(props) {
|
||||||
const router = useRouter()
|
|
||||||
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
||||||
return <DynamicLayout theme={theme} router={router} {...props} />
|
return <DynamicLayout theme={theme} layoutName='LayoutPostList' {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getStaticProps({ params: { category, page } }) {
|
export async function getStaticProps({ params: { category, page } }) {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import BLOG from '@/blog.config'
|
|||||||
import { siteConfig } from '@/lib/config'
|
import { siteConfig } from '@/lib/config'
|
||||||
import { getGlobalData } from '@/lib/db/getSiteData'
|
import { getGlobalData } from '@/lib/db/getSiteData'
|
||||||
import { DynamicLayout } from '@/themes/theme'
|
import { DynamicLayout } from '@/themes/theme'
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分类首页
|
* 分类首页
|
||||||
@@ -10,9 +9,8 @@ import { useRouter } from 'next/router'
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export default function Category(props) {
|
export default function Category(props) {
|
||||||
const router = useRouter()
|
|
||||||
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
||||||
return <DynamicLayout theme={theme} router={router} {...props} />
|
return <DynamicLayout theme={theme} layoutName='LayoutPostList' {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getStaticProps({ locale }) {
|
export async function getStaticProps({ locale }) {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import BLOG from '@/blog.config'
|
|||||||
import { siteConfig } from '@/lib/config'
|
import { siteConfig } from '@/lib/config'
|
||||||
import { getGlobalData, getPost, getPostBlocks } from '@/lib/db/getSiteData'
|
import { getGlobalData, getPost, getPostBlocks } from '@/lib/db/getSiteData'
|
||||||
import { DynamicLayout } from '@/themes/theme'
|
import { DynamicLayout } from '@/themes/theme'
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据notion的slug访问页面
|
* 根据notion的slug访问页面
|
||||||
@@ -11,9 +10,8 @@ import { useRouter } from 'next/router'
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const Dashboard = props => {
|
const Dashboard = props => {
|
||||||
const router = useRouter()
|
|
||||||
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
||||||
return <DynamicLayout theme={theme} router={router} {...props} />
|
return <DynamicLayout theme={theme} layoutName='LayoutDashboard' {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getStaticProps({ locale }) {
|
export async function getStaticProps({ locale }) {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { generateRobotsTxt } from '@/lib/robots.txt'
|
|||||||
import { generateRss } from '@/lib/rss'
|
import { generateRss } from '@/lib/rss'
|
||||||
import { generateSitemapXml } from '@/lib/sitemap.xml'
|
import { generateSitemapXml } from '@/lib/sitemap.xml'
|
||||||
import { DynamicLayout } from '@/themes/theme'
|
import { DynamicLayout } from '@/themes/theme'
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 首页布局
|
* 首页布局
|
||||||
@@ -13,9 +12,8 @@ import { useRouter } from 'next/router'
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const Index = props => {
|
const Index = props => {
|
||||||
const router = useRouter()
|
|
||||||
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
||||||
return <DynamicLayout theme={theme} router={router} {...props} />
|
return <DynamicLayout theme={theme} layoutName='LayoutIndex' {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import BLOG from '@/blog.config'
|
|||||||
import { siteConfig } from '@/lib/config'
|
import { siteConfig } from '@/lib/config'
|
||||||
import { getGlobalData, getPostBlocks } from '@/lib/db/getSiteData'
|
import { getGlobalData, getPostBlocks } from '@/lib/db/getSiteData'
|
||||||
import { DynamicLayout } from '@/themes/theme'
|
import { DynamicLayout } from '@/themes/theme'
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文章列表分页
|
* 文章列表分页
|
||||||
@@ -10,9 +9,8 @@ import { useRouter } from 'next/router'
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const Page = props => {
|
const Page = props => {
|
||||||
const router = useRouter()
|
|
||||||
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
||||||
return <DynamicLayout theme={theme} router={router} {...props} />
|
return <DynamicLayout theme={theme} layoutName='LayoutPostList' {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getStaticPaths({ locale }) {
|
export async function getStaticPaths({ locale }) {
|
||||||
|
|||||||
@@ -3,12 +3,10 @@ import { getDataFromCache } from '@/lib/cache/cache_manager'
|
|||||||
import { siteConfig } from '@/lib/config'
|
import { siteConfig } from '@/lib/config'
|
||||||
import { getGlobalData } from '@/lib/db/getSiteData'
|
import { getGlobalData } from '@/lib/db/getSiteData'
|
||||||
import { DynamicLayout } from '@/themes/theme'
|
import { DynamicLayout } from '@/themes/theme'
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
|
|
||||||
const Index = props => {
|
const Index = props => {
|
||||||
const router = useRouter()
|
|
||||||
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
||||||
return <DynamicLayout theme={theme} router={router} {...props} />
|
return <DynamicLayout theme={theme} layoutName='LayoutSearch' {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,15 +3,13 @@ import { getDataFromCache } from '@/lib/cache/cache_manager'
|
|||||||
import { siteConfig } from '@/lib/config'
|
import { siteConfig } from '@/lib/config'
|
||||||
import { getGlobalData } from '@/lib/db/getSiteData'
|
import { getGlobalData } from '@/lib/db/getSiteData'
|
||||||
import { DynamicLayout } from '@/themes/theme'
|
import { DynamicLayout } from '@/themes/theme'
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
|
|
||||||
const Index = props => {
|
const Index = props => {
|
||||||
const { keyword } = props
|
const { keyword } = props
|
||||||
props = { ...props, currentSearch: keyword }
|
props = { ...props, currentSearch: keyword }
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
||||||
return <DynamicLayout theme={theme} router={router} {...props} />
|
return <DynamicLayout theme={theme} layoutName='LayoutSearch' {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ const Search = props => {
|
|||||||
props = { ...props, posts: filteredPosts }
|
props = { ...props, posts: filteredPosts }
|
||||||
|
|
||||||
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
||||||
return <DynamicLayout theme={theme} router={router} {...props} />
|
return <DynamicLayout theme={theme} layoutName='LayoutSearch' {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { siteConfig } from '@/lib/config'
|
|||||||
import { getGlobalData } from '@/lib/db/getSiteData'
|
import { getGlobalData } from '@/lib/db/getSiteData'
|
||||||
// import { getGlobalData } from '@/lib/db/getSiteData'
|
// import { getGlobalData } from '@/lib/db/getSiteData'
|
||||||
import { DynamicLayout } from '@/themes/theme'
|
import { DynamicLayout } from '@/themes/theme'
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录
|
* 登录
|
||||||
@@ -11,9 +10,8 @@ import { useRouter } from 'next/router'
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const SignIn = props => {
|
const SignIn = props => {
|
||||||
const router = useRouter()
|
|
||||||
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
||||||
return <DynamicLayout theme={theme} router={router} {...props} />
|
return <DynamicLayout theme={theme} layoutName='LayoutSignIn' {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getStaticProps(req) {
|
export async function getStaticProps(req) {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import BLOG from '@/blog.config'
|
|||||||
import { siteConfig } from '@/lib/config'
|
import { siteConfig } from '@/lib/config'
|
||||||
import { getGlobalData } from '@/lib/db/getSiteData'
|
import { getGlobalData } from '@/lib/db/getSiteData'
|
||||||
import { DynamicLayout } from '@/themes/theme'
|
import { DynamicLayout } from '@/themes/theme'
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 注册
|
* 注册
|
||||||
@@ -10,9 +9,8 @@ import { useRouter } from 'next/router'
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const SignUp = props => {
|
const SignUp = props => {
|
||||||
const router = useRouter()
|
|
||||||
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
||||||
return <DynamicLayout theme={theme} router={router} {...props} />
|
return <DynamicLayout theme={theme} layoutName='LayoutSignUp' {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getStaticProps(req) {
|
export async function getStaticProps(req) {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import BLOG from '@/blog.config'
|
|||||||
import { siteConfig } from '@/lib/config'
|
import { siteConfig } from '@/lib/config'
|
||||||
import { getGlobalData } from '@/lib/db/getSiteData'
|
import { getGlobalData } from '@/lib/db/getSiteData'
|
||||||
import { DynamicLayout } from '@/themes/theme'
|
import { DynamicLayout } from '@/themes/theme'
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 标签下的文章列表
|
* 标签下的文章列表
|
||||||
@@ -10,9 +9,8 @@ import { useRouter } from 'next/router'
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const Tag = props => {
|
const Tag = props => {
|
||||||
const router = useRouter()
|
|
||||||
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
||||||
return <DynamicLayout theme={theme} router={router} {...props} />
|
return <DynamicLayout theme={theme} layoutName='LayoutPostList' {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getStaticProps({ params: { tag }, locale }) {
|
export async function getStaticProps({ params: { tag }, locale }) {
|
||||||
|
|||||||
@@ -2,12 +2,10 @@ import BLOG from '@/blog.config'
|
|||||||
import { siteConfig } from '@/lib/config'
|
import { siteConfig } from '@/lib/config'
|
||||||
import { getGlobalData } from '@/lib/db/getSiteData'
|
import { getGlobalData } from '@/lib/db/getSiteData'
|
||||||
import { DynamicLayout } from '@/themes/theme'
|
import { DynamicLayout } from '@/themes/theme'
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
|
|
||||||
const Tag = props => {
|
const Tag = props => {
|
||||||
const router = useRouter()
|
|
||||||
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
||||||
return <DynamicLayout theme={theme} router={router} {...props} />
|
return <DynamicLayout theme={theme} layoutName='LayoutPostList' {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getStaticProps({ params: { tag, page }, locale }) {
|
export async function getStaticProps({ params: { tag, page }, locale }) {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { useRouter } from 'next/router'
|
|||||||
const TagIndex = props => {
|
const TagIndex = props => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
|
||||||
return <DynamicLayout theme={theme} router={router} {...props} />
|
return <DynamicLayout theme={theme} layoutName='LayoutPostList' {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getStaticProps(req) {
|
export async function getStaticProps(req) {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ html {
|
|||||||
position: sticky;
|
position: sticky;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
top: -1px;
|
top: -1px;
|
||||||
|
-webkit-backdrop-filter: blur(5px);
|
||||||
backdrop-filter: blur(5px);
|
backdrop-filter: blur(5px);
|
||||||
transition: all 0.5s cubic-bezier(0.4, 0, 0, 1);
|
transition: all 0.5s cubic-bezier(0.4, 0, 0, 1);
|
||||||
border-bottom-color: transparent;
|
border-bottom-color: transparent;
|
||||||
@@ -74,6 +75,7 @@ nav {
|
|||||||
|
|
||||||
@supports not (backdrop-filter: none) {
|
@supports not (backdrop-filter: none) {
|
||||||
.sticky-nav {
|
.sticky-nav {
|
||||||
|
-webkit-backdrop-filter: none;
|
||||||
backdrop-filter: none;
|
backdrop-filter: none;
|
||||||
@apply bg-day dark:bg-gray-800;
|
@apply bg-day dark:bg-gray-800;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
|
|||||||
key={post.id}
|
key={post.id}
|
||||||
data-aos='fade-up'
|
data-aos='fade-up'
|
||||||
data-aos-easing='ease-in-out'
|
data-aos-easing='ease-in-out'
|
||||||
data-aos-duration='800'
|
data-aos-duration='500'
|
||||||
data-aos-once='false'
|
data-aos-once='false'
|
||||||
data-aos-anchor-placement='top-bottom'
|
data-aos-anchor-placement='top-bottom'
|
||||||
id='blog-post-card'
|
id='blog-post-card'
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const Footer = ({ title }) => {
|
|||||||
<h1 className='text-xs pt-4 text-light-400 dark:text-gray-400'>
|
<h1 className='text-xs pt-4 text-light-400 dark:text-gray-400'>
|
||||||
{title} {siteConfig('BIO') && <>|</>} {siteConfig('BIO')}
|
{title} {siteConfig('BIO') && <>|</>} {siteConfig('BIO')}
|
||||||
</h1>
|
</h1>
|
||||||
<PoweredBy />
|
<PoweredBy className='justify-center' />
|
||||||
</span>
|
</span>
|
||||||
<br />
|
<br />
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -147,10 +147,10 @@ export default function Header(props) {
|
|||||||
{!showSearchInput && (
|
{!showSearchInput && (
|
||||||
<>
|
<>
|
||||||
{/* 左侧图标Logo */}
|
{/* 左侧图标Logo */}
|
||||||
<div className='flex gap-x-8 h-full'>
|
<div className='flex gap-x-2 lg:gap-x-4 h-full'>
|
||||||
<LogoBar {...props} />
|
<LogoBar className={'text-sm md:text-md lg:text-lg'} />
|
||||||
{/* 桌面端顶部菜单 */}
|
{/* 桌面端顶部菜单 */}
|
||||||
<ul className='hidden md:flex items-center gap-x-4 py-1'>
|
<ul className='hidden md:flex items-center gap-x-4 py-1 text-sm md:text-md'>
|
||||||
{links &&
|
{links &&
|
||||||
links?.map((link, index) => (
|
links?.map((link, index) => (
|
||||||
<MenuItemDrop key={index} link={link} />
|
<MenuItemDrop key={index} link={link} />
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import { siteConfig } from '@/lib/config'
|
import { siteConfig } from '@/lib/config'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
|
||||||
export default function LogoBar(props) {
|
export default function LogoBar({ className }) {
|
||||||
return (
|
return (
|
||||||
<div id='top-wrapper' className='w-full flex items-center '>
|
<div
|
||||||
|
id='top-wrapper'
|
||||||
|
className={`w-full flex items-center ${className || ''}`}>
|
||||||
<Link
|
<Link
|
||||||
href='/'
|
href='/'
|
||||||
className='logo flex text-md font-semibold md:text-xl hover:bg-black hover:text-white p-2 rounded-xl duration-200 dark:text-gray-200'>
|
className='logo flex font-semibold hover:bg-black hover:text-white p-2 rounded-xl duration-200 dark:text-gray-200'>
|
||||||
{/* <LazyImage
|
{/* <LazyImage
|
||||||
src={siteInfo?.icon}
|
src={siteInfo?.icon}
|
||||||
width={24}
|
width={24}
|
||||||
|
|||||||
@@ -17,10 +17,6 @@ export const MenuItemCollapse = props => {
|
|||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
if (!link || !link.show) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const selected = router.pathname === link.href || router.asPath === link.href
|
const selected = router.pathname === link.href || router.asPath === link.href
|
||||||
|
|
||||||
const toggleShow = () => {
|
const toggleShow = () => {
|
||||||
@@ -36,6 +32,10 @@ export const MenuItemCollapse = props => {
|
|||||||
setOpen(false)
|
setOpen(false)
|
||||||
}, [router])
|
}, [router])
|
||||||
|
|
||||||
|
if (!link || !link.show) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -22,13 +22,13 @@ export const MenuItemDrop = ({ link }) => {
|
|||||||
{hasSubMenu && (
|
{hasSubMenu && (
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'px-2 h-full whitespace-nowrap duration-300 text-md justify-between dark:text-gray-300 cursor-pointer flex flex-nowrap items-center ' +
|
'px-2 h-full whitespace-nowrap duration-300 justify-between dark:text-gray-300 cursor-pointer flex flex-nowrap items-center ' +
|
||||||
(selected
|
(selected
|
||||||
? 'bg-gray-600 text-white hover:text-white'
|
? 'bg-gray-600 text-white hover:text-white'
|
||||||
: 'hover:text-gray-600')
|
: 'hover:text-gray-600')
|
||||||
}>
|
}>
|
||||||
<div className='items-center flex gap-x-1'>
|
<div className='items-center flex'>
|
||||||
{link?.icon && <i className={link?.icon} />} {link?.name}
|
{link?.icon && <i className={`${link?.icon} pr-2`} />} {link?.name}
|
||||||
<i
|
<i
|
||||||
className={`px-1 fas fa-chevron-down duration-500 transition-all ${show ? ' rotate-180' : ''}`}></i>
|
className={`px-1 fas fa-chevron-down duration-500 transition-all ${show ? ' rotate-180' : ''}`}></i>
|
||||||
</div>
|
</div>
|
||||||
@@ -52,15 +52,15 @@ export const MenuItemDrop = ({ link }) => {
|
|||||||
{/* 子菜单 */}
|
{/* 子菜单 */}
|
||||||
{hasSubMenu && (
|
{hasSubMenu && (
|
||||||
<ul
|
<ul
|
||||||
className={`${show ? 'visible opacity-100 top-14' : 'invisible opacity-0 top-20'} absolute border bg-white dark:bg-black dark:border-gray-800 transition-all duration-150 z-20 block rounded-lg drop-shadow-lg p-4 `}>
|
className={`${show ? 'visible opacity-100 top-14' : 'invisible opacity-0 top-20'} p-1 absolute border bg-white dark:bg-black dark:border-gray-800 transition-all duration-150 z-20 block rounded-lg drop-shadow-lg`}>
|
||||||
{link?.subMenus?.map(sLink => {
|
{link?.subMenus?.map(sLink => {
|
||||||
return (
|
return (
|
||||||
<li
|
<li
|
||||||
key={sLink.id}
|
key={sLink.id}
|
||||||
className='dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-900 tracking-widest transition-all duration-200 dark:border-gray-800 py-3 pr-6 pl-3'>
|
className='py-3 pr-6 hover:bg-gray-100 dark:hover:bg-gray-900 dark:text-gray-200 tracking-widest transition-color duration-200 dark:border-gray-800 '>
|
||||||
<Link href={sLink.href} target={link?.target}>
|
<Link href={sLink.href} target={link?.target}>
|
||||||
<span className='text-sm'>
|
<span className='text-sm ml-2'>
|
||||||
{link?.icon && <i className={sLink?.icon}> </i>}
|
{link?.icon && <i className={`${sLink?.icon} pr-2`}> </i>}
|
||||||
{sLink.title}
|
{sLink.title}
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -14,10 +14,11 @@ import Swiper from './Swiper'
|
|||||||
const PostListRecommend = ({ latestPosts, allNavPages }) => {
|
const PostListRecommend = ({ latestPosts, allNavPages }) => {
|
||||||
// 获取推荐文章
|
// 获取推荐文章
|
||||||
const recommendPosts = getTopPosts({ latestPosts, allNavPages })
|
const recommendPosts = getTopPosts({ latestPosts, allNavPages })
|
||||||
|
const title = siteConfig('MAGZINE_RECOMMEND_POST_TITLE', '', CONFIG)
|
||||||
|
|
||||||
if (!recommendPosts || recommendPosts.length === 0) {
|
if (!recommendPosts || recommendPosts.length === 0) {
|
||||||
return <PostListEmpty />
|
return <PostListEmpty />
|
||||||
}
|
}
|
||||||
const title = siteConfig('MAGZINE_RECOMMEND_POST_TITLE', '', CONFIG)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`w-full py-10 px-2 bg-[#F6F6F1] dark:bg-black`}>
|
<div className={`w-full py-10 px-2 bg-[#F6F6F1] dark:bg-black`}>
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export const MenuItem = ({ link }) => {
|
|||||||
<li className='submenu-item group relative whitespace-nowrap'>
|
<li className='submenu-item group relative whitespace-nowrap'>
|
||||||
<button
|
<button
|
||||||
onClick={toggleSubMenu}
|
onClick={toggleSubMenu}
|
||||||
className={`cursor-pointer relative w-full px-8 flex items-center justify-between py-2 text-base font-medium text-dark group-hover:text-primary dark:text-white lg:ml-8 lg:mr-0 lg:inline-flex lg:py-6 lg:pl-0 lg:pr-4 ${
|
className={`cursor-pointer relative px-8 flex items-center justify-between py-2 text-base font-medium text-dark group-hover:text-primary dark:text-white lg:ml-8 lg:mr-0 lg:inline-flex lg:py-6 lg:pl-0 lg:pr-4 ${
|
||||||
router.route === '/'
|
router.route === '/'
|
||||||
? 'lg:text-white lg:group-hover:text-white'
|
? 'lg:text-white lg:group-hover:text-white'
|
||||||
: ''
|
: ''
|
||||||
|
|||||||
@@ -54,6 +54,11 @@ const Style = () => {
|
|||||||
color: rgb(55 88 249 / var(--tw-text-opacity));
|
color: rgb(55 88 249 / var(--tw-text-opacity));
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#theme-starter .sticky #navbarCollapse li > button{
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(17 25 40 / var(--tw-text-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
:is(.dark #theme-starter .sticky #navbarCollapse li > a){
|
:is(.dark #theme-starter .sticky #navbarCollapse li > a){
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
@@ -64,7 +69,12 @@ const Style = () => {
|
|||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: rgb(55 88 249 / var(--tw-text-opacity));
|
color: rgb(55 88 249 / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:is(.dark #theme-starter .sticky #navbarCollapse li > button){
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(255 255 255 / var(--tw-text-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
#navbarCollapse li .ud-menu-scroll.active{
|
#navbarCollapse li .ud-menu-scroll.active{
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import BLOG, { LAYOUT_MAPPINGS } from '@/blog.config'
|
|||||||
import * as ThemeComponents from '@theme-components'
|
import * as ThemeComponents from '@theme-components'
|
||||||
import getConfig from 'next/config'
|
import getConfig from 'next/config'
|
||||||
import dynamic from 'next/dynamic'
|
import dynamic from 'next/dynamic'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
import { getQueryParam, getQueryVariable, isBrowser } from '../lib/utils'
|
import { getQueryParam, getQueryVariable, isBrowser } from '../lib/utils'
|
||||||
|
|
||||||
// 在next.config.js中扫描所有主题
|
// 在next.config.js中扫描所有主题
|
||||||
@@ -56,19 +57,20 @@ export const getThemeConfig = async themeQuery => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 加载全局布局
|
* 加载全局布局
|
||||||
* @param {*} themeQuery
|
* @param {*} theme
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const getGlobalLayoutByTheme = themeQuery => {
|
export const getBaseLayoutByTheme = theme => {
|
||||||
if (themeQuery !== BLOG.THEME) {
|
const LayoutBase = ThemeComponents['LayoutBase']
|
||||||
|
const isDefaultTheme = !theme || theme === BLOG.THEME
|
||||||
|
if (!isDefaultTheme) {
|
||||||
return dynamic(
|
return dynamic(
|
||||||
() =>
|
() => import(`@/themes/${theme}`).then(m => m['LayoutBase']),
|
||||||
import(`@/themes/${themeQuery}`).then(m => m[getLayoutNameByPath(-1)]),
|
|
||||||
{ ssr: true }
|
{ ssr: true }
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
return ThemeComponents[getLayoutNameByPath('-1')]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return LayoutBase
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,8 +78,8 @@ export const getGlobalLayoutByTheme = themeQuery => {
|
|||||||
* @param {*} props
|
* @param {*} props
|
||||||
*/
|
*/
|
||||||
export const DynamicLayout = props => {
|
export const DynamicLayout = props => {
|
||||||
const { router, theme } = props
|
const { theme, layoutName } = props
|
||||||
const SelectedLayout = getLayoutByTheme({ router, theme })
|
const SelectedLayout = getLayoutByTheme({ layoutName, theme })
|
||||||
return <SelectedLayout {...props} />
|
return <SelectedLayout {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,26 +89,31 @@ export const DynamicLayout = props => {
|
|||||||
* @param {*} theme
|
* @param {*} theme
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const getLayoutByTheme = ({ router, theme }) => {
|
export const getLayoutByTheme = ({ layoutName, theme }) => {
|
||||||
const themeQuery = getQueryParam(router.asPath, 'theme') || theme
|
// const layoutName = getLayoutNameByPath(router.pathname, router.asPath)
|
||||||
const layoutName = getLayoutNameByPath(router.pathname, router.asPath)
|
const LayoutComponents =
|
||||||
|
ThemeComponents[layoutName] || ThemeComponents.LayoutSlug
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const themeQuery = getQueryParam(router?.asPath, 'theme') || theme
|
||||||
const isDefaultTheme = !themeQuery || themeQuery === BLOG.THEME
|
const isDefaultTheme = !themeQuery || themeQuery === BLOG.THEME
|
||||||
|
|
||||||
const loadThemeComponents = componentsSource => {
|
// 加载非当前默认主题
|
||||||
const components =
|
if (!isDefaultTheme) {
|
||||||
componentsSource[layoutName] || componentsSource.LayoutSlug
|
const loadThemeComponents = componentsSource => {
|
||||||
setTimeout(fixThemeDOM, isDefaultTheme ? 100 : 500) // 根据主题选择延迟时间
|
const components =
|
||||||
return components
|
componentsSource[layoutName] || componentsSource.LayoutSlug
|
||||||
}
|
setTimeout(fixThemeDOM, 500)
|
||||||
|
return components
|
||||||
if (isDefaultTheme) {
|
}
|
||||||
return loadThemeComponents(ThemeComponents)
|
|
||||||
} else {
|
|
||||||
return dynamic(
|
return dynamic(
|
||||||
() => import(`@/themes/${themeQuery}`).then(m => loadThemeComponents(m)),
|
() => import(`@/themes/${themeQuery}`).then(m => loadThemeComponents(m)),
|
||||||
{ ssr: true }
|
{ ssr: true }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setTimeout(fixThemeDOM, 100)
|
||||||
|
return LayoutComponents
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,8 +135,6 @@ const fixThemeDOM = () => {
|
|||||||
if (isBrowser) {
|
if (isBrowser) {
|
||||||
const elements = document.querySelectorAll('[id^="theme-"]')
|
const elements = document.querySelectorAll('[id^="theme-"]')
|
||||||
if (elements?.length > 1) {
|
if (elements?.length > 1) {
|
||||||
elements[elements.length - 1].scrollIntoView()
|
|
||||||
// 删除前面的元素,只保留最后一个元素
|
|
||||||
for (let i = 0; i < elements.length - 1; i++) {
|
for (let i = 0; i < elements.length - 1; i++) {
|
||||||
if (
|
if (
|
||||||
elements[i] &&
|
elements[i] &&
|
||||||
@@ -139,6 +144,7 @@ const fixThemeDOM = () => {
|
|||||||
elements[i].parentNode.removeChild(elements[i])
|
elements[i].parentNode.removeChild(elements[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
elements[0]?.scrollIntoView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user