diff --git a/.env.local b/.env.local index fd53e2f4..35e50011 100644 --- a/.env.local +++ b/.env.local @@ -1,2 +1,2 @@ # 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables -NEXT_PUBLIC_VERSION=3.13.4 \ No newline at end of file +NEXT_PUBLIC_VERSION=3.13.5 \ No newline at end of file diff --git a/README.md b/README.md index 2fefab40..2505564c 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,10 @@ - [个性配置手册 - 如何配置功能插件](https://tangly1024.com/article/notion-next-guide) - [二次开发指引 - 如何进行本地开发](https://tangly1024.com/article/how-to-develop-with-notion-next) - + +- [更新操作指南 - 获取最新升级补丁](https://tangly1024.com/article/how-to-update-notionnext) + +- [历史版本汇总 - 查询版本功能特性](https://tangly1024.com/article/notion-next-changelogs) ## 致谢 感谢Craig Hart发起的Nobelium项目 diff --git a/README_EN.md b/README_EN.md index b2a9f85c..dbb75684 100644 --- a/README_EN.md +++ b/README_EN.md @@ -35,12 +35,15 @@ Live Demo:[https://preview.tangly1024.com/](https://preview.tangly1024.com/) It only takes a few minutes to set up your personal site: -- [快速部署教程 - 多种方案可供选择](https://tangly1024.com/article/notion-next) +- [Quick Deployment Tutorial - Multiple Options Available](https://tangly1024.com/article/notion-next) -- [个性配置手册 - 如何配置功能插件](https://tangly1024.com/article/notion-next-guide) +- [Customization Guide - How to Configure Feature Plugins](https://tangly1024.com/article/notion-next-guide) -- [二次开发指引 - 如何进行本地开发](https://tangly1024.com/article/how-to-develop-with-notion-next) +- [Development Guide - How to Conduct Local Development](https://tangly1024.com/article/how-to-develop-with-notion-next) +- [Update Guide - How to Get the Latest Upgrade Patch](https://tangly1024.com/article/how-to-update-notionnext) + +- [Version History - Check Feature Highlights for Each Version](https://tangly1024.com/article/notion-next-changelogs) ## Acknowledgements diff --git a/blog.config.js b/blog.config.js index 1b6755f8..7ea32205 100644 --- a/blog.config.js +++ b/blog.config.js @@ -96,6 +96,10 @@ const BLOG = { BACKGROUND_DARK: '#000000', // use hex value, don't forget '#' SUB_PATH: '', // leave this empty unless you want to deploy in a folder + POST_SHARE_BAR_ENABLE: process.env.NEXT_PUBLIC_POST_SHARE_BAR || 'true', // 文章分享功能 ,将在底部显示一个分享条 + POSTS_SHARE_SERVICES: process.env.NEXT_PUBLIC_POST_SHARE_SERVICES || 'link,wechat,qq,weibo,email,facebook,twitter,telegram,messenger,line,reddit,whatsapp,linkedin', // 分享的服務,按顺序显示,逗号隔开 + // 所有支持的分享服务:link(复制链接),wechat(微信),qq,weibo(微博),email(邮件),facebook,twitter,telegram,messenger,line,reddit,whatsapp,linkedin,vkshare,okshare,tumblr,livejournal,mailru,viber,workplace,pocket,instapaper,hatena + POST_URL_PREFIX: process.env.NEXT_PUBLIC_POST_URL_PREFIX || 'article', // POST类型文章的默认路径前缀,例如默认POST类型的路径是 /article/[slug] // 如果此项配置为 '' 空, 则文章将没有前缀路径,使用场景: 希望文章前缀路径为 /post 的情况 支持多级 diff --git a/components/ShareBar.js b/components/ShareBar.js new file mode 100644 index 00000000..347dc16e --- /dev/null +++ b/components/ShareBar.js @@ -0,0 +1,27 @@ +import BLOG from '@/blog.config' +import { useRouter } from 'next/router' +import React from 'react' +import ShareButtons from './ShareButtons' + +const ShareBar = ({ post }) => { + const router = useRouter() + + if (!JSON.parse(BLOG.POST_SHARE_BAR_ENABLE) || !post || post?.type !== 'Post') { + return <> + } + + const shareUrl = BLOG.LINK + router.asPath + + return
+ +
+} +export default ShareBar diff --git a/components/ShareButtons.js b/components/ShareButtons.js new file mode 100644 index 00000000..2aee7a78 --- /dev/null +++ b/components/ShareButtons.js @@ -0,0 +1,372 @@ +import BLOG from '@/blog.config' +import { useGlobal } from '@/lib/global' +import copy from 'copy-to-clipboard' +import QRCode from 'qrcode.react' +import { useState } from 'react' + +import { + FacebookShareButton, + FacebookIcon, + FacebookMessengerShareButton, + FacebookMessengerIcon, + RedditShareButton, + RedditIcon, + LineShareButton, + LineIcon, + EmailShareButton, + EmailIcon, + TwitterShareButton, + TwitterIcon, + TelegramShareButton, + TelegramIcon, + WhatsappShareButton, + WhatsappIcon, + LinkedinShareButton, + LinkedinIcon, + PinterestShareButton, + PinterestIcon, + VKIcon, + VKShareButton, + OKShareButton, + OKIcon, + TumblrShareButton, + TumblrIcon, + LivejournalIcon, + LivejournalShareButton, + MailruShareButton, + MailruIcon, + ViberIcon, + ViberShareButton, + WorkplaceShareButton, + WorkplaceIcon, + WeiboShareButton, + WeiboIcon, + PocketShareButton, + PocketIcon, + InstapaperShareButton, + InstapaperIcon, + HatenaShareButton, + HatenaIcon +} from 'react-share' + +/** + * @author https://github.com/txs + * @param {*} param0 + * @returns + */ +const ShareButtons = ({ shareUrl, title, body, image }) => { + const services = BLOG.POSTS_SHARE_SERVICES.split(',') + const titleWithSiteInfo = title + ' | ' + BLOG.TITLE + const { locale } = useGlobal() + const [qrCodeShow, setQrCodeShow] = useState(false) + + const copyUrl = () => { + copy(shareUrl) + alert(locale.COMMON.URL_COPIED) + } + + const openPopover = () => { + setQrCodeShow(true) + } + const closePopover = () => { + setQrCodeShow(false) + } + + return ( + <> + {services.map(singleService => { + if (singleService === 'facebook') { + return ( + + + + ) + } + if (singleService === 'messenger') { + return ( + + + + ) + } + if (singleService === 'line') { + return ( + + + + ) + } + if (singleService === 'reddit') { + return ( + + + + ) + } + if (singleService === 'email') { + return ( + + + + ) + } + if (singleService === 'twitter') { + return ( + + + + ) + } + if (singleService === 'telegram') { + return ( + + + + ) + } + if (singleService === 'whatsapp') { + return ( + + + + ) + } + if (singleService === 'linkedin') { + return ( + + + + ) + } + if (singleService === 'pinterest') { + return ( + + + + ) + } + if (singleService === 'vkshare') { + return ( + + + + ) + } + if (singleService === 'okshare') { + return ( + + + + ) + } + if (singleService === 'tumblr') { + return ( + + + + ) + } + if (singleService === 'livejournal') { + return ( + + + + ) + } + if (singleService === 'mailru') { + return ( + + + + ) + } + if (singleService === 'viber') { + return ( + + + + ) + } + if (singleService === 'workplace') { + return ( + + + + ) + } + if (singleService === 'weibo') { + return ( + + + + ) + } + if (singleService === 'pocket') { + return ( + + + + ) + } + if (singleService === 'instapaper') { + return ( + + + + ) + } + if (singleService === 'hatena') { + return ( + + + + ) + } + if (singleService === 'qq') { + return + } + if (singleService === 'wechat') { + return + } + if (singleService === 'link') { + return + } + return <> + })} + + ) +} + +export default ShareButtons diff --git a/lib/lang/zh-CN.js b/lib/lang/zh-CN.js index 1dddddb9..8379c75f 100644 --- a/lib/lang/zh-CN.js +++ b/lib/lang/zh-CN.js @@ -17,7 +17,7 @@ export default { NO_TAG: 'NoTag', CATEGORY: '分类', SHARE: '分享', - SCAN_QR_CODE: '扫一扫二维码', + SCAN_QR_CODE: '微信扫码分享', URL_COPIED: '链接已复制!', TABLE_OF_CONTENTS: '目录', RELATE_POSTS: '相关文章', diff --git a/lib/notion/getNotionData.js b/lib/notion/getNotionData.js index e723a83d..9b586e65 100644 --- a/lib/notion/getNotionData.js +++ b/lib/notion/getNotionData.js @@ -65,7 +65,7 @@ export async function getNotionPageData({ pageId, from }) { const cacheKey = 'page_block_' + pageId const data = await getDataFromCache(cacheKey) if (data && data.pageIds?.length > 0) { - console.log('[命中缓存]:', `from:${from}`, `root-page-id:${pageId}`) + console.log('[缓存]:', `from:${from}`, `root-page-id:${pageId}`) return data } const pageRecordMap = await getDataBaseInfoByNotionAPI({ pageId, from }) diff --git a/lib/notion/getPostBlocks.js b/lib/notion/getPostBlocks.js index 5fe2af84..8e764f7b 100644 --- a/lib/notion/getPostBlocks.js +++ b/lib/notion/getPostBlocks.js @@ -14,7 +14,7 @@ export async function getPostBlocks(id, from, slice) { const cacheKey = 'page_block_' + id let pageBlock = await getDataFromCache(cacheKey) if (pageBlock) { - console.log('[命中缓存]:', `from:${from}`, cacheKey) + console.log('[缓存]:', `from:${from}`, cacheKey) return filterPostBlocks(id, pageBlock, slice) } diff --git a/package.json b/package.json index 58e579fd..db5d13fc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "notion-next", - "version": "3.13.4", + "version": "3.13.5", "homepage": "https://github.com/tangly1024/NotionNext.git", "license": "MIT", "repository": { @@ -22,7 +22,6 @@ "dependencies": { "@giscus/react": "^2.2.6", "@next/bundle-analyzer": "^12.1.1", - "@popperjs/core": "^2.9.3", "@vercel/analytics": "^1.0.0", "animate.css": "^4.1.1", "animejs": "^3.2.1", @@ -53,7 +52,7 @@ "react-facebook": "^8.1.4", "react-messenger-customer-chat": "^0.8.0", "react-notion-x": "6.16.0", - "react-share": "^4.4.0", + "react-share": "^4.4.1", "react-tweet-embed": "~2.0.0", "smoothscroll-polyfill": "^0.4.4", "twikoo": "^1.6.16", diff --git a/themes/example/LayoutSlug.js b/themes/example/LayoutSlug.js index b16892b7..b19f51ff 100644 --- a/themes/example/LayoutSlug.js +++ b/themes/example/LayoutSlug.js @@ -3,6 +3,7 @@ import { ArticleLock } from './components/ArticleLock' import NotionPage from '@/components/NotionPage' import { ArticleInfo } from './components/ArticleInfo' import Comment from '@/components/Comment' +import ShareBar from '@/components/ShareBar' export const LayoutSlug = props => { const { post, lock, validPassword } = props @@ -17,10 +18,10 @@ export const LayoutSlug = props => { {lock && } {!lock &&
- {post && <> + }
} diff --git a/themes/fukasawa/components/ArticleDetail.js b/themes/fukasawa/components/ArticleDetail.js index 65af8400..e9e82b0f 100644 --- a/themes/fukasawa/components/ArticleDetail.js +++ b/themes/fukasawa/components/ArticleDetail.js @@ -1,5 +1,6 @@ import Comment from '@/components/Comment' import NotionPage from '@/components/NotionPage' +import ShareBar from '@/components/ShareBar' import formatDate from '@/lib/formatDate' import { useGlobal } from '@/lib/global' import Link from 'next/link' @@ -84,6 +85,11 @@ export default function ArticleDetail(props) { {post && } +
+ {/* 分享 */} + +
+
{/* 文章内嵌广告 */} { const { post, lock, validPassword } = props @@ -68,6 +69,8 @@ export const LayoutSlug = props => { data-ad-slot="3806269138" />
+ {/* 分享 */} + {post.type === 'Post' && } {post.type === 'Post' && } {post.type === 'Post' && } diff --git a/themes/matery/LayoutSlug.js b/themes/matery/LayoutSlug.js index 12fefce4..da07db06 100644 --- a/themes/matery/LayoutSlug.js +++ b/themes/matery/LayoutSlug.js @@ -10,6 +10,7 @@ import { ArticleInfo } from './components/ArticleInfo' import Catalog from './components/Catalog' import JumpToCommentButton from './components/JumpToCommentButton' import throttle from 'lodash.throttle' +import ShareBar from '@/components/ShareBar' export const LayoutSlug = props => { const { post, lock, validPassword } = props @@ -80,7 +81,8 @@ export const LayoutSlug = props => { data-ad-client="ca-pub-2708419466378217" data-ad-slot="3806269138" /> - + {/* 分享 */} + {/* 文章版权说明 */} {post.type === 'Post' && } diff --git a/themes/medium/LayoutSlug.js b/themes/medium/LayoutSlug.js index 6000c3f3..401c4a03 100644 --- a/themes/medium/LayoutSlug.js +++ b/themes/medium/LayoutSlug.js @@ -13,6 +13,7 @@ import ArticleAround from './components/ArticleAround' import TocDrawer from './components/TocDrawer' import CategoryItem from './components/CategoryItem' import TagItemMini from './components/TagItemMini' +import ShareBar from '@/components/ShareBar' export const LayoutSlug = props => { const { post, prev, next, siteInfo, lock, validPassword } = props @@ -85,12 +86,17 @@ export const LayoutSlug = props => {
+ + {/* 分享 */} + + {/* 文章分类和标签信息 */}
{CONFIG_MEDIUM.POST_DETAIL_CATEGORY && post.category && }
{CONFIG_MEDIUM.POST_DETAIL_TAG && post?.tagItems?.map(tag => )}
+ {post.type === 'Post' && }
diff --git a/themes/next/components/ArticleDetail.js b/themes/next/components/ArticleDetail.js index e5b8dba2..c0c2efac 100644 --- a/themes/next/components/ArticleDetail.js +++ b/themes/next/components/ArticleDetail.js @@ -2,7 +2,7 @@ import BLOG from '@/blog.config' import BlogAround from './BlogAround' import Comment from '@/components/Comment' import RecommendPosts from './RecommendPosts' -import ShareBar from './ShareBar' +import ShareBar from '@/components/ShareBar' import TagItem from './TagItem' import formatDate from '@/lib/formatDate' import { useGlobal } from '@/lib/global' @@ -94,6 +94,10 @@ export default function ArticleDetail(props) { {showArticleInfo && <> + + {/* 分享 */} + + {/* 版权声明 */} {post.type === 'Post' && } @@ -124,7 +128,6 @@ export default function ArticleDetail(props) { ))} )} - )} diff --git a/themes/next/components/ShareBar.js b/themes/next/components/ShareBar.js deleted file mode 100644 index c595da13..00000000 --- a/themes/next/components/ShareBar.js +++ /dev/null @@ -1,88 +0,0 @@ -import BLOG from '@/blog.config' -import { useRouter } from 'next/router' -import React from 'react' -import { createPopper } from '@popperjs/core' -import copy from 'copy-to-clipboard' -import QRCode from 'qrcode.react' -import { useGlobal } from '@/lib/global' -import CONFIG_NEXT from '../config_next' - -const ShareBar = ({ post }) => { - const router = useRouter() - const [qrCodeShow, setQrCodeShow] = React.useState(false) - const { locale } = useGlobal() - if (!CONFIG_NEXT.ARTICLE_SHARE) { - return <> - } - const shareUrl = BLOG.LINK + router.asPath - - // 二维码悬浮 - const btnRef = React.createRef() - const popoverRef = React.createRef() - - const openPopover = () => { - createPopper(btnRef.current, popoverRef.current, { - placement: 'top' - }) - setQrCodeShow(true) - } - const closePopover = () => { - setQrCodeShow(false) - } - - const copyUrl = () => { - copy(shareUrl) - alert(locale.COMMON.URL_COPIED) - } - - return <> -
-
{locale.COMMON.SHARE}:
-
- - - -
-
- - - -
-
- - - -
- -
- - - -
-
- - - -
-
- - - -
-
- -} -export default ShareBar diff --git a/themes/next/components/ShareButton.js b/themes/next/components/ShareButton.js deleted file mode 100644 index 39fea1f2..00000000 --- a/themes/next/components/ShareButton.js +++ /dev/null @@ -1,34 +0,0 @@ -import React from 'react' -import ShareBar from './ShareBar' - -/** - * 悬浮在屏幕右下角,分享按钮 - * @returns {JSX.Element} - * @constructor - */ -const ShareButton = ({ post }) => { - const [popoverShow, setPopoverShow] = React.useState(false) - const btnRef = React.createRef() - - const openPopover = () => { - setPopoverShow(true) - } - const closePopover = () => { - setPopoverShow(false) - } - return ( -
{ openPopover() }} - onMouseLeave={() => { closePopover() }}> -
- -
-
- -
-
- ) -} - -export default ShareButton diff --git a/themes/next/config_next.js b/themes/next/config_next.js index 5504b8df..d341cee0 100644 --- a/themes/next/config_next.js +++ b/themes/next/config_next.js @@ -30,7 +30,6 @@ const CONFIG_NEXT = { WIDGET_DARK_MODE: false, // 显示日间/夜间模式切换 WIDGET_TOC: true, // 移动端显示悬浮目录 - ARTICLE_SHARE: process.env.NEXT_PUBLIC_ARTICLE_SHARE || false, // 文章分享功能 ARTICLE_RELATE_POSTS: true, // 相关文章推荐 ARTICLE_COPYRIGHT: true // 文章版权声明 diff --git a/themes/nobelium/LayoutSlug.js b/themes/nobelium/LayoutSlug.js index d60062a0..d27628af 100644 --- a/themes/nobelium/LayoutSlug.js +++ b/themes/nobelium/LayoutSlug.js @@ -4,6 +4,7 @@ import NotionPage from '@/components/NotionPage' import { ArticleInfo } from './components/ArticleInfo' import Comment from '@/components/Comment' import { ArticleFooter } from './components/ArticleFooter' +import ShareBar from '@/components/ShareBar' export const LayoutSlug = props => { const { post, lock, validPassword } = props @@ -21,6 +22,7 @@ export const LayoutSlug = props => { {post && <> + } diff --git a/themes/simple/LayoutSlug.js b/themes/simple/LayoutSlug.js index 6cf7c82b..96f42c3e 100644 --- a/themes/simple/LayoutSlug.js +++ b/themes/simple/LayoutSlug.js @@ -4,6 +4,7 @@ import NotionPage from '@/components/NotionPage' import { ArticleInfo } from './components/ArticleInfo' import Comment from '@/components/Comment' import ArticleAround from './components/ArticleAround' +import ShareBar from '@/components/ShareBar' export const LayoutSlug = props => { const { post, lock, validPassword, prev, next } = props @@ -22,6 +23,8 @@ export const LayoutSlug = props => { {post && <> + {/* 分享 */} + {post.type === 'Post' && } }