mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-31 23:16:54 +00:00
Merge branch 'main' into theme-next
# Conflicts: # themes/NEXT/components/Footer.js # themes/NEXT/components/MenuButtonGroup.js
This commit is contained in:
@@ -9,10 +9,10 @@ import { delCacheData } from '@/lib/cache/cache_manager'
|
|||||||
* 获取所有文章列表
|
* 获取所有文章列表
|
||||||
* @param notionPageData
|
* @param notionPageData
|
||||||
* @param from
|
* @param from
|
||||||
* @param includePage 是否包含Page类型
|
* @param pageType 页面类型数组 ['Post','Page']
|
||||||
* @returns {Promise<*[]>}
|
* @returns {Promise<*[]>}
|
||||||
*/
|
*/
|
||||||
export async function getAllPosts ({ notionPageData, from, includePage = false }) {
|
export async function getAllPosts ({ notionPageData, from, pageType }) {
|
||||||
if (!notionPageData) {
|
if (!notionPageData) {
|
||||||
notionPageData = await getNotionPageData({ from })
|
notionPageData = await getNotionPageData({ from })
|
||||||
}
|
}
|
||||||
@@ -31,8 +31,8 @@ export async function getAllPosts ({ notionPageData, from, includePage = false }
|
|||||||
const id = pageIds[i]
|
const id = pageIds[i]
|
||||||
const properties = (await getPageProperties(id, pageBlock, schema)) || null
|
const properties = (await getPageProperties(id, pageBlock, schema)) || null
|
||||||
properties.slug = properties.slug ?? properties.id
|
properties.slug = properties.slug ?? properties.id
|
||||||
properties.createdTime = new Date(pageBlock[id].value?.created_time).toString()
|
properties.createdTime = new Date(pageBlock[id].value?.created_time).toString() // FIXME 似乎没有created_time 字段了
|
||||||
properties.lastEditedTime = new Date(pageBlock[id].value?.last_edited_time).toString()
|
properties.lastEditedTime = new Date(pageBlock[id].value?.last_edited_time).toString() // FIXME 似乎没有created_time 字段了
|
||||||
properties.fullWidth = pageBlock[id].value?.format?.page_full_width ?? false
|
properties.fullWidth = pageBlock[id].value?.format?.page_full_width ?? false
|
||||||
properties.page_cover = getPostCover(id, pageBlock) ?? null
|
properties.page_cover = getPostCover(id, pageBlock) ?? null
|
||||||
properties.content = pageBlock[id].value?.content ?? []
|
properties.content = pageBlock[id].value?.content ?? []
|
||||||
@@ -45,19 +45,7 @@ export async function getAllPosts ({ notionPageData, from, includePage = false }
|
|||||||
|
|
||||||
// remove all the the items doesn't meet requirements
|
// remove all the the items doesn't meet requirements
|
||||||
const posts = data.filter(post => {
|
const posts = data.filter(post => {
|
||||||
if (includePage) {
|
return post.title && post?.status?.[0] === 'Published' && pageType.indexOf(post?.type?.[0]) > -1
|
||||||
return (
|
|
||||||
post.title && post.slug &&
|
|
||||||
post?.status?.[0] === 'Published' &&
|
|
||||||
(post?.type?.[0] === 'Post' || post?.type?.[0] === 'Page')
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
post.title && post.slug &&
|
|
||||||
post?.status?.[0] === 'Published' &&
|
|
||||||
(post?.type?.[0] === 'Post')
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!posts || posts.length === 0) {
|
if (!posts || posts.length === 0) {
|
||||||
@@ -65,6 +53,7 @@ export async function getAllPosts ({ notionPageData, from, includePage = false }
|
|||||||
const cacheKey = 'page_block_' + BLOG.NOTION_PAGE_ID
|
const cacheKey = 'page_block_' + BLOG.NOTION_PAGE_ID
|
||||||
await delCacheData(cacheKey)
|
await delCacheData(cacheKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort by date
|
// Sort by date
|
||||||
if (BLOG.POSTS_SORT_BY === 'date') {
|
if (BLOG.POSTS_SORT_BY === 'date') {
|
||||||
posts.sort((a, b) => {
|
posts.sort((a, b) => {
|
||||||
@@ -84,3 +73,19 @@ function getPostCover (id, block) {
|
|||||||
if (pageCover.startsWith('http')) return defaultMapImageUrl(pageCover, block[id].value)
|
if (pageCover.startsWith('http')) return defaultMapImageUrl(pageCover, block[id].value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取博文总数
|
||||||
|
* @param {*} param0
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export async function getAllPostCount ({ notionPageData, from }) {
|
||||||
|
if (!notionPageData) {
|
||||||
|
notionPageData = await getNotionPageData({ from })
|
||||||
|
}
|
||||||
|
if (!notionPageData) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
const allPosts = await getAllPosts({ notionPageData, from, pageType: ['Post'] })
|
||||||
|
return allPosts?.length || 0
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { getDataFromCache, setDataToCache } from '@/lib/cache/cache_manager'
|
|||||||
import { getPostBlocks } from '@/lib/notion/getPostBlocks'
|
import { getPostBlocks } from '@/lib/notion/getPostBlocks'
|
||||||
import { idToUuid } from 'notion-utils'
|
import { idToUuid } from 'notion-utils'
|
||||||
import { getAllCategories } from './getAllCategories'
|
import { getAllCategories } from './getAllCategories'
|
||||||
import { getAllPosts } from './getAllPosts'
|
import { getAllPosts, getAllPostCount } from './getAllPosts'
|
||||||
import { getAllTags } from './getAllTags'
|
import { getAllTags } from './getAllTags'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -12,23 +12,29 @@ import { getAllTags } from './getAllTags'
|
|||||||
* @param {*} from
|
* @param {*} from
|
||||||
* @param latestPostCount 截取最新文章数量
|
* @param latestPostCount 截取最新文章数量
|
||||||
* @param tagsCount 截取标签数量
|
* @param tagsCount 截取标签数量
|
||||||
* @param includePage 是否包含PAGE类型
|
* @param pageType 过滤的文章类型,数组格式 ['Page','Post']
|
||||||
* @returns {}
|
* @returns {
|
||||||
* allPosts 所有博客
|
allPosts, 所有博客
|
||||||
* categories 所有分类
|
latestPosts,
|
||||||
* tags 所有标签
|
categories, 所有分类
|
||||||
|
postCount,
|
||||||
|
customNav, 自定义导航菜单
|
||||||
|
tags 所有标签
|
||||||
|
}
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
export async function getGlobalNotionData ({
|
export async function getGlobalNotionData ({
|
||||||
pageId = BLOG.NOTION_PAGE_ID,
|
pageId = BLOG.NOTION_PAGE_ID,
|
||||||
from,
|
from,
|
||||||
latestPostCount = 5,
|
latestPostCount = 5,
|
||||||
tagsCount = 16,
|
tagsCount = 16,
|
||||||
includePage
|
pageType = ['Post']
|
||||||
}) {
|
}) {
|
||||||
const notionPageData = await getNotionPageData({ pageId, from })
|
const notionPageData = await getNotionPageData({ pageId, from })
|
||||||
const tagOptions = notionPageData.tagOptions
|
const tagOptions = notionPageData.tagOptions
|
||||||
const allPosts = await getAllPosts({ notionPageData, from, includePage })
|
const allPosts = await getAllPosts({ notionPageData, from, pageType })
|
||||||
const postCount = allPosts?.length
|
const postCount = await getAllPostCount({ notionPageData, from })
|
||||||
|
const customNav = await getCustomNav({ notionPageData })
|
||||||
const categories = await getAllCategories(allPosts)
|
const categories = await getAllCategories(allPosts)
|
||||||
const tags = await getAllTags({ allPosts, tagOptions, sliceCount: tagsCount })
|
const tags = await getAllTags({ allPosts, tagOptions, sliceCount: tagsCount })
|
||||||
// 深拷贝
|
// 深拷贝
|
||||||
@@ -47,6 +53,7 @@ export async function getGlobalNotionData ({
|
|||||||
latestPosts,
|
latestPosts,
|
||||||
categories,
|
categories,
|
||||||
postCount,
|
postCount,
|
||||||
|
customNav,
|
||||||
tags
|
tags
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,6 +80,23 @@ export async function getNotionPageData ({ pageId, from }) {
|
|||||||
return pageRecordMap
|
return pageRecordMap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getCustomNav ({ notionPageData }) {
|
||||||
|
if (!notionPageData) {
|
||||||
|
notionPageData = await getNotionPageData({ from: 'custom-nav' })
|
||||||
|
}
|
||||||
|
if (!notionPageData) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
const allPage = await getAllPosts({ notionPageData, from: 'custom-nav', pageType: ['Page'] })
|
||||||
|
const customNav = []
|
||||||
|
if (allPage && allPage.length > 0) {
|
||||||
|
allPage.forEach(p => {
|
||||||
|
customNav.push({ icon: p.icon || null, name: p.title, to: '/' + p.slug, show: true })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return customNav
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取标签选项
|
* 获取标签选项
|
||||||
* @param schema
|
* @param schema
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ import BLOG from '@/blog.config'
|
|||||||
export function generateRss (posts) {
|
export function generateRss (posts) {
|
||||||
const year = new Date().getFullYear()
|
const year = new Date().getFullYear()
|
||||||
const feed = new Feed({
|
const feed = new Feed({
|
||||||
TITLE: BLOG.TITLE,
|
title: BLOG.TITLE,
|
||||||
DESCRIPTION: BLOG.DESCRIPTION,
|
description: BLOG.DESCRIPTION,
|
||||||
id: `${BLOG.LINK}/${BLOG.PATH}`,
|
id: `${BLOG.LINK}/${BLOG.PATH}`,
|
||||||
LINK: `${BLOG.LINK}/${BLOG.PATH}`,
|
link: `${BLOG.LINK}/${BLOG.PATH}`,
|
||||||
language: BLOG.LANG,
|
language: BLOG.LANG,
|
||||||
favicon: `${BLOG.LINK}/favicon.png`,
|
favicon: `${BLOG.LINK}/favicon.png`,
|
||||||
copyright: `All rights reserved ${year}, ${BLOG.AUTHOR}`,
|
copyright: `All rights reserved ${year}, ${BLOG.AUTHOR}`,
|
||||||
AUTHOR: {
|
author: {
|
||||||
name: BLOG.AUTHOR,
|
name: BLOG.AUTHOR,
|
||||||
email: BLOG.CONTACT_EMAIL,
|
email: BLOG.CONTACT_EMAIL,
|
||||||
link: BLOG.LINK
|
link: BLOG.LINK
|
||||||
|
|||||||
10
package.json
10
package.json
@@ -19,10 +19,6 @@
|
|||||||
"post-build": "next-sitemap --config next-sitemap.config.js"
|
"post-build": "next-sitemap --config next-sitemap.config.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.36",
|
|
||||||
"@fortawesome/free-brands-svg-icons": "^5.15.4",
|
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
|
||||||
"@fortawesome/react-fontawesome": "^0.1.16",
|
|
||||||
"@popperjs/core": "^2.9.3",
|
"@popperjs/core": "^2.9.3",
|
||||||
"animate.css": "^4.1.1",
|
"animate.css": "^4.1.1",
|
||||||
"axios": ">=0.21.1",
|
"axios": ">=0.21.1",
|
||||||
@@ -33,15 +29,15 @@
|
|||||||
"lodash.throttle": "^4.1.1",
|
"lodash.throttle": "^4.1.1",
|
||||||
"memory-cache": "^0.2.0",
|
"memory-cache": "^0.2.0",
|
||||||
"next": "^12.0.5",
|
"next": "^12.0.5",
|
||||||
"notion-client": "4.14.1",
|
"notion-client": "4.16.0",
|
||||||
"notion-utils": "4.14.1",
|
"notion-utils": "4.16.0",
|
||||||
"preact": "^10.5.15",
|
"preact": "^10.5.15",
|
||||||
"qrcode.react": "^1.0.1",
|
"qrcode.react": "^1.0.1",
|
||||||
"react": "17.0.2",
|
"react": "17.0.2",
|
||||||
"react-cookies": "^0.1.1",
|
"react-cookies": "^0.1.1",
|
||||||
"react-cusdis": "^2.1.3",
|
"react-cusdis": "^2.1.3",
|
||||||
"react-dom": "17.0.2",
|
"react-dom": "17.0.2",
|
||||||
"react-notion-x": "4.14.2",
|
"react-notion-x": "4.16.0",
|
||||||
"smoothscroll-polyfill": "^0.4.4",
|
"smoothscroll-polyfill": "^0.4.4",
|
||||||
"typed.js": "^2.0.12",
|
"typed.js": "^2.0.12",
|
||||||
"use-ackee": "^3.0.0"
|
"use-ackee": "^3.0.0"
|
||||||
|
|||||||
58
pages/[slug].js
Normal file
58
pages/[slug].js
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import BLOG from '@/blog.config'
|
||||||
|
import { getPostBlocks } from '@/lib/notion'
|
||||||
|
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
|
||||||
|
import { LayoutSlug } from '@/themes'
|
||||||
|
import Custom404 from '@/pages/404'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据notion的slug访问页面,针对类型为Page的页面
|
||||||
|
* @param {*} props
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const Slug = (props) => {
|
||||||
|
if (!props.post) {
|
||||||
|
return <Custom404 {...props} />
|
||||||
|
}
|
||||||
|
return <LayoutSlug {...props} showArticleInfo={false}/>
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getStaticPaths () {
|
||||||
|
if (!BLOG.isProd) {
|
||||||
|
return {
|
||||||
|
paths: [],
|
||||||
|
fallback: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const from = 'slug-paths'
|
||||||
|
const { allPosts } = await getGlobalNotionData({ from, pageType: ['Page'] })
|
||||||
|
return {
|
||||||
|
paths: allPosts.map(row => ({ params: { slug: row.slug } })),
|
||||||
|
fallback: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getStaticProps ({ params: { slug } }) {
|
||||||
|
const from = `slug-props-${slug}`
|
||||||
|
const { allPosts, categories, tags, postCount, latestPosts, customNav } = await getGlobalNotionData({ from, pageType: ['Page'] })
|
||||||
|
const post = allPosts.find(p => p.slug === slug)
|
||||||
|
if (!post) {
|
||||||
|
return { props: {}, revalidate: 1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
post.blockMap = await getPostBlocks(post.id, 'slug')
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
post,
|
||||||
|
tags,
|
||||||
|
categories,
|
||||||
|
postCount,
|
||||||
|
latestPosts,
|
||||||
|
customNav
|
||||||
|
},
|
||||||
|
revalidate: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Slug
|
||||||
@@ -14,9 +14,6 @@ import 'prismjs/themes/prism-okaidia.css'
|
|||||||
import 'katex/dist/katex.min.css'
|
import 'katex/dist/katex.min.css'
|
||||||
import dynamic from 'next/dynamic'
|
import dynamic from 'next/dynamic'
|
||||||
import { GlobalContextProvider } from '@/lib/global'
|
import { GlobalContextProvider } from '@/lib/global'
|
||||||
import { config } from '@fortawesome/fontawesome-svg-core'
|
|
||||||
import '@fortawesome/fontawesome-svg-core/styles.css'
|
|
||||||
config.autoAddCss = false
|
|
||||||
|
|
||||||
const Ackee = dynamic(() => import('@/components/Ackee'), { ssr: false })
|
const Ackee = dynamic(() => import('@/components/Ackee'), { ssr: false })
|
||||||
const Gtag = dynamic(() => import('@/components/Gtag'), { ssr: false })
|
const Gtag = dynamic(() => import('@/components/Gtag'), { ssr: false })
|
||||||
@@ -30,6 +27,7 @@ const MyApp = ({ Component, pageProps }) => {
|
|||||||
{BLOG.ANALYTICS_GOOGLE_ID && <Gtag />}
|
{BLOG.ANALYTICS_GOOGLE_ID && <Gtag />}
|
||||||
{JSON.parse(BLOG.ANALYTICS_BUSUANZI_ENABLE) && <Busuanzi/>}
|
{JSON.parse(BLOG.ANALYTICS_BUSUANZI_ENABLE) && <Busuanzi/>}
|
||||||
{BLOG.ADSENSE_GOOGLE_ID && <GoogleAdsense/>}
|
{BLOG.ADSENSE_GOOGLE_ID && <GoogleAdsense/>}
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" integrity="sha512-1ycn6IcaQQ40/MKBW2W4Rhis/DbILU74C1vSrLJxCq57o941Ym01SwNsOMqvEBFlcgUa6xLiPY/NS5R+E6ztJQ==" crossOrigin="anonymous" referrerPolicy="no-referrer" />
|
||||||
<Component {...pageProps} />
|
<Component {...pageProps} />
|
||||||
</GlobalContextProvider>
|
</GlobalContextProvider>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
import { getPostBlocks } from '@/lib/notion'
|
|
||||||
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
|
|
||||||
import Custom404 from '@/pages/404'
|
|
||||||
import React from 'react'
|
|
||||||
import { LayoutSlug } from '@/themes'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 关于页面,默认取notion中slug为about的文章
|
|
||||||
* @param {*} props
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
const About = (props) => {
|
|
||||||
if (!props.post) {
|
|
||||||
return <Custom404 {...props} />
|
|
||||||
}
|
|
||||||
return <LayoutSlug {...props} />
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getStaticProps () {
|
|
||||||
const from = 'about-props'
|
|
||||||
const {
|
|
||||||
allPosts,
|
|
||||||
categories,
|
|
||||||
tags,
|
|
||||||
postCount,
|
|
||||||
latestPosts
|
|
||||||
} = await getGlobalNotionData({
|
|
||||||
from,
|
|
||||||
includePage: true
|
|
||||||
})
|
|
||||||
const post = allPosts.find(p => p.slug === 'about')
|
|
||||||
|
|
||||||
if (!post) {
|
|
||||||
return {
|
|
||||||
props: {},
|
|
||||||
revalidate: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
post.blockMap = await getPostBlocks(post.id, 'slug')
|
|
||||||
|
|
||||||
const index = allPosts.indexOf(post)
|
|
||||||
const prev = allPosts.slice(index - 1, index)[0] ?? allPosts.slice(-1)[0]
|
|
||||||
const next = allPosts.slice(index + 1, index + 2)[0] ?? allPosts[0]
|
|
||||||
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
post,
|
|
||||||
tags,
|
|
||||||
prev,
|
|
||||||
next,
|
|
||||||
categories,
|
|
||||||
postCount,
|
|
||||||
latestPosts
|
|
||||||
},
|
|
||||||
revalidate: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default About
|
|
||||||
@@ -13,7 +13,7 @@ const Slug = (props) => {
|
|||||||
if (!props.post) {
|
if (!props.post) {
|
||||||
return <Custom404 {...props} />
|
return <Custom404 {...props} />
|
||||||
}
|
}
|
||||||
return <LayoutSlug {...props} />
|
return <LayoutSlug {...props} showArticleInfo={true}/>
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getStaticPaths () {
|
export async function getStaticPaths () {
|
||||||
@@ -25,7 +25,7 @@ export async function getStaticPaths () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const from = 'slug-paths'
|
const from = 'slug-paths'
|
||||||
const { allPosts } = await getGlobalNotionData({ from, includePage: true })
|
const { allPosts } = await getGlobalNotionData({ from })
|
||||||
return {
|
return {
|
||||||
paths: allPosts.map(row => ({ params: { slug: row.slug } })),
|
paths: allPosts.map(row => ({ params: { slug: row.slug } })),
|
||||||
fallback: true
|
fallback: true
|
||||||
@@ -34,8 +34,8 @@ export async function getStaticPaths () {
|
|||||||
|
|
||||||
export async function getStaticProps ({ params: { slug } }) {
|
export async function getStaticProps ({ params: { slug } }) {
|
||||||
const from = `slug-props-${slug}`
|
const from = `slug-props-${slug}`
|
||||||
const { allPosts, categories, tags, postCount, latestPosts } =
|
const { customNav, allPosts, categories, tags, postCount, latestPosts } =
|
||||||
await getGlobalNotionData({ from, includePage: true })
|
await getGlobalNotionData({ from, pageType: ['Post'] })
|
||||||
|
|
||||||
const post = allPosts.find(p => p.slug === slug)
|
const post = allPosts.find(p => p.slug === slug)
|
||||||
|
|
||||||
@@ -45,10 +45,9 @@ export async function getStaticProps ({ params: { slug } }) {
|
|||||||
|
|
||||||
post.blockMap = await getPostBlocks(post.id, 'slug')
|
post.blockMap = await getPostBlocks(post.id, 'slug')
|
||||||
|
|
||||||
const posts = allPosts.filter(post => post?.type?.[0] === 'Post')
|
const index = allPosts.indexOf(post)
|
||||||
const index = posts.indexOf(post)
|
const prev = allPosts.slice(index - 1, index)[0] ?? allPosts.slice(-1)[0]
|
||||||
const prev = posts.slice(index - 1, index)[0] ?? posts.slice(-1)[0]
|
const next = allPosts.slice(index + 1, index + 2)[0] ?? allPosts[0]
|
||||||
const next = posts.slice(index + 1, index + 2)[0] ?? posts[0]
|
|
||||||
|
|
||||||
const recommendPosts = getRecommendPost(post, allPosts)
|
const recommendPosts = getRecommendPost(post, allPosts)
|
||||||
|
|
||||||
@@ -61,29 +60,33 @@ export async function getStaticProps ({ params: { slug } }) {
|
|||||||
recommendPosts,
|
recommendPosts,
|
||||||
categories,
|
categories,
|
||||||
postCount,
|
postCount,
|
||||||
latestPosts
|
latestPosts,
|
||||||
|
customNav
|
||||||
},
|
},
|
||||||
revalidate: 1
|
revalidate: 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* 获取文章的关联推荐文章列表,目前根据标签关联性筛选
|
||||||
* @param post
|
* @param post
|
||||||
* @param {*} allPosts
|
* @param {*} allPosts
|
||||||
* @param {*} count
|
* @param {*} count
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function getRecommendPost (post, allPosts, count = 5) {
|
function getRecommendPost (post, allPosts, count = 5) {
|
||||||
let filteredPosts = Object.create(allPosts)
|
let filteredPosts = []
|
||||||
// 筛选同标签
|
for (const i in allPosts) {
|
||||||
|
const p = allPosts[i]
|
||||||
|
filteredPosts.push(Object.assign(p))
|
||||||
|
}
|
||||||
|
|
||||||
if (post.tags && post.tags.length) {
|
if (post.tags && post.tags.length) {
|
||||||
const currentTag = post.tags[0]
|
const currentTag = post.tags[0]
|
||||||
filteredPosts = filteredPosts.filter(
|
filteredPosts = filteredPosts.filter(
|
||||||
p => p && p.tags && p.tags.includes(currentTag) && p.slug !== post.slug && p.type === 'post'
|
p => p && p.slug !== post.slug && p.tags && p.tags?.includes(currentTag) && p.type === ['Post']
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
shuffleSort(filteredPosts)
|
|
||||||
|
|
||||||
// 筛选前5个
|
// 筛选前5个
|
||||||
if (filteredPosts.length > count) {
|
if (filteredPosts.length > count) {
|
||||||
@@ -92,21 +95,4 @@ function getRecommendPost (post, allPosts, count = 5) {
|
|||||||
return filteredPosts
|
return filteredPosts
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 洗牌乱序:从数组的最后位置开始,从前面随机一个位置,对两个数进行交换,直到循环完毕
|
|
||||||
* @param arr
|
|
||||||
* @returns {*}
|
|
||||||
*/
|
|
||||||
function shuffleSort (arr) {
|
|
||||||
let i = arr.length - 1
|
|
||||||
while (i > 0) {
|
|
||||||
const rIndex = Math.floor(Math.random() * i)
|
|
||||||
const temp = arr[rIndex]
|
|
||||||
arr[rIndex] = arr[i]
|
|
||||||
arr[i] = temp
|
|
||||||
i--
|
|
||||||
}
|
|
||||||
return arr
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Slug
|
export default Slug
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const Index = (props) => {
|
|||||||
|
|
||||||
export async function getStaticProps () {
|
export async function getStaticProps () {
|
||||||
const from = 'index'
|
const from = 'index'
|
||||||
const { allPosts, latestPosts, categories, tags, postCount } = await getGlobalNotionData({ from })
|
const { allPosts, latestPosts, categories, tags, postCount, customNav } = await getGlobalNotionData({ from, pageType: ['Post'] })
|
||||||
const meta = {
|
const meta = {
|
||||||
title: `${BLOG.TITLE}`,
|
title: `${BLOG.TITLE}`,
|
||||||
description: BLOG.DESCRIPTION,
|
description: BLOG.DESCRIPTION,
|
||||||
@@ -45,7 +45,8 @@ export async function getStaticProps () {
|
|||||||
postCount,
|
postCount,
|
||||||
tags,
|
tags,
|
||||||
categories,
|
categories,
|
||||||
meta
|
meta,
|
||||||
|
customNav
|
||||||
},
|
},
|
||||||
revalidate: 1
|
revalidate: 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export async function getStaticProps () {
|
|||||||
tags,
|
tags,
|
||||||
postCount,
|
postCount,
|
||||||
latestPosts
|
latestPosts
|
||||||
} = await getGlobalNotionData({ from: 'search-props' })
|
} = await getGlobalNotionData({ from: 'search-props', pageType: ['Post'] })
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
posts: allPosts,
|
posts: allPosts,
|
||||||
|
|||||||
@@ -50,10 +50,7 @@ function getTagNames (tags) {
|
|||||||
|
|
||||||
export async function getStaticPaths () {
|
export async function getStaticPaths () {
|
||||||
const from = 'tag-static-path'
|
const from = 'tag-static-path'
|
||||||
const { tags } = await getGlobalNotionData({
|
const { tags } = await getGlobalNotionData({ from, tagsCount: 0 })
|
||||||
from,
|
|
||||||
tagsCount: 0
|
|
||||||
})
|
|
||||||
const tagNames = getTagNames(tags)
|
const tagNames = getTagNames(tags)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -8,16 +8,7 @@ const TagIndex = (props) => {
|
|||||||
|
|
||||||
export async function getStaticProps () {
|
export async function getStaticProps () {
|
||||||
const from = 'tag-index-props'
|
const from = 'tag-index-props'
|
||||||
const {
|
const { categories, tags, postCount, latestPosts } = await getGlobalNotionData({ from, tagsCount: 0 })
|
||||||
categories,
|
|
||||||
tags,
|
|
||||||
postCount,
|
|
||||||
latestPosts
|
|
||||||
} = await getGlobalNotionData({
|
|
||||||
from,
|
|
||||||
includePage: false,
|
|
||||||
tagsCount: 0
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import LayoutBase from '../Hexo/LayoutBase'
|
import LayoutBase from '../Empty/LayoutBase'
|
||||||
|
|
||||||
export const LayoutPage = (props) => {
|
export const LayoutPage = (props) => {
|
||||||
const { page } = props
|
const { page } = props
|
||||||
|
|||||||
@@ -20,17 +20,13 @@ const LayoutBase = (props) => {
|
|||||||
const {
|
const {
|
||||||
children,
|
children,
|
||||||
headerSlot,
|
headerSlot,
|
||||||
tags,
|
meta
|
||||||
meta,
|
|
||||||
currentCategory,
|
|
||||||
currentTag,
|
|
||||||
categories
|
|
||||||
} = props
|
} = props
|
||||||
return (<>
|
return (<>
|
||||||
<CommonHead meta={meta} />
|
<CommonHead meta={meta} />
|
||||||
<TopNav {...props}/>
|
<TopNav {...props}/>
|
||||||
<div className='flex'>
|
<div className='flex'>
|
||||||
<AsideLeft tags={tags} currentTag={currentTag} categories={categories} currentCategory={currentCategory}/>
|
<AsideLeft {...props}/>
|
||||||
<main id='wrapper' className='flex w-full py-8 justify-center'>
|
<main id='wrapper' className='flex w-full py-8 justify-center'>
|
||||||
<div className='2xl:max-w-6xl md:max-w-3xl w-full'>
|
<div className='2xl:max-w-6xl md:max-w-3xl w-full'>
|
||||||
<div> {headerSlot} </div>
|
<div> {headerSlot} </div>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { faFolder, faTh } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import LayoutBase from './LayoutBase'
|
import LayoutBase from './LayoutBase'
|
||||||
|
|
||||||
@@ -16,14 +14,14 @@ export const LayoutCategoryIndex = (props) => {
|
|||||||
return <LayoutBase {...props} meta={meta}>
|
return <LayoutBase {...props} meta={meta}>
|
||||||
<div className='bg-white dark:bg-gray-700 px-10 py-10 shadow'>
|
<div className='bg-white dark:bg-gray-700 px-10 py-10 shadow'>
|
||||||
<div className='dark:text-gray-200 mb-5'>
|
<div className='dark:text-gray-200 mb-5'>
|
||||||
<FontAwesomeIcon icon={faTh} className='mr-4' />{locale.COMMON.CATEGORY}:
|
<i className='mr-4 fas fa-th' />{locale.COMMON.CATEGORY}:
|
||||||
</div>
|
</div>
|
||||||
<div id='category-list' className='duration-200 flex flex-wrap'>
|
<div id='category-list' className='duration-200 flex flex-wrap'>
|
||||||
{Object.keys(categories).map(category => {
|
{Object.keys(categories).map(category => {
|
||||||
return <Link key={category} href={`/category/${category}`} passHref>
|
return <Link key={category} href={`/category/${category}`} passHref>
|
||||||
<div
|
<div
|
||||||
className={'hover:text-black dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600 px-5 cursor-pointer py-2 hover:bg-gray-100'}>
|
className={'hover:text-black dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600 px-5 cursor-pointer py-2 hover:bg-gray-100'}>
|
||||||
<FontAwesomeIcon icon={faFolder} className='mr-4' />{category}({categories[category]})
|
<i className='mr-4 fas fa-folder' />{category}({categories[category]})
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
|
import { getPageTableOfContents } from 'notion-utils'
|
||||||
import 'prismjs'
|
import 'prismjs'
|
||||||
import 'prismjs/components/prism-bash'
|
import 'prismjs/components/prism-bash'
|
||||||
import 'prismjs/components/prism-javascript'
|
import 'prismjs/components/prism-javascript'
|
||||||
@@ -17,6 +18,11 @@ export const LayoutSlug = (props) => {
|
|||||||
tags: post.tags
|
tags: post.tags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (post?.blockMap?.block) {
|
||||||
|
post.content = Object.keys(post.blockMap.block)
|
||||||
|
post.toc = getPageTableOfContents(post, post.blockMap)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutBase meta={meta} {...props} >
|
<LayoutBase meta={meta} {...props} >
|
||||||
<ArticleDetail {...props} />
|
<ArticleDetail {...props} />
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { faTag } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import TagItem from './components/TagItem'
|
import TagItem from './components/TagItem'
|
||||||
import LayoutBase from './LayoutBase'
|
import LayoutBase from './LayoutBase'
|
||||||
|
|
||||||
@@ -16,7 +14,7 @@ export const LayoutTagIndex = (props) => {
|
|||||||
|
|
||||||
return <LayoutBase {...props} meta={meta}>
|
return <LayoutBase {...props} meta={meta}>
|
||||||
<div className='bg-white dark:bg-gray-700 px-10 py-10 shadow'>
|
<div className='bg-white dark:bg-gray-700 px-10 py-10 shadow'>
|
||||||
<div className='dark:text-gray-200 mb-5'><FontAwesomeIcon icon={faTag} className='mr-4'/>{locale.COMMON.TAGS}:</div>
|
<div className='dark:text-gray-200 mb-5'><i className='mr-4 fas fa-tag'/>{locale.COMMON.TAGS}:</div>
|
||||||
<div id='tags-list' className='duration-200 flex flex-wrap'>
|
<div id='tags-list' className='duration-200 flex flex-wrap'>
|
||||||
{ tags.map(tag => {
|
{ tags.map(tag => {
|
||||||
return <div key={tag.name} className='p-2'><TagItem key={tag.name} tag={tag} /></div>
|
return <div key={tag.name} className='p-2'><TagItem key={tag.name} tag={tag} /></div>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faAngleDoubleLeft, faAngleDoubleRight } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上一篇,下一篇文章
|
* 上一篇,下一篇文章
|
||||||
@@ -14,12 +12,12 @@ export default function ArticleAround ({ prev, next }) {
|
|||||||
return <section className='text-gray-800 h-28 flex items-center justify-between space-x-5 my-4'>
|
return <section className='text-gray-800 h-28 flex items-center justify-between space-x-5 my-4'>
|
||||||
<Link href={`/article/${prev.slug}`} passHref>
|
<Link href={`/article/${prev.slug}`} passHref>
|
||||||
<a className='text-sm cursor-pointer justify-center items-center flex w-full h-full bg-gray-400 bg-opacity-40 hover:bg-gray-700 hover:text-white duration-300'>
|
<a className='text-sm cursor-pointer justify-center items-center flex w-full h-full bg-gray-400 bg-opacity-40 hover:bg-gray-700 hover:text-white duration-300'>
|
||||||
<FontAwesomeIcon icon={faAngleDoubleLeft} className='mr-1' />{prev.title}
|
<i className='mr-1 fas fa-angle-double-left' />{prev.title}
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
<Link href={`/article/${next.slug}`} passHref>
|
<Link href={`/article/${next.slug}`} passHref>
|
||||||
<a className='text-sm cursor-pointer justify-center items-center flex w-full h-full bg-gray-400 bg-opacity-40 hover:bg-gray-700 hover:text-white duration-300'>{next.title}
|
<a className='text-sm cursor-pointer justify-center items-center flex w-full h-full bg-gray-400 bg-opacity-40 hover:bg-gray-700 hover:text-white duration-300'>{next.title}
|
||||||
<FontAwesomeIcon icon={faAngleDoubleRight} className='ml-1 my-1' />
|
<i className='ml-1 my-1 fas fa-angle-double-right' />
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import Comment from '@/components/Comment'
|
import Comment from '@/components/Comment'
|
||||||
import formatDate from '@/lib/formatDate'
|
import formatDate from '@/lib/formatDate'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { faEye, faFolderOpen } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import mediumZoom from 'medium-zoom'
|
import mediumZoom from 'medium-zoom'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import 'prismjs'
|
import 'prismjs'
|
||||||
@@ -64,7 +62,7 @@ export default function ArticleDetail ({ post, recommendPosts, prev, next }) {
|
|||||||
<div>
|
<div>
|
||||||
<Link href={`/category/${post.category}`} passHref>
|
<Link href={`/category/${post.category}`} passHref>
|
||||||
<a className="cursor-pointer text-md mr-2 hover:text-black dark:hover:text-white border-b dark:border-gray-500 border-dashed">
|
<a className="cursor-pointer text-md mr-2 hover:text-black dark:hover:text-white border-b dark:border-gray-500 border-dashed">
|
||||||
<FontAwesomeIcon icon={faFolderOpen} className="mr-1" />
|
<i className="mr-1 fas fa-folder-open" />
|
||||||
{post.category}
|
{post.category}
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
@@ -83,7 +81,7 @@ export default function ArticleDetail ({ post, recommendPosts, prev, next }) {
|
|||||||
</>)}
|
</>)}
|
||||||
|
|
||||||
<div className="hidden busuanzi_container_page_pv font-light mr-2">
|
<div className="hidden busuanzi_container_page_pv font-light mr-2">
|
||||||
<FontAwesomeIcon icon={faEye} className='mr-1'/>
|
<i className='mr-1 fas fa-eye'/>
|
||||||
|
|
||||||
<span className="mr-2 busuanzi_value_page_pv"/>
|
<span className="mr-2 busuanzi_value_page_pv"/>
|
||||||
<span className='mr-2'>|</span>
|
<span className='mr-2'>|</span>
|
||||||
|
|||||||
@@ -5,15 +5,18 @@ import GroupMenu from './GroupMenu'
|
|||||||
import GroupTag from './GroupTag'
|
import GroupTag from './GroupTag'
|
||||||
import SearchInput from './SearchInput'
|
import SearchInput from './SearchInput'
|
||||||
import SiteInfo from './SiteInfo'
|
import SiteInfo from './SiteInfo'
|
||||||
|
import Catalog from './Catalog'
|
||||||
|
|
||||||
|
function AsideLeft (props) {
|
||||||
|
const { tags, currentTag, categories, currentCategory, post } = props
|
||||||
|
console.log(post)
|
||||||
|
|
||||||
function AsideLeft ({ tags, currentTag, categories, currentCategory }) {
|
|
||||||
return <div className='w-72 bg-white min-h-screen px-10 py-14 hidden lg:block'>
|
return <div className='w-72 bg-white min-h-screen px-10 py-14 hidden lg:block'>
|
||||||
|
|
||||||
<Logo />
|
<Logo />
|
||||||
|
|
||||||
<section className='flex flex-col text-gray-600'>
|
<section className='flex flex-col text-gray-600'>
|
||||||
<hr className='w-12 my-8' />
|
<hr className='w-12 my-8' />
|
||||||
<GroupMenu/>
|
<GroupMenu {...props}/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className='flex flex-col text-gray-600'>
|
<section className='flex flex-col text-gray-600'>
|
||||||
@@ -41,6 +44,10 @@ function AsideLeft ({ tags, currentTag, categories, currentCategory }) {
|
|||||||
<SiteInfo/>
|
<SiteInfo/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section className='sticky top-0 pt-12'>
|
||||||
|
<Catalog toc={post?.toc}/>
|
||||||
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
81
themes/Fukasawa/components/Catalog.js
Normal file
81
themes/Fukasawa/components/Catalog.js
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import throttle from 'lodash.throttle'
|
||||||
|
import { uuidToId } from 'notion-utils'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 目录导航组件
|
||||||
|
* @param toc
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
const Catalog = ({ toc }) => {
|
||||||
|
// 无目录就直接返回空
|
||||||
|
if (!toc || toc.length < 1) {
|
||||||
|
return <></>
|
||||||
|
}
|
||||||
|
// 监听滚动事件
|
||||||
|
React.useEffect(() => {
|
||||||
|
window.addEventListener('scroll', actionSectionScrollSpy)
|
||||||
|
actionSectionScrollSpy()
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('scroll', actionSectionScrollSpy)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
// 同步选中目录事件
|
||||||
|
const [activeSection, setActiveSection] = React.useState(null)
|
||||||
|
const throttleMs = 100
|
||||||
|
const actionSectionScrollSpy = React.useCallback(throttle(() => {
|
||||||
|
const sections = document.getElementsByClassName('notion-h')
|
||||||
|
let prevBBox = null
|
||||||
|
let currentSectionId = activeSection
|
||||||
|
for (let i = 0; i < sections.length; ++i) {
|
||||||
|
const section = sections[i]
|
||||||
|
if (!section || !(section instanceof Element)) continue
|
||||||
|
if (!currentSectionId) {
|
||||||
|
currentSectionId = section.getAttribute('data-id')
|
||||||
|
}
|
||||||
|
const bbox = section.getBoundingClientRect()
|
||||||
|
const prevHeight = prevBBox ? bbox.top - prevBBox.bottom : 0
|
||||||
|
const offset = Math.max(150, prevHeight / 4)
|
||||||
|
// GetBoundingClientRect returns values relative to viewport
|
||||||
|
if (bbox.top - offset < 0) {
|
||||||
|
currentSectionId = section.getAttribute('data-id')
|
||||||
|
prevBBox = bbox
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// No need to continue loop, if last element has been detected
|
||||||
|
break
|
||||||
|
}
|
||||||
|
setActiveSection(currentSectionId)
|
||||||
|
}, throttleMs))
|
||||||
|
|
||||||
|
return <div>
|
||||||
|
<div className='w-full'><i className='mr-1 fas fa-stream' /> 目录</div>
|
||||||
|
<nav className='font-sans overflow-y-auto scroll-hidden text-black'>
|
||||||
|
{toc.map((tocItem) => {
|
||||||
|
const id = uuidToId(tocItem.id)
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
key={id}
|
||||||
|
href={`#${id}`}
|
||||||
|
className={`notion-table-of-contents-item duration-300 transform font-light
|
||||||
|
notion-table-of-contents-item-indent-level-${tocItem.indentLevel} `}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
display: 'inline-block',
|
||||||
|
marginLeft: tocItem.indentLevel * 16
|
||||||
|
}}
|
||||||
|
className={`${activeSection === id && ' font-bold text-red-400 underline'}`}
|
||||||
|
>
|
||||||
|
{tocItem.text}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Catalog
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
import { faFolder, faFolderOpen } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
@@ -17,7 +15,7 @@ function GroupCategory ({ currentCategory, categories }) {
|
|||||||
? 'hover:text-white dark:hover:text-white bg-gray-600 text-white '
|
? 'hover:text-white dark:hover:text-white bg-gray-600 text-white '
|
||||||
: 'dark:text-gray-400 text-gray-500 hover:text-white hover:bg-gray-500 dark:hover:text-white') +
|
: 'dark:text-gray-400 text-gray-500 hover:text-white hover:bg-gray-500 dark:hover:text-white') +
|
||||||
' text-sm w-full items-center duration-300 px-2 cursor-pointer py-1 font-light'}>
|
' text-sm w-full items-center duration-300 px-2 cursor-pointer py-1 font-light'}>
|
||||||
<FontAwesomeIcon icon={selected ? faFolderOpen : faFolder} className={`${selected ? 'text-white' : 'text-gray-400'} mr-2`} />{category}({categories[category]})
|
<i className={`${selected ? 'text-white fa-folder-open' : 'fa-folder text-gray-400'} fas mr-2`} />{category}({categories[category]})
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -4,22 +4,26 @@ import { useRouter } from 'next/router'
|
|||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import CONFIG_FUKA from '../config_fuka'
|
import CONFIG_FUKA from '../config_fuka'
|
||||||
|
|
||||||
function GroupMenu () {
|
function GroupMenu ({ customNav }) {
|
||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const links = [
|
let links = [
|
||||||
{ id: 0, name: locale.NAV.INDEX, to: '/' || '/', show: true },
|
{ name: locale.NAV.INDEX, to: '/' || '/', show: true },
|
||||||
{ id: 1, name: locale.COMMON.CATEGORY, to: '/category', show: CONFIG_FUKA.MENU_CATEGORY },
|
{ name: locale.COMMON.CATEGORY, to: '/category', show: CONFIG_FUKA.MENU_CATEGORY },
|
||||||
{ id: 2, name: locale.COMMON.TAGS, to: '/tag', show: CONFIG_FUKA.MENU_TAG },
|
{ name: locale.COMMON.TAGS, to: '/tag', show: CONFIG_FUKA.MENU_TAG },
|
||||||
{ id: 3, name: locale.NAV.ARCHIVE, to: '/archive', show: CONFIG_FUKA.MENU_ARCHIVE },
|
{ name: locale.NAV.ARCHIVE, to: '/archive', show: CONFIG_FUKA.MENU_ARCHIVE }
|
||||||
{ id: 4, name: locale.NAV.ABOUT, to: '/about', show: CONFIG_FUKA.MENU_ABOUT }
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if (customNav) {
|
||||||
|
links = links.concat(customNav)
|
||||||
|
}
|
||||||
|
|
||||||
return <nav id='nav' className='font-sans text-sm'>
|
return <nav id='nav' className='font-sans text-sm'>
|
||||||
{links.map(link => {
|
{links.map(link => {
|
||||||
if (link.show) {
|
if (link.show) {
|
||||||
const selected = (router.pathname === link.to) || (router.asPath === link.to)
|
const selected = (router.pathname === link.to) || (router.asPath === link.to)
|
||||||
return <Link key={`${link.id}-${link.to}`} title={link.to} href={link.to} >
|
return <Link key={`${link.to}`} title={link.to} href={link.to} >
|
||||||
<a className={'py-0.5 duration-500 justify-between text-gray-500 hover:text-black cursor-pointer flex flex-nowrap items-center ' +
|
<a className={'py-0.5 duration-500 justify-between text-gray-500 hover:text-black cursor-pointer flex flex-nowrap items-center ' +
|
||||||
(selected ? 'text-black' : ' ')} >
|
(selected ? 'text-black' : ' ')} >
|
||||||
<div className='my-auto items-center justify-center flex '>
|
<div className='my-auto items-center justify-center flex '>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useImperativeHandle, useRef, useState } from 'react'
|
import { useImperativeHandle, useRef, useState } from 'react'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faSearch, faSpinner, faTimes } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
|
|
||||||
const SearchInput = ({ currentTag, currentSearch, cRef }) => {
|
const SearchInput = ({ currentTag, currentSearch, cRef }) => {
|
||||||
const [searchKey, setSearchKey] = useState(currentSearch || '')
|
const [searchKey, setSearchKey] = useState(currentSearch || '')
|
||||||
@@ -54,12 +52,12 @@ const SearchInput = ({ currentTag, currentSearch, cRef }) => {
|
|||||||
|
|
||||||
<div className='-ml-8 cursor-pointer dark:bg-gray-600 dark:hover:bg-gray-800 float-right items-center justify-center py-2'
|
<div className='-ml-8 cursor-pointer dark:bg-gray-600 dark:hover:bg-gray-800 float-right items-center justify-center py-2'
|
||||||
onClick={() => { handleSearch(searchKey) }}>
|
onClick={() => { handleSearch(searchKey) }}>
|
||||||
<FontAwesomeIcon spin={onLoading} icon={onLoading ? faSpinner : faSearch} className='hover:text-black transform duration-200 text-gray-500 cursor-pointer' />
|
<i className={`hover:text-black transform duration-200 text-gray-500 cursor-pointer fas ${onLoading ? 'fa-spinner animate-spin' : 'fa-search'}`} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{(searchKey && searchKey.length &&
|
{(searchKey && searchKey.length &&
|
||||||
<div className='-ml-12 cursor-pointer dark:bg-gray-600 dark:hover:bg-gray-800 float-right items-center justify-center py-2'>
|
<div className='-ml-12 cursor-pointer dark:bg-gray-600 dark:hover:bg-gray-800 float-right items-center justify-center py-2'>
|
||||||
<FontAwesomeIcon icon={faTimes} className='hover:text-black transform duration-200 text-gray-400 cursor-pointer' onClick={cleanSearch} />
|
<i className='hover:text-black transform duration-200 text-gray-400 cursor-pointer fas fa-times' onClick={cleanSearch} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import { faEye, faShieldAlt, faUsers } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
|
|
||||||
function SiteInfo ({ title }) {
|
function SiteInfo ({ title }) {
|
||||||
const d = new Date()
|
const d = new Date()
|
||||||
@@ -14,10 +12,10 @@ function SiteInfo ({ title }) {
|
|||||||
|
|
||||||
<span>Powered by <a href='https://github.com/tangly1024/NotionNext' className='underline font-bold text-gray-500 dark:text-gray-300'>NotionNext</a>.</span><br /></span>
|
<span>Powered by <a href='https://github.com/tangly1024/NotionNext' className='underline font-bold text-gray-500 dark:text-gray-300'>NotionNext</a>.</span><br /></span>
|
||||||
|
|
||||||
{BLOG.BEI_AN && <><FontAwesomeIcon icon={faShieldAlt} /> <a href='https://beian.miit.gov.cn/' className='mr-2'>{BLOG.BEI_AN}</a><br/></>}
|
{BLOG.BEI_AN && <><i className='fas fa-shield-alt' /> <a href='https://beian.miit.gov.cn/' className='mr-2'>{BLOG.BEI_AN}</a><br/></>}
|
||||||
|
|
||||||
<span className='hidden busuanzi_container_site_pv'> <FontAwesomeIcon icon={faEye} /><span className='px-1 busuanzi_value_site_pv'> </span> </span>
|
<span className='hidden busuanzi_container_site_pv'> <i className='fas fa-eye' /><span className='px-1 busuanzi_value_site_pv'> </span> </span>
|
||||||
<span className='pl-2 hidden busuanzi_container_site_uv'> <FontAwesomeIcon icon={faUsers} /> <span className='px-1 busuanzi_value_site_uv'> </span> </span>
|
<span className='pl-2 hidden busuanzi_container_site_uv'> <i className='fas fa-users' /> <span className='px-1 busuanzi_value_site_uv'> </span> </span>
|
||||||
<br />
|
<br />
|
||||||
<h1>{title}</h1>
|
<h1>{title}</h1>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { faTag } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
@@ -16,7 +14,7 @@ const TagItem = ({ tag, selected }) => {
|
|||||||
duration-200 mr-1 my-1 px-2 py-1 text-sm whitespace-nowrap
|
duration-200 mr-1 my-1 px-2 py-1 text-sm whitespace-nowrap
|
||||||
hover:bg-gray-200 dark:hover:bg-gray-800 `}>
|
hover:bg-gray-200 dark:hover:bg-gray-800 `}>
|
||||||
<div className='text-gray-600 dark:text-gray-300 dark:hover:text-white'>
|
<div className='text-gray-600 dark:text-gray-300 dark:hover:text-white'>
|
||||||
{selected && <FontAwesomeIcon icon={faTag} className='mr-1'/>} {`${tag.name} `} {tag.count ? `(${tag.count})` : ''}
|
{selected && <i className='mr-1 fas fa-tag'/>} {`${tag.name} `} {tag.count ? `(${tag.count})` : ''}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { faTag } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
|
||||||
const TagItemMini = ({ tag, selected = false }) => {
|
const TagItemMini = ({ tag, selected = false }) => {
|
||||||
@@ -9,7 +7,7 @@ const TagItemMini = ({ tag, selected = false }) => {
|
|||||||
${selected
|
${selected
|
||||||
? 'text-white dark:text-gray-300 bg-black dark:bg-black dark:hover:bg-gray-900'
|
? 'text-white dark:text-gray-300 bg-black dark:bg-black dark:hover:bg-gray-900'
|
||||||
: `text-gray-600 hover:shadow-xl dark:border-gray-400 notion-${tag.color}_background dark:bg-gray-800`}` }>
|
: `text-gray-600 hover:shadow-xl dark:border-gray-400 notion-${tag.color}_background dark:bg-gray-800`}` }>
|
||||||
<div className='font-light dark:text-gray-400'>{selected && <FontAwesomeIcon icon={faTag} className='mr-1'/>} {tag.name + (tag.count ? `(${tag.count})` : '')} </div>
|
<div className='font-light dark:text-gray-400'>{selected && <i className='mr-1 fas fa-tag'/>} {tag.name + (tag.count ? `(${tag.count})` : '')} </div>
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { faBars, faTimes } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import Collapse from './Collapse'
|
import Collapse from './Collapse'
|
||||||
import GroupMenu from './GroupMenu'
|
import GroupMenu from './GroupMenu'
|
||||||
@@ -10,7 +8,7 @@ import Logo from './Logo'
|
|||||||
* @param {*} param0
|
* @param {*} param0
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const TopNav = ({ tags, currentTag, categories, currentCategory, postCount }) => {
|
const TopNav = (props) => {
|
||||||
const [isOpen, changeShow] = useState(false)
|
const [isOpen, changeShow] = useState(false)
|
||||||
|
|
||||||
const toggleMenuOpen = () => {
|
const toggleMenuOpen = () => {
|
||||||
@@ -23,23 +21,21 @@ const TopNav = ({ tags, currentTag, categories, currentCategory, postCount }) =>
|
|||||||
<div id='sticky-nav' className={'lg:relative w-full top-0 z-20 transform duration-500'}>
|
<div id='sticky-nav' className={'lg:relative w-full top-0 z-20 transform duration-500'}>
|
||||||
<Collapse isOpen={isOpen}>
|
<Collapse isOpen={isOpen}>
|
||||||
<div className='bg-white py-1 px-5'>
|
<div className='bg-white py-1 px-5'>
|
||||||
<GroupMenu/>
|
<GroupMenu {...props}/>
|
||||||
</div>
|
</div>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
<div className='w-full flex justify-between items-center p-4 bg-white'>
|
<div className='w-full flex justify-between items-center p-4 bg-white'>
|
||||||
{/* 左侧LOGO 标题 */}
|
{/* 左侧LOGO 标题 */}
|
||||||
<div className='flex flex-none flex-grow-0'>
|
<div className='flex flex-none flex-grow-0'>
|
||||||
<Logo/>
|
<Logo/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='flex'>
|
<div className='flex'>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 右侧功能 */}
|
{/* 右侧功能 */}
|
||||||
<div className='mr-1 flex justify-end items-center text-sm space-x-4 font-serif dark:text-gray-200'>
|
<div className='mr-1 flex justify-end items-center text-sm space-x-4 font-serif dark:text-gray-200'>
|
||||||
<div onClick={toggleMenuOpen} className='w-18 cursor-pointer'>
|
<div onClick={toggleMenuOpen} className='w-18 cursor-pointer'>
|
||||||
菜单 { isOpen ? <FontAwesomeIcon icon={faTimes} size={'lg'}/> : <FontAwesomeIcon icon={faBars} size={'lg'}/> }
|
菜单 { isOpen ? <i className='fas fa-times'/> : <i className='fas fa-bars'/> }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import { faSpinner } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import LayoutBase from './LayoutBase'
|
import LayoutBase from './LayoutBase'
|
||||||
@@ -26,7 +24,7 @@ export const Layout404 = props => {
|
|||||||
<div className="text-black w-full h-screen text-center justify-center content-center items-center flex flex-col">
|
<div className="text-black w-full h-screen text-center justify-center content-center items-center flex flex-col">
|
||||||
<div className="dark:text-gray-200">
|
<div className="dark:text-gray-200">
|
||||||
<h2 className="inline-block border-r-2 border-gray-600 mr-2 px-3 py-2 align-top">
|
<h2 className="inline-block border-r-2 border-gray-600 mr-2 px-3 py-2 align-top">
|
||||||
<FontAwesomeIcon icon={faSpinner} spin={true} className="mr-2" />
|
<i className="mr-2 fas fa-spinner animate-spin" />
|
||||||
404
|
404
|
||||||
</h2>
|
</h2>
|
||||||
<div className="inline-block text-left h-32 leading-10 items-center">
|
<div className="inline-block text-left h-32 leading-10 items-center">
|
||||||
|
|||||||
@@ -44,9 +44,9 @@ const LayoutBase = (props) => {
|
|||||||
|
|
||||||
{headerSlot}
|
{headerSlot}
|
||||||
|
|
||||||
<main id='wrapper' className='mt-12 lg:mt-0 flex w-full justify-center py-8 min-h-screen'>
|
<main id='wrapper' className='flex w-full justify-center py-8 min-h-screen'>
|
||||||
|
|
||||||
<div id='container-inner' className='w-full mx-auto flex justify-between space-x-4 max-w-6xl'>
|
<div id='container-inner' className='pt-14 w-full mx-auto flex justify-between space-x-4 max-w-6xl'>
|
||||||
<div className='flex-grow w-full'>{children}</div>
|
<div className='flex-grow w-full'>{children}</div>
|
||||||
<SideRight {...props}/>
|
<SideRight {...props}/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { faFolder, faTh } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import Card from './components/Card'
|
import Card from './components/Card'
|
||||||
import LayoutBase from './LayoutBase'
|
import LayoutBase from './LayoutBase'
|
||||||
@@ -18,7 +16,7 @@ export const LayoutCategoryIndex = props => {
|
|||||||
<LayoutBase {...props} meta={meta}>
|
<LayoutBase {...props} meta={meta}>
|
||||||
<Card className="bg-white dark:bg-gray-700 w-full min-h-screen">
|
<Card className="bg-white dark:bg-gray-700 w-full min-h-screen">
|
||||||
<div className="dark:text-gray-200 mb-5 mx-3">
|
<div className="dark:text-gray-200 mb-5 mx-3">
|
||||||
<FontAwesomeIcon icon={faTh} className="mr-4" />
|
<i className="mr-4 fas fa-th" />
|
||||||
{locale.COMMON.CATEGORY}:
|
{locale.COMMON.CATEGORY}:
|
||||||
</div>
|
</div>
|
||||||
<div id="category-list" className="duration-200 flex flex-wrap mx-8">
|
<div id="category-list" className="duration-200 flex flex-wrap mx-8">
|
||||||
@@ -30,7 +28,7 @@ export const LayoutCategoryIndex = props => {
|
|||||||
' duration-300 dark:hover:text-white rounded-lg px-5 cursor-pointer py-2 hover:bg-blue-600 hover:text-white'
|
' duration-300 dark:hover:text-white rounded-lg px-5 cursor-pointer py-2 hover:bg-blue-600 hover:text-white'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faFolder} className="mr-4" />
|
<i className="mr-4 fas fa-folder" />
|
||||||
{category}({categories[category]})
|
{category}({categories[category]})
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { faTag } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import Card from './components/Card'
|
import Card from './components/Card'
|
||||||
import TagItemMini from './components/TagItemMini'
|
import TagItemMini from './components/TagItemMini'
|
||||||
import LayoutBase from './LayoutBase'
|
import LayoutBase from './LayoutBase'
|
||||||
@@ -18,7 +16,7 @@ export const LayoutTagIndex = props => {
|
|||||||
<LayoutBase {...props} meta={meta}>
|
<LayoutBase {...props} meta={meta}>
|
||||||
<Card className='w-full'>
|
<Card className='w-full'>
|
||||||
<div className="dark:text-gray-200 mb-5 ml-4">
|
<div className="dark:text-gray-200 mb-5 ml-4">
|
||||||
<FontAwesomeIcon icon={faTag} className="mr-4" />
|
<i className="mr-4 fas fa-tag" />
|
||||||
{locale.COMMON.TAGS}:
|
{locale.COMMON.TAGS}:
|
||||||
</div>
|
</div>
|
||||||
<div id="tags-list" className="duration-200 flex flex-wrap ml-8">
|
<div id="tags-list" className="duration-200 flex flex-wrap ml-8">
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import { faFolder } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
@@ -51,7 +49,7 @@ const BlogPostCard = ({ post, showSummary }) => {
|
|||||||
|
|
||||||
<Link href={`/category/${post.category}`} passHref>
|
<Link href={`/category/${post.category}`} passHref>
|
||||||
<a className='cursor-pointer font-light text-sm hover:underline transform'>
|
<a className='cursor-pointer font-light text-sm hover:underline transform'>
|
||||||
<FontAwesomeIcon icon={faFolder} className='mr-1' />{post.category}
|
<i className='mr-1 fas fa-folder' />{post.category}
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
<div className='md:flex-nowrap flex-wrap md:justify-start inline-block'>
|
<div className='md:flex-nowrap flex-wrap md:justify-start inline-block'>
|
||||||
|
|||||||
@@ -2,9 +2,6 @@ import React from 'react'
|
|||||||
import throttle from 'lodash.throttle'
|
import throttle from 'lodash.throttle'
|
||||||
import { uuidToId } from 'notion-utils'
|
import { uuidToId } from 'notion-utils'
|
||||||
import Progress from './Progress'
|
import Progress from './Progress'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faStream } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
// import { cs } from 'react-notion-x'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 目录导航组件
|
* 目录导航组件
|
||||||
@@ -55,7 +52,7 @@ const Catalog = ({ toc }) => {
|
|||||||
}, throttleMs))
|
}, throttleMs))
|
||||||
|
|
||||||
return <div className='px-3'>
|
return <div className='px-3'>
|
||||||
<div className='w-full'><FontAwesomeIcon className='mr-1' icon={faStream}/> 目录</div>
|
<div className='w-full'><i className='mr-1 fas fa-stream' /> 目录</div>
|
||||||
<div className='w-full py-1'>
|
<div className='w-full py-1'>
|
||||||
<Progress/>
|
<Progress/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { faFolder, faFolderOpen } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
@@ -16,7 +14,7 @@ const CategoryGroup = ({ currentCategory, categories }) => {
|
|||||||
? 'hover:text-white dark:hover:text-white bg-blue-600 text-white '
|
? 'hover:text-white dark:hover:text-white bg-blue-600 text-white '
|
||||||
: 'dark:text-gray-400 text-gray-500 hover:text-white dark:hover:text-white hover:bg-blue-600') +
|
: 'dark:text-gray-400 text-gray-500 hover:text-white dark:hover:text-white hover:bg-blue-600') +
|
||||||
' text-sm w-full items-center duration-300 px-2 cursor-pointer py-1 font-light'}>
|
' text-sm w-full items-center duration-300 px-2 cursor-pointer py-1 font-light'}>
|
||||||
<div> <FontAwesomeIcon icon={selected ? faFolderOpen : faFolder} className={'mr-2'} />{category}({categories[category]})</div>
|
<div> <i className={`mr-2 fas ${selected ? 'fa-folder-open' : 'fa-folder'}`} />{category}({categories[category]})</div>
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { faCopyright, faEye, faShieldAlt, faUsers, faHeart } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
|
|
||||||
@@ -11,16 +9,16 @@ const Footer = ({ title }) => {
|
|||||||
<footer
|
<footer
|
||||||
className='dark:bg-gray-900 flex-shrink-0 justify-center text-center m-auto w-full leading-6 text-gray-400 text-sm p-6'
|
className='dark:bg-gray-900 flex-shrink-0 justify-center text-center m-auto w-full leading-6 text-gray-400 text-sm p-6'
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faCopyright} /> {`${startYear}${currentYear}`} <span><FontAwesomeIcon icon={faHeart} className='mx-1 animate-pulse'/> <a href={BLOG.LINK} className='underline font-bold text-gray-500 dark:text-gray-300 '>{BLOG.AUTHOR}</a>.
|
<i className='fas fa-copyright' /> {`${startYear}${currentYear}`} <span><i className='mx-1 animate-pulse fas fa-heart'/> <a href={BLOG.LINK} className='underline font-bold text-gray-500 dark:text-gray-300 '>{BLOG.AUTHOR}</a>.
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<span>Powered by <a href='https://notion.so' className='underline font-bold text-gray-500 dark:text-gray-300'>Notion</a> & <a href='https://github.com/tangly1024/NotionNext' className='underline font-bold text-gray-500 dark:text-gray-300'>NotionNext</a>.</span></span>
|
<span>Powered by <a href='https://notion.so' className='underline font-bold text-gray-500 dark:text-gray-300'>Notion</a> & <a href='https://github.com/tangly1024/NotionNext' className='underline font-bold text-gray-500 dark:text-gray-300'>NotionNext</a>.</span></span>
|
||||||
|
|
||||||
{BLOG.BEI_AN && <><br /><FontAwesomeIcon icon={faShieldAlt} /> <a href='https://beian.miit.gov.cn/' className='mr-2'>{BLOG.BEI_AN}</a><br/></>}
|
{BLOG.BEI_AN && <><br /><i className='fas fa-shield-alt' /> <a href='https://beian.miit.gov.cn/' className='mr-2'>{BLOG.BEI_AN}</a><br/></>}
|
||||||
<span className='hidden busuanzi_container_site_pv'>
|
<span className='hidden busuanzi_container_site_pv'>
|
||||||
<FontAwesomeIcon icon={faEye}/><span className='px-1 busuanzi_value_site_pv'> </span> </span>
|
<i className='fas fa-eye'/><span className='px-1 busuanzi_value_site_pv'> </span> </span>
|
||||||
<span className='pl-2 hidden busuanzi_container_site_uv'>
|
<span className='pl-2 hidden busuanzi_container_site_uv'>
|
||||||
<FontAwesomeIcon icon={faUsers}/> <span className='px-1 busuanzi_value_site_uv'> </span> </span>
|
<i className='fas fa-users'/> <span className='px-1 busuanzi_value_site_uv'> </span> </span>
|
||||||
<br/>
|
<br/>
|
||||||
<h1>{title}</h1>
|
<h1>{title}</h1>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { faAngleDown } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
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'
|
||||||
@@ -116,7 +114,7 @@ export default function Header () {
|
|||||||
}}
|
}}
|
||||||
className="cursor-pointer w-full text-center py-4 text-3xl absolute bottom-10 text-white"
|
className="cursor-pointer w-full text-center py-4 text-3xl absolute bottom-10 text-white"
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faAngleDown} className='animate-bounce'/>
|
<i className='animate-bounce fas fa-angle-down'/>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { faFolderOpen } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import formatDate from '@/lib/formatDate'
|
import formatDate from '@/lib/formatDate'
|
||||||
@@ -50,13 +48,15 @@ export default function HeaderArticle ({ post }) {
|
|||||||
|
|
||||||
<section className="flex-wrap shadow-text flex justify-center mt-2 text-white dark:text-gray-400 font-light leading-8">
|
<section className="flex-wrap shadow-text flex justify-center mt-2 text-white dark:text-gray-400 font-light leading-8">
|
||||||
<div>
|
<div>
|
||||||
<Link href={`/category/${post.category}`} passHref>
|
{post.category && <>
|
||||||
|
<Link href={`/category/${post.category}`} passHref>
|
||||||
<a className="cursor-pointer text-md mr-2 dark:hover:text-white border-b dark:border-gray-500 border-dashed">
|
<a className="cursor-pointer text-md mr-2 dark:hover:text-white border-b dark:border-gray-500 border-dashed">
|
||||||
<FontAwesomeIcon icon={faFolderOpen} className="mr-1" />
|
<i className="mr-1 fas fa-folder-open" />
|
||||||
{post.category}
|
{post.category}
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
<span className="mr-2">|</span>
|
<span className="mr-2">|</span>
|
||||||
|
</>}
|
||||||
|
|
||||||
{post.type[0] !== 'Page' && (
|
{post.type[0] !== 'Page' && (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { faArrowUp } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import CONFIG_HEXO from '../config_hexo'
|
import CONFIG_HEXO from '../config_hexo'
|
||||||
|
|
||||||
@@ -19,7 +17,7 @@ const JumpToTopButton = ({ showPercent = true, percent }) => {
|
|||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
return (<div className='flex space-x-1 items-center transform hover:scale-105 duration-200 py-2 px-3' onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })} >
|
return (<div className='flex space-x-1 items-center transform hover:scale-105 duration-200 py-2 px-3' onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })} >
|
||||||
<div className='dark:text-gray-200' title={locale.POST.TOP} >
|
<div className='dark:text-gray-200' title={locale.POST.TOP} >
|
||||||
<FontAwesomeIcon icon={faArrowUp} />
|
<i className='fas fa-arrow-up' />
|
||||||
</div>
|
</div>
|
||||||
{showPercent && (<div className='text-xs dark:text-gray-200 block lg:hidden'>{percent}%</div>)}
|
{showPercent && (<div className='text-xs dark:text-gray-200 block lg:hidden'>{percent}%</div>)}
|
||||||
</div>)
|
</div>)
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { faArchive, faFileAlt } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
@@ -21,7 +19,7 @@ const LatestPostsGroup = ({ posts }) => {
|
|||||||
|
|
||||||
return <>
|
return <>
|
||||||
<div className='font-sans mb-2 px-1 flex flex-nowrap justify-between'>
|
<div className='font-sans mb-2 px-1 flex flex-nowrap justify-between'>
|
||||||
<div><FontAwesomeIcon icon={faArchive} className='mr-2' />{locale.COMMON.LATEST_POSTS}</div>
|
<div><i className='mr-2 fas fa-archive' />{locale.COMMON.LATEST_POSTS}</div>
|
||||||
</div>
|
</div>
|
||||||
{posts.map(post => {
|
{posts.map(post => {
|
||||||
const selected = currentPath === `${BLOG.PATH}/article/${post.slug}`
|
const selected = currentPath === `${BLOG.PATH}/article/${post.slug}`
|
||||||
@@ -30,7 +28,7 @@ const LatestPostsGroup = ({ posts }) => {
|
|||||||
<a className={ 'my-1 flex font-light'}>
|
<a className={ 'my-1 flex font-light'}>
|
||||||
<div className={ (selected ? 'text-white bg-blue-600 ' : 'text-gray-500 dark:text-gray-400 ') + ' text-xs py-1.5 flex overflow-x-hidden whitespace-nowrap hover:bg-blue-600 px-2 duration-200 w-full ' +
|
<div className={ (selected ? 'text-white bg-blue-600 ' : 'text-gray-500 dark:text-gray-400 ') + ' text-xs py-1.5 flex overflow-x-hidden whitespace-nowrap hover:bg-blue-600 px-2 duration-200 w-full ' +
|
||||||
'hover:text-white dark:hover:text-white cursor-pointer' }>
|
'hover:text-white dark:hover:text-white cursor-pointer' }>
|
||||||
<FontAwesomeIcon icon={faFileAlt} className='mr-2'/>
|
<i className='mr-2 fas fa-file-alt'/>
|
||||||
<div className='truncate'>{post.title}</div>
|
<div className='truncate'>{post.title}</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -2,22 +2,24 @@ import React from 'react'
|
|||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faArchive, faHome, faTag, faTh, faUser } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import CONFIG_HEXO from '../config_hexo'
|
import CONFIG_HEXO from '../config_hexo'
|
||||||
|
|
||||||
const MenuButtonGroup = ({ postCount }) => {
|
const MenuButtonGroup = (props) => {
|
||||||
|
const { postCount, customNav } = props
|
||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const archiveSlot = <div className='bg-blue-300 dark:bg-blue-500 rounded-md text-gray-50 px-1 text-xs'>{postCount}</div>
|
const archiveSlot = <div className='bg-blue-300 dark:bg-blue-500 rounded-md text-gray-50 px-1 text-xs'>{postCount}</div>
|
||||||
|
|
||||||
const links = [
|
let links = [
|
||||||
{ id: 0, icon: faHome, name: locale.NAV.INDEX, to: '/' || '/', show: true },
|
{ id: 0, icon: 'fas fa-home', name: locale.NAV.INDEX, to: '/' || '/', show: true },
|
||||||
{ id: 1, icon: faTh, name: locale.COMMON.CATEGORY, to: '/category', show: CONFIG_HEXO.MENU_CATEGORY },
|
{ id: 1, icon: 'fas fa-th', name: locale.COMMON.CATEGORY, to: '/category', show: CONFIG_HEXO.MENU_CATEGORY },
|
||||||
{ id: 2, icon: faTag, name: locale.COMMON.TAGS, to: '/tag', show: CONFIG_HEXO.MENU_TAG },
|
{ id: 2, icon: 'fas fa-tag', name: locale.COMMON.TAGS, to: '/tag', show: CONFIG_HEXO.MENU_TAG },
|
||||||
{ id: 3, icon: faArchive, name: locale.NAV.ARCHIVE, to: '/archive', slot: archiveSlot, show: CONFIG_HEXO.MENU_ARCHIVE },
|
{ id: 3, icon: 'fas fa-archive', name: locale.NAV.ARCHIVE, to: '/archive', slot: archiveSlot, show: CONFIG_HEXO.MENU_ARCHIVE },
|
||||||
{ id: 4, icon: faUser, name: locale.NAV.ABOUT, to: '/about', show: CONFIG_HEXO.MENU_ABOUT }
|
{ id: 4, icon: 'fas fa-user', name: locale.NAV.ABOUT, to: '/about', show: CONFIG_HEXO.MENU_ABOUT }
|
||||||
]
|
]
|
||||||
|
if (customNav) {
|
||||||
|
links = links.concat(customNav)
|
||||||
|
}
|
||||||
return <nav id='nav' className='leading-8 text-gray-500 dark:text-gray-400 font-sans w-full'>
|
return <nav id='nav' className='leading-8 text-gray-500 dark:text-gray-400 font-sans w-full'>
|
||||||
{links.map(link => {
|
{links.map(link => {
|
||||||
if (link.show) {
|
if (link.show) {
|
||||||
@@ -26,7 +28,7 @@ const MenuButtonGroup = ({ postCount }) => {
|
|||||||
<a className={'py-1.5 my-1 px-5 duration-300 text-base justify-between hover:bg-blue-600 hover:text-white hover:shadow-lg cursor-pointer flex flex-nowrap items-center ' +
|
<a className={'py-1.5 my-1 px-5 duration-300 text-base justify-between hover:bg-blue-600 hover:text-white hover:shadow-lg cursor-pointer flex flex-nowrap items-center ' +
|
||||||
(selected ? 'bg-blue-600 text-white' : ' ')} >
|
(selected ? 'bg-blue-600 text-white' : ' ')} >
|
||||||
<div className='my-auto items-center justify-center flex '>
|
<div className='my-auto items-center justify-center flex '>
|
||||||
<FontAwesomeIcon icon={link.icon} />
|
<i className={link.icon} />
|
||||||
<div className={'ml-4'}>{link.name}</div>
|
<div className={'ml-4'}>{link.name}</div>
|
||||||
</div>
|
</div>
|
||||||
{link.slot}
|
{link.slot}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faAngleLeft, faAngleRight } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数字翻页插件
|
* 数字翻页插件
|
||||||
@@ -29,7 +27,7 @@ const PaginationNumber = ({ page, totalPage }) => {
|
|||||||
rel='prev'
|
rel='prev'
|
||||||
className={`${currentPage === 1 ? 'invisible' : 'block'} pb-0.5 border-white dark:border-blue-700 hover:border-blue-400 dark:hover:border-blue-400 w-6 text-center cursor-pointer duration-200 hover:font-bold`}
|
className={`${currentPage === 1 ? 'invisible' : 'block'} pb-0.5 border-white dark:border-blue-700 hover:border-blue-400 dark:hover:border-blue-400 w-6 text-center cursor-pointer duration-200 hover:font-bold`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faAngleLeft}/>
|
<i className='fas fa-angle-left'/>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
@@ -41,7 +39,7 @@ const PaginationNumber = ({ page, totalPage }) => {
|
|||||||
rel='next'
|
rel='next'
|
||||||
className={`${+showNext ? 'block' : 'invisible'} pb-0.5 border-t-2 border-white dark:border-blue-700 hover:border-blue-400 dark:hover:border-blue-400 w-6 text-center cursor-pointer duration-500 hover:font-bold`}
|
className={`${+showNext ? 'block' : 'invisible'} pb-0.5 border-t-2 border-white dark:border-blue-700 hover:border-blue-400 dark:hover:border-blue-400 w-6 text-center cursor-pointer duration-500 hover:font-bold`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faAngleRight}/>
|
<i className='fas fa-angle-right'/>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useImperativeHandle, useRef, useState } from 'react'
|
import { useImperativeHandle, useRef, useState } from 'react'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faSearch, faSpinner, faTimes } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
|
|
||||||
const SearchInput = ({ currentTag, currentSearch, cRef }) => {
|
const SearchInput = ({ currentTag, currentSearch, cRef }) => {
|
||||||
const [searchKey, setSearchKey] = useState(currentSearch || '')
|
const [searchKey, setSearchKey] = useState(currentSearch || '')
|
||||||
@@ -46,7 +44,7 @@ const SearchInput = ({ currentTag, currentSearch, cRef }) => {
|
|||||||
<input
|
<input
|
||||||
ref={searchInputRef}
|
ref={searchInputRef}
|
||||||
type='text'
|
type='text'
|
||||||
className={'w-full rounded-lg bg-white text-sm pl-2 transition focus:shadow-lg font-light leading-10 text-black bg-gray-100'}
|
className={'w-full rounded-lg text-sm pl-2 transition focus:shadow-lg font-light leading-10 text-black bg-gray-100'}
|
||||||
onKeyUp={handleKeyUp}
|
onKeyUp={handleKeyUp}
|
||||||
onChange={e => updateSearchKey(e.target.value)}
|
onChange={e => updateSearchKey(e.target.value)}
|
||||||
defaultValue={searchKey}
|
defaultValue={searchKey}
|
||||||
@@ -54,12 +52,12 @@ const SearchInput = ({ currentTag, currentSearch, cRef }) => {
|
|||||||
|
|
||||||
<div className='-ml-8 cursor-pointer dark:hover:bg-gray-800 float-right items-center justify-center py-2'
|
<div className='-ml-8 cursor-pointer dark:hover:bg-gray-800 float-right items-center justify-center py-2'
|
||||||
onClick={() => { handleSearch(searchKey) }}>
|
onClick={() => { handleSearch(searchKey) }}>
|
||||||
<FontAwesomeIcon spin={onLoading} icon={onLoading ? faSpinner : faSearch} className='hover:text-black transform duration-200 text-gray-500 cursor-pointer' />
|
<i className={`hover:text-black transform duration-200 text-gray-500 cursor-pointer fas ${onLoading ? 'fa-spinner animate-spin' : 'fa-search'}`} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{(searchKey && searchKey.length &&
|
{(searchKey && searchKey.length &&
|
||||||
<div className='-ml-12 cursor-pointer dark:hover:bg-gray-800 float-right items-center justify-center py-2'>
|
<div className='-ml-12 cursor-pointer dark:hover:bg-gray-800 float-right items-center justify-center py-2'>
|
||||||
<FontAwesomeIcon icon={faTimes} className='hover:text-black transform duration-200 text-gray-400 cursor-pointer' onClick={cleanSearch} />
|
<i className='hover:text-black transform duration-200 text-gray-400 cursor-pointer fas fa-times' onClick={cleanSearch} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import BLOG from '@/blog.config'
|
|||||||
import Card from './Card'
|
import Card from './Card'
|
||||||
import MenuButtonGroup from './MenuButtonGroup'
|
import MenuButtonGroup from './MenuButtonGroup'
|
||||||
import SearchInput from './SearchInput'
|
import SearchInput from './SearchInput'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faChartArea, faTh } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import CategoryGroup from './CategoryGroup'
|
import CategoryGroup from './CategoryGroup'
|
||||||
import LatestPostsGroup from './LatestPostsGroup'
|
import LatestPostsGroup from './LatestPostsGroup'
|
||||||
import TagGroups from './TagGroups'
|
import TagGroups from './TagGroups'
|
||||||
@@ -51,7 +49,7 @@ export default function SideRight (props) {
|
|||||||
</Card>
|
</Card>
|
||||||
<Card>
|
<Card>
|
||||||
<div className='ml-2 mb-3 font-sans'>
|
<div className='ml-2 mb-3 font-sans'>
|
||||||
<FontAwesomeIcon icon={faChartArea} /> 统计
|
<i className='fas fa-chart-area' /> 统计
|
||||||
</div>
|
</div>
|
||||||
<div className='text-xs font-sans font-light justify-center mx-7'>
|
<div className='text-xs font-sans font-light justify-center mx-7'>
|
||||||
<div className='inline'>
|
<div className='inline'>
|
||||||
@@ -78,7 +76,7 @@ export default function SideRight (props) {
|
|||||||
{showCategory && (
|
{showCategory && (
|
||||||
<Card>
|
<Card>
|
||||||
<div className='ml-2 mb-1 font-sans'>
|
<div className='ml-2 mb-1 font-sans'>
|
||||||
<FontAwesomeIcon icon={faTh} /> 分类
|
<i className='fas fa-th'/> 分类
|
||||||
</div>
|
</div>
|
||||||
<CategoryGroup
|
<CategoryGroup
|
||||||
currentCategory={currentCategory}
|
currentCategory={currentCategory}
|
||||||
@@ -96,7 +94,7 @@ export default function SideRight (props) {
|
|||||||
</Card>}
|
</Card>}
|
||||||
|
|
||||||
{post && post.toc && (
|
{post && post.toc && (
|
||||||
<Card className='sticky top-4'>
|
<Card className='sticky top-12'>
|
||||||
<Catalog toc={post.toc} />
|
<Catalog toc={post.toc} />
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import { faGithub, faTelegram, faTwitter, faWeibo } from '@fortawesome/free-brands-svg-icons'
|
|
||||||
import { faEnvelope, faRss } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -13,22 +10,22 @@ const SocialButton = () => {
|
|||||||
return <div className='w-full justify-center flex-wrap flex'>
|
return <div className='w-full justify-center flex-wrap flex'>
|
||||||
<div className='space-x-3 text-xl text-gray-600 dark:text-gray-400 '>
|
<div className='space-x-3 text-xl text-gray-600 dark:text-gray-400 '>
|
||||||
{BLOG.CONTACT_GITHUB && <a target='_blank' rel='noreferrer' title={'github'} href={BLOG.CONTACT_GITHUB} >
|
{BLOG.CONTACT_GITHUB && <a target='_blank' rel='noreferrer' title={'github'} href={BLOG.CONTACT_GITHUB} >
|
||||||
<FontAwesomeIcon icon={faGithub} className='transform hover:scale-125 duration-150'/>
|
<i className='transform hover:scale-125 duration-150 fab fa-github'/>
|
||||||
</a>}
|
</a>}
|
||||||
{BLOG.CONTACT_TWITTER && <a target='_blank' rel='noreferrer' title={'twitter'} href={BLOG.CONTACT_TWITTER} >
|
{BLOG.CONTACT_TWITTER && <a target='_blank' rel='noreferrer' title={'twitter'} href={BLOG.CONTACT_TWITTER} >
|
||||||
<FontAwesomeIcon icon={faTwitter} className='transform hover:scale-125 duration-150'/>
|
<i className='transform hover:scale-125 duration-150 fab fa-twitter'/>
|
||||||
</a>}
|
</a>}
|
||||||
{BLOG.CONTACT_TELEGRAM && <a target='_blank' rel='noreferrer' href={BLOG.CONTACT_TELEGRAM} title={'telegram'} >
|
{BLOG.CONTACT_TELEGRAM && <a target='_blank' rel='noreferrer' href={BLOG.CONTACT_TELEGRAM} title={'telegram'} >
|
||||||
<FontAwesomeIcon icon={faTelegram} className='transform hover:scale-125 duration-150'/>
|
<i className='transform hover:scale-125 duration-150 fab fa-telegram'/>
|
||||||
</a>}
|
</a>}
|
||||||
{BLOG.CONTACT_WEIBO && <a target='_blank' rel='noreferrer' title={'weibo'} href={BLOG.CONTACT_WEIBO} >
|
{BLOG.CONTACT_WEIBO && <a target='_blank' rel='noreferrer' title={'weibo'} href={BLOG.CONTACT_WEIBO} >
|
||||||
<FontAwesomeIcon icon={faWeibo} className='transform hover:scale-125 duration-150'/>
|
<i className='transform hover:scale-125 duration-150 fab fa-weibo'/>
|
||||||
</a>}
|
</a>}
|
||||||
{BLOG.CONTACT_EMAIL && <a target='_blank' rel='noreferrer' title={'email'} href={`mailto:${BLOG.CONTACT_EMAIL}`} >
|
{BLOG.CONTACT_EMAIL && <a target='_blank' rel='noreferrer' title={'email'} href={`mailto:${BLOG.CONTACT_EMAIL}`} >
|
||||||
<FontAwesomeIcon icon={faEnvelope} className='transform hover:scale-125 duration-150'/>
|
<i className='transform hover:scale-125 duration-150 fas fa-envelope'/>
|
||||||
</a>}
|
</a>}
|
||||||
<a target='_blank' rel='noreferrer' title={'RSS'} href={'/feed'} >
|
<a target='_blank' rel='noreferrer' title={'RSS'} href={'/feed'} >
|
||||||
<FontAwesomeIcon icon={faRss} className='transform hover:scale-125 duration-150'/>
|
<i className='transform hover:scale-125 duration-150 fas fa-rss'/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { faTag } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import TagItemMini from './TagItemMini'
|
import TagItemMini from './TagItemMini'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -13,7 +11,7 @@ const TagGroups = ({ tags, currentTag }) => {
|
|||||||
if (!tags) return <></>
|
if (!tags) return <></>
|
||||||
return (
|
return (
|
||||||
<div id='tags-group' className='dark:border-gray-600 space-y-2'>
|
<div id='tags-group' className='dark:border-gray-600 space-y-2'>
|
||||||
<div className='font-light text-xs ml-2 mb-2'><FontAwesomeIcon icon={faTag} className='mr-1' />标签</div>
|
<div className='font-light text-xs ml-2 mb-2'><i className='mr-1 fas fa-tag' />标签</div>
|
||||||
<div className='px-4'>
|
<div className='px-4'>
|
||||||
{
|
{
|
||||||
tags.map(tag => {
|
tags.map(tag => {
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { faTag } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
|
||||||
const TagItemMini = ({ tag, selected = false }) => {
|
const TagItemMini = ({ tag, selected = false }) => {
|
||||||
@@ -9,7 +7,7 @@ const TagItemMini = ({ tag, selected = false }) => {
|
|||||||
${selected
|
${selected
|
||||||
? 'text-white dark:text-gray-300 bg-black dark:bg-black dark:hover:bg-blue-900'
|
? 'text-white dark:text-gray-300 bg-black dark:bg-black dark:hover:bg-blue-900'
|
||||||
: `text-gray-600 hover:shadow-xl dark:border-gray-400 notion-${tag.color}_background dark:bg-blue-800`}` }>
|
: `text-gray-600 hover:shadow-xl dark:border-gray-400 notion-${tag.color}_background dark:bg-blue-800`}` }>
|
||||||
<div className='font-light dark:text-gray-400'>{selected && <FontAwesomeIcon icon={faTag} className='mr-1'/>} {tag.name + (tag.count ? `(${tag.count})` : '')} </div>
|
<div className='font-light dark:text-gray-400'>{selected && <i className='mr-1 fa-tag'/>} {tag.name + (tag.count ? `(${tag.count})` : '')} </div>
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { faListOl } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import CONFIG_HEXO from '../config_hexo'
|
import CONFIG_HEXO from '../config_hexo'
|
||||||
|
|
||||||
@@ -17,7 +15,7 @@ const TocDrawerButton = (props) => {
|
|||||||
}
|
}
|
||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
return (<div onClick={props.onClick} className='py-2 px-3 cursor-pointer dark:text-gray-200 text-center transform hover:scale-150 duration-200 flex justify-center items-center' title={locale.POST.TOP} >
|
return (<div onClick={props.onClick} className='py-2 px-3 cursor-pointer dark:text-gray-200 text-center transform hover:scale-150 duration-200 flex justify-center items-center' title={locale.POST.TOP} >
|
||||||
<FontAwesomeIcon icon={faListOl}/>
|
<i className='fas fa-list-ol'/>
|
||||||
</div>)
|
</div>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { faAngleDoubleRight, faBars, faTag, faThList, faTimes } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import throttle from 'lodash.throttle'
|
import throttle from 'lodash.throttle'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
@@ -60,10 +58,10 @@ const TopNav = ({ tags, currentTag, categories, currentCategory, postCount }) =>
|
|||||||
{ categories && (
|
{ categories && (
|
||||||
<section className='mt-8'>
|
<section className='mt-8'>
|
||||||
<div className='text-sm flex flex-nowrap justify-between font-light px-2'>
|
<div className='text-sm flex flex-nowrap justify-between font-light px-2'>
|
||||||
<div className='text-gray-600 dark:text-gray-200'><FontAwesomeIcon icon={faThList} className='mr-2' />{locale.COMMON.CATEGORY}</div>
|
<div className='text-gray-600 dark:text-gray-200'><i className='mr-2 fas fa-th-list' />{locale.COMMON.CATEGORY}</div>
|
||||||
<Link href={'/category'} passHref>
|
<Link href={'/category'} passHref>
|
||||||
<a className='mb-3 text-gray-400 hover:text-black dark:text-gray-400 dark:hover:text-white hover:underline cursor-pointer'>
|
<a className='mb-3 text-gray-400 hover:text-black dark:text-gray-400 dark:hover:text-white hover:underline cursor-pointer'>
|
||||||
{locale.COMMON.MORE} <FontAwesomeIcon icon={faAngleDoubleRight} />
|
{locale.COMMON.MORE} <i className='fas fa-angle-double-right' />
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@@ -74,10 +72,10 @@ const TopNav = ({ tags, currentTag, categories, currentCategory, postCount }) =>
|
|||||||
{ tags && (
|
{ tags && (
|
||||||
<section className='mt-4'>
|
<section className='mt-4'>
|
||||||
<div className='text-sm py-2 px-2 flex flex-nowrap justify-between font-light dark:text-gray-200'>
|
<div className='text-sm py-2 px-2 flex flex-nowrap justify-between font-light dark:text-gray-200'>
|
||||||
<div className='text-gray-600 dark:text-gray-200'><FontAwesomeIcon icon={faTag} className='mr-2'/>{locale.COMMON.TAGS}</div>
|
<div className='text-gray-600 dark:text-gray-200'><i className='mr-2 fas fa-tag'/>{locale.COMMON.TAGS}</div>
|
||||||
<Link href={'/tag'} passHref>
|
<Link href={'/tag'} passHref>
|
||||||
<a className='text-gray-400 hover:text-black dark:hover:text-white hover:underline cursor-pointer'>
|
<a className='text-gray-400 hover:text-black dark:hover:text-white hover:underline cursor-pointer'>
|
||||||
{locale.COMMON.MORE} <FontAwesomeIcon icon={faAngleDoubleRight} />
|
{locale.COMMON.MORE} <i className='fas fa-angle-double-right' />
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@@ -92,8 +90,8 @@ const TopNav = ({ tags, currentTag, categories, currentCategory, postCount }) =>
|
|||||||
<SearchDrawer cRef={searchDrawer} slot={searchDrawerSlot}/>
|
<SearchDrawer cRef={searchDrawer} slot={searchDrawerSlot}/>
|
||||||
|
|
||||||
{/* 导航栏 */}
|
{/* 导航栏 */}
|
||||||
<div id='sticky-nav' className={`${CONFIG_HEXO.NAV_TYPE !== 'normal' ? 'fixed' : ''} bg-white bg-opacity-70 text-black w-full top-0 z-20 transform duration-500 font-sans`}>
|
<div id='sticky-nav' className={`${CONFIG_HEXO.NAV_TYPE !== 'normal' ? 'fixed bg-white' : ' bg-none -mb-10'} bg-opacity-70 text-black w-full top-0 z-20 transform duration-500 font-sans`}>
|
||||||
<div className='w-full flex justify-between items-center p-4 shadow-md'>
|
<div className='w-full flex justify-between items-center px-4 py-2 shadow-md'>
|
||||||
<div className='flex'>
|
<div className='flex'>
|
||||||
<Logo/>
|
<Logo/>
|
||||||
</div>
|
</div>
|
||||||
@@ -101,7 +99,7 @@ const TopNav = ({ tags, currentTag, categories, currentCategory, postCount }) =>
|
|||||||
{/* 右侧功能 */}
|
{/* 右侧功能 */}
|
||||||
<div className='mr-1 flex lg:hidden justify-end items-center text-sm space-x-4 font-serif dark:text-gray-200'>
|
<div className='mr-1 flex lg:hidden justify-end items-center text-sm space-x-4 font-serif dark:text-gray-200'>
|
||||||
<div onClick={toggleMenuOpen} className='w-8 cursor-pointer'>
|
<div onClick={toggleMenuOpen} className='w-8 cursor-pointer'>
|
||||||
{ isOpen ? <FontAwesomeIcon icon={faTimes} size={'lg'}/> : <FontAwesomeIcon icon={faBars} size={'lg'}/> }
|
{ isOpen ? <i className='fas fa-times'/> : <i className='fas fa-bars'/> }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ const LayoutBase = props => {
|
|||||||
|
|
||||||
<div className='w-full'>
|
<div className='w-full'>
|
||||||
{/* 移动端顶部菜单 */}
|
{/* 移动端顶部菜单 */}
|
||||||
<TopNavBar />
|
<TopNavBar {...props}/>
|
||||||
<div className='px-5 max-w-5xl justify-center mx-auto'>
|
<div className='px-5 max-w-5xl justify-center mx-auto min-h-screen'>
|
||||||
{slotTop}
|
{slotTop}
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import LayoutBase from './LayoutBase'
|
import LayoutBase from './LayoutBase'
|
||||||
import BlogPostListScroll from './components/BlogPostListScroll'
|
import BlogPostListScroll from './components/BlogPostListScroll'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faTh } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
|
|
||||||
export const LayoutCategory = (props) => {
|
export const LayoutCategory = (props) => {
|
||||||
const { category } = props
|
const { category } = props
|
||||||
const slotTop = <div className='flex items-center font-sans p-8'><div className='text-xl'><FontAwesomeIcon icon={faTh} className='mr-2'/>分类:</div>{category}</div>
|
const slotTop = <div className='flex items-center font-sans p-8'><div className='text-xl'><i className='mr-2 fas fa-th'/>分类:</div>{category}</div>
|
||||||
|
|
||||||
return <LayoutBase {...props} slotTop={slotTop}>
|
return <LayoutBase {...props} slotTop={slotTop}>
|
||||||
<BlogPostListScroll {...props} />
|
<BlogPostListScroll {...props} />
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ import mediumZoom from 'medium-zoom'
|
|||||||
import React, { useEffect, useRef } from 'react'
|
import React, { useEffect, useRef } from 'react'
|
||||||
import ArticleAround from './components/ArticleAround'
|
import ArticleAround from './components/ArticleAround'
|
||||||
import Catalog from './components/Catalog'
|
import Catalog from './components/Catalog'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faEye } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import CategoryItem from './components/CategoryItem'
|
import CategoryItem from './components/CategoryItem'
|
||||||
import TagItemMini from './components/TagItemMini'
|
import TagItemMini from './components/TagItemMini'
|
||||||
import CONFIG_MEDIUM from './config_medium'
|
import CONFIG_MEDIUM from './config_medium'
|
||||||
@@ -104,7 +102,7 @@ export const LayoutSlug = props => {
|
|||||||
</Link>
|
</Link>
|
||||||
<div className="text-gray-500">{date}</div>
|
<div className="text-gray-500">{date}</div>
|
||||||
<div className="hidden busuanzi_container_page_pv text-gray-500 font-light mr-2">
|
<div className="hidden busuanzi_container_page_pv text-gray-500 font-light mr-2">
|
||||||
<FontAwesomeIcon icon={faEye} className="ml-3 mr-0.5" />
|
<i className="ml-3 mr-0.5 fas fa-eye" />
|
||||||
|
|
||||||
<span className="mr-2 busuanzi_value_page_pv" />
|
<span className="mr-2 busuanzi_value_page_pv" />
|
||||||
</div>
|
</div>
|
||||||
@@ -139,7 +137,7 @@ export const LayoutSlug = props => {
|
|||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<div className='flex justify-between'>
|
<div className='flex justify-between'>
|
||||||
{ CONFIG_MEDIUM.POST_DETAIL_CATEGORY && <CategoryItem category={post.category}/>}
|
{ CONFIG_MEDIUM.POST_DETAIL_CATEGORY && post.category && <CategoryItem category={post.category}/>}
|
||||||
<div>
|
<div>
|
||||||
{ CONFIG_MEDIUM.POST_DETAIL_TAG && post?.tagItems?.map(tag => <TagItemMini key={tag.name} tag={tag} />)}
|
{ CONFIG_MEDIUM.POST_DETAIL_TAG && post?.tagItems?.map(tag => <TagItemMini key={tag.name} tag={tag} />)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import LayoutBase from './LayoutBase'
|
import LayoutBase from './LayoutBase'
|
||||||
import BlogPostListScroll from './components/BlogPostListScroll'
|
import BlogPostListScroll from './components/BlogPostListScroll'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faTag } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
|
|
||||||
export const LayoutTag = (props) => {
|
export const LayoutTag = (props) => {
|
||||||
const { tag } = props
|
const { tag } = props
|
||||||
const slotTop = <div className='flex items-center font-sans p-8'><div className='text-xl'><FontAwesomeIcon icon={faTag} className='mr-2'/>标签:</div>{tag}</div>
|
const slotTop = <div className='flex items-center font-sans p-8'><div className='text-xl'><i className='mr-2 fas fa-tag'/>标签:</div>{tag}</div>
|
||||||
|
|
||||||
return <LayoutBase {...props} slotTop={slotTop}>
|
return <LayoutBase {...props} slotTop={slotTop}>
|
||||||
<BlogPostListScroll {...props} />
|
<BlogPostListScroll {...props} />
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faAngleDoubleLeft, faAngleDoubleRight } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上一篇,下一篇文章
|
* 上一篇,下一篇文章
|
||||||
@@ -14,12 +12,12 @@ export default function ArticleAround ({ prev, next }) {
|
|||||||
return <section className='text-gray-800 h-12 flex items-center justify-between space-x-5 my-4'>
|
return <section className='text-gray-800 h-12 flex items-center justify-between space-x-5 my-4'>
|
||||||
<Link href={`/article/${prev.slug}`} passHref>
|
<Link href={`/article/${prev.slug}`} passHref>
|
||||||
<a className='text-sm cursor-pointer justify-start items-center flex hover:underline duration-300'>
|
<a className='text-sm cursor-pointer justify-start items-center flex hover:underline duration-300'>
|
||||||
<FontAwesomeIcon icon={faAngleDoubleLeft} className='mr-1' />{prev.title}
|
<i className='mr-1 fas fa-angle-double-left' />{prev.title}
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
<Link href={`/article/${next.slug}`} passHref>
|
<Link href={`/article/${next.slug}`} passHref>
|
||||||
<a className='text-sm cursor-pointer justify-end items-center flex hover:underline duration-300'>{next.title}
|
<a className='text-sm cursor-pointer justify-end items-center flex hover:underline duration-300'>{next.title}
|
||||||
<FontAwesomeIcon icon={faAngleDoubleRight} className='ml-1 my-1' />
|
<i className='ml-1 my-1 fas fa-angle-double-right' />
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { faAngleRight } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Code, Collection, Equation, NotionRenderer } from 'react-notion-x'
|
import { Code, Collection, Equation, NotionRenderer } from 'react-notion-x'
|
||||||
@@ -17,7 +15,7 @@ const BlogPostCard = ({ post, showSummary }) => {
|
|||||||
|
|
||||||
<div className='lg:p-8 p-4 flex flex-col w-full'>
|
<div className='lg:p-8 p-4 flex flex-col w-full'>
|
||||||
<Link href={`${BLOG.PATH}/article/${post.slug}`} passHref>
|
<Link href={`${BLOG.PATH}/article/${post.slug}`} passHref>
|
||||||
<a className={'cursor-pointer font-bold font-sans hover:underline text-3xl flex justify-start leading-tight text-gray-700 dark:text-gray-100 hover:text-blue-500 dark:hover:text-blue-400'}>
|
<a className={'cursor-pointer font-bold font-sans hover:underline text-3xl flex justify-start leading-tight text-gray-700 dark:text-gray-100 hover:text-green-500 dark:hover:text-green-400'}>
|
||||||
{post.title}
|
{post.title}
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
@@ -52,7 +50,7 @@ const BlogPostCard = ({ post, showSummary }) => {
|
|||||||
<Link href={`${BLOG.PATH}/article/${post.slug}`} passHref>
|
<Link href={`${BLOG.PATH}/article/${post.slug}`} passHref>
|
||||||
<a className='hover:bg-opacity-100 hover:scale-105 duration-200 pointer-events-auto transform text-red-500 cursor-pointer'>
|
<a className='hover:bg-opacity-100 hover:scale-105 duration-200 pointer-events-auto transform text-red-500 cursor-pointer'>
|
||||||
{locale.COMMON.ARTICLE_DETAIL}
|
{locale.COMMON.ARTICLE_DETAIL}
|
||||||
<FontAwesomeIcon className='ml-1' icon={faAngleRight} /></a>
|
<i className='ml-1 fas fa-angle-right'/></a>
|
||||||
|
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { faHome, faSearch } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import JumpToTopButton from '@/themes/Medium/components/JumpToTopButton'
|
import JumpToTopButton from '@/themes/Medium/components/JumpToTopButton'
|
||||||
@@ -10,12 +8,12 @@ export default function BottomMenuBar ({ className }) {
|
|||||||
<div className='flex justify-between h-full shadow-card'>
|
<div className='flex justify-between h-full shadow-card'>
|
||||||
<Link href='/' passHref>
|
<Link href='/' passHref>
|
||||||
<div className='flex w-full items-center justify-center cursor-pointer'>
|
<div className='flex w-full items-center justify-center cursor-pointer'>
|
||||||
<FontAwesomeIcon icon={faHome} />
|
<i className='fas fa-home' />
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
<Link href='/search' passHref>
|
<Link href='/search' passHref>
|
||||||
<div className='flex w-full items-center justify-center cursor-pointer'>
|
<div className='flex w-full items-center justify-center cursor-pointer'>
|
||||||
<FontAwesomeIcon icon={faSearch} />
|
<i className='fas fa-search'/>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
<div className='flex w-full items-center justify-center cursor-pointer'>
|
<div className='flex w-full items-center justify-center cursor-pointer'>
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { faTh } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import CategoryItem from './CategoryItem'
|
import CategoryItem from './CategoryItem'
|
||||||
|
|
||||||
@@ -8,7 +6,7 @@ const CategoryGroup = ({ currentCategory, categories }) => {
|
|||||||
return <></>
|
return <></>
|
||||||
}
|
}
|
||||||
return <div id='category-list' className='pt-4'>
|
return <div id='category-list' className='pt-4'>
|
||||||
<div className='mb-2'><FontAwesomeIcon icon={faTh} className='mr-2' />分类</div>
|
<div className='mb-2'><i className='mr-2 fas fa-th' />分类</div>
|
||||||
<div className='flex flex-wrap'>
|
<div className='flex flex-wrap'>
|
||||||
{Object.keys(categories).map(category => {
|
{Object.keys(categories).map(category => {
|
||||||
const selected = currentCategory === category
|
const selected = currentCategory === category
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faFolderOpen, faFolder } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
|
|
||||||
export default function CategoryItem ({ selected, category, categoryCount }) {
|
export default function CategoryItem ({ selected, category, categoryCount }) {
|
||||||
return <Link href={`/category/${category}`} passHref>
|
return <Link href={`/category/${category}`} passHref>
|
||||||
<a className={(selected
|
<a className={(selected
|
||||||
? 'hover:text-white dark:hover:text-white bg-gray-600 text-white '
|
? 'hover:text-white dark:hover:text-white bg-green-600 text-white '
|
||||||
: 'dark:text-gray-400 text-gray-500 hover:text-white dark:hover:text-white hover:bg-gray-600') +
|
: 'dark:text-green-400 text-gray-500 hover:text-white dark:hover:text-white hover:bg-green-600') +
|
||||||
' flex text-sm items-center duration-300 cursor-pointer py-1 font-light px-2 whitespace-nowrap'}>
|
' flex text-sm items-center duration-300 cursor-pointer py-1 font-light px-2 whitespace-nowrap'}>
|
||||||
<div><FontAwesomeIcon icon={selected ? faFolderOpen : faFolder}
|
<div><i className={`mr-2 fas ${selected ? 'fa-folder-open' : 'fa-folder'}`} />{category} {categoryCount && (categoryCount)}
|
||||||
className={'mr-2'} />{category} {categoryCount && (categoryCount)}
|
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { faCopyright, faEye, faShieldAlt, faUsers, faHeart } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
|
|
||||||
@@ -11,16 +9,16 @@ const Footer = ({ title }) => {
|
|||||||
<footer
|
<footer
|
||||||
className='dark:bg-gray-900 flex-shrink-0 justify-center text-center m-auto w-full leading-6 text-gray-400 text-sm p-6'
|
className='dark:bg-gray-900 flex-shrink-0 justify-center text-center m-auto w-full leading-6 text-gray-400 text-sm p-6'
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faCopyright} /> {`${startYear}${currentYear}`} <span><FontAwesomeIcon icon={faHeart} className='mx-1 animate-pulse'/> <a href={BLOG.LINK} className='underline font-bold text-gray-500 dark:text-gray-300 '>{BLOG.AUTHOR}</a>.
|
<i className='fas fa-copyright' /> {`${startYear}${currentYear}`} <span><i className='mx-1 animate-pulse fas fa-heart'/> <a href={BLOG.LINK} className='underline font-bold text-gray-500 dark:text-gray-300 '>{BLOG.AUTHOR}</a>.
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<span>Powered by <a href='https://notion.so' className='underline font-bold text-gray-500 dark:text-gray-300'>Notion</a> & <a href='https://github.com/tangly1024/NotionNext' className='underline font-bold text-gray-500 dark:text-gray-300'>NotionNext</a>.</span></span>
|
<span>Powered by <a href='https://notion.so' className='underline font-bold text-gray-500 dark:text-gray-300'>Notion</a> & <a href='https://github.com/tangly1024/NotionNext' className='underline font-bold text-gray-500 dark:text-gray-300'>NotionNext</a>.</span></span>
|
||||||
|
|
||||||
{BLOG.BEI_AN && <><br /><FontAwesomeIcon icon={faShieldAlt} /> <a href='https://beian.miit.gov.cn/' className='mr-2'>{BLOG.BEI_AN}</a><br/></>}
|
{BLOG.BEI_AN && <><br /><i className='fas fa-shield-alt'/> <a href='https://beian.miit.gov.cn/' className='mr-2'>{BLOG.BEI_AN}</a><br/></>}
|
||||||
<span className='hidden busuanzi_container_site_pv'>
|
<span className='hidden busuanzi_container_site_pv'>
|
||||||
<FontAwesomeIcon icon={faEye}/><span className='px-1 busuanzi_value_site_pv'> </span> </span>
|
<i className='fas fa-eye'/><span className='px-1 busuanzi_value_site_pv'> </span> </span>
|
||||||
<span className='pl-2 hidden busuanzi_container_site_uv'>
|
<span className='pl-2 hidden busuanzi_container_site_uv'>
|
||||||
<FontAwesomeIcon icon={faUsers}/> <span className='px-1 busuanzi_value_site_uv'> </span> </span>
|
<i className='fas fa-users'/> <span className='px-1 busuanzi_value_site_uv'> </span> </span>
|
||||||
<br/>
|
<br/>
|
||||||
<h1>{title}</h1>
|
<h1>{title}</h1>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { faArrowUp } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import CONFIG_MEDIUM from '../config_medium'
|
import CONFIG_MEDIUM from '../config_medium'
|
||||||
|
|
||||||
@@ -19,7 +17,7 @@ const JumpToTopButton = ({ showPercent = false, percent, className }) => {
|
|||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
return (<div className={'flex space-x-1 items-center cursor-pointer w-full justify-center ' + className } onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })} >
|
return (<div className={'flex space-x-1 items-center cursor-pointer w-full justify-center ' + className } onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })} >
|
||||||
<div title={locale.POST.TOP} >
|
<div title={locale.POST.TOP} >
|
||||||
<FontAwesomeIcon icon={faArrowUp} />
|
<i className='fas fa-arrow-up'/>
|
||||||
</div>
|
</div>
|
||||||
{showPercent && (<div className='text-xs dark:text-gray-200 block lg:hidden'>{percent}%</div>)}
|
{showPercent && (<div className='text-xs dark:text-gray-200 block lg:hidden'>{percent}%</div>)}
|
||||||
</div>)
|
</div>)
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faHome } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
export default function LeftMenuBar () {
|
export default function LeftMenuBar () {
|
||||||
@@ -8,7 +6,7 @@ export default function LeftMenuBar () {
|
|||||||
<section>
|
<section>
|
||||||
<Link href='/'>
|
<Link href='/'>
|
||||||
<div className='text-center cursor-pointer hover:text-black'>
|
<div className='text-center cursor-pointer hover:text-black'>
|
||||||
<FontAwesomeIcon icon={faHome} size='lg' color='gray' />
|
<i className='fas fa-home text-gray-500'/>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const PaginationSimple = ({ page, totalPage }) => {
|
|||||||
} } passHref >
|
} } passHref >
|
||||||
<a
|
<a
|
||||||
rel='prev'
|
rel='prev'
|
||||||
className={`${currentPage === 1 ? 'invisible' : 'block'} text-center w-full duration-200 px-4 py-2 hover:border-black border-b-2 hover:font-bold`}
|
className={`${currentPage === 1 ? 'invisible' : 'block'} text-center w-full duration-200 px-4 py-2 hover:border-green-500 border-b-2 hover:font-bold`}
|
||||||
>
|
>
|
||||||
← {locale.PAGINATION.PREV}
|
← {locale.PAGINATION.PREV}
|
||||||
</a>
|
</a>
|
||||||
@@ -31,7 +31,7 @@ const PaginationSimple = ({ page, totalPage }) => {
|
|||||||
<Link href={ { pathname: `/page/${currentPage + 1}`, query: router.query.s ? { s: router.query.s } : {} } } passHref>
|
<Link href={ { pathname: `/page/${currentPage + 1}`, query: router.query.s ? { s: router.query.s } : {} } } passHref>
|
||||||
<a
|
<a
|
||||||
rel='next'
|
rel='next'
|
||||||
className={`${+showNext ? 'block' : 'invisible'} text-center w-full duration-200 px-4 py-2 hover:border-black border-b-2 hover:font-bold`}
|
className={`${+showNext ? 'block' : 'invisible'} text-center w-full duration-200 px-4 py-2 hover:border-green-500 border-b-2 hover:font-bold`}
|
||||||
>
|
>
|
||||||
{locale.PAGINATION.NEXT} →
|
{locale.PAGINATION.NEXT} →
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useImperativeHandle, useRef, useState } from 'react'
|
import { useImperativeHandle, useRef, useState } from 'react'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faSearch, faSpinner, faTimes } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
|
|
||||||
const SearchInput = ({ currentTag, currentSearch, cRef, className }) => {
|
const SearchInput = ({ currentTag, currentSearch, cRef, className }) => {
|
||||||
const [searchKey, setSearchKey] = useState(currentSearch || getSearchKey() || '')
|
const [searchKey, setSearchKey] = useState(currentSearch || getSearchKey() || '')
|
||||||
@@ -55,12 +53,12 @@ const SearchInput = ({ currentTag, currentSearch, cRef, className }) => {
|
|||||||
|
|
||||||
<div className='-ml-8 cursor-pointer dark:bg-gray-600 dark:hover:bg-gray-800 float-right items-center justify-center py-2'
|
<div className='-ml-8 cursor-pointer dark:bg-gray-600 dark:hover:bg-gray-800 float-right items-center justify-center py-2'
|
||||||
onClick={() => { handleSearch(searchKey) }}>
|
onClick={() => { handleSearch(searchKey) }}>
|
||||||
<FontAwesomeIcon spin={onLoading} icon={onLoading ? faSpinner : faSearch} className='hover:text-black transform duration-200 text-gray-500 cursor-pointer' />
|
<i className={`hover:text-black transform duration-200 text-gray-500 cursor-pointer fas ${onLoading ? 'fa-spinner animate-spin' : 'fa-search'} `} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{(searchKey && searchKey.length &&
|
{(searchKey && searchKey.length &&
|
||||||
<div className='-ml-12 cursor-pointer dark:bg-gray-600 dark:hover:bg-gray-800 float-right items-center justify-center py-2'>
|
<div className='-ml-12 cursor-pointer dark:bg-gray-600 dark:hover:bg-gray-800 float-right items-center justify-center py-2'>
|
||||||
<FontAwesomeIcon icon={faTimes} className='hover:text-black transform duration-200 text-gray-400 cursor-pointer' onClick={cleanSearch} />
|
<i className='fas fa-times hover:text-black transform duration-200 text-gray-400 cursor-pointer' onClick={cleanSearch} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import { faGithub, faTelegram, faTwitter, faWeibo } from '@fortawesome/free-brands-svg-icons'
|
|
||||||
import { faEnvelope, faRss } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -12,22 +9,22 @@ import React from 'react'
|
|||||||
const SocialButton = () => {
|
const SocialButton = () => {
|
||||||
return <div className='space-x-3 text-xl text-gray-600 dark:text-gray-400 flex-wrap flex justify-center '>
|
return <div className='space-x-3 text-xl text-gray-600 dark:text-gray-400 flex-wrap flex justify-center '>
|
||||||
{BLOG.CONTACT_GITHUB && <a target='_blank' rel='noreferrer' title={'github'} href={BLOG.CONTACT_GITHUB} >
|
{BLOG.CONTACT_GITHUB && <a target='_blank' rel='noreferrer' title={'github'} href={BLOG.CONTACT_GITHUB} >
|
||||||
<FontAwesomeIcon icon={faGithub} className='transform hover:scale-125 duration-150'/>
|
<i className='fab fa-github transform hover:scale-125 duration-150 hover:text-green-600'/>
|
||||||
</a>}
|
</a>}
|
||||||
{BLOG.CONTACT_TWITTER && <a target='_blank' rel='noreferrer' title={'twitter'} href={BLOG.CONTACT_TWITTER} >
|
{BLOG.CONTACT_TWITTER && <a target='_blank' rel='noreferrer' title={'twitter'} href={BLOG.CONTACT_TWITTER} >
|
||||||
<FontAwesomeIcon icon={faTwitter} className='transform hover:scale-125 duration-150'/>
|
<i className='fab fa-twitter transform hover:scale-125 duration-150 hover:text-green-600'/>
|
||||||
</a>}
|
</a>}
|
||||||
{BLOG.CONTACT_TELEGRAM && <a target='_blank' rel='noreferrer' href={BLOG.CONTACT_TELEGRAM} title={'telegram'} >
|
{BLOG.CONTACT_TELEGRAM && <a target='_blank' rel='noreferrer' href={BLOG.CONTACT_TELEGRAM} title={'telegram'} >
|
||||||
<FontAwesomeIcon icon={faTelegram} className='transform hover:scale-125 duration-150'/>
|
<i className='fab fa-telegram transform hover:scale-125 duration-150 hover:text-green-600'/>
|
||||||
</a>}
|
</a>}
|
||||||
{BLOG.CONTACT_WEIBO && <a target='_blank' rel='noreferrer' title={'weibo'} href={BLOG.CONTACT_WEIBO} >
|
{BLOG.CONTACT_WEIBO && <a target='_blank' rel='noreferrer' title={'weibo'} href={BLOG.CONTACT_WEIBO} >
|
||||||
<FontAwesomeIcon icon={faWeibo} className='transform hover:scale-125 duration-150'/>
|
<i className='fab fa-weibo transform hover:scale-125 duration-150 hover:text-green-600'/>
|
||||||
</a>}
|
</a>}
|
||||||
{BLOG.CONTACT_EMAIL && <a target='_blank' rel='noreferrer' title={'email'} href={`mailto:${BLOG.CONTACT_EMAIL}`} >
|
{BLOG.CONTACT_EMAIL && <a target='_blank' rel='noreferrer' title={'email'} href={`mailto:${BLOG.CONTACT_EMAIL}`} >
|
||||||
<FontAwesomeIcon icon={faEnvelope} className='transform hover:scale-125 duration-150'/>
|
<i className='fas fa-envelope transform hover:scale-125 duration-150 hover:text-green-600'/>
|
||||||
</a>}
|
</a>}
|
||||||
<a target='_blank' rel='noreferrer' title={'RSS'} href={'/feed'} >
|
<a target='_blank' rel='noreferrer' title={'RSS'} href={'/feed'} >
|
||||||
<FontAwesomeIcon icon={faRss} className='transform hover:scale-125 duration-150'/>
|
<i className='fas fa-rss transform hover:scale-125 duration-150 hover:text-green-600'/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { faTag } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import TagItemMini from './TagItemMini'
|
import TagItemMini from './TagItemMini'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -13,7 +11,7 @@ const TagGroups = ({ tags, currentTag }) => {
|
|||||||
if (!tags) return <></>
|
if (!tags) return <></>
|
||||||
return (
|
return (
|
||||||
<div id='tags-group' className='dark:border-gray-600 py-4'>
|
<div id='tags-group' className='dark:border-gray-600 py-4'>
|
||||||
<div className='mb-2'><FontAwesomeIcon icon={faTag} className='mr-2' />标签</div>
|
<div className='mb-2'><i className='mr-2 fas fa-tag' />标签</div>
|
||||||
<div className='space-y-2'>
|
<div className='space-y-2'>
|
||||||
{
|
{
|
||||||
tags.map(tag => {
|
tags.map(tag => {
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { faTag } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
|
||||||
const TagItemMini = ({ tag, selected = false }) => {
|
const TagItemMini = ({ tag, selected = false }) => {
|
||||||
@@ -9,7 +7,7 @@ const TagItemMini = ({ tag, selected = false }) => {
|
|||||||
${selected
|
${selected
|
||||||
? 'text-white dark:text-gray-300 bg-black dark:bg-black dark:hover:bg-gray-900'
|
? 'text-white dark:text-gray-300 bg-black dark:bg-black dark:hover:bg-gray-900'
|
||||||
: `text-gray-600 hover:shadow-xl dark:border-gray-400 notion-${tag.color}_background dark:bg-gray-800`}` }>
|
: `text-gray-600 hover:shadow-xl dark:border-gray-400 notion-${tag.color}_background dark:bg-gray-800`}` }>
|
||||||
<div className='font-light dark:text-gray-400'>{selected && <FontAwesomeIcon icon={faTag} className='mr-1'/>} {tag.name + (tag.count ? `(${tag.count})` : '')} </div>
|
<div className='font-light dark:text-gray-400'>{selected && <i className='mr-1 fas fa-tag'/>} {tag.name + (tag.count ? `(${tag.count})` : '')} </div>
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,40 @@
|
|||||||
import LogoBar from '@/themes/Medium/components/LogoBar'
|
import LogoBar from '@/themes/Medium/components/LogoBar'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 顶部导航栏 + 菜单
|
||||||
|
* @param {} param0
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function TopNavBar (props) {
|
||||||
|
const { className, customNav } = props
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
export default function TopNavBar ({ className }) {
|
|
||||||
return <div id='top-nav' className={'sticky top-0 lg:relative w-full z-50 ' + className}>
|
return <div id='top-nav' className={'sticky top-0 lg:relative w-full z-50 ' + className}>
|
||||||
<div className='flex w-full h-12 shadow bg-white px-5 items-center'>
|
<div className='flex w-full h-12 shadow bg-white px-5 items-between'>
|
||||||
<LogoBar />
|
<LogoBar />
|
||||||
|
|
||||||
|
{/* 顶部菜单 */}
|
||||||
|
<div className='flex'>
|
||||||
|
{customNav && customNav.map(link => {
|
||||||
|
if (link.show) {
|
||||||
|
const selected = (router.pathname === link.to) || (router.asPath === link.to)
|
||||||
|
return <Link key={`${link.id}-${link.to}`} title={link.to} href={link.to} >
|
||||||
|
<a className={'px-5 duration-300 text-base justify-between hover:underline cursor-pointer flex flex-nowrap items-center ' +
|
||||||
|
(selected ? 'bg-green-600 text-white hover:text-white' : 'hover:text-green-600 ')} >
|
||||||
|
<div className='items-center justify-center flex '>
|
||||||
|
<i className={link.icon} />
|
||||||
|
<div className='ml-4 whitespace-nowrap'>{link.name}</div>
|
||||||
|
</div>
|
||||||
|
{link.slot}
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import LayoutBase from './LayoutBase'
|
import LayoutBase from './LayoutBase'
|
||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faSpinner } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
export const Layout404 = () => {
|
export const Layout404 = () => {
|
||||||
@@ -25,7 +23,7 @@ export const Layout404 = () => {
|
|||||||
<div
|
<div
|
||||||
className='md:-mt-20 text-black w-full h-screen text-center justify-center content-center items-center flex flex-col'>
|
className='md:-mt-20 text-black w-full h-screen text-center justify-center content-center items-center flex flex-col'>
|
||||||
<div className='dark:text-gray-200'>
|
<div className='dark:text-gray-200'>
|
||||||
<h2 className='inline-block border-r-2 border-gray-600 mr-2 px-3 py-2 align-top'><FontAwesomeIcon icon={faSpinner} spin={true} className='mr-2'/>404</h2>
|
<h2 className='inline-block border-r-2 border-gray-600 mr-2 px-3 py-2 align-top'><i className='mr-2 fa-spinner animate-spin'/>404</h2>
|
||||||
<div className='inline-block text-left h-32 leading-10 items-center'>
|
<div className='inline-block text-left h-32 leading-10 items-center'>
|
||||||
<h2 className='m-0 p-0'>页面无法加载,即将返回首页</h2>
|
<h2 className='m-0 p-0'>页面无法加载,即将返回首页</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,33 +15,11 @@ import CONFIG_NEXT from './config_next'
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 基础布局 采用左右两侧布局,移动端使用顶部导航栏
|
* 基础布局 采用左右两侧布局,移动端使用顶部导航栏
|
||||||
* @param children
|
|
||||||
* @param layout
|
|
||||||
* @param tags
|
|
||||||
* @param meta
|
|
||||||
* @param post
|
|
||||||
* @param currentSearch
|
|
||||||
* @param currentCategory
|
|
||||||
* @param currentTag
|
|
||||||
* @param categories
|
|
||||||
* @returns {JSX.Element}
|
* @returns {JSX.Element}
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
const LayoutBase = ({
|
const LayoutBase = (props) => {
|
||||||
children,
|
const { children, headerSlot, meta, sideBarSlot, floatSlot, rightAreaSlot } = props
|
||||||
headerSlot,
|
|
||||||
tags,
|
|
||||||
meta,
|
|
||||||
post,
|
|
||||||
postCount,
|
|
||||||
sideBarSlot,
|
|
||||||
floatSlot,
|
|
||||||
rightAreaSlot,
|
|
||||||
currentSearch,
|
|
||||||
currentCategory,
|
|
||||||
currentTag,
|
|
||||||
categories
|
|
||||||
}) => {
|
|
||||||
const { onLoading } = useGlobal()
|
const { onLoading } = useGlobal()
|
||||||
const targetRef = useRef(null)
|
const targetRef = useRef(null)
|
||||||
|
|
||||||
@@ -71,23 +49,18 @@ const LayoutBase = ({
|
|||||||
|
|
||||||
<CommonHead meta={meta} />
|
<CommonHead meta={meta} />
|
||||||
|
|
||||||
<TopNav tags={tags} postCount={postCount} post={post} slot={sideBarSlot} currentSearch={currentSearch} categories={categories} currentCategory={currentCategory} />
|
<TopNav slot={sideBarSlot} {...props}/>
|
||||||
|
|
||||||
<>{headerSlot}</>
|
<>{headerSlot}</>
|
||||||
|
|
||||||
<div className='h-0.5 w-full bg-gray-700 dark:bg-gray-600 hidden lg:block'/>
|
<div className='h-0.5 w-full bg-gray-700 dark:bg-gray-600 hidden lg:block'/>
|
||||||
|
|
||||||
<main id='wrapper' className='flex justify-center flex-1 pb-12'>
|
<main id='wrapper' className='flex justify-center flex-1 pb-12'>
|
||||||
<SideAreaLeft targetRef={targetRef} post={post} postCount={postCount} tags={tags} currentSearch={currentSearch} currentTag={currentTag} categories={categories} currentCategory={currentCategory}/>
|
<SideAreaLeft targetRef={targetRef} {...props}/>
|
||||||
<section id='center' className={`${CONFIG_NEXT.NAV_TYPE !== 'normal' ? 'mt-40' : ''} lg:max-w-3xl xl:max-w-4xl flex-grow md:mt-0 min-h-screen w-full`} ref={targetRef}>
|
<section id='center' className={`${CONFIG_NEXT.NAV_TYPE !== 'normal' ? 'mt-40' : ''} lg:max-w-3xl xl:max-w-4xl flex-grow md:mt-0 min-h-screen w-full`} ref={targetRef}>
|
||||||
{onLoading
|
{onLoading ? <LoadingCover/> : <> {children}</> }
|
||||||
? <LoadingCover/>
|
|
||||||
: <>
|
|
||||||
{children}
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
</section>
|
</section>
|
||||||
<SideAreaRight targetRef={targetRef} post={post} slot={rightAreaSlot} postCount={postCount} tags={tags} currentSearch={currentSearch} currentTag={currentTag} categories={categories} currentCategory={currentCategory}/>
|
<SideAreaRight targetRef={targetRef} slot={rightAreaSlot} {...props}/>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
{/* 右下角悬浮 */}
|
{/* 右下角悬浮 */}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import LayoutBase from './LayoutBase'
|
import LayoutBase from './LayoutBase'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faFolder, faThList } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
|
||||||
export const LayoutCategoryIndex = ({
|
export const LayoutCategoryIndex = ({
|
||||||
@@ -21,14 +19,14 @@ export const LayoutCategoryIndex = ({
|
|||||||
return <LayoutBase meta={meta} totalPosts={allPosts} tags={tags} postCount={postCount} latestPosts={latestPosts}>
|
return <LayoutBase meta={meta} totalPosts={allPosts} tags={tags} postCount={postCount} latestPosts={latestPosts}>
|
||||||
<div className='bg-white dark:bg-gray-700 px-10 py-10 shadow'>
|
<div className='bg-white dark:bg-gray-700 px-10 py-10 shadow'>
|
||||||
<div className='dark:text-gray-200 mb-5'>
|
<div className='dark:text-gray-200 mb-5'>
|
||||||
<FontAwesomeIcon icon={faThList} className='mr-4' />{locale.COMMON.CATEGORY}:
|
<i className='mr-4 fas faTh' />{locale.COMMON.CATEGORY}:
|
||||||
</div>
|
</div>
|
||||||
<div id='category-list' className='duration-200 flex flex-wrap'>
|
<div id='category-list' className='duration-200 flex flex-wrap'>
|
||||||
{Object.keys(categories).map(category => {
|
{Object.keys(categories).map(category => {
|
||||||
return <Link key={category} href={`/category/${category}`} passHref>
|
return <Link key={category} href={`/category/${category}`} passHref>
|
||||||
<div
|
<div
|
||||||
className={'hover:text-black dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600 px-5 cursor-pointer py-2 hover:bg-gray-100'}>
|
className={'hover:text-black dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600 px-5 cursor-pointer py-2 hover:bg-gray-100'}>
|
||||||
<FontAwesomeIcon icon={faFolder} className='mr-4' />{category}({categories[category]})
|
<i className='mr-4 fas fa-folder' />{category}({categories[category]})
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -6,24 +6,18 @@ import BlogPostListScroll from './components/BlogPostListScroll'
|
|||||||
import BlogPostListPage from './components/BlogPostListPage'
|
import BlogPostListPage from './components/BlogPostListPage'
|
||||||
import CONFIG_NEXT from './config_next'
|
import CONFIG_NEXT from './config_next'
|
||||||
|
|
||||||
export const LayoutIndex = ({ posts, tags, meta, categories, postCount, latestPosts }) => {
|
export const LayoutIndex = (props) => {
|
||||||
|
const { latestPosts } = props
|
||||||
|
const rightAreaSlot = CONFIG_NEXT.RIGHT_LATEST_POSTS && <Card><LatestPostsGroup posts={latestPosts} /></Card>
|
||||||
return <LayoutBase
|
return <LayoutBase
|
||||||
headerSlot={CONFIG_NEXT.HOME_BANNER && <Header />}
|
headerSlot={CONFIG_NEXT.HOME_BANNER && <Header />}
|
||||||
meta={meta}
|
|
||||||
tags={tags}
|
|
||||||
sideBarSlot={<LatestPostsGroup posts={latestPosts} />}
|
sideBarSlot={<LatestPostsGroup posts={latestPosts} />}
|
||||||
rightAreaSlot={
|
rightAreaSlot={rightAreaSlot}
|
||||||
CONFIG_NEXT.RIGHT_LATEST_POSTS && <Card><LatestPostsGroup posts={latestPosts} /></Card>
|
{...props}
|
||||||
}
|
|
||||||
postCount={postCount}
|
|
||||||
categories={categories}
|
|
||||||
>
|
>
|
||||||
{CONFIG_NEXT.POST_LIST_TYPE !== 'page'
|
{CONFIG_NEXT.POST_LIST_TYPE !== 'page'
|
||||||
? (
|
? <BlogPostListScroll {...props} showSummary={true} />
|
||||||
<BlogPostListScroll posts={posts} tags={tags} showSummary={true} />
|
: <BlogPostListPage {...props} />
|
||||||
)
|
}
|
||||||
: (
|
|
||||||
<BlogPostListPage posts={posts} tags={tags} postCount={postCount} />
|
|
||||||
)}
|
|
||||||
</LayoutBase>
|
</LayoutBase>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import LayoutBase from './LayoutBase'
|
import LayoutBase from './LayoutBase'
|
||||||
import StickyBar from './components/StickyBar'
|
import StickyBar from './components/StickyBar'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faSearch } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import BlogPostListScroll from './components/BlogPostListScroll'
|
import BlogPostListScroll from './components/BlogPostListScroll'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
@@ -36,7 +34,7 @@ export const LayoutSearch = ({ posts, tags, categories, postCount }) => {
|
|||||||
>
|
>
|
||||||
<StickyBar>
|
<StickyBar>
|
||||||
<div className="p-4 dark:text-gray-200">
|
<div className="p-4 dark:text-gray-200">
|
||||||
<FontAwesomeIcon icon={faSearch} className="mr-1" />{' '}
|
<i className="mr-1 fas fa-search" />{' '}
|
||||||
{filteredPosts.length} {locale.COMMON.RESULT_OF_SEARCH}
|
{filteredPosts.length} {locale.COMMON.RESULT_OF_SEARCH}
|
||||||
</div>
|
</div>
|
||||||
</StickyBar>
|
</StickyBar>
|
||||||
|
|||||||
@@ -10,16 +10,8 @@ import Live2D from './components/Live2D'
|
|||||||
import { useRef } from 'react'
|
import { useRef } from 'react'
|
||||||
import CONFIG_NEXT from './config_next'
|
import CONFIG_NEXT from './config_next'
|
||||||
|
|
||||||
export const LayoutSlug = ({
|
export const LayoutSlug = (props) => {
|
||||||
post,
|
const { post, prev, next, recommendPosts, latestPosts, showArticleInfo } = props
|
||||||
tags,
|
|
||||||
prev,
|
|
||||||
next,
|
|
||||||
recommendPosts,
|
|
||||||
categories,
|
|
||||||
postCount,
|
|
||||||
latestPosts
|
|
||||||
}) => {
|
|
||||||
const meta = {
|
const meta = {
|
||||||
title: `${post.title} | ${BLOG.TITLE}`,
|
title: `${post.title} | ${BLOG.TITLE}`,
|
||||||
description: post.summary,
|
description: post.summary,
|
||||||
@@ -41,12 +33,8 @@ export const LayoutSlug = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutBase
|
<LayoutBase
|
||||||
|
{...props}
|
||||||
meta={meta}
|
meta={meta}
|
||||||
tags={tags}
|
|
||||||
post={post}
|
|
||||||
postCount={postCount}
|
|
||||||
latestPosts={latestPosts}
|
|
||||||
categories={categories}
|
|
||||||
floatSlot={floatSlot}
|
floatSlot={floatSlot}
|
||||||
rightAreaSlot={
|
rightAreaSlot={
|
||||||
CONFIG_NEXT.RIGHT_LATEST_POSTS && <Card><LatestPostsGroup posts={latestPosts} /></Card>
|
CONFIG_NEXT.RIGHT_LATEST_POSTS && <Card><LatestPostsGroup posts={latestPosts} /></Card>
|
||||||
@@ -54,9 +42,10 @@ export const LayoutSlug = ({
|
|||||||
>
|
>
|
||||||
<ArticleDetail
|
<ArticleDetail
|
||||||
post={post}
|
post={post}
|
||||||
recommendPosts={recommendPosts}
|
|
||||||
prev={prev}
|
prev={prev}
|
||||||
next={next}
|
next={next}
|
||||||
|
recommendPosts={recommendPosts}
|
||||||
|
showArticleInfo={showArticleInfo}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 悬浮目录按钮 */}
|
{/* 悬浮目录按钮 */}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import LayoutBase from './LayoutBase'
|
import LayoutBase from './LayoutBase'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faTags } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import TagItem from './components/TagItem'
|
import TagItem from './components/TagItem'
|
||||||
|
|
||||||
export const LayoutTagIndex = ({ tags, categories, postCount, latestPosts }) => {
|
export const LayoutTagIndex = ({ tags, categories, postCount, latestPosts }) => {
|
||||||
@@ -14,7 +12,7 @@ export const LayoutTagIndex = ({ tags, categories, postCount, latestPosts }) =>
|
|||||||
}
|
}
|
||||||
return <LayoutBase meta={meta} categories={categories} postCount={postCount} latestPosts={latestPosts}>
|
return <LayoutBase meta={meta} categories={categories} postCount={postCount} latestPosts={latestPosts}>
|
||||||
<div className='bg-white dark:bg-gray-700 px-10 py-10 shadow'>
|
<div className='bg-white dark:bg-gray-700 px-10 py-10 shadow'>
|
||||||
<div className='dark:text-gray-200 mb-5'><FontAwesomeIcon icon={faTags} className='mr-4'/>{locale.COMMON.TAGS}:</div>
|
<div className='dark:text-gray-200 mb-5'><i className='fas fa-tags mr-4'/>{locale.COMMON.TAGS}:</div>
|
||||||
<div id='tags-list' className='duration-200 flex flex-wrap'>
|
<div id='tags-list' className='duration-200 flex flex-wrap'>
|
||||||
{ tags.map(tag => {
|
{ tags.map(tag => {
|
||||||
return <div key={tag.name} className='p-2'><TagItem key={tag.name} tag={tag} /></div>
|
return <div key={tag.name} className='p-2'><TagItem key={tag.name} tag={tag} /></div>
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ import ShareBar from './ShareBar'
|
|||||||
import TagItem from './TagItem'
|
import TagItem from './TagItem'
|
||||||
import formatDate from '@/lib/formatDate'
|
import formatDate from '@/lib/formatDate'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { faEye, faFolderOpen } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import mediumZoom from 'medium-zoom'
|
import mediumZoom from 'medium-zoom'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
@@ -28,7 +26,8 @@ import WordCount from './WordCount'
|
|||||||
* @param {*} param0
|
* @param {*} param0
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export default function ArticleDetail ({ post, recommendPosts, prev, next }) {
|
export default function ArticleDetail (props) {
|
||||||
|
const { post, recommendPosts, prev, next, showArticleInfo } = props
|
||||||
const url = BLOG.LINK + useRouter().asPath
|
const url = BLOG.LINK + useRouter().asPath
|
||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
const date = formatDate(post?.date?.start_date || post.createdTime, locale.LOCALE)
|
const date = formatDate(post?.date?.start_date || post.createdTime, locale.LOCALE)
|
||||||
@@ -56,20 +55,11 @@ export default function ArticleDetail ({ post, recommendPosts, prev, next }) {
|
|||||||
className="subpixel-antialiased py-10 px-5 lg:pt-24 md:px-24 dark:border-gray-700 bg-white dark:bg-gray-800"
|
className="subpixel-antialiased py-10 px-5 lg:pt-24 md:px-24 dark:border-gray-700 bg-white dark:bg-gray-800"
|
||||||
>
|
>
|
||||||
|
|
||||||
<header className='animate__slideInDown animate__animated'>
|
{showArticleInfo && <header className='animate__slideInDown animate__animated'>
|
||||||
{post.type && !post.type.includes('Page') && post?.page_cover && (
|
{post.type && !post.type.includes('Page') && post?.page_cover && (
|
||||||
<div className="w-full relative md:flex-shrink-0 overflow-hidden">
|
<div className="w-full relative md:flex-shrink-0 overflow-hidden">
|
||||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
<img alt={post.title} src={post?.page_cover} className='object-center w-full' />
|
<img alt={post.title} src={post?.page_cover} className='object-center w-full' />
|
||||||
{/* <div className="w-full h-60 relative lg:h-96 transform duration-200 md:flex-shrink-0 overflow-hidden">
|
|
||||||
<Image
|
|
||||||
src={post?.page_cover}
|
|
||||||
loading="eager"
|
|
||||||
objectFit="cover"
|
|
||||||
layout="fill"
|
|
||||||
alt={post.title}
|
|
||||||
/>
|
|
||||||
</div> */}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -80,14 +70,14 @@ export default function ArticleDetail ({ post, recommendPosts, prev, next }) {
|
|||||||
|
|
||||||
<section className="flex-wrap flex mt-2 text-gray-400 dark:text-gray-400 font-light leading-8">
|
<section className="flex-wrap flex mt-2 text-gray-400 dark:text-gray-400 font-light leading-8">
|
||||||
<div>
|
<div>
|
||||||
<Link href={`/category/${post.category}`} passHref>
|
{post.category && <>
|
||||||
|
<Link href={`/category/${post.category}`} passHref>
|
||||||
<a className="cursor-pointer text-md mr-2 hover:text-black dark:hover:text-white border-b dark:border-gray-500 border-dashed">
|
<a className="cursor-pointer text-md mr-2 hover:text-black dark:hover:text-white border-b dark:border-gray-500 border-dashed">
|
||||||
<FontAwesomeIcon icon={faFolderOpen} className="mr-1" />
|
<i className="mr-1 far fa-folder-open" /> {post.category}
|
||||||
{post.category}
|
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
<span className='mr-2'>|</span>
|
<span className='mr-2'>|</span>
|
||||||
|
</>}
|
||||||
{post.type[0] !== 'Page' && (<>
|
{post.type[0] !== 'Page' && (<>
|
||||||
<Link
|
<Link
|
||||||
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`}
|
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`}
|
||||||
@@ -101,7 +91,7 @@ export default function ArticleDetail ({ post, recommendPosts, prev, next }) {
|
|||||||
</>)}
|
</>)}
|
||||||
|
|
||||||
<div className="hidden busuanzi_container_page_pv font-light mr-2">
|
<div className="hidden busuanzi_container_page_pv font-light mr-2">
|
||||||
<FontAwesomeIcon icon={faEye} className='mr-1'/>
|
<i className='mr-1 fa-eye'/>
|
||||||
|
|
||||||
<span className="mr-2 busuanzi_value_page_pv"/>
|
<span className="mr-2 busuanzi_value_page_pv"/>
|
||||||
<span className='mr-2'>|</span>
|
<span className='mr-2'>|</span>
|
||||||
@@ -113,11 +103,9 @@ export default function ArticleDetail ({ post, recommendPosts, prev, next }) {
|
|||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* <hr className="mt-2" /> */}
|
</header>}
|
||||||
|
|
||||||
</header>
|
{/* Notion内容主体 */}
|
||||||
|
|
||||||
{/* Notion文章主体 */}
|
|
||||||
<article id='notion-article' className='px-1'>
|
<article id='notion-article' className='px-1'>
|
||||||
{post.blockMap && (
|
{post.blockMap && (
|
||||||
<NotionRenderer
|
<NotionRenderer
|
||||||
@@ -144,6 +132,7 @@ export default function ArticleDetail ({ post, recommendPosts, prev, next }) {
|
|||||||
data-ad-slot="3806269138"/>
|
data-ad-slot="3806269138"/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{showArticleInfo && <>
|
||||||
{/* 版权声明 */}
|
{/* 版权声明 */}
|
||||||
<ArticleCopyright author={BLOG.AUTHOR} url={url} />
|
<ArticleCopyright author={BLOG.AUTHOR} url={url} />
|
||||||
|
|
||||||
@@ -168,6 +157,7 @@ export default function ArticleDetail ({ post, recommendPosts, prev, next }) {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<BlogAround prev={prev} next={next} />
|
<BlogAround prev={prev} next={next} />
|
||||||
|
</>}
|
||||||
|
|
||||||
{/* 评论互动 */}
|
{/* 评论互动 */}
|
||||||
<div className="duration-200 w-full dark:border-gray-700 bg-white dark:bg-gray-800">
|
<div className="duration-200 w-full dark:border-gray-700 bg-white dark:bg-gray-800">
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faAngleDoubleLeft, faAngleDoubleRight } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上一篇,下一篇文章
|
* 上一篇,下一篇文章
|
||||||
@@ -14,12 +12,12 @@ export default function BlogAround ({ prev, next }) {
|
|||||||
return <section className='text-gray-800 border-t dark:text-gray-300 flex flex-wrap lg:flex-nowrap lg:space-x-10 justify-between py-2'>
|
return <section className='text-gray-800 border-t dark:text-gray-300 flex flex-wrap lg:flex-nowrap lg:space-x-10 justify-between py-2'>
|
||||||
{prev && <Link href={`/article/${prev.slug}`} passHref>
|
{prev && <Link href={`/article/${prev.slug}`} passHref>
|
||||||
<a className='text-sm py-3 text-gray-400 hover:underline cursor-pointer'>
|
<a className='text-sm py-3 text-gray-400 hover:underline cursor-pointer'>
|
||||||
<FontAwesomeIcon icon={faAngleDoubleLeft} className='mr-1' />{prev.title}
|
<i className='mr-1 fas fa-angle-double-left' />{prev.title}
|
||||||
</a>
|
</a>
|
||||||
</Link>}
|
</Link>}
|
||||||
{next && <Link href={`/article/${next.slug}`} passHref>
|
{next && <Link href={`/article/${next.slug}`} passHref>
|
||||||
<a className='text-sm flex py-3 text-gray-400 hover:underline cursor-pointer'>{next.title}
|
<a className='text-sm flex py-3 text-gray-400 hover:underline cursor-pointer'>{next.title}
|
||||||
<FontAwesomeIcon icon={faAngleDoubleRight} className='ml-1 my-1' />
|
<i className='ml-1 my-1 fas -fa-angle-double-right' />
|
||||||
</a>
|
</a>
|
||||||
</Link>}
|
</Link>}
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { faAngleRight, faFolder } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
@@ -26,12 +24,14 @@ const BlogPostCard = ({ post, showSummary }) => {
|
|||||||
|
|
||||||
<div className={`flex mt-2 items-center ${showPreview ? 'justify-center' : 'justify-start'} flex-wrap dark:text-gray-500 text-gray-400 hover:text-blue-500 dark:hover:text-blue-400 `}>
|
<div className={`flex mt-2 items-center ${showPreview ? 'justify-center' : 'justify-start'} flex-wrap dark:text-gray-500 text-gray-400 hover:text-blue-500 dark:hover:text-blue-400 `}>
|
||||||
<div>
|
<div>
|
||||||
|
{ post.category && (<>
|
||||||
<Link href={`/category/${post.category}`} passHref>
|
<Link href={`/category/${post.category}`} passHref>
|
||||||
<a className='cursor-pointer font-light text-sm hover:underline transform'>
|
<a className='cursor-pointer font-light text-sm hover:underline transform'>
|
||||||
<FontAwesomeIcon icon={faFolder} className='mr-1' />{post.category}
|
<i className='mr-1 fas fa-folder' />{post.category}
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
<span className='mx-2'>|</span>
|
<span className='mx-2'>|</span>
|
||||||
|
</>) }
|
||||||
<Link href={`/archive#${post?.date?.start_date?.substr(0, 7)}`} passHref>
|
<Link href={`/archive#${post?.date?.start_date?.substr(0, 7)}`} passHref>
|
||||||
<a className='font-light hover:underline cursor-pointer text-sm leading-4 mr-3'>{post.date.start_date}</a>
|
<a className='font-light hover:underline cursor-pointer text-sm leading-4 mr-3'>{post.date.start_date}</a>
|
||||||
</Link>
|
</Link>
|
||||||
@@ -63,7 +63,7 @@ const BlogPostCard = ({ post, showSummary }) => {
|
|||||||
<Link href={`${BLOG.PATH}/article/${post.slug}`}>
|
<Link href={`${BLOG.PATH}/article/${post.slug}`}>
|
||||||
<a className='hover:bg-opacity-100 hover:scale-105 hover:underline pointer-events-auto transform duration-300 p-3 text-white bg-gray-800 cursor-pointer'>
|
<a className='hover:bg-opacity-100 hover:scale-105 hover:underline pointer-events-auto transform duration-300 p-3 text-white bg-gray-800 cursor-pointer'>
|
||||||
{locale.COMMON.ARTICLE_DETAIL}
|
{locale.COMMON.ARTICLE_DETAIL}
|
||||||
<FontAwesomeIcon className='ml-1' icon={faAngleRight} /></a>
|
<i className='ml-1 fas fa-angle-right' /></a>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { faFolder, faFolderOpen } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
@@ -13,7 +11,7 @@ const CategoryGroup = ({ currentCategory, categories }) => {
|
|||||||
? 'hover:text-white dark:hover:text-white bg-gray-600 text-white '
|
? 'hover:text-white dark:hover:text-white bg-gray-600 text-white '
|
||||||
: 'dark:text-gray-400 text-gray-500 hover:text-white hover:bg-gray-500 dark:hover:text-white') +
|
: 'dark:text-gray-400 text-gray-500 hover:text-white hover:bg-gray-500 dark:hover:text-white') +
|
||||||
' text-sm w-full items-center duration-300 px-2 cursor-pointer py-1 font-light'}>
|
' text-sm w-full items-center duration-300 px-2 cursor-pointer py-1 font-light'}>
|
||||||
<FontAwesomeIcon icon={selected ? faFolderOpen : faFolder} className={`${selected ? 'text-white' : 'text-gray-400'} mr-2`} />{category}({categories[category]})
|
<i className={`${selected ? 'text-white fa-folder-open ' : 'text-gray-400 fa-folder '} mr-2 fas`} />{category}({categories[category]})
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faFolder, faFolderOpen } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
|
|
||||||
const CategoryList = ({ currentCategory, categories }) => {
|
const CategoryList = ({ currentCategory, categories }) => {
|
||||||
@@ -24,7 +22,7 @@ const CategoryList = ({ currentCategory, categories }) => {
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<a>
|
<a>
|
||||||
<FontAwesomeIcon icon={selected ? faFolderOpen : faFolder} className='mr-1' />
|
<i className={`${selected ? 'fa-folder-open ' : 'fa-folder '} fas mr-1`}/>
|
||||||
{`${category} `}
|
{`${category} `}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faInfo } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 悬浮在屏幕右下角,联系我的按钮
|
* 悬浮在屏幕右下角,联系我的按钮
|
||||||
@@ -14,7 +12,7 @@ const ContactButton = () => {
|
|||||||
<a className={'fixed right-10 bottom-40 animate__fadeInRight animate__animated animate__faster'}>
|
<a className={'fixed right-10 bottom-40 animate__fadeInRight animate__animated animate__faster'}>
|
||||||
<span
|
<span
|
||||||
className='dark:bg-black bg-white px-5 py-3 cursor-pointer shadow-card text-xl hover:bg-blue-500 transform duration-200 hover:text-white hover:shadow'>
|
className='dark:bg-black bg-white px-5 py-3 cursor-pointer shadow-card text-xl hover:bg-blue-500 transform duration-200 hover:text-white hover:shadow'>
|
||||||
<FontAwesomeIcon icon={faInfo} className='dark:text-gray-200 ' title='about' />
|
<i className='dark:text-gray-200 fas fa-info' title='about' />
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { faMoon, faSun } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { loadUserThemeFromCookies, saveTheme } from '@/lib/theme'
|
import { loadUserThemeFromCookies, saveTheme } from '@/lib/theme'
|
||||||
|
|
||||||
const DarkModeButton = () => {
|
const DarkModeButton = () => {
|
||||||
@@ -14,7 +12,7 @@ const DarkModeButton = () => {
|
|||||||
changeTheme(newTheme)
|
changeTheme(newTheme)
|
||||||
}
|
}
|
||||||
return <div className='z-10 duration-200 text-xs cursor-pointer py-1.5 px-1'>
|
return <div className='z-10 duration-200 text-xs cursor-pointer py-1.5 px-1'>
|
||||||
<FontAwesomeIcon icon={userTheme === 'dark' ? faSun : faMoon} id='darkModeButton' className='hover:scale-125 transform duration-200'
|
<i id='darkModeButton' className={`hover:scale-125 transform duration-200 fas ${userTheme === 'dark' ? 'fa-sun' : 'fa-moon'}`}
|
||||||
onClick={handleChangeDarkMode} />
|
onClick={handleChangeDarkMode} />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { loadUserThemeFromCookies, saveTheme } from '@/lib/theme'
|
import { loadUserThemeFromCookies, saveTheme } from '@/lib/theme'
|
||||||
import { faMoon, faSun } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import CONFIG_NEXT from '../config_next'
|
import CONFIG_NEXT from '../config_next'
|
||||||
|
|
||||||
export default function FloatDarkModeButton () {
|
export default function FloatDarkModeButton () {
|
||||||
@@ -27,10 +25,9 @@ export default function FloatDarkModeButton () {
|
|||||||
className={ ' text-black dark:border-gray-500 flex justify-center items-center dark:text-gray-200 py-2 px-3'
|
className={ ' text-black dark:border-gray-500 flex justify-center items-center dark:text-gray-200 py-2 px-3'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<i
|
||||||
icon={userTheme === 'dark' ? faSun : faMoon}
|
|
||||||
id="darkModeButton"
|
id="darkModeButton"
|
||||||
className="hover:scale-150 transform duration-200"
|
className={`${userTheme === 'dark' ? 'fa-sun' : 'fa-moon'} fas hover:scale-150 transform duration-200`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { faCopyright, faEye, faShieldAlt, faUsers, faHeart } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import Link from 'next/link'
|
|
||||||
|
|
||||||
const Footer = ({ title }) => {
|
const Footer = ({ title }) => {
|
||||||
const d = new Date()
|
const d = new Date()
|
||||||
@@ -12,16 +9,16 @@ const Footer = ({ title }) => {
|
|||||||
<footer
|
<footer
|
||||||
className='dark:bg-gray-900 flex-shrink-0 justify-center text-center m-auto w-full leading-6 text-gray-400 text-sm p-6'
|
className='dark:bg-gray-900 flex-shrink-0 justify-center text-center m-auto w-full leading-6 text-gray-400 text-sm p-6'
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faCopyright} /> {`${startYear}${currentYear}`} <span><FontAwesomeIcon icon={faHeart} className='mx-1 animate-pulse'/> <Link href='/about'><a className='underline font-bold text-gray-500 dark:text-gray-300 '>{BLOG.AUTHOR}</a></Link>.
|
<i className='fas fa-copyright' /> {`${startYear}${currentYear}`} <span><i className='mx-1 animate-pulse fas fas-heart'/> <a href={BLOG.LINK} className='underline font-bold text-gray-500 dark:text-gray-300 '>{BLOG.AUTHOR}</a>.
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<span>Powered by <a href='https://notion.so' className='underline font-bold text-gray-500 dark:text-gray-300'>Notion</a> & <a href='https://github.com/tangly1024/NotionNext' className='underline font-bold text-gray-500 dark:text-gray-300'>NotionNext</a>.</span></span>
|
<span>Powered by <a href='https://notion.so' className='underline font-bold text-gray-500 dark:text-gray-300'>Notion</a> & <a href='https://github.com/tangly1024/NotionNext' className='underline font-bold text-gray-500 dark:text-gray-300'>NotionNext</a>.</span></span>
|
||||||
|
|
||||||
{BLOG.BEI_AN && <><br /><FontAwesomeIcon icon={faShieldAlt} /> <a href='https://beian.miit.gov.cn/' className='mr-2'>{BLOG.BEI_AN}</a><br/></>}
|
{BLOG.BEI_AN && <><br /><i className='fas fa-shield-alt' /> <a href='https://beian.miit.gov.cn/' className='mr-2'>{BLOG.BEI_AN}</a><br/></>}
|
||||||
<span className='hidden busuanzi_container_site_pv'>
|
<span className='hidden busuanzi_container_site_pv'>
|
||||||
<FontAwesomeIcon icon={faEye}/><span className='px-1 busuanzi_value_site_pv'> </span> </span>
|
<i className='fas fa-eye'/><span className='px-1 busuanzi_value_site_pv'> </span> </span>
|
||||||
<span className='pl-2 hidden busuanzi_container_site_uv'>
|
<span className='pl-2 hidden busuanzi_container_site_uv'>
|
||||||
<FontAwesomeIcon icon={faUsers}/> <span className='px-1 busuanzi_value_site_uv'> </span> </span>
|
<i className='fas fa-users'/> <span className='px-1 busuanzi_value_site_uv'> </span> </span>
|
||||||
<br/>
|
<br/>
|
||||||
<h1>{title}</h1>
|
<h1>{title}</h1>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { faAngleDown } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import Typed from 'typed.js'
|
import Typed from 'typed.js'
|
||||||
import CONFIG_NEXT from '../config_next'
|
import CONFIG_NEXT from '../config_next'
|
||||||
@@ -111,7 +109,7 @@ export default function Header () {
|
|||||||
}}
|
}}
|
||||||
className="cursor-pointer w-full text-center py-4 text-5xl absolute bottom-10 text-white"
|
className="cursor-pointer w-full text-center py-4 text-5xl absolute bottom-10 text-white"
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faAngleDown} className='animate-bounce'/>
|
<i className='animate-bounce fas fa-angle-down'/>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { faArrowDown } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import smoothscroll from 'smoothscroll-polyfill'
|
import smoothscroll from 'smoothscroll-polyfill'
|
||||||
import CONFIG_NEXT from '../config_next'
|
import CONFIG_NEXT from '../config_next'
|
||||||
@@ -47,7 +45,7 @@ const JumpToBottomButton = ({ showPercent = false }) => {
|
|||||||
|
|
||||||
return (<div className='flex space-x-1 transform hover:scale-105 duration-200 py-2 px-3' onClick={scrollToBottom} >
|
return (<div className='flex space-x-1 transform hover:scale-105 duration-200 py-2 px-3' onClick={scrollToBottom} >
|
||||||
<div className='dark:text-gray-200' >
|
<div className='dark:text-gray-200' >
|
||||||
<FontAwesomeIcon icon={faArrowDown} />
|
<i className='fas fa-arrow-down' />
|
||||||
</div>
|
</div>
|
||||||
{showPercent && (<div className='dark:text-gray-200 block lg:hidden'>{percent}%</div>)}
|
{showPercent && (<div className='dark:text-gray-200 block lg:hidden'>{percent}%</div>)}
|
||||||
</div>)
|
</div>)
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { faArrowUp } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import CONFIG_NEXT from '../config_next'
|
import CONFIG_NEXT from '../config_next'
|
||||||
|
|
||||||
@@ -19,7 +17,7 @@ const JumpToTopButton = ({ showPercent = true, percent }) => {
|
|||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
return (<div className='flex space-x-1 items-center transform hover:scale-105 duration-200 py-2 px-3' onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })} >
|
return (<div className='flex space-x-1 items-center transform hover:scale-105 duration-200 py-2 px-3' onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })} >
|
||||||
<div className='dark:text-gray-200' title={locale.POST.TOP} >
|
<div className='dark:text-gray-200' title={locale.POST.TOP} >
|
||||||
<FontAwesomeIcon icon={faArrowUp} />
|
<i className='fa-arrow-up fas' />
|
||||||
</div>
|
</div>
|
||||||
{showPercent && (<div className='text-xs dark:text-gray-200 block lg:hidden'>{percent}%</div>)}
|
{showPercent && (<div className='text-xs dark:text-gray-200 block lg:hidden'>{percent}%</div>)}
|
||||||
</div>)
|
</div>)
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { faArchive, faFileAlt } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
@@ -21,7 +19,7 @@ const LatestPostsGroup = ({ posts }) => {
|
|||||||
|
|
||||||
return <>
|
return <>
|
||||||
<div className='text-sm pb-1 px-2 flex flex-nowrap justify-between'>
|
<div className='text-sm pb-1 px-2 flex flex-nowrap justify-between'>
|
||||||
<div className='font-light text-gray-600 dark:text-gray-200'><FontAwesomeIcon icon={faArchive} className='mr-2' />{locale.COMMON.LATEST_POSTS}</div>
|
<div className='font-light text-gray-600 dark:text-gray-200'><i className='mr-2 fas fa-archive' />{locale.COMMON.LATEST_POSTS}</div>
|
||||||
</div>
|
</div>
|
||||||
{posts.map(post => {
|
{posts.map(post => {
|
||||||
const selected = currentPath === `${BLOG.PATH}/article/${post.slug}`
|
const selected = currentPath === `${BLOG.PATH}/article/${post.slug}`
|
||||||
@@ -30,7 +28,7 @@ const LatestPostsGroup = ({ posts }) => {
|
|||||||
<a className={ 'my-1 flex font-light'}>
|
<a className={ 'my-1 flex font-light'}>
|
||||||
<div className={ (selected ? 'text-white bg-gray-600 ' : 'text-gray-500 dark:text-gray-400 ') + ' text-xs py-1.5 flex overflow-x-hidden whitespace-nowrap hover:bg-gray-500 px-2 duration-200 w-full ' +
|
<div className={ (selected ? 'text-white bg-gray-600 ' : 'text-gray-500 dark:text-gray-400 ') + ' text-xs py-1.5 flex overflow-x-hidden whitespace-nowrap hover:bg-gray-500 px-2 duration-200 w-full ' +
|
||||||
'hover:text-white dark:hover:text-white cursor-pointer' }>
|
'hover:text-white dark:hover:text-white cursor-pointer' }>
|
||||||
<FontAwesomeIcon icon={faFileAlt} className='mr-2'/>
|
<i className='mr-2 fas fa-file-alt'/>
|
||||||
<div className='truncate'>{post.title}</div>
|
<div className='truncate'>{post.title}</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import throttle from 'lodash.throttle'
|
import throttle from 'lodash.throttle'
|
||||||
import DarkModeButton from './DarkModeButton'
|
import DarkModeButton from './DarkModeButton'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faBars } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 左上角悬浮菜单栏
|
* 左上角悬浮菜单栏
|
||||||
@@ -32,8 +30,7 @@ const LeftFloatButton = () => {
|
|||||||
{/* 菜单折叠 */}
|
{/* 菜单折叠 */}
|
||||||
<div className='p-1 border hover:shadow-xl duration-200 dark:border-gray-500 h-12 bg-white dark:bg-gray-600 dark:bg-opacity-70 bg-opacity-70
|
<div className='p-1 border hover:shadow-xl duration-200 dark:border-gray-500 h-12 bg-white dark:bg-gray-600 dark:bg-opacity-70 bg-opacity-70
|
||||||
dark:hover:bg-gray-100 text-xl cursor-pointer mr-2 my-2 dark:text-gray-300 dark:hover:text-black'>
|
dark:hover:bg-gray-100 text-xl cursor-pointer mr-2 my-2 dark:text-gray-300 dark:hover:text-black'>
|
||||||
<FontAwesomeIcon icon={faBars} className='p-2.5 hover:scale-125 transform duration-200'
|
<i className='p-2.5 hover:scale-125 transform duration-200 fas fa-bars' onClick={() => changeCollapse(!collapse)} />
|
||||||
onClick={() => changeCollapse(!collapse)} />
|
|
||||||
</div>
|
</div>
|
||||||
{/* 夜间模式 */}
|
{/* 夜间模式 */}
|
||||||
<DarkModeButton />
|
<DarkModeButton />
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faSpinner } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
|
|
||||||
export default function LoadingCover () {
|
export default function LoadingCover () {
|
||||||
return (<div id="loading-cover" className={'md:-mt-20 flex-grow dark:text-white text-black animate__animated animate__fadeIn flex flex-col justify-center z-10 w-full h-screen container mx-auto'}>
|
return (<div id="loading-cover" className={'md:-mt-20 flex-grow dark:text-white text-black animate__animated animate__fadeIn flex flex-col justify-center z-10 w-full h-screen container mx-auto'}>
|
||||||
<div className="mx-auto">
|
<div className="mx-auto">
|
||||||
<FontAwesomeIcon icon={faSpinner} spin size='2x'/>
|
<i className="fas fa-spinner animate-spin"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,31 +2,34 @@ import React from 'react'
|
|||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faArchive, faHome, faTag, faTh, faUser } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import CONFIG_NEXT from '../config_next'
|
import CONFIG_NEXT from '../config_next'
|
||||||
|
|
||||||
const MenuButtonGroup = ({ postCount }) => {
|
const MenuButtonGroup = (props) => {
|
||||||
|
const { postCount, customNav } = props
|
||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const archiveSlot = <div className='bg-gray-300 dark:bg-gray-500 rounded-md text-gray-50 px-1 text-xs'>{postCount}</div>
|
const archiveSlot = <div className='bg-gray-300 dark:bg-gray-500 rounded-md text-gray-50 px-1 text-xs'>{postCount}</div>
|
||||||
|
|
||||||
const links = [
|
let links = [
|
||||||
{ id: 0, icon: faHome, name: locale.NAV.INDEX, to: '/' || '/', show: CONFIG_NEXT.MENU_HOME },
|
{ icon: 'fas fa-home', name: locale.NAV.INDEX, to: '/' || '/', show: true },
|
||||||
{ id: 1, icon: faTh, name: locale.COMMON.CATEGORY, to: '/category', show: CONFIG_NEXT.MENU_CATEGORY },
|
{ icon: 'fas fa-th', name: locale.COMMON.CATEGORY, to: '/category', show: CONFIG_NEXT.MENU_CATEGORY },
|
||||||
{ id: 2, icon: faTag, name: locale.COMMON.TAGS, to: '/tag', show: CONFIG_NEXT.MENU_TAG },
|
{ icon: 'fas fa-tag', name: locale.COMMON.TAGS, to: '/tag', show: CONFIG_NEXT.MENU_TAG },
|
||||||
{ id: 3, icon: faArchive, name: locale.NAV.ARCHIVE, to: '/archive', slot: archiveSlot, show: CONFIG_NEXT.MENU_ARCHIVE },
|
{ icon: 'fas fa-archive', name: locale.NAV.ARCHIVE, to: '/archive', slot: archiveSlot, show: CONFIG_NEXT.MENU_ARCHIVE },
|
||||||
{ id: 4, icon: faUser, name: locale.NAV.ABOUT, to: '/about', show: CONFIG_NEXT.MENU_ABOUT }
|
{ icon: 'fas fa-user', name: locale.NAV.ABOUT, to: '/about', show: CONFIG_NEXT.MENU_ABOUT }
|
||||||
]
|
]
|
||||||
|
if (customNav) {
|
||||||
|
links = links.concat(customNav)
|
||||||
|
}
|
||||||
|
|
||||||
return <nav id='nav' className='leading-8 text-gray-500 dark:text-gray-400 font-sans'>
|
return <nav id='nav' className='leading-8 text-gray-500 dark:text-gray-400 font-sans'>
|
||||||
{links.map(link => {
|
{links.map(link => {
|
||||||
if (link.show) {
|
if (link && link.show) {
|
||||||
const selected = (router.pathname === link.to) || (router.asPath === link.to)
|
const selected = (router.pathname === link.to) || (router.asPath === link.to)
|
||||||
return <Link key={`${link.id}-${link.to}`} title={link.to} href={link.to} >
|
return <Link key={`${link.to}`} title={link.to} href={link.to} >
|
||||||
<a className={'py-1.5 px-5 duration-300 text-base justify-between hover:bg-gray-700 hover:text-white hover:shadow-lg cursor-pointer font-light flex flex-nowrap items-center ' +
|
<a className={'py-1.5 px-5 duration-300 text-base justify-between hover:bg-gray-700 hover:text-white hover:shadow-lg cursor-pointer font-light flex flex-nowrap items-center ' +
|
||||||
(selected ? 'bg-gray-200 text-black' : ' ')} >
|
(selected ? 'bg-gray-200 text-black' : ' ')} >
|
||||||
<div className='my-auto items-center justify-center flex '>
|
<div className='my-auto items-center justify-center flex '>
|
||||||
<FontAwesomeIcon icon={link.icon} />
|
<i className={`${link.icon} w-4 text-center`} />
|
||||||
<div className={'ml-4'}>{link.name}</div>
|
<div className={'ml-4'}>{link.name}</div>
|
||||||
</div>
|
</div>
|
||||||
{link.slot}
|
{link.slot}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faAngleLeft, faAngleRight } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数字翻页插件
|
* 数字翻页插件
|
||||||
@@ -29,7 +27,7 @@ const PaginationNumber = ({ page, totalPage }) => {
|
|||||||
rel='prev'
|
rel='prev'
|
||||||
className={`${currentPage === 1 ? 'invisible' : 'block'} border-white dark:border-gray-700 hover:border-gray-400 dark:hover:border-gray-400 w-6 text-center cursor-pointer duration-200 hover:font-bold`}
|
className={`${currentPage === 1 ? 'invisible' : 'block'} border-white dark:border-gray-700 hover:border-gray-400 dark:hover:border-gray-400 w-6 text-center cursor-pointer duration-200 hover:font-bold`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faAngleLeft}/>
|
<i className='fas fa-angle-left'/>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
@@ -41,7 +39,7 @@ const PaginationNumber = ({ page, totalPage }) => {
|
|||||||
rel='next'
|
rel='next'
|
||||||
className={`${+showNext ? 'block' : 'invisible'} border-t-2 border-white dark:border-gray-700 hover:border-gray-400 dark:hover:border-gray-400 w-6 text-center cursor-pointer duration-500 hover:font-bold`}
|
className={`${+showNext ? 'block' : 'invisible'} border-t-2 border-white dark:border-gray-700 hover:border-gray-400 dark:hover:border-gray-400 w-6 text-center cursor-pointer duration-500 hover:font-bold`}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faAngleRight}/>
|
<i className='fas fa-angle-right'/>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faQrcode } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 赞赏按钮
|
* 赞赏按钮
|
||||||
@@ -23,7 +21,7 @@ const RewardButton = () => {
|
|||||||
<div className='justify-center'>
|
<div className='justify-center'>
|
||||||
<div onMouseEnter={openPopover} onMouseLeave={closePopover}
|
<div onMouseEnter={openPopover} onMouseLeave={closePopover}
|
||||||
className='bg-pink-500 py-2 w-36 mx-auto animate__jello text-white hover:bg-green-400 duration-200 transform hover:scale-110 px-3 rounded cursor-pointer'>
|
className='bg-pink-500 py-2 w-36 mx-auto animate__jello text-white hover:bg-green-400 duration-200 transform hover:scale-110 px-3 rounded cursor-pointer'>
|
||||||
<FontAwesomeIcon icon={faQrcode} className='mr-2' />
|
<i className='mr-2 fas fa-qrcode' />
|
||||||
<span>打赏一杯咖啡</span>
|
<span>打赏一杯咖啡</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { useImperativeHandle, useRef, useState } from 'react'
|
import { useImperativeHandle, useRef, useState } from 'react'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faSearch, faSpinner, faTimes } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
|
|
||||||
const SearchInput = ({ currentTag, currentSearch, cRef }) => {
|
const SearchInput = ({ currentTag, currentSearch, cRef }) => {
|
||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
@@ -54,11 +52,11 @@ const SearchInput = ({ currentTag, currentSearch, cRef }) => {
|
|||||||
onChange={e => updateSearchKey(e.target.value)}
|
onChange={e => updateSearchKey(e.target.value)}
|
||||||
defaultValue={searchKey}
|
defaultValue={searchKey}
|
||||||
/>
|
/>
|
||||||
{(searchKey && searchKey.length && <FontAwesomeIcon icon={faTimes} className='text-gray-300 float-right m-3 cursor-pointer' onClick={cleanSearch} />)}
|
{(searchKey && searchKey.length && <i className='fas fa-times text-gray-300 float-right m-3 cursor-pointer' onClick={cleanSearch} />)}
|
||||||
|
|
||||||
<div className='p-3 bg-gray-50 flex border-l dark:border-gray-700 dark:hover:bg-gray-800 dark:bg-gray-600 justify-center items-center cursor-pointer'
|
<div className='p-3 bg-gray-50 flex border-l dark:border-gray-700 dark:hover:bg-gray-800 dark:bg-gray-600 justify-center items-center cursor-pointer'
|
||||||
onClick={() => { handleSearch(searchKey) }}>
|
onClick={() => { handleSearch(searchKey) }}>
|
||||||
<FontAwesomeIcon spin={onLoading} icon={onLoading ? faSpinner : faSearch} className='hover:scale-125 hover:text-black transform duration-200 dark:text-gray-300 dark:hover:text-white text-gray-600 cursor-pointer ' />
|
<i className={`${onLoading ? 'fa-spinner animate-spin ' : 'fa-search'} fas hover:scale-125 hover:text-black transform duration-200 dark:text-gray-300 dark:hover:text-white text-gray-600 cursor-pointer`} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,16 +5,6 @@ import { createPopper } from '@popperjs/core'
|
|||||||
import copy from 'copy-to-clipboard'
|
import copy from 'copy-to-clipboard'
|
||||||
import QRCode from 'qrcode.react'
|
import QRCode from 'qrcode.react'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import {
|
|
||||||
faFacebookSquare,
|
|
||||||
faQq,
|
|
||||||
faTelegram,
|
|
||||||
faTwitterSquare,
|
|
||||||
faWeibo,
|
|
||||||
faWeixin
|
|
||||||
} from '@fortawesome/free-brands-svg-icons'
|
|
||||||
import { faLink } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import CONFIG_NEXT from '../config_next'
|
import CONFIG_NEXT from '../config_next'
|
||||||
|
|
||||||
const ShareBar = ({ post }) => {
|
const ShareBar = ({ post }) => {
|
||||||
@@ -51,22 +41,22 @@ const ShareBar = ({ post }) => {
|
|||||||
<div className='hidden md:block text-gray-800 dark:text-gray-300 mr-2 my-2 whitespace-nowrap'>{locale.COMMON.SHARE}:</div>
|
<div className='hidden md:block text-gray-800 dark:text-gray-300 mr-2 my-2 whitespace-nowrap'>{locale.COMMON.SHARE}:</div>
|
||||||
<div className='text-3xl cursor-pointer'>
|
<div className='text-3xl cursor-pointer'>
|
||||||
<a className='text-blue-700' href={`https://www.facebook.com/sharer.php?u=${shareUrl}`} >
|
<a className='text-blue-700' href={`https://www.facebook.com/sharer.php?u=${shareUrl}`} >
|
||||||
<FontAwesomeIcon icon={faFacebookSquare}/>
|
<i className='fab fa-facebook-square'/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div className='text-3xl cursor-pointer'>
|
<div className='text-3xl cursor-pointer'>
|
||||||
<a className='text-blue-400' target='_blank' rel='noreferrer' href={`https://twitter.com/intent/tweet?title=${post.title}&url${shareUrl}`} >
|
<a className='text-blue-400' target='_blank' rel='noreferrer' href={`https://twitter.com/intent/tweet?title=${post.title}&url${shareUrl}`} >
|
||||||
<FontAwesomeIcon icon={faTwitterSquare}/>
|
<i className='fab fa-twitter-square'/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div className='text-3xl cursor-pointer'>
|
<div className='text-3xl cursor-pointer'>
|
||||||
<a className='text-blue-500' href={`https://telegram.me/share/url?url=${shareUrl}&text=${post.title}`} >
|
<a className='text-blue-500' href={`https://telegram.me/share/url?url=${shareUrl}&text=${post.title}`} >
|
||||||
<FontAwesomeIcon icon={faTelegram}/>
|
<i className='fab fa-telegram'/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<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}>
|
||||||
<FontAwesomeIcon icon={faWeixin}/>
|
<i className='fab fa-weixin'/>
|
||||||
<div ref={popoverRef} className={(qrCodeShow ? 'animate__animated animate__fadeIn ' : 'hidden') + ' text-center py-2'}>
|
<div ref={popoverRef} className={(qrCodeShow ? 'animate__animated animate__fadeIn ' : 'hidden') + ' text-center py-2'}>
|
||||||
<div className='p-2 bg-white border-0 duration-200 transform block z-50 font-normal shadow-xl mr-10'>
|
<div className='p-2 bg-white border-0 duration-200 transform block z-50 font-normal shadow-xl mr-10'>
|
||||||
<QRCode value={shareUrl} fgColor='#000000' />
|
<QRCode value={shareUrl} fgColor='#000000' />
|
||||||
@@ -79,17 +69,17 @@ const ShareBar = ({ post }) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className='cursor-pointer text-2xl'>
|
<div className='cursor-pointer text-2xl'>
|
||||||
<a className='text-red-600' target='_blank' rel='noreferrer' href={`https://service.weibo.com/share/share.php?url=${shareUrl}&title=${post.title}`} >
|
<a className='text-red-600' target='_blank' rel='noreferrer' href={`https://service.weibo.com/share/share.php?url=${shareUrl}&title=${post.title}`} >
|
||||||
<FontAwesomeIcon icon={faWeibo}/>
|
<i className='fab fa-weibo'/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div className='cursor-pointer text-2xl'>
|
<div className='cursor-pointer text-2xl'>
|
||||||
<a className='text-blue-400' target='_blank' rel='noreferrer' href={`http://connect.qq.com/widget/shareqq/index.html?url=${shareUrl}&sharesource=qzone&title=${post.title}&desc=${post.summary}`} >
|
<a className='text-blue-400' target='_blank' rel='noreferrer' href={`http://connect.qq.com/widget/shareqq/index.html?url=${shareUrl}&sharesource=qzone&title=${post.title}&desc=${post.summary}`} >
|
||||||
<FontAwesomeIcon icon={faQq}/>
|
<i className='fab fa-qq'/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div className='cursor-pointer text-2xl'>
|
<div className='cursor-pointer text-2xl'>
|
||||||
<a className='text-yellow-600' onClick={copyUrl} >
|
<a className='text-yellow-600' onClick={copyUrl} >
|
||||||
<FontAwesomeIcon icon={faLink}/>
|
<i className='fab fa-link'/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ShareBar from './ShareBar'
|
import ShareBar from './ShareBar'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import { faShareAltSquare } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 悬浮在屏幕右下角,分享按钮
|
* 悬浮在屏幕右下角,分享按钮
|
||||||
@@ -27,7 +25,7 @@ const ShareButton = ({ post }) => {
|
|||||||
</div>
|
</div>
|
||||||
<div ref={btnRef}
|
<div ref={btnRef}
|
||||||
className='z-20 border dark:border-gray-500 dark:bg-gray-600 bg-white cursor-pointer text-md hover:shadow-2xl shadow-lg'>
|
className='z-20 border dark:border-gray-500 dark:bg-gray-600 bg-white cursor-pointer text-md hover:shadow-2xl shadow-lg'>
|
||||||
<FontAwesomeIcon icon={faShareAltSquare} className='transform duration-200 hover:scale-150 dark:text-gray-200 p-4' title='share' />
|
<i className='fas fa-share-alt-square transform duration-200 hover:scale-150 dark:text-gray-200 p-4' title='share' />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ import CONFIG_NEXT from '../config_next'
|
|||||||
* @returns {JSX.Element}
|
* @returns {JSX.Element}
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
const SideAreaLeft = ({ currentTag, post, postCount, currentSearch }) => {
|
const SideAreaLeft = (props) => {
|
||||||
|
const { currentTag, post, postCount, currentSearch } = props
|
||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
const showToc = post && post.toc && post.toc.length > 1
|
const showToc = post && post.toc && post.toc.length > 1
|
||||||
return <aside id='left' className='hidden lg:block flex-col w-60 mr-4'>
|
return <aside id='left' className='hidden lg:block flex-col w-60 mr-4'>
|
||||||
@@ -28,7 +29,7 @@ const SideAreaLeft = ({ currentTag, post, postCount, currentSearch }) => {
|
|||||||
<section className='shadow hidden lg:block mb-5 pb-4 bg-white dark:bg-gray-800 hover:shadow-xl duration-200'>
|
<section className='shadow hidden lg:block mb-5 pb-4 bg-white dark:bg-gray-800 hover:shadow-xl duration-200'>
|
||||||
<Logo/>
|
<Logo/>
|
||||||
<div className='pt-2 px-2 font-sans'>
|
<div className='pt-2 px-2 font-sans'>
|
||||||
<MenuButtonGroup allowCollapse={true} postCount={postCount} />
|
<MenuButtonGroup allowCollapse={true} {...props} />
|
||||||
</div>
|
</div>
|
||||||
{CONFIG_NEXT.MENU_SEARCH && <div className='px-2 pt-2 font-sans'>
|
{CONFIG_NEXT.MENU_SEARCH && <div className='px-2 pt-2 font-sans'>
|
||||||
<SearchInput currentTag={currentTag} currentSearch={currentSearch} />
|
<SearchInput currentTag={currentTag} currentSearch={currentSearch} />
|
||||||
@@ -47,7 +48,6 @@ const SideAreaLeft = ({ currentTag, post, postCount, currentSearch }) => {
|
|||||||
<div key={locale.NAV.ABOUT} className='mb-5 bg-white dark:bg-gray-800 duration-200 py-6'>
|
<div key={locale.NAV.ABOUT} className='mb-5 bg-white dark:bg-gray-800 duration-200 py-6'>
|
||||||
<InfoCard />
|
<InfoCard />
|
||||||
<>
|
<>
|
||||||
{/* <div className='px-5 text-sm font-light pb-1 text-gray-600 dark:text-gray-200'><FontAwesomeIcon icon={faChartBar} className='mr-2' />{locale.COMMON.ANALYTICS}</div> */}
|
|
||||||
<div className='mt-2 text-center dark:text-gray-300 font-light text-xs'>
|
<div className='mt-2 text-center dark:text-gray-300 font-light text-xs'>
|
||||||
<span className='px-1 '>
|
<span className='px-1 '>
|
||||||
<strong className='font-medium'>{postCount}</strong>{locale.COMMON.POSTS}</span>
|
<strong className='font-medium'>{postCount}</strong>{locale.COMMON.POSTS}</span>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { faAngleDoubleRight, faAngleRight, faTag, faThList } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import Card from './Card'
|
import Card from './Card'
|
||||||
@@ -51,10 +49,10 @@ const SideAreaRight = ({
|
|||||||
{CONFIG_NEXT.RIGHT_CATEGORY_LIST && categories && (
|
{CONFIG_NEXT.RIGHT_CATEGORY_LIST && categories && (
|
||||||
<Card>
|
<Card>
|
||||||
<div className='text-sm px-2 flex flex-nowrap justify-between font-light'>
|
<div className='text-sm px-2 flex flex-nowrap justify-between font-light'>
|
||||||
<div className='pb-1 text-gray-600 dark:text-gray-300'><FontAwesomeIcon icon={faThList} className='mr-2' />{locale.COMMON.CATEGORY}</div>
|
<div className='pb-1 text-gray-600 dark:text-gray-300'><i icon={faThList} className='mr-2' />{locale.COMMON.CATEGORY}</div>
|
||||||
<Link href={'/category'} passHref>
|
<Link href={'/category'} passHref>
|
||||||
<a className='text-gray-400 hover:text-black dark:text-gray-400 dark:hover:text-white hover:underline cursor-pointer'>
|
<a className='text-gray-400 hover:text-black dark:text-gray-400 dark:hover:text-white hover:underline cursor-pointer'>
|
||||||
{locale.COMMON.MORE} <FontAwesomeIcon icon={faAngleRight} />
|
{locale.COMMON.MORE} <i icon={faAngleRight} />
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@@ -68,13 +66,13 @@ const SideAreaRight = ({
|
|||||||
<Card>
|
<Card>
|
||||||
<div className="text-sm pb-1 px-2 flex flex-nowrap justify-between font-light dark:text-gray-200">
|
<div className="text-sm pb-1 px-2 flex flex-nowrap justify-between font-light dark:text-gray-200">
|
||||||
<div className="text-gray-600 dark:text-gray-200">
|
<div className="text-gray-600 dark:text-gray-200">
|
||||||
<FontAwesomeIcon icon={faTag} className="mr-2" />
|
<i className="mr-2 fas fa-tag" />
|
||||||
{locale.COMMON.TAGS}
|
{locale.COMMON.TAGS}
|
||||||
</div>
|
</div>
|
||||||
<Link href={'/tag'} passHref>
|
<Link href={'/tag'} passHref>
|
||||||
<a className="text-gray-400 hover:text-black dark:hover:text-white hover:underline cursor-pointer">
|
<a className="text-gray-400 hover:text-black dark:hover:text-white hover:underline cursor-pointer">
|
||||||
{locale.COMMON.MORE}{' '}
|
{locale.COMMON.MORE}{' '}
|
||||||
<FontAwesomeIcon icon={faAngleDoubleRight} />
|
<i className='fas fa-angle-double-right' />
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ import CategoryGroup from './CategoryGroup'
|
|||||||
import InfoCard from './InfoCard'
|
import InfoCard from './InfoCard'
|
||||||
import TagGroups from './TagGroups'
|
import TagGroups from './TagGroups'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import { faAngleDoubleRight, faTag, faThList } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
@@ -32,10 +30,10 @@ const SideBar = ({ tags, currentTag, post, slot, categories, currentCategory })
|
|||||||
{categories && (
|
{categories && (
|
||||||
<section className='mt-8'>
|
<section className='mt-8'>
|
||||||
<div className='text-sm px-5 flex flex-nowrap justify-between font-light'>
|
<div className='text-sm px-5 flex flex-nowrap justify-between font-light'>
|
||||||
<div className='text-gray-600 dark:text-gray-200'><FontAwesomeIcon icon={faThList} className='mr-2' />{locale.COMMON.CATEGORY}</div>
|
<div className='text-gray-600 dark:text-gray-200'><i className='mr-2 fas fa-th-list' />{locale.COMMON.CATEGORY}</div>
|
||||||
<Link href={'/category'} passHref>
|
<Link href={'/category'} passHref>
|
||||||
<a className='mb-3 text-gray-400 hover:text-black dark:text-gray-400 dark:hover:text-white hover:underline cursor-pointer'>
|
<a className='mb-3 text-gray-400 hover:text-black dark:text-gray-400 dark:hover:text-white hover:underline cursor-pointer'>
|
||||||
{locale.COMMON.MORE} <FontAwesomeIcon icon={faAngleDoubleRight} />
|
{locale.COMMON.MORE} <i className='fas fa-angle-double-right'/>
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@@ -47,10 +45,10 @@ const SideBar = ({ tags, currentTag, post, slot, categories, currentCategory })
|
|||||||
{tags && (
|
{tags && (
|
||||||
<section className='mt-4'>
|
<section className='mt-4'>
|
||||||
<div className='text-sm py-2 px-5 flex flex-nowrap justify-between font-light dark:text-gray-200'>
|
<div className='text-sm py-2 px-5 flex flex-nowrap justify-between font-light dark:text-gray-200'>
|
||||||
<div className='text-gray-600 dark:text-gray-200'><FontAwesomeIcon icon={faTag} className='mr-2'/>{locale.COMMON.TAGS}</div>
|
<div className='text-gray-600 dark:text-gray-200'><i className='mr-2 fas fa-tag'/>{locale.COMMON.TAGS}</div>
|
||||||
<Link href={'/tag'} passHref>
|
<Link href={'/tag'} passHref>
|
||||||
<a className='text-gray-400 hover:text-black dark:hover:text-white hover:underline cursor-pointer'>
|
<a className='text-gray-400 hover:text-black dark:hover:text-white hover:underline cursor-pointer'>
|
||||||
{locale.COMMON.MORE} <FontAwesomeIcon icon={faAngleDoubleRight} />
|
{locale.COMMON.MORE} <i className='fas fa-angle-double-right'/>
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import { faGithub, faTelegram, faTwitter, faWeibo } from '@fortawesome/free-brands-svg-icons'
|
|
||||||
import { faEnvelope, faRss } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -13,22 +10,22 @@ const SocialButton = () => {
|
|||||||
return <div className='w-52 justify-center flex-wrap flex'>
|
return <div className='w-52 justify-center flex-wrap flex'>
|
||||||
<div className='space-x-3 text-xl text-gray-600 dark:text-gray-400 '>
|
<div className='space-x-3 text-xl text-gray-600 dark:text-gray-400 '>
|
||||||
{BLOG.CONTACT_GITHUB && <a target='_blank' rel='noreferrer' title={'github'} href={BLOG.CONTACT_GITHUB} >
|
{BLOG.CONTACT_GITHUB && <a target='_blank' rel='noreferrer' title={'github'} href={BLOG.CONTACT_GITHUB} >
|
||||||
<FontAwesomeIcon icon={faGithub} className='transform hover:scale-125 duration-150'/>
|
<i className='fab fa-github transform hover:scale-125 duration-150'/>
|
||||||
</a>}
|
</a>}
|
||||||
{BLOG.CONTACT_TWITTER && <a target='_blank' rel='noreferrer' title={'twitter'} href={BLOG.CONTACT_TWITTER} >
|
{BLOG.CONTACT_TWITTER && <a target='_blank' rel='noreferrer' title={'twitter'} href={BLOG.CONTACT_TWITTER} >
|
||||||
<FontAwesomeIcon icon={faTwitter} className='transform hover:scale-125 duration-150'/>
|
<i className='fab fa-twitter transform hover:scale-125 duration-150'/>
|
||||||
</a>}
|
</a>}
|
||||||
{BLOG.CONTACT_TELEGRAM && <a target='_blank' rel='noreferrer' href={BLOG.CONTACT_TELEGRAM} title={'telegram'} >
|
{BLOG.CONTACT_TELEGRAM && <a target='_blank' rel='noreferrer' href={BLOG.CONTACT_TELEGRAM} title={'telegram'} >
|
||||||
<FontAwesomeIcon icon={faTelegram} className='transform hover:scale-125 duration-150'/>
|
<i className='fab fa-telegram transform hover:scale-125 duration-150'/>
|
||||||
</a>}
|
</a>}
|
||||||
{BLOG.CONTACT_WEIBO && <a target='_blank' rel='noreferrer' title={'weibo'} href={BLOG.CONTACT_WEIBO} >
|
{BLOG.CONTACT_WEIBO && <a target='_blank' rel='noreferrer' title={'weibo'} href={BLOG.CONTACT_WEIBO} >
|
||||||
<FontAwesomeIcon icon={faWeibo} className='transform hover:scale-125 duration-150'/>
|
<i className='fab fa-weibo transform hover:scale-125 duration-150'/>
|
||||||
</a>}
|
</a>}
|
||||||
{BLOG.CONTACT_EMAIL && <a target='_blank' rel='noreferrer' title={'email'} href={`mailto:${BLOG.CONTACT_EMAIL}`} >
|
{BLOG.CONTACT_EMAIL && <a target='_blank' rel='noreferrer' title={'email'} href={`mailto:${BLOG.CONTACT_EMAIL}`} >
|
||||||
<FontAwesomeIcon icon={faEnvelope} className='transform hover:scale-125 duration-150'/>
|
<i className='fas fa-envelope transform hover:scale-125 duration-150'/>
|
||||||
</a>}
|
</a>}
|
||||||
<a target='_blank' rel='noreferrer' title={'RSS'} href={'/feed'} >
|
<a target='_blank' rel='noreferrer' title={'RSS'} href={'/feed'} >
|
||||||
<FontAwesomeIcon icon={faRss} className='transform hover:scale-125 duration-150'/>
|
<i className='fas fa-rss transform hover:scale-125 duration-150'/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { faTag } from '@fortawesome/free-solid-svg-icons'
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
@@ -16,7 +14,7 @@ const TagItem = ({ tag, selected }) => {
|
|||||||
duration-200 mr-1 my-1 px-2 py-1 text-sm whitespace-nowrap
|
duration-200 mr-1 my-1 px-2 py-1 text-sm whitespace-nowrap
|
||||||
hover:bg-gray-200 dark:hover:bg-gray-800 `}>
|
hover:bg-gray-200 dark:hover:bg-gray-800 `}>
|
||||||
<div className='text-gray-600 dark:text-gray-300 dark:hover:text-white'>
|
<div className='text-gray-600 dark:text-gray-300 dark:hover:text-white'>
|
||||||
{selected && <FontAwesomeIcon icon={faTag} className='mr-1'/>} {`${tag.name} `} {tag.count ? `(${tag.count})` : ''}
|
{selected && <i className='fas fa-tag mr-1'/>} {`${tag.name} `} {tag.count ? `(${tag.count})` : ''}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user