Skip to content

Commit

Permalink
gitbook 增加新文章红点机制
Browse files Browse the repository at this point in the history
  • Loading branch information
tangly1024 committed Mar 6, 2024
1 parent 9494dae commit 0d1004a
Show file tree
Hide file tree
Showing 12 changed files with 86 additions and 23 deletions.
15 changes: 9 additions & 6 deletions blog.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,15 @@ const BLOG = {
MAILCHIMP_LIST_ID: process.env.MAILCHIMP_LIST_ID || null, // 开启mailichimp邮件订阅 客户列表ID ,具体使用方法参阅文档
MAILCHIMP_API_KEY: process.env.MAILCHIMP_API_KEY || null, // 开启mailichimp邮件订阅 APIkey

// ANIMATE.css 动画
ANIMATE_CSS_URL: process.env.NEXT_PUBLIC_ANIMATE_CSS_URL || 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css', // 动画CDN

// 网站图片
IMG_LAZY_LOAD_PLACEHOLDER: process.env.NEXT_PUBLIC_IMG_LAZY_LOAD_PLACEHOLDER || 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==', // 懒加载占位图片地址,支持base64或url
IMG_URL_TYPE: process.env.NEXT_PUBLIC_IMG_TYPE || 'Notion', // 此配置已失效,请勿使用;AMAZON方案不再支持,仅支持Notion方案。 ['Notion','AMAZON'] 站点图片前缀 默认 Notion:(https://notion.so/images/xx) , AMAZON(https://s3.us-west-2.amazonaws.com/xxx)
IMG_SHADOW: process.env.NEXT_PUBLIC_IMG_SHADOW || false, // 文章图片是否自动添加阴影
IMG_COMPRESS_WIDTH: process.env.NEXT_PUBLIC_IMG_COMPRESS_WIDTH || 800, // Notion图片压缩宽度

// 作废配置
AVATAR: process.env.NEXT_PUBLIC_AVATAR || '/avatar.svg', // 作者头像,被notion中的ICON覆盖。若无ICON则取public目录下的avatar.png
TITLE: process.env.NEXT_PUBLIC_TITLE || 'NotionNext BLOG', // 站点标题 ,被notion中的页面标题覆盖;此处请勿留空白,否则服务器无法编译
Expand All @@ -446,12 +455,6 @@ const BLOG = {
DESCRIPTION:
process.env.NEXT_PUBLIC_DESCRIPTION || '这是一个由NotionNext生成的站点', // 站点描述,被notion中的页面描述覆盖

// 网站图片
IMG_LAZY_LOAD_PLACEHOLDER: process.env.NEXT_PUBLIC_IMG_LAZY_LOAD_PLACEHOLDER || 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==', // 懒加载占位图片地址,支持base64或url
IMG_URL_TYPE: process.env.NEXT_PUBLIC_IMG_TYPE || 'Notion', // 此配置已失效,请勿使用;AMAZON方案不再支持,仅支持Notion方案。 ['Notion','AMAZON'] 站点图片前缀 默认 Notion:(https://notion.so/images/xx) , AMAZON(https://s3.us-west-2.amazonaws.com/xxx)
IMG_SHADOW: process.env.NEXT_PUBLIC_IMG_SHADOW || false, // 文章图片是否自动添加阴影
IMG_COMPRESS_WIDTH: process.env.NEXT_PUBLIC_IMG_COMPRESS_WIDTH || 800, // Notion图片压缩宽度

// 开发相关
NOTION_ACCESS_TOKEN: process.env.NOTION_ACCESS_TOKEN || '', // Useful if you prefer not to make your database public
DEBUG: process.env.NEXT_PUBLIC_DEBUG || false, // 是否显示调试按钮
Expand Down
11 changes: 11 additions & 0 deletions components/Badge.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* 红点
*/
export default function Badge() {
return <>
{/* 红点 */}
<span class="absolute right-1 top-1 flex h-2 w-2">
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75"></span>
<span class="relative inline-flex rounded-full h-2 w-2 bg-red-500"></span>
</span></>
}
5 changes: 5 additions & 0 deletions components/ExternalPlugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ const ExternalPlugin = (props) => {
const GLOBAL_JS = siteConfig('GLOBAL_JS')
const CLARITY_ID = siteConfig('CLARITY_ID')
const IMG_SHADOW = siteConfig('IMG_SHADOW')
const ANIMATE_CSS_URL = siteConfig('ANIMATE_CSS_URL')

// 自定义样式css和js引入
if (isBrowser) {
Expand All @@ -93,6 +94,10 @@ const ExternalPlugin = (props) => {
loadExternalResource('/css/img-shadow.css', 'css')
}

if (ANIMATE_CSS_URL) {
loadExternalResource(ANIMATE_CSS_URL, 'css')
}

// 导入外部自定义脚本
if (CUSTOM_EXTERNAL_JS && CUSTOM_EXTERNAL_JS.length > 0) {
for (const url of CUSTOM_EXTERNAL_JS) {
Expand Down
1 change: 1 addition & 0 deletions lib/wow.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const { loadExternalResource } = require('./utils');
* 是data-aos的平替 aos ≈ wowjs + animate
*/
export const loadWowJS = async () => {
await loadExternalResource('/css/wow/animate.css', 'css');
await loadExternalResource('https://cdnjs.cloudflare.com/ajax/libs/wow/1.1.2/wow.min.js', 'js');
// 配合animatecss 实现延时滚动动画,和AOS动画相似
const WOW = window.WOW;
Expand Down
2 changes: 1 addition & 1 deletion pages/_app.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import '@/styles/animate.css' // @see https://animate.style/
// import '@/styles/animate.css' // @see https://animate.style/
import '@/styles/globals.css'
import '@/styles/nprogress.css'
import '@/styles/utility-patterns.css'
Expand Down
2 changes: 1 addition & 1 deletion styles/animate.css → public/css/wow/animate.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

/*!
* animate.css -https://daneden.github.io/animate.css/
* Version - 3.7.2
* Version - 3.7.2 适配wowjs
* Licensed under the MIT license - http://opensource.org/licenses/MIT
*
* Copyright (c) 2019 Daniel Eden
Expand Down
13 changes: 9 additions & 4 deletions themes/gitbook/components/BlogPostCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,22 @@ import Link from 'next/link'
import { useRouter } from 'next/router'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
import NotionIcon from '@/components/NotionIcon'
import Badge from '@/components/Badge'
import CONFIG from '../config'

const BlogPostCard = ({ post, className }) => {
const router = useRouter()
const currentSelected = router.asPath.split('?')[0] === '/' + post.slug
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return (
<Link href={url} passHref> <div key={post.id} className={`${className} py-1.5 cursor-pointer px-1.5 hover:bg-gray-50 rounded-md dark:hover:bg-gray-600 ${currentSelected ? 'bg-green-50 text-green-500' : ''}`}>
<div className="w-full select-none">
<NotionIcon icon={post?.pageIcon}/> {post.title}
<Link href={url} passHref>
<div key={post.id} className={`${className} relative py-1.5 cursor-pointer px-1.5 hover:bg-gray-50 rounded-md dark:hover:bg-gray-600 ${currentSelected ? 'bg-green-50 text-green-500 dark:bg-yellow-100 dark:text-yellow-600' : ''}`}>
<div className="w-full select-none">
<NotionIcon icon={post?.pageIcon}/> {post.title}
</div>
{/* 最新文章加个红点 */}
{post?.isLatest && siteConfig('GITBOOK_LATEST_POST_RED_BADGE', false, CONFIG) && <Badge/>}
</div>
</div>
</Link>
)
}
Expand Down
10 changes: 8 additions & 2 deletions themes/gitbook/components/NavPostItem.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import BlogPostCard from './BlogPostCard'
import { useState } from 'react'
import Collapse from '@/components/Collapse'
import Badge from '@/components/Badge'
import { siteConfig } from '@/lib/config'
import CONFIG from '../config'

/**
* 导航列表
Expand All @@ -17,12 +20,15 @@ const NavPostItem = (props) => {
changeIsOpen(!isOpen)
}

const groupHasLatest = group?.items?.some(post => post.isLatest)

if (group?.category) {
return <>
<div onClick={toggleOpenSubMenu}
className='select-none flex justify-between text-sm cursor-pointer p-2 hover:bg-gray-50 rounded-md dark:hover:bg-gray-600' key={group?.category}>
className='select-none relative flex justify-between text-sm cursor-pointer p-2 hover:bg-gray-50 rounded-md dark:hover:bg-gray-600' key={group?.category}>
<span>{group?.category}</span>
<div className='inline-flex items-center select-none pointer-events-none '><i className={`px-2 fas fa-chevron-left transition-all duration-200 ${isOpen ? '-rotate-90' : ''}`}></i></div>
<div className='inline-flex items-center select-none pointer-events-none '><i className={`px-2 fas fa-chevron-left transition-all opacity-50 duration-200 ${isOpen ? '-rotate-90' : ''}`}></i></div>
{groupHasLatest && siteConfig('GITBOOK_LATEST_POST_RED_BADGE', false, CONFIG) && !isOpen && <Badge/>}
</div>
<Collapse isOpen={isOpen} onHeightChange={props.onHeightChange}>
{group?.items?.map(post => (<div key={post.id} className='ml-3 border-l'>
Expand Down
2 changes: 1 addition & 1 deletion themes/gitbook/components/SearchInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ const SearchInput = ({ currentSearch, cRef, className }) => {
<input
ref={searchInputRef}
type='text'
className={`${className} outline-none w-full text-sm pl-2 transition focus:shadow-lg font-light leading-10 text-black bg-gray-100 dark:bg-gray-900 dark:text-white`}
className={`${className} outline-none w-full text-sm pl-2 transition focus:shadow-lg font-light leading-10 text-black bg-gray-100 dark:bg-gray-800 dark:text-white`}
onFocus={handleFocus}
onKeyUp={handleKeyUp}
onCompositionStart={lockSearchInput}
Expand Down
2 changes: 2 additions & 0 deletions themes/gitbook/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const CONFIG = {

GITBOOK_AUTO_SORT: process.env.NEXT_PUBLIC_GITBOOK_AUTO_SORT || true, // 是否自动按分类名 归组排序文章;自动归组可能会打乱您Notion中的文章顺序

GITBOOK_LATEST_POST_RED_BADGE: process.env.NEXT_PUBLIC_GITBOOK_LATEST_POST_RED_BADGE || true, // 是否给最新文章显示红点

// 菜单
GITBOOK_MENU_CATEGORY: true, // 显示分类
GITBOOK_BOOK_MENU_TAG: true, // 显示标签
Expand Down
42 changes: 37 additions & 5 deletions themes/gitbook/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,46 @@ const WWAds = dynamic(() => import('@/components/WWAds'), { ssr: false })
const ThemeGlobalGitbook = createContext()
export const useGitBookGlobal = () => useContext(ThemeGlobalGitbook)

/**
* 给最新的文章标一个红点
*/
function getNavPagesWithLatest(allNavPages, latestPosts, post) {
// 检测需要去除红点的文章 ; localStorage 的 posts_read = {"${post.id}":"Date()"} 保存了所有已读的页面id,和阅读时间;
// 如果页面在这里面则不显示红点
const postRead = JSON.parse(localStorage.getItem('post_read') || '[]');
if (post && !postRead.includes(post.id)) {
postRead.push(post.id);
}
localStorage.setItem('post_read', JSON.stringify(postRead));

return allNavPages?.map(item => {
const res = {
id: item.id,
title: item.title || '',
pageCoverThumbnail: item.pageCoverThumbnail || '',
category: item.category || null,
tags: item.tags || null,
summary: item.summary || null,
slug: item.slug,
pageIcon: item.pageIcon || '',
lastEditedDate: item.lastEditedDate
}
if (latestPosts.some(post => post.id === item.id) && !postRead.includes(item.id)) {
return { ...res, isLatest: true };
} else {
return res;
}
})
}

/**
* 基础布局
* 采用左右两侧布局,移动端使用顶部导航栏
* @returns {JSX.Element}
* @constructor
*/
const LayoutBase = (props) => {
const { children, post, allNavPages, slotLeft, slotRight, slotTop } = props
const { children, post, allNavPages, latestPosts, slotLeft, slotRight, slotTop } = props
const { onLoading, fullWidth } = useGlobal()
const router = useRouter()
const [tocVisible, changeTocVisible] = useState(false)
Expand All @@ -60,8 +92,8 @@ const LayoutBase = (props) => {
const searchModal = useRef(null)

useEffect(() => {
setFilteredNavPages(allNavPages)
}, [post])
setFilteredNavPages(getNavPagesWithLatest(allNavPages, latestPosts, post))
}, [router])

return (
<ThemeGlobalGitbook.Provider value={{ searchModal, tocVisible, changeTocVisible, filteredNavPages, setFilteredNavPages, allNavPages, pageNavVisible, changePageNavVisible }}>
Expand All @@ -78,7 +110,7 @@ const LayoutBase = (props) => {
{/* 左侧推拉抽屉 */}
{fullWidth
? null
: (<div className={'hidden md:block border-r dark:border-transparent relative z-10 '}>
: (<div className={'hidden md:block border-r dark:border-transparent relative z-10 dark:bg-hexo-black-gray'}>
<div className='w-72 py-14 px-6 sticky top-0 overflow-y-scroll h-screen scroll-hidden'>
{slotLeft}
<SearchInput className='my-3 rounded-md' />
Expand All @@ -94,7 +126,7 @@ const LayoutBase = (props) => {
</div>
</div>) }

<div id='center-wrapper' className='flex flex-col justify-between w-full relative z-10 pt-14 min-h-screen'>
<div id='center-wrapper' className='flex flex-col justify-between w-full relative z-10 pt-14 min-h-screen dark:bg-black'>

<div id='container-inner' className={`w-full px-7 ${fullWidth ? 'px-10' : 'max-w-3xl'} justify-center mx-auto`}>
{slotTop}
Expand Down
4 changes: 1 addition & 3 deletions themes/heo/components/Hero.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ const Hero = props => {
<div
id="hero"
style={{ zIndex: 1 }}
className={
`animate__animated animate__fadeIn animate__fast
${HEO_HERO_REVERSE ? 'xl:flex-row-reverse' : ''}
className={`${HEO_HERO_REVERSE ? 'xl:flex-row-reverse' : ''}
recent-post-top rounded-[12px] 2xl:px-5 recent-top-post-group max-w-[86rem] overflow-x-scroll w-full mx-auto flex-row flex-nowrap flex relative`
}
>
Expand Down

0 comments on commit 0d1004a

Please sign in to comment.