Magzine主题基础版本

This commit is contained in:
tangly1024.com
2024-09-13 17:07:09 +08:00
parent e01d090e8c
commit 0dae01f547
23 changed files with 499 additions and 229 deletions

View File

@@ -63,7 +63,8 @@ const ExternalPlugin = props => {
const MOUSE_FOLLOW = siteConfig('MOUSE_FOLLOW')
const CUSTOM_EXTERNAL_CSS = siteConfig('CUSTOM_EXTERNAL_CSS')
const CUSTOM_EXTERNAL_JS = siteConfig('CUSTOM_EXTERNAL_JS')
const ENABLE_NPROGRSS = siteConfig('ENABLE_NPROGRSS', true)
// 默认关闭NProgress
const ENABLE_NPROGRSS = siteConfig('ENABLE_NPROGRSS', false)
// 自定义样式css和js引入
if (isBrowser) {

View File

@@ -73,8 +73,11 @@ const OpenWrite = () => {
console.error('OpenWrite 加载异常', error)
}
}
useEffect(() => {
if (process.env.NODE_ENV === 'development') {
console.log('开发环境:屏蔽OpenWrite')
return
}
if (isBrowser && blogId) {
// Check if the element with id 'read-more-wrap' already exists
const readMoreWrap = document.getElementById('read-more-wrap')

View File

@@ -8,7 +8,7 @@ import MemoryCache from './memory_cache'
* @returns
*/
export async function getDataFromCache(key, force) {
if (JSON.parse(BLOG.ENABLE_CACHE) || force) {
if (BLOG.ENABLE_CACHE || force) {
const dataFromCache = await getApi().getCache(key)
if (JSON.stringify(dataFromCache) === '[]') {
return null

View File

@@ -3,6 +3,9 @@ import dynamic from 'next/dynamic'
const NotionPage = dynamic(() => import('@/components/NotionPage'))
/**
* Magzine主题的公告
*/
const Announcement = ({ post, className }) => {
// const { locale } = useGlobal()
if (post?.blockMap) {

View File

@@ -2,6 +2,8 @@ import LazyImage from '@/components/LazyImage'
import NotionIcon from '@/components/NotionIcon'
import { siteConfig } from '@/lib/config'
import Link from 'next/link'
import CategoryItem from './CategoryItem'
import TagItemMini from './TagItemMini'
/**
* 文章详情页介绍
@@ -13,11 +15,42 @@ export default function ArticleInfo(props) {
return (
<>
{/* title */}
<h1 className='text-3xl pt-12 dark:text-gray-300'>
{siteConfig('POST_TITLE_ICON') && <NotionIcon icon={post?.pageIcon} />}
{post?.title}
</h1>
<div className='flex flex-col gap-y-8'>
<div className='flex justify-center py-2 mr-2 items-center'>
{siteConfig('MAGZINE_POST_LIST_CATEGORY') && (
<CategoryItem category={post?.category} />
)}
<div
className={
'flex items-center justify-start flex-wrap space-x-3 text-gray-400'
}>
{siteConfig('MAGZINE_POST_LIST_TAG') &&
post?.tagItems?.map(tag => (
<TagItemMini key={tag.name} tag={tag} />
))}
</div>
</div>
{/* title */}
<h2 className='text-5xl text-center dark:text-gray-300'>
{siteConfig('POST_TITLE_ICON') && (
<NotionIcon icon={post?.pageIcon} />
)}
{post?.title}
</h2>
<div className='text-xl text-center'>{post?.summary}</div>
</div>
{post?.type && !post?.type !== 'Page' && post?.pageCover && (
<div className='w-full relative md:flex-shrink-0 overflow-hidden'>
<LazyImage
alt={post?.title}
src={post?.pageCover}
className='object-cover max-h-[60vh] w-full'
/>
</div>
)}
{/* meta */}
<section className='py-2 items-center text-sm px-1'>

View File

@@ -1,56 +1,113 @@
import DarkModeButton from '@/components/DarkModeButton'
import LazyImage from '@/components/LazyImage'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import Link from 'next/link'
import SocialButton from './SocialButton'
/**
* 网页底脚
*/
const Footer = ({ title }) => {
const d = new Date()
const currentYear = d.getFullYear()
const since = siteConfig('SINCE')
const copyrightDate =
parseInt(since) < currentYear ? since + '-' + currentYear : currentYear
const { siteInfo } = useGlobal()
const MAGZINE_FOOTER_LINKS = siteConfig('MAGZINE_FOOTER_LINKS', [])
console.log('菜单', MAGZINE_FOOTER_LINKS)
return (
<footer className='z-10 bg-black text-white flex-shrink-0 justify-center text-center m-auto w-full leading-6 text-sm p-6 relative'>
<DarkModeButton />
<i className='fas fa-copyright' /> {`${copyrightDate}`}{' '}
<span>
<i className='mx-1 animate-pulse fas fa-heart' />{' '}
<a
href={siteConfig('LINK')}
className='underline font-bold justify-start '>
{siteConfig('AUTHOR')}
</a>
.<br />
{siteConfig('BEI_AN') && (
<>
<i className='fas fa-shield-alt' />{' '}
<a href='https://beian.miit.gov.cn/' className='mr-2'>
{siteConfig('BEI_AN')}
<footer className='z-10 bg-black text-white justify-center m-auto w-full p-6 relative'>
<div className='max-w-screen-2xl w-full mx-auto '>
{/* 信息与链接区块 */}
<div className='w-full flex justify-between py-16'>
<div className='gap-x-2 flex items-center'>
{/* 站长信息 */}
<LazyImage
src={siteInfo?.icon}
className='rounded-full'
width={40}
alt={siteConfig('AUTHOR')}
/>
<div>
<h1 className='text-lg'>{title}</h1>
<i className='fas fa-copyright' />
<a
href={siteConfig('LINK')}
className='underline font-bold justify-start '>
{siteConfig('AUTHOR')}
</a>
</div>
</div>
{/* 右侧链接区块 */}
<div className='grid grid-cols-4 gap-16'>
{MAGZINE_FOOTER_LINKS?.map((group, index) => {
return (
<div key={index}>
<div className='font-bold text-lg text-white pb-8'>
{group.name}
</div>
<div className='flex flex-col gap-y-2'>
{group?.menus?.map((menu, index) => {
return (
<div key={index}>
<Link href={menu.href} className='hover:underline'>
{menu.title}
</Link>
</div>
)
})}
</div>
</div>
)
})}
</div>
</div>
{/* 页脚 */}
<div className='py-4 flex justify-between items-center border-t border-gray-400'>
<span className='flex gap-x-2 items-center'>
<DarkModeButton />
{`${copyrightDate}`}
{siteConfig('BEI_AN') && (
<>
<i className='fas fa-shield-alt' />{' '}
<a href='https://beian.miit.gov.cn/' className='mr-2'>
{siteConfig('BEI_AN')}
</a>
<br />
</>
)}
</span>
<span className='text-sm font-serif'>
Powered by{' '}
<a
href='https://github.com/tangly1024/NotionNext'
className='underline justify-start text-white'>
NotionNext {siteConfig('VERSION')}
</a>
<br />
</>
)}
<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'>
<i className='fas fa-users' />{' '}
<span className='px-1 busuanzi_value_site_uv'> </span>{' '}
</span>
<br />
<h1>{title}</h1>
<span className='text-xs font-serif'>
Powered by{' '}
<a
href='https://github.com/tangly1024/NotionNext'
className='underline justify-start text-white'>
NotionNext {siteConfig('VERSION')}
</a>
.
</span>
</span>
<SocialButton />
.
</span>
<div className='flex items-center gap-x-2'>
<span>
<i className='mx-1 animate-pulse fas fa-heart' />{' '}
<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'>
<i className='fas fa-users' />{' '}
<span className='px-1 busuanzi_value_site_uv'> </span>{' '}
</span>
</span>
<SocialButton />
</div>
</div>
</div>
</footer>
)
}

View File

@@ -118,7 +118,7 @@ export default function Header(props) {
{/* 导航栏菜单内容 */}
<div
id='top-navbar'
className='flex w-full mx-auto max-w-7xl h-20 transition-all duration-200 items-center justify-between'>
className='flex w-full mx-auto max-w-screen-2xl h-20 transition-all duration-200 items-center justify-between'>
{/* 搜索栏 */}
{showSearchInput && (
<input

View File

@@ -25,7 +25,7 @@ const Hero = ({ posts }) => {
return (
<>
<div className='w-full mx-auto max-w-7xl xl:flex justify-between'>
<div className='w-full mx-auto max-w-screen-2xl xl:flex justify-between'>
{/* 左侧一篇主要置顶文章 */}
<div className='basis-1/2 mb-6'>
<PostItemCardTop post={postTop} />

View File

@@ -1,5 +1,4 @@
import { siteConfig } from '@/lib/config'
import CONFIG from '../config'
/**
* 跳转到网页顶部
@@ -10,7 +9,7 @@ import CONFIG from '../config'
* @constructor
*/
const JumpToTopButton = ({ showPercent = false, percent, className }) => {
if (!siteConfig('MAGZINE_WIDGET_TO_TOP', null, CONFIG)) {
if (!siteConfig('MAGZINE_WIDGET_TO_TOP')) {
return <></>
}
return (

View File

@@ -1,7 +0,0 @@
export default function LoadingCover() {
return <div id='cover-loading' className={'z-50 opacity-50 pointer-events-none transition-all duration-300'}>
<div className='w-full h-screen flex justify-center items-center'>
<i className="fa-solid fa-spinner text-2xl text-black dark:text-white animate-spin"> </i>
</div>
</div>
}

View File

@@ -1,6 +1,5 @@
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import CONFIG from '../config'
import { MenuItemCollapse } from './MenuItemCollapse'
export const MenuBarMobile = props => {
@@ -12,19 +11,19 @@ export const MenuBarMobile = props => {
{
name: locale.COMMON.CATEGORY,
href: '/category',
show: siteConfig('MAGZINE_MENU_CATEGORY', null, CONFIG)
show: siteConfig('MAGZINE_MENU_CATEGORY')
},
{
name: locale.COMMON.TAGS,
href: '/tag',
show: siteConfig('MAGZINE_MENU_TAG', null, CONFIG)
show: siteConfig('MAGZINE_MENU_TAG')
},
{
name: locale.NAV.ARCHIVE,
href: '/archive',
show: siteConfig('MAGZINE_MENU_ARCHIVE', null, CONFIG)
show: siteConfig('MAGZINE_MENU_ARCHIVE')
}
// { name: locale.NAV.SEARCH, href: '/search', show: siteConfig('MENU_SEARCH', null, CONFIG) }
// { name: locale.NAV.SEARCH, href: '/search', show: siteConfig('MENU_SEARCH', ) }
]
if (customNav) {

View File

@@ -0,0 +1,87 @@
import { siteConfig } from '@/lib/config'
import PostListHorizontal from './PostListHorizontal'
/**
* 按文章类别分组的文章列表区块
* @returns {JSX.Element}
* @constructor
*/
const PostBannerGroupByCategory = props => {
const { posts, categoryOptions, allNavPages, latestPosts } = props
if (!posts || posts.length === 0) {
return null
}
// 按分类将文章分组成文件夹
const categoryFolders = groupArticles(categoryOptions, allNavPages.slice(8))
return (
<>
{/* 不同的分类文章列表 */}
{categoryFolders?.map((categoryGroup, index) => {
if (
!categoryGroup ||
!categoryGroup.items ||
categoryGroup.items.length < 1
) {
return null
}
return (
<PostListHorizontal
key={index}
hasBg={index % 2 === 1}
title={categoryGroup?.category}
href={`/category/${categoryGroup?.category}`}
posts={categoryGroup?.items}
/>
)
})}
</>
)
}
// 按照分类将文章分组成文件夹
function groupArticles(categoryOptions, allPosts) {
if (!allPosts) {
return []
}
const groups = []
for (let i = 0; i < allPosts.length; i++) {
const item = allPosts[i]
const categoryName = item?.category ? item?.category : '' // 将 category 转换为字符串
let existingGroup = groups.find(group => group.category === categoryName) // 搜索同名的最后一个分组
if (existingGroup && existingGroup.category === categoryName) {
// 如果分组已存在并且该分组中的文章数量小于4添加文章
if (existingGroup.items.length < 4) {
existingGroup.items.push(item)
}
} else {
// 新建分组,并添加当前文章
groups.push({ category: categoryName, items: [item] })
}
}
const hiddenCategory = siteConfig('MAGZINE_HOME_HIDDEN_CATEGORY')
// 按照 categoryOptions 的顺序排序 groups
const sortedGroups = []
for (let i = 0; i < categoryOptions.length; i++) {
const option = categoryOptions[i]
const matchingGroup = groups.find(group => group.category === option.name)
if (matchingGroup) {
if (
hiddenCategory &&
hiddenCategory.indexOf(matchingGroup.category) >= 0
) {
continue
}
sortedGroups.push(matchingGroup)
}
}
return sortedGroups
}
export default PostBannerGroupByCategory

View File

@@ -1,43 +1,47 @@
import LazyImage from '@/components/LazyImage'
import NotionIcon from '@/components/NotionIcon'
import NotionPage from '@/components/NotionPage'
import TwikooCommentCount from '@/components/TwikooCommentCount'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import Link from 'next/link'
import CONFIG from '../config'
import CategoryItem from './CategoryItem'
import TagItemMini from './TagItemMini'
/**
* 普通的博客卡牌
* 带封面图
*/
const PostItemCard = ({ post, showSummary }) => {
const showPreview =
siteConfig('MAGZINE_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap
const { locale } = useGlobal()
const { siteInfo } = useGlobal()
const cover = post?.pageCoverThumbnail || siteInfo?.pageCover
return (
<div
key={post.id}
data-aos='fade-up'
data-aos-duration='300'
data-aos-once='false'
data-aos-anchor-placement='top-bottom'
className='mb-6 max-w-7xl border-b dark:border-gray-800 '>
<header className='lg:py-8 py-4 flex flex-col w-full'>
<div key={post.id} className='mb-6 max-w-screen-2xl'>
<div className='lg:py-8 py-4 flex flex-col w-full'>
{siteConfig('MAGZINE_POST_LIST_COVER') && (
<Link
href={post?.href}
passHref
className={
'cursor-pointer hover:underline leading-tight text-gray-700 dark:text-gray-300 hover:text-gray-500 dark:hover:text-gray-400'
}>
<div className='w-full h-40 aspect-video overflow-hidden mb-2'>
<LazyImage
src={cover}
style={cover ? {} : { height: '0px' }}
className='w-full h-40 aspect-video object-cover hover:scale-125 duration-150'
/>
</div>
</Link>
)}
{siteConfig('MAGZINE_POST_LIST_CATEGORY') && (
<CategoryItem category={post.category} />
)}
<Link
href={post?.href}
passHref
className={
'cursor-pointer font-bold hover:underline text-3xl leading-tight text-gray-700 dark:text-gray-300 hover:text-gray-500 dark:hover:text-gray-400'
'cursor-pointer hover:underline leading-tight text-gray-700 dark:text-gray-300 hover:text-gray-500 dark:hover:text-gray-400'
}>
<h2>
{siteConfig('MAGZINE_POST_LIST_COVER', null, CONFIG) && (
<div className='w-full max-h-96 object-cover overflow-hidden mb-2'>
<LazyImage
src={post.pageCoverThumbnail}
style={post.pageCoverThumbnail ? {} : { height: '0px' }}
className='w-full max-h-96 object-cover hover:scale-125 duration-150'
/>
</div>
)}
{siteConfig('POST_TITLE_ICON') && (
<NotionIcon icon={post.pageIcon} />
)}
@@ -45,46 +49,8 @@ const PostItemCard = ({ post, showSummary }) => {
</h2>
</Link>
<div
className={
'flex mt-2 items-center justify-start flex-wrap space-x-3 text-gray-400'
}>
<div className='text-sm py-1'>{post.date?.start_date}</div>
{siteConfig('MAGZINE_POST_LIST_CATEGORY', null, CONFIG) && (
<CategoryItem category={post.category} />
)}
{siteConfig('MAGZINE_POST_LIST_TAG', null, CONFIG) &&
post?.tagItems?.map(tag => (
<TagItemMini key={tag.name} tag={tag} />
))}
<TwikooCommentCount post={post} className='hover:underline' />
</div>
<div className='flex'></div>
{(!showPreview || showSummary) && (
<main className='my-4 text-gray-700 dark:text-gray-300 text-sm leading-7'>
{post.summary}
</main>
)}
{showPreview && (
<div className='overflow-ellipsis truncate'>
<NotionPage post={post} />
<div className='pointer-events-none border-t pt-8 border-dashed'>
<div className='w-full justify-start flex'>
<Link
href={post?.href}
passHref
className='hover:bg-opacity-100 hover:scale-105 duration-200 pointer-events-auto transform font-bold text-gray-500 cursor-pointer'>
{locale.COMMON.ARTICLE_DETAIL}
<i className='ml-1 fas fa-angle-right' />
</Link>
</div>
</div>
</div>
)}
</header>
<div className='text-sm py-1'>{post.date?.start_date}</div>
</div>
</div>
)
}

View File

@@ -2,7 +2,6 @@ import NotionIcon from '@/components/NotionIcon'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import Link from 'next/link'
import CONFIG from '../config'
import CategoryItem from './CategoryItem'
/**
@@ -11,15 +10,14 @@ import CategoryItem from './CategoryItem'
* @returns
*/
const PostItemCardSimple = ({ post, showSummary }) => {
const showPreview =
siteConfig('MAGZINE_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap
const showPreview = siteConfig('MAGZINE_POST_LIST_PREVIEW') && post.blockMap
const { locale } = useGlobal()
return (
<div
key={post.id}
className='mb-6 max-w-7xl border-t mr-8 py-2 gap-y-4 flex flex-col dark:border-gray-800 '>
className='mb-6 max-w-screen-2xl border-t mr-8 py-2 gap-y-4 flex flex-col dark:border-gray-800 '>
<div className='flex mr-2 items-center'>
{siteConfig('MAGZINE_POST_LIST_CATEGORY', null, CONFIG) && (
{siteConfig('MAGZINE_POST_LIST_CATEGORY') && (
<CategoryItem category={post.category} />
)}
</div>

View File

@@ -4,7 +4,6 @@ import NotionPage from '@/components/NotionPage'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import Link from 'next/link'
import CONFIG from '../config'
import CategoryItem from './CategoryItem'
import TagItemMini from './TagItemMini'
@@ -14,8 +13,7 @@ import TagItemMini from './TagItemMini'
* @returns
*/
const PostItemCardTop = ({ post, showSummary }) => {
const showPreview =
siteConfig('MAGZINE_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap
const showPreview = siteConfig('MAGZINE_POST_LIST_PREVIEW') && post.blockMap
const { locale } = useGlobal()
return (
<div
@@ -24,9 +22,9 @@ const PostItemCardTop = ({ post, showSummary }) => {
data-aos-duration='300'
data-aos-once='false'
data-aos-anchor-placement='top-bottom'
className='mb-6 max-w-7xl '>
className='mb-6 max-w-screen-2xl '>
<div className='flex flex-col w-full'>
{siteConfig('MAGZINE_POST_LIST_COVER', null, CONFIG) && (
{siteConfig('MAGZINE_POST_LIST_COVER') && (
<Link
href={post?.href}
passHref
@@ -44,14 +42,14 @@ const PostItemCardTop = ({ post, showSummary }) => {
)}
<div className='flex py-2 mr-2 items-center'>
{siteConfig('MAGZINE_POST_LIST_CATEGORY', null, CONFIG) && (
{siteConfig('MAGZINE_POST_LIST_CATEGORY') && (
<CategoryItem category={post.category} />
)}
<div
className={
'flex items-center justify-start flex-wrap space-x-3 text-gray-400'
}>
{siteConfig('MAGZINE_POST_LIST_TAG', null, CONFIG) &&
{siteConfig('MAGZINE_POST_LIST_TAG') &&
post?.tagItems?.map(tag => (
<TagItemMini key={tag.name} tag={tag} />
))}

View File

@@ -4,7 +4,6 @@ import NotionPage from '@/components/NotionPage'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import Link from 'next/link'
import CONFIG from '../config'
import CategoryItem from './CategoryItem'
import TagItemMini from './TagItemMini'
@@ -14,8 +13,7 @@ import TagItemMini from './TagItemMini'
* @returns
*/
const PostItemCardWide = ({ post, showSummary }) => {
const showPreview =
siteConfig('MAGZINE_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap
const showPreview = siteConfig('MAGZINE_POST_LIST_PREVIEW') && post.blockMap
const { locale } = useGlobal()
return (
<div key={post.id} className='flex justify-between space-x-6 mb-6 '>
@@ -62,10 +60,10 @@ const PostItemCardWide = ({ post, showSummary }) => {
className={
'flex mt-2 items-center justify-start flex-wrap space-x-3 text-gray-400'
}>
{siteConfig('MAGZINE_POST_LIST_CATEGORY', null, CONFIG) && (
{siteConfig('MAGZINE_POST_LIST_CATEGORY') && (
<CategoryItem category={post.category} />
)}
{siteConfig('MAGZINE_POST_LIST_TAG', null, CONFIG) &&
{siteConfig('MAGZINE_POST_LIST_TAG') &&
post?.tagItems?.map(tag => (
<TagItemMini key={tag.name} tag={tag} />
))}

View File

@@ -1,21 +1,22 @@
import Link from 'next/link'
import PostItemCardSimple from './PostItemCardSimple'
import PostItemCard from './PostItemCard'
import PostListEmpty from './PostListEmpty'
/**
* 博文水平列表
* 含封面
* 可以指定是否有模块背景色
* @returns {JSX.Element}
* @constructor
*/
const PostListHorizontal = ({ title, href, posts }) => {
const PostListHorizontal = ({ title, href, posts, hasBg }) => {
if (!posts || posts.length === 0) {
return <PostListEmpty />
}
return (
<div className='w-full py-10 bg-[#F6F6F1]'>
<div className='max-w-7xl w-full mx-auto'>
<div className={`w-full py-10 ${hasBg ? 'bg-[#F6F6F1]' : ''}`}>
<div className='max-w-screen-2xl w-full mx-auto'>
{/* 标题 */}
<div className='flex justify-between items-center py-6'>
<h3 className='text-2xl'>{title}</h3>
@@ -25,9 +26,9 @@ const PostListHorizontal = ({ title, href, posts }) => {
</Link>
</div>
{/* 列表 */}
<ul className='flex'>
{posts?.map(p => {
return <PostItemCardSimple key={p.id} post={p} />
<ul className='flex gap-4'>
{posts?.map((p, index) => {
return <PostItemCard key={index} post={p} />
})}
</ul>
</div>

View File

@@ -0,0 +1,79 @@
import { siteConfig } from '@/lib/config'
import PostItemCard from './PostItemCard'
import PostListEmpty from './PostListEmpty'
/**
* 博文水平列表
* 含封面
* 可以指定是否有模块背景色
* @returns {JSX.Element}
* @constructor
*/
const PostListRecommend = ({ latestPosts, allNavPages }) => {
// 获取推荐文章
const recommendPosts = getTopPosts({ latestPosts, allNavPages })
if (!recommendPosts || recommendPosts.length === 0) {
return <PostListEmpty />
}
const title = siteConfig('MAGZINE_RECOMMEND_POST_TITLE')
return (
<div className={`w-full py-10 bg-[#F6F6F1]`}>
<div className='max-w-screen-2xl w-full mx-auto'>
{/* 标题 */}
<div className='flex justify-between items-center py-6'>
<h3 className='text-4xl font-bold'>{title}</h3>
</div>
{/* 列表 */}
<ul className='flex gap-4 overflow-x-scroll'>
{recommendPosts?.map(p => {
return <PostItemCard key={p.id} post={p} />
})}
</ul>
</div>
</div>
)
}
/**
* 获取推荐置顶文章
*/
function getTopPosts({ latestPosts, allNavPages }) {
// 默认展示最近更新
if (
!siteConfig('MAGZINE_RECOMMEND_POST_TAG') ||
siteConfig('MAGZINE_RECOMMEND_POST_TAG') === ''
) {
return latestPosts
}
// 显示包含‘推荐’标签的文章
let sortPosts = []
// 排序方式
if (siteConfig('MAGZINE_RECOMMEND_POST_SORT_BY_UPDATE_TIME')) {
sortPosts = Object.create(allNavPages).sort((a, b) => {
const dateA = new Date(a?.lastEditedDate)
const dateB = new Date(b?.lastEditedDate)
return dateB - dateA
})
} else {
sortPosts = Object.create(allNavPages)
}
const count = siteConfig('MAGZINE_RECOMMEND_POST_COUNT', 6)
// 只取前4篇
const topPosts = []
for (const post of sortPosts) {
if (topPosts.length === count) {
break
}
// 查找标签
if (post?.tags?.indexOf(siteConfig('MAGZINE_RECOMMEND_POST_TAG')) >= 0) {
topPosts.push(post)
}
}
return topPosts
}
export default PostListRecommend

View File

@@ -14,7 +14,7 @@ const PostSimpleListHorizontal = ({ title, href, posts }) => {
return (
<div className='w-full py-10 bg-[#F6F6F1]'>
<div className='max-w-7xl w-full mx-auto'>
<div className='max-w-screen-2xl w-full mx-auto'>
{/* 标题 */}
<div className='flex justify-between items-center py-6'>
<h3 className='text-2xl'>{title}</h3>

View File

@@ -7,14 +7,14 @@ import { siteConfig } from '@/lib/config'
*/
const SocialButton = () => {
return (
<div className='space-x-3 text-xl text-gray-600 dark:text-gray-400 flex-wrap flex justify-start '>
<div className='space-x-3 text-xl text-white flex-wrap flex justify-start '>
{siteConfig('CONTACT_GITHUB') && (
<a
target='_blank'
rel='noreferrer'
title={'github'}
href={siteConfig('CONTACT_GITHUB')}>
<i className='fab fa-github transform hover:scale-125 duration-150 hover:text-gray-600' />
<i className='fab fa-github transform hover:scale-125 duration-150 hover:text-gray-100' />
</a>
)}
{siteConfig('CONTACT_TWITTER') && (
@@ -23,7 +23,7 @@ const SocialButton = () => {
rel='noreferrer'
title={'twitter'}
href={siteConfig('CONTACT_TWITTER')}>
<i className='fab fa-twitter transform hover:scale-125 duration-150 hover:text-gray-600' />
<i className='fab fa-twitter transform hover:scale-125 duration-150 hover:text-gray-100' />
</a>
)}
{siteConfig('CONTACT_TELEGRAM') && (
@@ -32,7 +32,7 @@ const SocialButton = () => {
rel='noreferrer'
href={siteConfig('CONTACT_TELEGRAM')}
title={'telegram'}>
<i className='fab fa-telegram transform hover:scale-125 duration-150 hover:text-gray-600' />
<i className='fab fa-telegram transform hover:scale-125 duration-150 hover:text-gray-100' />
</a>
)}
{siteConfig('CONTACT_LINKEDIN') && (
@@ -50,7 +50,7 @@ const SocialButton = () => {
rel='noreferrer'
title={'weibo'}
href={siteConfig('CONTACT_WEIBO')}>
<i className='fab fa-weibo transform hover:scale-125 duration-150 hover:text-gray-600' />
<i className='fab fa-weibo transform hover:scale-125 duration-150 hover:text-gray-100' />
</a>
)}
{siteConfig('CONTACT_INSTAGRAM') && (
@@ -59,7 +59,7 @@ const SocialButton = () => {
rel='noreferrer'
title={'instagram'}
href={siteConfig('CONTACT_INSTAGRAM')}>
<i className='fab fa-instagram transform hover:scale-125 duration-150 hover:text-gray-600' />
<i className='fab fa-instagram transform hover:scale-125 duration-150 hover:text-gray-100' />
</a>
)}
{siteConfig('CONTACT_EMAIL') && (
@@ -68,7 +68,7 @@ const SocialButton = () => {
rel='noreferrer'
title={'email'}
href={`mailto:${siteConfig('CONTACT_EMAIL')}`}>
<i className='fas fa-envelope transform hover:scale-125 duration-150 hover:text-gray-600' />
<i className='fas fa-envelope transform hover:scale-125 duration-150 hover:text-gray-100' />
</a>
)}
{JSON.parse(siteConfig('ENABLE_RSS')) && (
@@ -77,7 +77,7 @@ const SocialButton = () => {
rel='noreferrer'
title={'RSS'}
href={'/rss/feed.xml'}>
<i className='fas fa-rss transform hover:scale-125 duration-150 hover:text-gray-600' />
<i className='fas fa-rss transform hover:scale-125 duration-150 hover:text-gray-100' />
</a>
)}
{siteConfig('CONTACT_BILIBILI') && (
@@ -86,7 +86,7 @@ const SocialButton = () => {
rel='noreferrer'
title={'bilibili'}
href={siteConfig('CONTACT_BILIBILI')}>
<i className='fab fa-bilibili transform hover:scale-125 duration-150 hover:text-gray-600' />
<i className='fab fa-bilibili transform hover:scale-125 duration-150 hover:text-gray-100' />
</a>
)}
{siteConfig('CONTACT_YOUTUBE') && (
@@ -95,7 +95,7 @@ const SocialButton = () => {
rel='noreferrer'
title={'youtube'}
href={siteConfig('CONTACT_YOUTUBE')}>
<i className='fab fa-youtube transform hover:scale-125 duration-150 hover:text-gray-600' />
<i className='fab fa-youtube transform hover:scale-125 duration-150 hover:text-gray-100' />
</a>
)}
</div>

View File

@@ -2,7 +2,6 @@ import Collapse from '@/components/Collapse'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import { useRef, useState } from 'react'
import CONFIG from '../config'
import LogoBar from './LogoBar'
import { MenuBarMobile } from './MenuBarMobile'
import { MenuItemDrop } from './MenuItemDrop'
@@ -24,25 +23,25 @@ export default function TopNavBar(props) {
icon: 'fas fa-th',
name: locale.COMMON.CATEGORY,
href: '/category',
show: siteConfig('MAGZINE_MENU_CATEGORY', null, CONFIG)
show: siteConfig('MAGZINE_MENU_CATEGORY')
},
{
icon: 'fas fa-tag',
name: locale.COMMON.TAGS,
href: '/tag',
show: siteConfig('MAGZINE_MENU_TAG', null, CONFIG)
show: siteConfig('MAGZINE_MENU_TAG')
},
{
icon: 'fas fa-archive',
name: locale.NAV.ARCHIVE,
href: '/archive',
show: siteConfig('MAGZINE_MENU_ARCHIVE', null, CONFIG)
show: siteConfig('MAGZINE_MENU_ARCHIVE')
},
{
icon: 'fas fa-search',
name: locale.NAV.SEARCH,
href: '/search',
show: siteConfig('MAGZINE_MENU_SEARCH', null, CONFIG)
show: siteConfig('MAGZINE_MENU_SEARCH')
}
]

View File

@@ -5,11 +5,19 @@ const CONFIG = {
MAGZINE_HOME_BUTTON_URL: '/about',
MAGZINE_HOME_BUTTON_TEXT: '了解更多',
MAGZINE_HOME_HIDDEN_CATEGORY: '分享杂文', //不希望在首页展示的文章分类,用英文逗号隔开
MAGZINE_HOME_TITLE: '立即开创您的在线业务。完全免费。',
MAGZINE_HOME_DESCRIPTION:
'借助NotionNext获得助您开创、经营和扩展业务所需的全部工具和帮助。',
MAGZINE_HOME_TIPS: 'AI时代来临这是属于超级个体的狂欢盛宴',
// 首页底部推荐文章标签, 例如 [推荐] , 最多六篇文章; 若留空白'',则推荐最近更新文章
MAGZINE_RECOMMEND_POST_TAG: '推荐',
MAGZINE_RECOMMEND_POST_COUNT: 6,
MAGZINE_RECOMMEND_POST_TITLE: '推荐文章',
MAGZINE_RECOMMEND_POST_SORT_BY_UPDATE_TIME: false, // 推荐文章排序,为`true`时将强制按最后修改时间倒序
// Style
MAGZINE_RIGHT_PANEL_DARK: process.env.NEXT_PUBLIC_MAGZINE_RIGHT_DARK || false, // 右侧面板深色模式
@@ -21,15 +29,95 @@ const CONFIG = {
MAGZINE_POST_DETAIL_CATEGORY: true, // 文章显示分类
MAGZINE_POST_DETAIL_TAG: true, // 文章显示标签
// 菜单
// 页脚菜单
MAGZINE_FOOTER_LINKS: [
{
name: '友情链接',
menus: [
{ title: '尘世の歌', href: 'https://chenge.ink' },
{
title: '设计狮网址导航',
href: 'https://ct.ued.cat/'
},
{
title: '积极的长腿怪',
href: 'https://jjdctg.com'
},
{
title: '自动驾驶小白说',
href: 'https://www.helloxiaobai.cn/about'
},
{
title: 'AI-皇帝',
href: 'https://www.ai-hd.com/'
},
{
title: 'Andy`s Pro',
href: 'https://tw.andys.pro/'
},
{ title: 'LUCEN', href: 'https://www.lucenczz.top/' }
]
},
{
name: '开发者',
menus: [
{ title: 'Github', href: 'https://github.com/tangly1024/NotionNext' },
{
title: '开发帮助',
href: 'https://docs.tangly1024.com/article/how-to-develop-with-notion-next'
},
{
title: '功能反馈',
href: 'https://github.com/tangly1024/NotionNext/issues/new/choose'
},
{
title: '技术讨论',
href: 'https://github.com/tangly1024/NotionNext/discussions'
},
{
title: '关于作者',
href: 'https://blog.tangly1024.com/about'
}
]
},
{
name: '支持',
menus: [
{
title: '站长社群',
href: 'https://docs.tangly1024.com/article/chat-community'
},
{
title: '咨询与定制',
href: 'https://docs.tangly1024.com/article/my-service'
},
{
title: '升级手册',
href: 'https://docs.tangly1024.com/article/my-service'
},
{
title: '安装教程',
href: 'https://docs.tangly1024.com/article/how-to-update-notionnext'
},
{ title: 'SEO推广', href: 'https://seo.tangly1024.com/' }
]
},
{
name: '解决方案',
menus: [
{ title: '建站工具', href: 'https://www.tangly1024.com/' },
{ title: 'NotionNext', href: 'https://docs.tangly1024.com/about' }
]
}
],
// 旧版本顶部菜单
MAGZINE_MENU_CATEGORY: true, // 显示分类
MAGZINE_MENU_TAG: true, // 显示标签
MAGZINE_MENU_ARCHIVE: true, // 显示归档
MAGZINE_MENU_SEARCH: true, // 显示搜索
// Widget
MAGZINE_WIDGET_REVOLVER_MAPS:
process.env.NEXT_PUBLIC_WIDGET_REVOLVER_MAPS || 'false', // 地图插件
MAGZINE_WIDGET_TO_TOP: true // 跳回顶部
}
export default CONFIG

View File

@@ -1,4 +1,5 @@
import Comment from '@/components/Comment'
import LoadingCover from '@/components/LoadingCover'
import replaceSearchResult from '@/components/Mark'
import NotionPage from '@/components/NotionPage'
import ShareBar from '@/components/ShareBar'
@@ -8,6 +9,7 @@ import { isBrowser } from '@/lib/utils'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { createContext, useContext, useEffect, useState } from 'react'
import Announcement from './components/Announcement'
import ArchiveItem from './components/ArchiveItem'
import ArticleAround from './components/ArticleAround'
import ArticleInfo from './components/ArticleInfo'
@@ -18,8 +20,9 @@ import CategoryItem from './components/CategoryItem'
import Footer from './components/Footer'
import Header from './components/Header'
import Hero from './components/Hero'
import PostListHorizontal from './components/PostListHorizontal'
import PostBannerGroupByCategory from './components/PostBannerGroupByCategory'
import PostListPage from './components/PostListPage'
import PostListRecommend from './components/PostListRecommend'
import PostListScroll from './components/PostListScroll'
import PostSimpleListHorizontal from './components/PostListSimpleHorizontal'
import SearchInput from './components/SearchInput'
@@ -40,7 +43,7 @@ export const useMagzineGlobal = () => useContext(ThemeGlobalMagzine)
* @constructor
*/
const LayoutBase = props => {
const { children, showInfoCard = true, post, notice } = props
const { children, notice, showInfoCard = true, post } = props
const { locale } = useGlobal()
const router = useRouter()
const [tocVisible, changeTocVisible] = useState(false)
@@ -65,9 +68,14 @@ const LayoutBase = props => {
{children}
</div>
{/* 底部 */}
<Announcement
post={notice}
className={'text-center text-black bg-[#7BE986] py-16'}
/>
<Footer title={siteConfig('TITLE')} />
</div>
</main>
<LoadingCover />
</div>
</ThemeGlobalMagzine.Provider>
)
@@ -80,15 +88,12 @@ const LayoutBase = props => {
* @returns
*/
const LayoutIndex = props => {
const { posts, allNavPages } = props
const { posts, categoryOptions, allNavPages, latestPosts } = props
// 最新文章 从第4个元素开始截取出4个
const newPosts = posts.slice(3, 7)
// 按分类将文章分组成文件夹
const categoryFolders = groupArticles(allNavPages.slice(8))
return (
<div className='py-10 md:py-18'>
<div className='pt-10 md:pt-18'>
{/* 首屏宣传区块 */}
<Hero posts={posts} />
@@ -99,53 +104,14 @@ const LayoutIndex = props => {
posts={newPosts}
/>
{/* 不同的分类文章列表 */}
{categoryFolders?.map((categoryGroup, index) => {
if (
!categoryGroup ||
!categoryGroup.items ||
categoryGroup.items.length < 1
) {
return null
}
{/* 文章分类陈列区 */}
<PostBannerGroupByCategory {...props} />
return (
<PostListHorizontal
title={categoryGroup?.category}
href={`/category/${categoryGroup?.category}`}
posts={categoryGroup?.items}
/>
)
})}
{/* 文章推荐 */}
<PostListRecommend {...props} />
</div>
)
}
// 按照分类将文章分组成文件夹
function groupArticles(allPosts) {
if (!allPosts) {
return []
}
const groups = []
for (let i = 0; i < allPosts.length; i++) {
const item = allPosts[i]
const categoryName = item?.category ? item?.category : '' // 将 category 转换为字符串
let existingGroup = groups.find(group => group.category === categoryName) // 搜索同名的最后一个分组
if (existingGroup && existingGroup.category === categoryName) {
// 如果分组已存在并且该分组中的文章数量小于4添加文章
if (existingGroup.items.length < 4) {
existingGroup.items.push(item)
}
} else {
// 新建分组,并添加当前文章
groups.push({ category: categoryName, items: [item] })
}
}
return groups
}
/**
* 博客列表
@@ -171,13 +137,14 @@ const LayoutPostList = props => {
const LayoutSlug = props => {
const { post, prev, next, lock, validPassword } = props
const { locale } = useGlobal()
const router = useRouter()
const slotRight = post?.toc && post?.toc?.length >= 3 && (
<div key={locale.COMMON.TABLE_OF_CONTENTS}>
<Catalog toc={post?.toc} />
</div>
)
console.log('post-文章', post)
const router = useRouter()
useEffect(() => {
// 404
if (!post) {
@@ -198,7 +165,7 @@ const LayoutSlug = props => {
}, [post])
return (
<div {...props}>
<div {...props} className='w-full mx-auto max-w-screen-2xl'>
{/* 文章锁 */}
{lock && <ArticleLock validPassword={validPassword} />}
@@ -209,7 +176,7 @@ const LayoutSlug = props => {
{/* Notion文章主体 */}
<article id='article-wrapper' className='px-1 max-w-4xl'>
{post && <NotionPage post={post} />}
<NotionPage post={post} />
</article>
{/* 文章底部区域 */}
@@ -218,10 +185,11 @@ const LayoutSlug = props => {
<ShareBar post={post} />
{/* 文章分类和标签信息 */}
<div className='flex justify-between'>
{siteConfig('MAGZINE_POST_DETAIL_CATEGORY', null, CONFIG) &&
post?.category && <CategoryItem category={post?.category} />}
{siteConfig('MAGZINE_POST_DETAIL_CATEGORY') && post?.category && (
<CategoryItem category={post?.category} />
)}
<div>
{siteConfig('MAGZINE_POST_DETAIL_TAG', null, CONFIG) &&
{siteConfig('MAGZINE_POST_DETAIL_TAG') &&
post?.tagItems?.map(tag => (
<TagItemMini key={tag.name} tag={tag} />
))}