mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-06-03 15:10:19 +00:00
Merge branch 'tangly1024:main' into main
This commit is contained in:
@@ -1,2 +1,2 @@
|
|||||||
# 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables
|
# 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables
|
||||||
NEXT_PUBLIC_VERSION=3.12.2
|
NEXT_PUBLIC_VERSION=3.12.3
|
||||||
|
|||||||
@@ -81,8 +81,9 @@
|
|||||||
|
|
||||||
<td align="center"><a href="https://github.com/Pylogmon"><img src="https://avatars.githubusercontent.com/u/59004461" width="64px;" alt="Pylogmon"/><br/><sub><b>派了个萌 </b></sub></a><br/><a href="https://github.com/tangly1024/NotionNext/commits?author=Pylogmon" title="Pylogmon" >🔧 🐛</a></td>
|
<td align="center"><a href="https://github.com/Pylogmon"><img src="https://avatars.githubusercontent.com/u/59004461" width="64px;" alt="Pylogmon"/><br/><sub><b>派了个萌 </b></sub></a><br/><a href="https://github.com/tangly1024/NotionNext/commits?author=Pylogmon" title="Pylogmon" >🔧 🐛</a></td>
|
||||||
|
|
||||||
<td align="center"><a href="https://github.com/SkysCrystal"><img src="https://avatars.githubusercontent.com/u/49473463" width="64px;" alt="SkysCrystal"/><br/><sub><b>Simon Shi
|
<td align="center"><a href="https://github.com/SkysCrystal"><img src="https://avatars.githubusercontent.com/u/49473463" width="64px;" alt="SkysCrystal"/><br/><sub><b>Simon Shi</b></sub></a><br/><a href="https://github.com/tangly1024/NotionNext/commits?author=SkysCrystal" title="SkysCrystal" >🔧 🐛</a></td>
|
||||||
</b></sub></a><br/><a href="https://github.com/tangly1024/NotionNext/commits?author=SkysCrystal" title="SkysCrystal" >🔧 🐛</a></td>
|
|
||||||
|
<td align="center"><a href="https://github.com/siygle"><img src="https://avatars.githubusercontent.com/u/173408" width="64px;" alt="S.Y. Lee"/><br/><sub><b>S.Y. Lee</b></sub></a><br/><a href="https://github.com/tangly1024/NotionNext/commits?author=siygle" title="siygle" >🔧 🐛</a></td>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -214,6 +214,9 @@ const BLOG = {
|
|||||||
icon: process.env.NEXT_PUBLIC_NOTION_PROPERTY_ICON || 'icon'
|
icon: process.env.NEXT_PUBLIC_NOTION_PROPERTY_ICON || 'icon'
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// RSS
|
||||||
|
ENABLE_RSS: process.env.NEXT_PUBLIC_ENABLE_RSS || true, // 是否开启RSS订阅功能
|
||||||
|
|
||||||
// 作废配置
|
// 作废配置
|
||||||
AVATAR: process.env.NEXT_PUBLIC_AVATAR || '/avatar.png', // 作者头像,被notion中的ICON覆盖。若无ICON则取public目录下的avatar.png
|
AVATAR: process.env.NEXT_PUBLIC_AVATAR || '/avatar.png', // 作者头像,被notion中的ICON覆盖。若无ICON则取public目录下的avatar.png
|
||||||
TITLE: process.env.NEXT_PUBLIC_TITLE || 'NotionNext BLOG', // 站点标题 ,被notion中的页面标题覆盖
|
TITLE: process.env.NEXT_PUBLIC_TITLE || 'NotionNext BLOG', // 站点标题 ,被notion中的页面标题覆盖
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import { isBrowser, loadExternalResource } from '@/lib/utils'
|
import { loadExternalResource } from '@/lib/utils'
|
||||||
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定义引入外部JS 和 CSS
|
* 自定义引入外部JS 和 CSS
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const ExternalScript = () => {
|
const ExternalScript = () => {
|
||||||
if (isBrowser()) {
|
useEffect(() => {
|
||||||
// 静态导入本地自定义样式
|
// 静态导入本地自定义样式
|
||||||
loadExternalResource(BLOG.FONT_AWESOME, 'css')
|
loadExternalResource(BLOG.FONT_AWESOME, 'css')
|
||||||
loadExternalResource('/css/custom.css', 'css')
|
loadExternalResource('/css/custom.css', 'css')
|
||||||
@@ -25,7 +26,7 @@ const ExternalScript = () => {
|
|||||||
BLOG.FONT_URL?.forEach(e => {
|
BLOG.FONT_URL?.forEach(e => {
|
||||||
loadExternalResource(e, 'css')
|
loadExternalResource(e, 'css')
|
||||||
})
|
})
|
||||||
}
|
}, [])
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
19
lib/robots.txt.js
Normal file
19
lib/robots.txt.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
import fs from 'fs'
|
||||||
|
import BLOG from '@/blog.config'
|
||||||
|
|
||||||
|
export async function generateRobotsTxt() {
|
||||||
|
fs.mkdirSync('./public/rss', { recursive: true })
|
||||||
|
fs.writeFileSync('./public/robots.txt', `
|
||||||
|
# *
|
||||||
|
User-agent: *
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
# Host
|
||||||
|
Host: ${BLOG.LINK}
|
||||||
|
|
||||||
|
# Sitemaps
|
||||||
|
Sitemap: ${BLOG.LINK}/sitemap.xml
|
||||||
|
|
||||||
|
`)
|
||||||
|
}
|
||||||
36
lib/rss.js
36
lib/rss.js
@@ -5,21 +5,6 @@ import ReactDOMServer from 'react-dom/server'
|
|||||||
import { getPostBlocks } from './notion'
|
import { getPostBlocks } from './notion'
|
||||||
import NotionPage from '@/components/NotionPage'
|
import NotionPage from '@/components/NotionPage'
|
||||||
|
|
||||||
const createFeedContent = async post => {
|
|
||||||
// 加密的文章内容只返回摘要
|
|
||||||
if (post.password && post.password !== '') {
|
|
||||||
return post.summary
|
|
||||||
}
|
|
||||||
const blockMap = await getPostBlocks(post.id, 'rss-content')
|
|
||||||
if (blockMap) {
|
|
||||||
post.blockMap = blockMap
|
|
||||||
const content = ReactDOMServer.renderToString(<NotionPage post={post} />)
|
|
||||||
const regexExp =
|
|
||||||
/<div class="notion-collection-row"><div class="notion-collection-row-body"><div class="notion-collection-row-property"><div class="notion-collection-column-title"><svg.*?class="notion-collection-column-title-icon">.*?<\/svg><div class="notion-collection-column-title-body">.*?<\/div><\/div><div class="notion-collection-row-value">.*?<\/div><\/div><\/div><\/div>/g
|
|
||||||
return content.replace(regexExp, '')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function generateRss(posts) {
|
export async function generateRss(posts) {
|
||||||
const year = new Date().getFullYear()
|
const year = new Date().getFullYear()
|
||||||
const feed = new Feed({
|
const feed = new Feed({
|
||||||
@@ -38,7 +23,6 @@ export async function generateRss(posts) {
|
|||||||
for (const post of posts) {
|
for (const post of posts) {
|
||||||
feed.addItem({
|
feed.addItem({
|
||||||
title: post.title,
|
title: post.title,
|
||||||
guid: `${post.id}`,
|
|
||||||
link: `${BLOG.LINK}/${post.slug}`,
|
link: `${BLOG.LINK}/${post.slug}`,
|
||||||
description: post.summary,
|
description: post.summary,
|
||||||
content: await createFeedContent(post),
|
content: await createFeedContent(post),
|
||||||
@@ -51,3 +35,23 @@ export async function generateRss(posts) {
|
|||||||
fs.writeFileSync('./public/rss/atom.xml', feed.atom1())
|
fs.writeFileSync('./public/rss/atom.xml', feed.atom1())
|
||||||
fs.writeFileSync('./public/rss/feed.json', feed.json1())
|
fs.writeFileSync('./public/rss/feed.json', feed.json1())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成RSS内容
|
||||||
|
* @param {*} post
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const createFeedContent = async post => {
|
||||||
|
// 加密的文章内容只返回摘要
|
||||||
|
if (post.password && post.password !== '') {
|
||||||
|
return post.summary
|
||||||
|
}
|
||||||
|
const blockMap = await getPostBlocks(post.id, 'rss-content')
|
||||||
|
if (blockMap) {
|
||||||
|
post.blockMap = blockMap
|
||||||
|
const content = ReactDOMServer.renderToString(<NotionPage post={post} />)
|
||||||
|
const regexExp =
|
||||||
|
/<div class="notion-collection-row"><div class="notion-collection-row-body"><div class="notion-collection-row-property"><div class="notion-collection-column-title"><svg.*?class="notion-collection-column-title-icon">.*?<\/svg><div class="notion-collection-column-title-body">.*?<\/div><\/div><div class="notion-collection-row-value">.*?<\/div><\/div><\/div><\/div>/g
|
||||||
|
return content.replace(regexExp, '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
57
lib/sitemap.xml.js
Normal file
57
lib/sitemap.xml.js
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
|
||||||
|
import fs from 'fs'
|
||||||
|
import BLOG from '@/blog.config'
|
||||||
|
|
||||||
|
export async function generateSitemapXml({ allPages }) {
|
||||||
|
fs.mkdirSync('./public', { recursive: true })
|
||||||
|
|
||||||
|
const urls = [{
|
||||||
|
loc: `${BLOG.LINK}`,
|
||||||
|
lastmod: new Date().toISOString().split('T')[0],
|
||||||
|
changefreq: 'daily'
|
||||||
|
}, {
|
||||||
|
loc: `${BLOG.LINK}/archive`,
|
||||||
|
lastmod: new Date().toISOString().split('T')[0],
|
||||||
|
changefreq: 'daily'
|
||||||
|
}, {
|
||||||
|
loc: `${BLOG.LINK}/category`,
|
||||||
|
lastmod: new Date().toISOString().split('T')[0],
|
||||||
|
changefreq: 'daily'
|
||||||
|
}, {
|
||||||
|
loc: `${BLOG.LINK}/tag`,
|
||||||
|
lastmod: new Date().toISOString().split('T')[0],
|
||||||
|
changefreq: 'daily'
|
||||||
|
}]
|
||||||
|
|
||||||
|
allPages?.forEach(post => {
|
||||||
|
urls.push({
|
||||||
|
loc: `${BLOG.LINK}/${post.slug}`,
|
||||||
|
lastmod: new Date(post?.date?.start_date || post?.createdTime).toISOString().split('T')[0],
|
||||||
|
changefreq: 'daily'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
const xml = createSitemapXml(urls)
|
||||||
|
fs.writeFileSync('./public/sitemap.xml', xml)
|
||||||
|
}
|
||||||
|
|
||||||
|
function createSitemapXml(urls) {
|
||||||
|
let urlsXml = ''
|
||||||
|
urls.forEach(u => {
|
||||||
|
urlsXml += `<url>
|
||||||
|
<loc>${u.loc}</loc>
|
||||||
|
<lastmod>${u.lastmod}</lastmod>
|
||||||
|
<changefreq>${u.changefreq}</changefreq>
|
||||||
|
</url>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
|
||||||
|
return `
|
||||||
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
||||||
|
xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
|
||||||
|
xmlns:xhtml="http://www.w3.org/1999/xhtml"
|
||||||
|
xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0"
|
||||||
|
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
|
||||||
|
${urlsXml}
|
||||||
|
</urlset>
|
||||||
|
`
|
||||||
|
}
|
||||||
@@ -11,7 +11,9 @@ module.exports = withBundleAnalyzer({
|
|||||||
'gravatar.com',
|
'gravatar.com',
|
||||||
'www.notion.so',
|
'www.notion.so',
|
||||||
'avatars.githubusercontent.com',
|
'avatars.githubusercontent.com',
|
||||||
'images.unsplash.com'
|
'images.unsplash.com',
|
||||||
|
'source.unsplash.com',
|
||||||
|
'p1.qhimg.com'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
// 默认将feed重定向至 /public/rss/feed.xml
|
// 默认将feed重定向至 /public/rss/feed.xml
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "notion-next",
|
"name": "notion-next",
|
||||||
"version": "3.12.2",
|
"version": "3.12.3",
|
||||||
"homepage": "https://github.com/tangly1024/NotionNext.git",
|
"homepage": "https://github.com/tangly1024/NotionNext.git",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
@@ -58,12 +58,12 @@ const MyApp = ({ Component, pageProps }) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
AOS.init()
|
AOS.init()
|
||||||
smoothscroll.polyfill()
|
smoothscroll.polyfill()
|
||||||
})
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GlobalContextProvider>
|
<GlobalContextProvider>
|
||||||
{externalPlugins}
|
|
||||||
<Component {...pageProps} />
|
<Component {...pageProps} />
|
||||||
|
{externalPlugins}
|
||||||
</GlobalContextProvider>
|
</GlobalContextProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { getGlobalNotionData } from '@/lib/notion/getNotionData'
|
|||||||
import * as ThemeMap from '@/themes'
|
import * as ThemeMap from '@/themes'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { generateRss } from '@/lib/rss'
|
import { generateRss } from '@/lib/rss'
|
||||||
|
import { generateRobotsTxt } from '@/lib/robots.txt'
|
||||||
|
import { generateSitemapXml } from '@/lib/sitemap.xml'
|
||||||
const Index = props => {
|
const Index = props => {
|
||||||
const { theme } = useGlobal()
|
const { theme } = useGlobal()
|
||||||
const ThemeComponents = ThemeMap[theme]
|
const ThemeComponents = ThemeMap[theme]
|
||||||
@@ -17,7 +19,6 @@ export async function getStaticProps() {
|
|||||||
const { siteInfo } = props
|
const { siteInfo } = props
|
||||||
props.posts = props.allPages.filter(page => page.type === 'Post' && page.status === 'Published')
|
props.posts = props.allPages.filter(page => page.type === 'Post' && page.status === 'Published')
|
||||||
|
|
||||||
delete props.allPages
|
|
||||||
const meta = {
|
const meta = {
|
||||||
title: `${siteInfo?.title} | ${siteInfo?.description}`,
|
title: `${siteInfo?.title} | ${siteInfo?.description}`,
|
||||||
description: siteInfo?.description,
|
description: siteInfo?.description,
|
||||||
@@ -43,8 +44,16 @@ export async function getStaticProps() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 异步生成Feed订阅
|
// 生成Feed订阅
|
||||||
generateRss(props?.latestPosts || [])
|
if (JSON.parse(BLOG.ENABLE_RSS)) {
|
||||||
|
generateRss(props?.latestPosts || [])
|
||||||
|
}
|
||||||
|
// 生成robotTxt
|
||||||
|
generateRobotsTxt()
|
||||||
|
// 生成sitemap.xml
|
||||||
|
generateSitemapXml({ allPages: props.allPages })
|
||||||
|
|
||||||
|
delete props.allPages
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
// pages/sitemap.xml.js
|
|
||||||
import { getServerSideSitemap } from 'next-sitemap'
|
|
||||||
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
|
|
||||||
import BLOG from '@/blog.config'
|
|
||||||
|
|
||||||
export const getServerSideProps = async (ctx) => {
|
|
||||||
const { allPages } = await getGlobalNotionData({ from: 'rss' })
|
|
||||||
const defaultFields = [
|
|
||||||
{
|
|
||||||
loc: `${BLOG.LINK}`,
|
|
||||||
lastmod: new Date().toISOString().split('T')[0],
|
|
||||||
changefreq: 'daily',
|
|
||||||
priority: '0.7'
|
|
||||||
}, {
|
|
||||||
loc: `${BLOG.LINK}/archive`,
|
|
||||||
lastmod: new Date().toISOString().split('T')[0],
|
|
||||||
changefreq: 'daily',
|
|
||||||
priority: '0.7'
|
|
||||||
}, {
|
|
||||||
loc: `${BLOG.LINK}/category`,
|
|
||||||
lastmod: new Date().toISOString().split('T')[0],
|
|
||||||
changefreq: 'daily',
|
|
||||||
priority: '0.7'
|
|
||||||
}, {
|
|
||||||
loc: `${BLOG.LINK}/feed`,
|
|
||||||
lastmod: new Date().toISOString().split('T')[0],
|
|
||||||
changefreq: 'daily',
|
|
||||||
priority: '0.7'
|
|
||||||
}, {
|
|
||||||
loc: `${BLOG.LINK}/search`,
|
|
||||||
lastmod: new Date().toISOString().split('T')[0],
|
|
||||||
changefreq: 'daily',
|
|
||||||
priority: '0.7'
|
|
||||||
}, {
|
|
||||||
loc: `${BLOG.LINK}/tag`,
|
|
||||||
lastmod: new Date().toISOString().split('T')[0],
|
|
||||||
changefreq: 'daily',
|
|
||||||
priority: '0.7'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
const postFields = allPages?.map(post => {
|
|
||||||
return {
|
|
||||||
loc: `${BLOG.LINK}/${post.slug}`,
|
|
||||||
lastmod: new Date(post?.date?.start_date || post?.createdTime).toISOString().split('T')[0],
|
|
||||||
changefreq: 'daily',
|
|
||||||
priority: '0.7'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const fields = defaultFields.concat(postFields)
|
|
||||||
|
|
||||||
// 缓存
|
|
||||||
// ctx.res.setHeader(
|
|
||||||
// 'Cache-Control',
|
|
||||||
// 'public, s-maxage=10, stale-while-revalidate=59'
|
|
||||||
// )
|
|
||||||
|
|
||||||
return getServerSideSitemap(ctx, fields)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default () => { }
|
|
||||||
BIN
public/bg_image.jpg
Normal file → Executable file
BIN
public/bg_image.jpg
Normal file → Executable file
Binary file not shown.
|
Before Width: | Height: | Size: 167 KiB After Width: | Height: | Size: 16 KiB |
@@ -167,6 +167,13 @@ nav {
|
|||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.waline-recent-content .wl-emoji {
|
||||||
|
height: 1.1rem !important;
|
||||||
|
display: inline-block !important;
|
||||||
|
line-height: 1.25rem !important;
|
||||||
|
vertical-align: text-bottom !important;
|
||||||
|
}
|
||||||
|
|
||||||
.vcontent .wl-emoji {
|
.vcontent .wl-emoji {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
|
|||||||
@@ -14,7 +14,13 @@ import dynamic from 'next/dynamic'
|
|||||||
|
|
||||||
const FacebookPage = dynamic(
|
const FacebookPage = dynamic(
|
||||||
() => {
|
() => {
|
||||||
return import('@/components/FacebookPage')
|
let facebook = <></>
|
||||||
|
try {
|
||||||
|
facebook = import('@/components/FacebookPage')
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
|
return facebook
|
||||||
},
|
},
|
||||||
{ ssr: false }
|
{ ssr: false }
|
||||||
)
|
)
|
||||||
@@ -59,14 +65,14 @@ const LayoutBase = props => {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id='theme-hexo' className="bg-hexo-background-gray dark:bg-black">
|
<div id='theme-hexo'>
|
||||||
<CommonHead meta={meta} siteInfo={siteInfo}/>
|
<CommonHead meta={meta} siteInfo={siteInfo}/>
|
||||||
|
|
||||||
<TopNav {...props} />
|
<TopNav {...props} />
|
||||||
|
|
||||||
{headerSlot}
|
{headerSlot}
|
||||||
|
|
||||||
<main id="wrapper" className="w-full py-8 md:px-8 lg:px-24 min-h-screen relative">
|
<main id="wrapper" className="bg-hexo-background-gray dark:bg-black w-full py-8 md:px-8 lg:px-24 min-h-screen relative">
|
||||||
<div
|
<div
|
||||||
id="container-inner"
|
id="container-inner"
|
||||||
className={(BLOG.LAYOUT_SIDEBAR_REVERSE ? 'flex-row-reverse' : '') + ' pt-14 w-full mx-auto lg:flex lg:space-x-4 justify-center relative z-10'}
|
className={(BLOG.LAYOUT_SIDEBAR_REVERSE ? 'flex-row-reverse' : '') + ' pt-14 w-full mx-auto lg:flex lg:space-x-4 justify-center relative z-10'}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import React from 'react'
|
|||||||
export const LayoutIndex = (props) => {
|
export const LayoutIndex = (props) => {
|
||||||
const headerSlot = CONFIG_HEXO.HOME_BANNER_ENABLE && <Header {...props} />
|
const headerSlot = CONFIG_HEXO.HOME_BANNER_ENABLE && <Header {...props} />
|
||||||
return <LayoutBase {...props} headerSlot={headerSlot}>
|
return <LayoutBase {...props} headerSlot={headerSlot}>
|
||||||
|
|
||||||
{BLOG.POST_LIST_STYLE === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />}
|
{BLOG.POST_LIST_STYLE === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />}
|
||||||
</LayoutBase>
|
</LayoutBase>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,7 @@ const NotionPage = dynamic(() => import('@/components/NotionPage'))
|
|||||||
const Announcement = ({ post, className }) => {
|
const Announcement = ({ post, className }) => {
|
||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
if (post?.blockMap) {
|
if (post?.blockMap) {
|
||||||
return <div
|
return <div className={className}>
|
||||||
data-aos="fade-up"
|
|
||||||
data-aos-duration="300"
|
|
||||||
data-aos-once="false"
|
|
||||||
data-aos-anchor-placement="top-bottom"
|
|
||||||
className={className}>
|
|
||||||
<section id='announcement-wrapper' className="hover:shadow-md dark:text-gray-300 border dark:border-black rounded-xl px-2 py-4 bg-white dark:bg-hexo-black-gray">
|
<section id='announcement-wrapper' className="hover:shadow-md dark:text-gray-300 border dark:border-black rounded-xl px-2 py-4 bg-white dark:bg-hexo-black-gray">
|
||||||
<div><i className='mr-2 fas fa-bullhorn' />{locale.COMMON.ANNOUNCEMENT}</div>
|
<div><i className='mr-2 fas fa-bullhorn' />{locale.COMMON.ANNOUNCEMENT}</div>
|
||||||
{post && (<div id="announcement-content">
|
{post && (<div id="announcement-content">
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import React from 'react'
|
|||||||
import TagItemMini from './TagItemMini'
|
import TagItemMini from './TagItemMini'
|
||||||
import CONFIG_HEXO from '../config_hexo'
|
import CONFIG_HEXO from '../config_hexo'
|
||||||
import NotionPage from '@/components/NotionPage'
|
import NotionPage from '@/components/NotionPage'
|
||||||
|
import Image from 'next/image'
|
||||||
|
|
||||||
const BlogPostCard = ({ post, showSummary, siteInfo }) => {
|
const BlogPostCard = ({ post, showSummary, siteInfo }) => {
|
||||||
const showPreview = CONFIG_HEXO.POST_LIST_PREVIEW && post.blockMap
|
const showPreview = CONFIG_HEXO.POST_LIST_PREVIEW && post.blockMap
|
||||||
@@ -15,6 +16,7 @@ const BlogPostCard = ({ post, showSummary, siteInfo }) => {
|
|||||||
<div
|
<div
|
||||||
key={post.id}
|
key={post.id}
|
||||||
data-aos="fade-up"
|
data-aos="fade-up"
|
||||||
|
data-aso-delay="200"
|
||||||
data-aos-duration="200"
|
data-aos-duration="200"
|
||||||
data-aos-once="true"
|
data-aos-once="true"
|
||||||
data-aos-anchor-placement="top-bottom"
|
data-aos-anchor-placement="top-bottom"
|
||||||
@@ -92,15 +94,25 @@ const BlogPostCard = ({ post, showSummary, siteInfo }) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{showPageCover && !showPreview && post?.page_cover && (
|
{showPageCover && !showPreview && post?.page_cover && (
|
||||||
<div className="flex relative duration-200 cursor-pointer transform overflow-hidden md:w-5/12 ">
|
<div className="flex overflow-hidden md:w-5/12 h-full">
|
||||||
<Link href={`${BLOG.SUB_PATH}/${post.slug}`} passHref legacyBehavior>
|
<Link href={`${BLOG.SUB_PATH}/${post.slug}`} passHref legacyBehavior>
|
||||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
<img
|
{/* <img
|
||||||
src={post?.page_cover}
|
src={post?.page_cover}
|
||||||
alt={post.title}
|
alt={post.title}
|
||||||
className="h-full w-full hover:scale-125 transform object-cover duration-500"
|
className="w-full cursor-pointer object-cover duration-200 hover:scale-125 "
|
||||||
/>
|
/> */}
|
||||||
{/* <Image className='hover:scale-125 transform duration-500' src={post?.page_cover} alt={post.title} layout='fill' objectFit='cover' loading='lazy' /> */}
|
<div className='relative w-full h-full'>
|
||||||
|
<Image
|
||||||
|
className='hover:scale-125 transition cursor-pointer duration-500'
|
||||||
|
src={post?.page_cover}
|
||||||
|
alt={post.title}
|
||||||
|
quality={30}
|
||||||
|
placeholder='blur'
|
||||||
|
blurDataURL='/bg_image.jpg'
|
||||||
|
style={{ objectFit: 'cover' }}
|
||||||
|
fill/>
|
||||||
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import Image from 'next/image'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import Typed from 'typed.js'
|
import Typed from 'typed.js'
|
||||||
import CONFIG_HEXO from '../config_hexo'
|
import CONFIG_HEXO from '../config_hexo'
|
||||||
@@ -45,7 +46,7 @@ const Header = props => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
function updateHeaderHeight () {
|
function updateHeaderHeight() {
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
const wrapperElement = document.getElementById('wrapper')
|
const wrapperElement = document.getElementById('wrapper')
|
||||||
wrapperTop = wrapperElement?.offsetTop
|
wrapperTop = wrapperElement?.offsetTop
|
||||||
@@ -53,32 +54,36 @@ const Header = props => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header
|
<header
|
||||||
id="header"
|
id="header"
|
||||||
className="md:bg-fixed w-full bg-cover bg-center h-screen bg-black text-white relative z-10"
|
className="w-full h-screen bg-black text-white relative"
|
||||||
style={{
|
>
|
||||||
backgroundImage:
|
<div className='w-full h-full'>
|
||||||
`linear-gradient(rgba(0, 0, 0, 0.9), rgba(0,0,0,0.5), rgba(0,0,0,0.3), rgba(0,0,0,0.5), rgba(0, 0, 0, 0.9) ),url("${siteInfo?.pageCover}")`
|
<Image src={siteInfo.pageCover} fill
|
||||||
}}
|
style={{ objectFit: 'cover' }}
|
||||||
>
|
className='opacity-70'
|
||||||
<div className="absolute flex flex-col h-full items-center justify-center w-full ">
|
placeholder='blur'
|
||||||
<div className='text-4xl md:text-5xl text-white shadow-text'>{siteInfo?.title}</div>
|
blurDataURL='/bg_image.jpg' />
|
||||||
<div className='mt-2 h-12 items-center text-center shadow-text text-white text-lg'>
|
</div>
|
||||||
<span id='typed'/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 首页导航插件 */}
|
<div className="absolute bottom-0 flex flex-col h-full items-center justify-center w-full ">
|
||||||
{ CONFIG_HEXO.HOME_NAV_BUTTONS && <NavButtonGroup {...props}/>}
|
<div className='text-4xl md:text-5xl text-white shadow-text'>{siteInfo?.title}</div>
|
||||||
|
<div className='mt-2 h-12 items-center text-center shadow-text text-white text-lg'>
|
||||||
|
<span id='typed' />
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
{/* 首页导航插件 */}
|
||||||
|
{CONFIG_HEXO.HOME_NAV_BUTTONS && <NavButtonGroup {...props} />}
|
||||||
|
|
||||||
<div
|
</div>
|
||||||
onClick={() => { window.scrollTo({ top: wrapperTop, behavior: 'smooth' }) }}
|
|
||||||
className="cursor-pointer w-full text-center py-4 text-3xl absolute bottom-10 text-white"
|
<div
|
||||||
>
|
onClick={() => { window.scrollTo({ top: wrapperTop, behavior: 'smooth' }) }}
|
||||||
<i className='animate-bounce fas fa-angle-down'/>
|
className="cursor-pointer w-full text-center py-4 text-3xl absolute bottom-10 text-white"
|
||||||
</div>
|
>
|
||||||
</header>
|
<i className='animate-bounce fas fa-angle-down' />
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,12 +109,12 @@ const scrollTrigger = () => {
|
|||||||
) {
|
) {
|
||||||
autoScroll = true
|
autoScroll = true
|
||||||
window.scrollTo({ top: wrapperTop, behavior: 'smooth' })
|
window.scrollTo({ top: wrapperTop, behavior: 'smooth' })
|
||||||
requestAnimationFrame(autoScrollEnd)
|
autoScrollEnd()
|
||||||
}
|
}
|
||||||
if ((scrollS < windowTop) && (scrollS < window.innerHeight) && !autoScroll) {
|
if ((scrollS < windowTop) && (scrollS < window.innerHeight) && !autoScroll) {
|
||||||
autoScroll = true
|
autoScroll = true
|
||||||
window.scrollTo({ top: 0, behavior: 'smooth' })
|
window.scrollTo({ top: 0, behavior: 'smooth' })
|
||||||
requestAnimationFrame(autoScrollEnd)
|
autoScrollEnd()
|
||||||
}
|
}
|
||||||
windowTop = scrollS
|
windowTop = scrollS
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
|
import Image from 'next/image'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
@@ -19,46 +20,51 @@ const LatestPostsGroup = ({ latestPosts, siteInfo }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<div className=" mb-2 px-1 flex flex-nowrap justify-between">
|
<div className=" mb-2 px-1 flex flex-nowrap justify-between">
|
||||||
<div>
|
|
||||||
<i className="mr-2 fas fas fa-history" />
|
|
||||||
{locale.COMMON.LATEST_POSTS}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{latestPosts.map(post => {
|
|
||||||
const selected = currentPath === `${BLOG.SUB_PATH}/${post.slug}`
|
|
||||||
const headerImage = post?.page_cover
|
|
||||||
? `url("${post.page_cover}")`
|
|
||||||
: `url("${siteInfo?.pageCover}")`
|
|
||||||
|
|
||||||
return (
|
|
||||||
(<Link
|
|
||||||
key={post.id}
|
|
||||||
title={post.title}
|
|
||||||
href={`${BLOG.SUB_PATH}/${post.slug}`}
|
|
||||||
passHref
|
|
||||||
className={'my-2 flex'}>
|
|
||||||
|
|
||||||
<div
|
|
||||||
className="w-20 h-16 bg-cover bg-center bg-no-repeat"
|
|
||||||
style={{ backgroundImage: headerImage }}
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
(selected ? ' text-indigo-400 ' : 'dark:text-gray-400 ') +
|
|
||||||
' text-sm overflow-x-hidden hover:text-indigo-600 px-2 duration-200 w-full rounded ' +
|
|
||||||
' hover:text-indigo-400 cursor-pointer items-center flex'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div>
|
<div>
|
||||||
<div className='text-line-2'>{post.title}</div>
|
<i className="mr-2 fas fas fa-history" />
|
||||||
<div className="text-gray-500">{post.lastEditedTime}</div>
|
{locale.COMMON.LATEST_POSTS}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{latestPosts.map(post => {
|
||||||
|
const selected = currentPath === `${BLOG.SUB_PATH}/${post.slug}`
|
||||||
|
|
||||||
</Link>)
|
const headerImage = post?.page_cover ? post.page_cover : siteInfo?.pageCover
|
||||||
)
|
|
||||||
})}
|
return (
|
||||||
</>
|
(<Link
|
||||||
|
key={post.id}
|
||||||
|
title={post.title}
|
||||||
|
href={`${BLOG.SUB_PATH}/${post.slug}`}
|
||||||
|
passHref
|
||||||
|
className={'my-2 flex'}>
|
||||||
|
|
||||||
|
<div className="w-20 h-16 overflow-hidden relative">
|
||||||
|
<Image
|
||||||
|
src={headerImage}
|
||||||
|
fill
|
||||||
|
style={{ objectFit: 'cover' }}
|
||||||
|
placeholder='blur'
|
||||||
|
blurDataURL='/bg_image.jpg'
|
||||||
|
quality={10}
|
||||||
|
alt={post.title} />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
(selected ? ' text-indigo-400 ' : 'dark:text-gray-400 ') +
|
||||||
|
' text-sm overflow-x-hidden hover:text-indigo-600 px-2 duration-200 w-full rounded ' +
|
||||||
|
' hover:text-indigo-400 cursor-pointer items-center flex'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div className='text-line-2'>{post.title}</div>
|
||||||
|
<div className="text-gray-500">{post.lastEditedTime}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</Link>)
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
export default LatestPostsGroup
|
export default LatestPostsGroup
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ const TopNav = props => {
|
|||||||
nav && nav.classList.replace('transparent', 'dark:bg-hexo-black-gray')
|
nav && nav.classList.replace('transparent', 'dark:bg-hexo-black-gray')
|
||||||
}
|
}
|
||||||
|
|
||||||
const showNav = scrollS <= windowTop || scrollS < 5 || (header && scrollS <= header.clientHeight)// 非首页无大图时影藏顶部 滚动条置顶时隐藏
|
const showNav = scrollS <= windowTop || scrollS < 5 || (header && scrollS <= header.clientHeight * 2)// 非首页无大图时影藏顶部 滚动条置顶时隐藏
|
||||||
if (!showNav) {
|
if (!showNav) {
|
||||||
nav && nav.classList.replace('top-0', '-top-20')
|
nav && nav.classList.replace('top-0', '-top-20')
|
||||||
windowTop = scrollS
|
windowTop = scrollS
|
||||||
|
|||||||
@@ -23,18 +23,11 @@ const LayoutBase = props => {
|
|||||||
|
|
||||||
const scrollListener = () => {
|
const scrollListener = () => {
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
// const targetRef = document.getElementById('wrapper')
|
|
||||||
// const clientHeight = targetRef?.clientHeight
|
|
||||||
const scrollY = window.pageYOffset
|
const scrollY = window.pageYOffset
|
||||||
// const fullHeight = clientHeight - window.outerHeight
|
|
||||||
// let per = parseFloat(((scrollY / fullHeight) * 100).toFixed(0))
|
|
||||||
// if (per > 100) per = 100
|
|
||||||
const shouldShow = scrollY > 300
|
const shouldShow = scrollY > 300
|
||||||
console.log(scrollY)
|
|
||||||
if (shouldShow !== show) {
|
if (shouldShow !== show) {
|
||||||
switchShow(shouldShow)
|
switchShow(shouldShow)
|
||||||
}
|
}
|
||||||
// changePercent(per)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import Link from 'next/link'
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import TagItemMini from './TagItemMini'
|
import TagItemMini from './TagItemMini'
|
||||||
import CONFIG_MATERY from '../config_matery'
|
import CONFIG_MATERY from '../config_matery'
|
||||||
|
import Image from 'next/image'
|
||||||
|
|
||||||
const BlogPostCard = ({ post, showSummary, siteInfo }) => {
|
const BlogPostCard = ({ post, showSummary, siteInfo }) => {
|
||||||
const showPreview = CONFIG_MATERY.POST_LIST_PREVIEW && post.blockMap
|
const showPreview = CONFIG_MATERY.POST_LIST_PREVIEW && post.blockMap
|
||||||
@@ -14,7 +15,7 @@ const BlogPostCard = ({ post, showSummary, siteInfo }) => {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-aos="zoom-in"
|
data-aos="zoom-in"
|
||||||
data-aos-duration="300"
|
data-aos-duration="200"
|
||||||
data-aos-once="false"
|
data-aos-once="false"
|
||||||
data-aos-anchor-placement="top-bottom"
|
data-aos-anchor-placement="top-bottom"
|
||||||
className="w-full mb-4 h-full overflow-auto shadow-md border dark:border-black rounded-xl bg-white dark:bg-hexo-black-gray">
|
className="w-full mb-4 h-full overflow-auto shadow-md border dark:border-black rounded-xl bg-white dark:bg-hexo-black-gray">
|
||||||
@@ -27,11 +28,22 @@ const BlogPostCard = ({ post, showSummary, siteInfo }) => {
|
|||||||
<Link href={`${BLOG.SUB_PATH}/${post.slug}`} passHref legacyBehavior>
|
<Link href={`${BLOG.SUB_PATH}/${post.slug}`} passHref legacyBehavior>
|
||||||
<div className="flex flex-grow w-full relative duration-200 bg-black rounded-t-md cursor-pointer transform overflow-hidden">
|
<div className="flex flex-grow w-full relative duration-200 bg-black rounded-t-md cursor-pointer transform overflow-hidden">
|
||||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
<img
|
{/* <img
|
||||||
src={post?.page_cover}
|
src={post?.page_cover}
|
||||||
alt={post.title}
|
alt={post.title}
|
||||||
className="opacity-50 h-full w-full hover:scale-125 rounded-t-md transform object-cover duration-500"
|
className="opacity-50 h-full w-full hover:scale-125 rounded-t-md transform object-cover duration-500"
|
||||||
/>
|
/> */}
|
||||||
|
<div className='relative w-full'>
|
||||||
|
<Image
|
||||||
|
className='hover:scale-125 opacity-50 transition cursor-pointer duration-500'
|
||||||
|
src={post?.page_cover}
|
||||||
|
alt={post.title}
|
||||||
|
quality={30}
|
||||||
|
placeholder='blur'
|
||||||
|
blurDataURL='/bg_image.jpg'
|
||||||
|
style={{ objectFit: 'cover' }}
|
||||||
|
fill/>
|
||||||
|
</div>
|
||||||
<span className='absolute bottom-0 left-0 text-white p-6 text-2xl replace' > {post.title}</span>
|
<span className='absolute bottom-0 left-0 text-white p-6 text-2xl replace' > {post.title}</span>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import Image from 'next/image'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import Typed from 'typed.js'
|
import Typed from 'typed.js'
|
||||||
import CONFIG_MATERY from '../config_matery'
|
import CONFIG_MATERY from '../config_matery'
|
||||||
@@ -49,9 +50,9 @@ const Header = props => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 吸附滚动,移动端关闭
|
* 吸附滚动,移动端关闭
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const scrollTrigger = () => {
|
const scrollTrigger = () => {
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
if (screen.width <= 768) {
|
if (screen.width <= 768) {
|
||||||
@@ -76,7 +77,7 @@ const Header = props => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateHeaderHeight () {
|
function updateHeaderHeight() {
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
const wrapperElement = document.getElementById('wrapper')
|
const wrapperElement = document.getElementById('wrapper')
|
||||||
wrapperTop = wrapperElement?.offsetTop
|
wrapperTop = wrapperElement?.offsetTop
|
||||||
@@ -84,26 +85,30 @@ const Header = props => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header
|
<header
|
||||||
id="header"
|
id="header"
|
||||||
className="duration-500 md:bg-fixed w-full bg-cover bg-center h-screen bg-black text-white relative z-10"
|
className="md:bg-fixed w-full h-screen bg-black text-white relative"
|
||||||
style={{
|
>
|
||||||
backgroundImage:
|
<div className='w-full h-full absolute'>
|
||||||
`linear-gradient(rgba(0, 0, 0, 0.9), rgba(0,0,0,0.5), rgba(0,0,0,0.3), rgba(0,0,0,0.5), rgba(0, 0, 0, 0.9) ),url("${siteInfo?.pageCover}")`
|
<Image src={siteInfo.pageCover} fill
|
||||||
}}
|
style={{ objectFit: 'cover' }}
|
||||||
>
|
className='opacity-70'
|
||||||
<div className="absolute flex flex-col h-full items-center justify-center w-full ">
|
placeholder='blur'
|
||||||
<div className='text-4xl md:text-5xl text-white shadow-text'>{siteInfo?.title}</div>
|
blurDataURL='/bg_image.jpg' />
|
||||||
<div className='mt-2 h-12 items-center text-center shadow-text text-white text-lg'>
|
</div>
|
||||||
<span id='typed'/>
|
|
||||||
</div>
|
|
||||||
<div onClick={() => { window.scrollTo({ top: wrapperTop, behavior: 'smooth' }) }}
|
|
||||||
className="mt-12 border cursor-pointer w-40 text-center pt-4 pb-3 text-md text-white hover:bg-orange-600 duration-300 rounded-3xl">
|
|
||||||
<i className='animate-bounce fas fa-angle-double-down'/> <span>开始阅读</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</header>
|
<div className="absolute flex flex-col h-full items-center justify-center w-full ">
|
||||||
|
<div className='text-4xl md:text-5xl text-white shadow-text'>{siteInfo?.title}</div>
|
||||||
|
<div className='mt-2 h-12 items-center text-center shadow-text text-white text-lg'>
|
||||||
|
<span id='typed' />
|
||||||
|
</div>
|
||||||
|
<div onClick={() => { window.scrollTo({ top: wrapperTop, behavior: 'smooth' }) }}
|
||||||
|
className="mt-12 border cursor-pointer w-40 text-center pt-4 pb-3 text-md text-white hover:bg-orange-600 duration-300 rounded-3xl">
|
||||||
|
<i className='animate-bounce fas fa-angle-double-down' /> <span>开始阅读</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</header>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import Image from 'next/image'
|
||||||
|
|
||||||
export default function HeaderArticle({ post, siteInfo }) {
|
export default function HeaderArticle({ post, siteInfo }) {
|
||||||
const headerImage = post?.page_cover ? post?.page_cover : siteInfo?.pageCover
|
const headerImage = post?.page_cover ? post?.page_cover : siteInfo?.pageCover
|
||||||
const title = post?.title
|
const title = post?.title
|
||||||
@@ -9,11 +11,16 @@ export default function HeaderArticle({ post, siteInfo }) {
|
|||||||
data-aos-anchor-placement="top-center"
|
data-aos-anchor-placement="top-center"
|
||||||
id='header' className="flex h-96 justify-center align-middle items-center w-full relative duration-200 bg-black">
|
id='header' className="flex h-96 justify-center align-middle items-center w-full relative duration-200 bg-black">
|
||||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
<img
|
{/* <img
|
||||||
src={headerImage}
|
src={headerImage}
|
||||||
alt={title}
|
alt={title}
|
||||||
className="opacity-50 dark:opacity-40 h-full w-full object-cover"
|
className="opacity-50 dark:opacity-40 h-full w-full object-cover"
|
||||||
/>
|
/> */}
|
||||||
|
<Image alt={title} src={headerImage} fill
|
||||||
|
style={{ objectFit: 'cover' }}
|
||||||
|
className='opacity-50'
|
||||||
|
placeholder='blur'
|
||||||
|
blurDataURL='/bg_image.jpg' />
|
||||||
<span className='absolute text-white p-6 text-3xl'>{title}</span>
|
<span className='absolute text-white p-6 text-3xl'>{title}</span>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const TopNav = props => {
|
|||||||
const scrollS = window.scrollY
|
const scrollS = window.scrollY
|
||||||
const nav = document.querySelector('#sticky-nav')
|
const nav = document.querySelector('#sticky-nav')
|
||||||
const header = document.querySelector('#header')
|
const header = document.querySelector('#header')
|
||||||
const showNav = scrollS <= windowTop || scrollS < 5 // 非首页无大图时影藏顶部 滚动条置顶时隐藏
|
const showNav = scrollS <= windowTop || scrollS < 5 || (header && scrollS <= header.clientHeight * 2)// 非首页无大图时影藏顶部 滚动条置顶时隐藏// 非首页无大图时影藏顶部 滚动条置顶时隐藏
|
||||||
// 是否将导航栏透明
|
// 是否将导航栏透明
|
||||||
const navTransparent = header && scrollS < 300 // 透明导航条的条件
|
const navTransparent = header && scrollS < 300 // 透明导航条的条件
|
||||||
|
|
||||||
|
|||||||
@@ -8,17 +8,17 @@ import { useGlobal } from '@/lib/global'
|
|||||||
import CONFIG_NEXT from '../config_next'
|
import CONFIG_NEXT from '../config_next'
|
||||||
|
|
||||||
const ShareBar = ({ post }) => {
|
const ShareBar = ({ post }) => {
|
||||||
|
const router = useRouter()
|
||||||
|
const [qrCodeShow, setQrCodeShow] = React.useState(false)
|
||||||
|
const { locale } = useGlobal()
|
||||||
if (!CONFIG_NEXT.ARTICLE_SHARE) {
|
if (!CONFIG_NEXT.ARTICLE_SHARE) {
|
||||||
return <></>
|
return <></>
|
||||||
}
|
}
|
||||||
const router = useRouter()
|
|
||||||
const shareUrl = BLOG.LINK + router.asPath
|
const shareUrl = BLOG.LINK + router.asPath
|
||||||
|
|
||||||
// 二维码悬浮
|
// 二维码悬浮
|
||||||
const [qrCodeShow, setQrCodeShow] = React.useState(false)
|
|
||||||
const btnRef = React.createRef()
|
const btnRef = React.createRef()
|
||||||
const popoverRef = React.createRef()
|
const popoverRef = React.createRef()
|
||||||
const { locale } = useGlobal()
|
|
||||||
|
|
||||||
const openPopover = () => {
|
const openPopover = () => {
|
||||||
createPopper(btnRef.current, popoverRef.current, {
|
createPopper(btnRef.current, popoverRef.current, {
|
||||||
@@ -57,7 +57,7 @@ const ShareBar = ({ post }) => {
|
|||||||
<div className='cursor-pointer text-2xl'>
|
<div className='cursor-pointer text-2xl'>
|
||||||
<a className='text-green-600' ref={btnRef} onMouseEnter={openPopover} onMouseLeave={closePopover}>
|
<a className='text-green-600' ref={btnRef} onMouseEnter={openPopover} onMouseLeave={closePopover}>
|
||||||
<i className='fab fa-weixin'/>
|
<i className='fab fa-weixin'/>
|
||||||
<div ref={popoverRef} className={(qrCodeShow ? 'animate__animated animate__fadeIn ' : 'hidden') + ' text-center py-2'}>
|
<div ref={popoverRef} className={(qrCodeShow ? 'opacity-100 ' : 'invisible opacity-0') + ' transition-all duration-200 text-center py-2'}>
|
||||||
<div className='p-2 bg-white border-0 duration-200 transform block z-40 font-normal shadow-xl mr-10'>
|
<div className='p-2 bg-white border-0 duration-200 transform block z-40 font-normal shadow-xl mr-10'>
|
||||||
<QRCode value={shareUrl} fgColor='#000000' />
|
<QRCode value={shareUrl} fgColor='#000000' />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ const CONFIG_NEXT = {
|
|||||||
WIDGET_DARK_MODE: false, // 显示日间/夜间模式切换
|
WIDGET_DARK_MODE: false, // 显示日间/夜间模式切换
|
||||||
WIDGET_TOC: true, // 移动端显示悬浮目录
|
WIDGET_TOC: true, // 移动端显示悬浮目录
|
||||||
|
|
||||||
ARTICLE_SHARE: false, // 文章分享功能
|
ARTICLE_SHARE: process.env.NEXT_PUBLIC_ARTICLE_SHARE || false, // 文章分享功能
|
||||||
ARTICLE_RELATE_POSTS: true, // 相关文章推荐
|
ARTICLE_RELATE_POSTS: true, // 相关文章推荐
|
||||||
ARTICLE_COPYRIGHT: true // 文章版权声明
|
ARTICLE_COPYRIGHT: true // 文章版权声明
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ const NavBar = props => {
|
|||||||
|
|
||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
let links = [
|
let links = [
|
||||||
{ id: 2, name: locale.NAV.RSS, to: '/feed', show: CONFIG_NOBELIUM.MENU_RSS, target: '_blank' },
|
{ id: 2, name: locale.NAV.RSS, to: '/feed', show: BLOG.ENABLE_RSS && CONFIG_NOBELIUM.MENU_RSS, target: '_blank' },
|
||||||
{ icon: 'fas fa-search', name: locale.NAV.SEARCH, to: '/search', show: CONFIG_NOBELIUM.MENU_SEARCH },
|
{ icon: 'fas fa-search', name: locale.NAV.SEARCH, to: '/search', show: CONFIG_NOBELIUM.MENU_SEARCH },
|
||||||
{ icon: 'fas fa-archive', name: locale.NAV.ARCHIVE, to: '/archive', show: CONFIG_NOBELIUM.MENU_ARCHIVE },
|
{ icon: 'fas fa-archive', name: locale.NAV.ARCHIVE, to: '/archive', show: CONFIG_NOBELIUM.MENU_ARCHIVE },
|
||||||
{ icon: 'fas fa-folder', name: locale.COMMON.CATEGORY, to: '/category', show: CONFIG_NOBELIUM.MENU_CATEGORY },
|
{ icon: 'fas fa-folder', name: locale.COMMON.CATEGORY, to: '/category', show: CONFIG_NOBELIUM.MENU_CATEGORY },
|
||||||
|
|||||||
Reference in New Issue
Block a user