From d31acf80b3920ce718169c321ba8abd7f241fc9c Mon Sep 17 00:00:00 2001 From: "tangly1024.com" Date: Thu, 12 Sep 2024 19:14:41 +0800 Subject: [PATCH 1/8] =?UTF-8?q?medium=E4=B8=BB=E9=A2=98=E5=BE=AE=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/medium/components/BottomMenuBar.js | 34 ++++++++++------ themes/medium/components/TocDrawer.js | 48 +++++++++++++++-------- 2 files changed, 53 insertions(+), 29 deletions(-) diff --git a/themes/medium/components/BottomMenuBar.js b/themes/medium/components/BottomMenuBar.js index 23979d9efa1..c04269c23fc 100644 --- a/themes/medium/components/BottomMenuBar.js +++ b/themes/medium/components/BottomMenuBar.js @@ -1,8 +1,8 @@ import Link from 'next/link' -import { useMediumGlobal } from '@/themes/medium' +import { useMediumGlobal } from '..' import JumpToTopButton from './JumpToTopButton' -export default function BottomMenuBar ({ post, className }) { +export default function BottomMenuBar({ post, className }) { const { tocVisible, changeTocVisible } = useMediumGlobal() const showTocButton = post?.toc?.length > 0 @@ -11,24 +11,34 @@ export default function BottomMenuBar ({ post, className }) { } return ( -
+
- +
- +
- {showTocButton &&
- -
} - { !showTocButton && -
- + {showTocButton && ( +
+
- } + )} + {!showTocButton && ( + +
+ +
+ + )}
) diff --git a/themes/medium/components/TocDrawer.js b/themes/medium/components/TocDrawer.js index 0df5cb564dd..9c04701e163 100644 --- a/themes/medium/components/TocDrawer.js +++ b/themes/medium/components/TocDrawer.js @@ -1,5 +1,5 @@ +import { useMediumGlobal } from '..' import Catalog from './Catalog' -import { useMediumGlobal } from '@/themes/medium' /** * 悬浮抽屉目录 @@ -13,22 +13,36 @@ const TocDrawer = ({ post, cRef }) => { const switchVisible = () => { changeTocVisible(!tocVisible) } - return <> -
- {/* 侧边菜单 */} -
- {post && <> -
- -
- } + return ( + <> +
+ {/* 侧边菜单 */} +
+ {post && ( + <> +
+ +
+ + )} +
-
- {/* 背景蒙版 */} -
- + {/* 背景蒙版 */} +
+ + ) } export default TocDrawer From 4ca437b93f26719df1b554bfca9ced31612ae4d6 Mon Sep 17 00:00:00 2001 From: "tangly1024.com" Date: Thu, 12 Sep 2024 19:14:57 +0800 Subject: [PATCH 2/8] =?UTF-8?q?magzine=E4=B8=BB=E9=A2=98=E9=9B=8F=E5=BD=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/magzine/components/Announcement.js | 27 ++ themes/magzine/components/ArticleAround.js | 32 ++ themes/magzine/components/ArticleInfo.js | 57 +++ themes/magzine/components/ArticleLock.js | 61 +++ themes/magzine/components/BlogArchiveItem.js | 36 ++ themes/magzine/components/BlogPostBar.js | 29 ++ themes/magzine/components/BlogPostCard.js | 92 +++++ .../components/BlogPostCardHorizontal.js | 85 ++++ themes/magzine/components/BlogPostCardTop.js | 106 +++++ .../magzine/components/BlogPostListEmpty.js | 14 + themes/magzine/components/BlogPostListPage.js | 37 ++ .../magzine/components/BlogPostListScroll.js | 107 +++++ themes/magzine/components/Card.js | 9 + themes/magzine/components/Catalog.js | 99 +++++ themes/magzine/components/CategoryGroup.js | 37 ++ themes/magzine/components/CategoryItem.js | 22 ++ themes/magzine/components/Footer.js | 30 ++ themes/magzine/components/Header.js | 136 +++++++ themes/magzine/components/InfoCard.js | 39 ++ themes/magzine/components/JumpToTopButton.js | 29 ++ themes/magzine/components/LeftMenuBar.js | 15 + themes/magzine/components/LoadingCover.js | 7 + themes/magzine/components/LogoBar.js | 20 + themes/magzine/components/MenuBarMobile.js | 54 +++ themes/magzine/components/MenuItemCollapse.js | 97 +++++ themes/magzine/components/MenuItemDrop.js | 76 ++++ .../components/MenuItemMobileNormal.js | 29 ++ themes/magzine/components/MenuItemPCNormal.js | 30 ++ themes/magzine/components/PaginationSimple.js | 55 +++ themes/magzine/components/Progress.js | 44 +++ themes/magzine/components/RevolverMaps.js | 36 ++ themes/magzine/components/SearchInput.js | 86 ++++ themes/magzine/components/SocialButton.js | 104 +++++ themes/magzine/components/TagGroups.js | 30 ++ themes/magzine/components/TagItemMini.js | 21 + themes/magzine/components/TocDrawer.js | 48 +++ themes/magzine/components/TopNavBar.js | 110 ++++++ themes/magzine/config.js | 24 ++ themes/magzine/index.js | 374 ++++++++++++++++++ themes/magzine/style.js | 18 + 40 files changed, 2362 insertions(+) create mode 100644 themes/magzine/components/Announcement.js create mode 100644 themes/magzine/components/ArticleAround.js create mode 100644 themes/magzine/components/ArticleInfo.js create mode 100644 themes/magzine/components/ArticleLock.js create mode 100644 themes/magzine/components/BlogArchiveItem.js create mode 100644 themes/magzine/components/BlogPostBar.js create mode 100644 themes/magzine/components/BlogPostCard.js create mode 100644 themes/magzine/components/BlogPostCardHorizontal.js create mode 100644 themes/magzine/components/BlogPostCardTop.js create mode 100644 themes/magzine/components/BlogPostListEmpty.js create mode 100644 themes/magzine/components/BlogPostListPage.js create mode 100644 themes/magzine/components/BlogPostListScroll.js create mode 100644 themes/magzine/components/Card.js create mode 100644 themes/magzine/components/Catalog.js create mode 100644 themes/magzine/components/CategoryGroup.js create mode 100644 themes/magzine/components/CategoryItem.js create mode 100644 themes/magzine/components/Footer.js create mode 100644 themes/magzine/components/Header.js create mode 100644 themes/magzine/components/InfoCard.js create mode 100644 themes/magzine/components/JumpToTopButton.js create mode 100644 themes/magzine/components/LeftMenuBar.js create mode 100644 themes/magzine/components/LoadingCover.js create mode 100644 themes/magzine/components/LogoBar.js create mode 100644 themes/magzine/components/MenuBarMobile.js create mode 100644 themes/magzine/components/MenuItemCollapse.js create mode 100644 themes/magzine/components/MenuItemDrop.js create mode 100644 themes/magzine/components/MenuItemMobileNormal.js create mode 100644 themes/magzine/components/MenuItemPCNormal.js create mode 100644 themes/magzine/components/PaginationSimple.js create mode 100644 themes/magzine/components/Progress.js create mode 100644 themes/magzine/components/RevolverMaps.js create mode 100644 themes/magzine/components/SearchInput.js create mode 100644 themes/magzine/components/SocialButton.js create mode 100644 themes/magzine/components/TagGroups.js create mode 100644 themes/magzine/components/TagItemMini.js create mode 100644 themes/magzine/components/TocDrawer.js create mode 100644 themes/magzine/components/TopNavBar.js create mode 100644 themes/magzine/config.js create mode 100644 themes/magzine/index.js create mode 100644 themes/magzine/style.js diff --git a/themes/magzine/components/Announcement.js b/themes/magzine/components/Announcement.js new file mode 100644 index 00000000000..4796f99140b --- /dev/null +++ b/themes/magzine/components/Announcement.js @@ -0,0 +1,27 @@ +// import { useGlobal } from '@/lib/global' +import dynamic from 'next/dynamic' + +const NotionPage = dynamic(() => import('@/components/NotionPage')) + +const Announcement = ({ post, className }) => { + // const { locale } = useGlobal() + if (post?.blockMap) { + return ( +
+
+ {/*
{locale.COMMON.ANNOUNCEMENT}
*/} + {post && ( +
+ +
+ )} +
+
+ ) + } else { + return <> + } +} +export default Announcement diff --git a/themes/magzine/components/ArticleAround.js b/themes/magzine/components/ArticleAround.js new file mode 100644 index 00000000000..95b6f83fc1d --- /dev/null +++ b/themes/magzine/components/ArticleAround.js @@ -0,0 +1,32 @@ +import Link from 'next/link' + +/** + * 上一篇,下一篇文章 + * @param {prev,next} param0 + * @returns + */ +export default function ArticleAround ({ prev, next }) { + if (!prev || !next) { + return <> + } + return ( +
+ + + {prev.title} + + + + {next.title} + + + +
+ ) +} diff --git a/themes/magzine/components/ArticleInfo.js b/themes/magzine/components/ArticleInfo.js new file mode 100644 index 00000000000..b5a71d26c9a --- /dev/null +++ b/themes/magzine/components/ArticleInfo.js @@ -0,0 +1,57 @@ +import LazyImage from '@/components/LazyImage' +import NotionIcon from '@/components/NotionIcon' +import { siteConfig } from '@/lib/config' +import Link from 'next/link' + +/** + * 文章详情页介绍 + * @param {*} props + * @returns + */ +export default function ArticleInfo(props) { + const { post, siteInfo } = props + + return ( + <> + {/* title */} +

+ {siteConfig('POST_TITLE_ICON') && } + {post?.title} +

+ + {/* meta */} +
+
+ + {' '} + + {post?.publishDay} + + | + + + {post?.lastEditedDay} + +
+ + +
+
+ +
+ + +
+ {siteConfig('AUTHOR')} +
+
+ +
+ + ) +} diff --git a/themes/magzine/components/ArticleLock.js b/themes/magzine/components/ArticleLock.js new file mode 100644 index 00000000000..6f2ca8cd46e --- /dev/null +++ b/themes/magzine/components/ArticleLock.js @@ -0,0 +1,61 @@ +import { useGlobal } from '@/lib/global' +import { useEffect, useRef } from 'react' + +/** + * 加密文章校验组件 + * @param {password, validPassword} props + * @param password 正确的密码 + * @param validPassword(bool) 回调函数,校验正确回调入参为true + * @returns + */ +export const ArticleLock = props => { + const { validPassword } = props + const { locale } = useGlobal() + + const submitPassword = () => { + const p = document.getElementById('password') + if (!validPassword(p?.value)) { + const tips = document.getElementById('tips') + if (tips) { + tips.innerHTML = '' + tips.innerHTML = `
${locale.COMMON.PASSWORD_ERROR}
` + } + } + } + + const passwordInputRef = useRef(null) + useEffect(() => { + // 选中密码输入框并将其聚焦 + passwordInputRef.current.focus() + }, []) + + return ( +
+
+
{locale.COMMON.ARTICLE_LOCK_TIPS}
+
+ { + if (e.key === 'Enter') { + submitPassword() + } + }} + ref={passwordInputRef} // 绑定ref到passwordInputRef变量 + className='outline-none w-full text-sm pl-5 rounded-l transition focus:shadow-lg dark:text-gray-300 font-light leading-10 text-black bg-gray-100 dark:bg-gray-500'> +
+ +  {locale.COMMON.SUBMIT} + +
+
+
+
+
+ ) +} diff --git a/themes/magzine/components/BlogArchiveItem.js b/themes/magzine/components/BlogArchiveItem.js new file mode 100644 index 00000000000..7d7b5a1c2e6 --- /dev/null +++ b/themes/magzine/components/BlogArchiveItem.js @@ -0,0 +1,36 @@ +import Link from 'next/link' + +/** + * 归档分组 + * @param {*} param0 + * @returns + */ +export default function BlogArchiveItem({ archiveTitle, archivePosts }) { + return ( +
+
+ {archiveTitle} +
+
    + {archivePosts[archiveTitle]?.map(post => { + return ( +
  • +
    + {post.date?.start_date}{' '} +   + + {post.title} + +
    +
  • + ) + })} +
+
+ ) +} diff --git a/themes/magzine/components/BlogPostBar.js b/themes/magzine/components/BlogPostBar.js new file mode 100644 index 00000000000..9f34aca5149 --- /dev/null +++ b/themes/magzine/components/BlogPostBar.js @@ -0,0 +1,29 @@ +import { useGlobal } from '@/lib/global' + +/** + * 文章列表上方嵌入 + * @param {*} props + * @returns + */ +export default function BlogPostBar(props) { + const { tag, category } = props + const { locale } = useGlobal() + + if (tag) { + return ( +
+ + {locale.COMMON.TAGS}:{tag} +
+ ) + } else if (category) { + return ( +
+ + {locale.COMMON.CATEGORY}:{category} +
+ ) + } else { + return <> + } +} diff --git a/themes/magzine/components/BlogPostCard.js b/themes/magzine/components/BlogPostCard.js new file mode 100644 index 00000000000..ac82bcc1a94 --- /dev/null +++ b/themes/magzine/components/BlogPostCard.js @@ -0,0 +1,92 @@ +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 BlogPostCard = ({ post, showSummary }) => { + const showPreview = + siteConfig('MEDIUM_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap + const { locale } = useGlobal() + return ( +
+
+ +

+ {siteConfig('MEDIUM_POST_LIST_COVER', null, CONFIG) && ( +
+ +
+ )} + {siteConfig('POST_TITLE_ICON') && ( + + )} + {post.title} +

+ + +
+
{post.date?.start_date}
+ {siteConfig('MEDIUM_POST_LIST_CATEGORY', null, CONFIG) && ( + + )} + {siteConfig('MEDIUM_POST_LIST_TAG', null, CONFIG) && + post?.tagItems?.map(tag => ( + + ))} + +
+ +
+ + {(!showPreview || showSummary) && ( +
+ {post.summary} +
+ )} + + {showPreview && ( +
+ +
+
+ + {locale.COMMON.ARTICLE_DETAIL} + + +
+
+
+ )} +
+
+ ) +} + +export default BlogPostCard diff --git a/themes/magzine/components/BlogPostCardHorizontal.js b/themes/magzine/components/BlogPostCardHorizontal.js new file mode 100644 index 00000000000..076b2d897a5 --- /dev/null +++ b/themes/magzine/components/BlogPostCardHorizontal.js @@ -0,0 +1,85 @@ +import LazyImage from '@/components/LazyImage' +import NotionIcon from '@/components/NotionIcon' +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' + +const BlogPostCardHorizontal = ({ post, showSummary }) => { + const showPreview = + siteConfig('MEDIUM_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap + const { locale } = useGlobal() + return ( +
+ {/* 卡牌左侧 */} +
+ +

+ {siteConfig('POST_TITLE_ICON') && ( + + )} + {post.title} +

+ + +
+
{post.date?.start_date}
+ {siteConfig('MEDIUM_POST_LIST_CATEGORY', null, CONFIG) && ( + + )} + {siteConfig('MEDIUM_POST_LIST_TAG', null, CONFIG) && + post?.tagItems?.map(tag => ( + + ))} +
+ + {(!showPreview || showSummary) && ( +
+ {post.summary} +
+ )} + + {showPreview && ( +
+ +
+
+ + {locale.COMMON.ARTICLE_DETAIL} + + +
+
+
+ )} +
+ + {/* 卡牌右侧图片 */} +
+ +
+
+ ) +} + +export default BlogPostCardHorizontal diff --git a/themes/magzine/components/BlogPostCardTop.js b/themes/magzine/components/BlogPostCardTop.js new file mode 100644 index 00000000000..2c02d02e6f3 --- /dev/null +++ b/themes/magzine/components/BlogPostCardTop.js @@ -0,0 +1,106 @@ +import LazyImage from '@/components/LazyImage' +import NotionIcon from '@/components/NotionIcon' +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' + +/** + * 置顶头条文章 + * @param {*} param0 + * @returns + */ +const BlogPostCardTop = ({ post, showSummary }) => { + const showPreview = + siteConfig('MEDIUM_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap + const { locale } = useGlobal() + return ( +
+
+ {siteConfig('MEDIUM_POST_LIST_COVER', null, CONFIG) && ( + +
+ +
+ + )} + +
+ {siteConfig('MEDIUM_POST_LIST_CATEGORY', null, CONFIG) && ( + + )} +
+ {siteConfig('MEDIUM_POST_LIST_TAG', null, CONFIG) && + post?.tagItems?.map(tag => ( + + ))} +
+
+ + +

+ {siteConfig('POST_TITLE_ICON') && ( + + )} + {post.title} +

+ + +
+ + {(!showPreview || showSummary) && ( +
+ {post.summary} +
+ )} + + {showPreview && ( +
+ +
+
+ + {locale.COMMON.ARTICLE_DETAIL} + + +
+
+
+ )} + +
{post.date?.start_date}
+
+
+ ) +} + +export default BlogPostCardTop diff --git a/themes/magzine/components/BlogPostListEmpty.js b/themes/magzine/components/BlogPostListEmpty.js new file mode 100644 index 00000000000..a26cf292d3d --- /dev/null +++ b/themes/magzine/components/BlogPostListEmpty.js @@ -0,0 +1,14 @@ +import { useGlobal } from '@/lib/global' + +/** + * 空白博客 列表 + * @returns {JSX.Element} + * @constructor + */ +const BlogPostListEmpty = ({ currentSearch }) => { + const { locale } = useGlobal() + return
+

{locale.COMMON.NO_RESULTS_FOUND} {(currentSearch &&

{currentSearch}
)}

+
+} +export default BlogPostListEmpty diff --git a/themes/magzine/components/BlogPostListPage.js b/themes/magzine/components/BlogPostListPage.js new file mode 100644 index 00000000000..79e031dd63e --- /dev/null +++ b/themes/magzine/components/BlogPostListPage.js @@ -0,0 +1,37 @@ +import { siteConfig } from '@/lib/config' +import { useGlobal } from '@/lib/global' +import BlogPostCard from './BlogPostCard' +import BlogPostListEmpty from './BlogPostListEmpty' +import PaginationSimple from './PaginationSimple' + +/** + * 文章列表分页表格 + * @param page 当前页 + * @param posts 所有文章 + * @param tags 所有标签 + * @returns {JSX.Element} + * @constructor + */ +const BlogPostListPage = ({ page = 1, posts = [], postCount }) => { + const { NOTION_CONFIG } = useGlobal() + const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', null, NOTION_CONFIG) + const totalPage = Math.ceil(postCount / POSTS_PER_PAGE) + + if (!posts || posts.length === 0) { + return + } + + return ( +
+
+ {/* 文章列表 */} + {posts?.map(post => ( + + ))} +
+ +
+ ) +} + +export default BlogPostListPage diff --git a/themes/magzine/components/BlogPostListScroll.js b/themes/magzine/components/BlogPostListScroll.js new file mode 100644 index 00000000000..22960779231 --- /dev/null +++ b/themes/magzine/components/BlogPostListScroll.js @@ -0,0 +1,107 @@ +import { siteConfig } from '@/lib/config' +import { useGlobal } from '@/lib/global' +import throttle from 'lodash.throttle' +import { useRouter } from 'next/router' +import { useCallback, useEffect, useRef, useState } from 'react' +import BlogPostCard from './BlogPostCard' +import BlogPostListEmpty from './BlogPostListEmpty' + +/** + * 博客列表滚动分页 + * @param posts 所有文章 + * @param tags 所有标签 + * @returns {JSX.Element} + * @constructor + */ +const BlogPostListScroll = ({ posts = [], currentSearch }) => { + const { NOTION_CONFIG } = useGlobal() + const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', null, NOTION_CONFIG) + const [page, updatePage] = useState(1) + const router = useRouter() + let filteredPosts = Object.assign(posts) + const searchKey = router?.query?.s || null + if (searchKey) { + filteredPosts = posts.filter(post => { + const tagContent = post?.tags ? post?.tags.join(' ') : '' + const searchContent = post.title + post.summary + tagContent + return searchContent.toLowerCase().includes(searchKey.toLowerCase()) + }) + } + const postsToShow = getPostByPage(page, filteredPosts, POSTS_PER_PAGE) + + let hasMore = false + if (filteredPosts) { + const totalCount = filteredPosts.length + hasMore = page * POSTS_PER_PAGE < totalCount + } + + const handleGetMore = () => { + if (!hasMore) return + updatePage(page + 1) + } + + // 监听滚动自动分页加载 + const scrollTrigger = useCallback( + throttle(() => { + const scrollS = window.scrollY + window.outerHeight + const clientHeight = targetRef + ? targetRef.current + ? targetRef.current.clientHeight + : 0 + : 0 + if (scrollS > clientHeight + 100) { + handleGetMore() + } + }, 500) + ) + + // 监听滚动 + useEffect(() => { + window.addEventListener('scroll', scrollTrigger) + return () => { + window.removeEventListener('scroll', scrollTrigger) + } + }) + + const targetRef = useRef(null) + const { locale } = useGlobal() + + if (!postsToShow || postsToShow.length === 0) { + return + } else { + return ( +
+ {/* 文章列表 */} +
+ {postsToShow?.map(post => ( + + ))} +
+ +
+
{ + handleGetMore() + }} + className='w-full my-4 py-4 text-center cursor-pointer dark:text-gray-200'> + {' '} + {hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '} +
+
+
+ ) + } +} + +/** + * 获取从第1页到指定页码的文章 + * @param page 第几页 + * @param totalPosts 所有文章 + * @param POSTS_PER_PAGE 每页文章数量 + * @returns {*} + */ +const getPostByPage = function (page, totalPosts, POSTS_PER_PAGE) { + return totalPosts.slice(0, POSTS_PER_PAGE * page) +} + +export default BlogPostListScroll diff --git a/themes/magzine/components/Card.js b/themes/magzine/components/Card.js new file mode 100644 index 00000000000..d24c046e476 --- /dev/null +++ b/themes/magzine/components/Card.js @@ -0,0 +1,9 @@ +const Card = ({ children, headerSlot, className }) => { + return
+ <>{headerSlot} +
+ {children} +
+
+} +export default Card diff --git a/themes/magzine/components/Catalog.js b/themes/magzine/components/Catalog.js new file mode 100644 index 00000000000..b390e68647f --- /dev/null +++ b/themes/magzine/components/Catalog.js @@ -0,0 +1,99 @@ +import throttle from 'lodash.throttle' +import { uuidToId } from 'notion-utils' +import { useCallback, useEffect, useRef, useState } from 'react' +import Progress from './Progress' + +/** + * 目录导航组件 + * @param toc + * @returns {JSX.Element} + * @constructor + */ +const Catalog = ({ toc }) => { + const tocIds = [] + + // 目录自动滚动 + const tRef = useRef(null) + // 同步选中目录事件 + const [activeSection, setActiveSection] = useState(null) + + // 监听滚动事件 + useEffect(() => { + window.addEventListener('scroll', actionSectionScrollSpy) + actionSectionScrollSpy() + return () => { + window.removeEventListener('scroll', actionSectionScrollSpy) + } + }, []) + + const throttleMs = 200 + const actionSectionScrollSpy = 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) + const index = tocIds.indexOf(currentSectionId) || 0 + tRef?.current?.scrollTo({ top: 28 * index, behavior: 'smooth' }) + }, throttleMs) + ) + + // 无目录就直接返回空 + if (!toc || toc.length < 1) { + return <> + } + + return ( +
+
+ +
+
+ +
+
+ ) +} + +export default Catalog diff --git a/themes/magzine/components/CategoryGroup.js b/themes/magzine/components/CategoryGroup.js new file mode 100644 index 00000000000..3fd6b67d716 --- /dev/null +++ b/themes/magzine/components/CategoryGroup.js @@ -0,0 +1,37 @@ +import { useGlobal } from '@/lib/global' +import CategoryItem from './CategoryItem' + +/** + * 分类 + * @param {*} param0 + * @returns + */ +const CategoryGroup = ({ currentCategory, categoryOptions }) => { + const { locale } = useGlobal() + if (!categoryOptions) { + return <> + } + return ( +
+
+ + {locale.COMMON.CATEGORY} +
+
+ {categoryOptions?.map(category => { + const selected = currentCategory === category.name + return ( + + ) + })} +
+
+ ) +} + +export default CategoryGroup diff --git a/themes/magzine/components/CategoryItem.js b/themes/magzine/components/CategoryItem.js new file mode 100644 index 00000000000..399049efd16 --- /dev/null +++ b/themes/magzine/components/CategoryItem.js @@ -0,0 +1,22 @@ +import Link from 'next/link' + +export default function CategoryItem({ selected, category, categoryCount }) { + return ( + +
+ + {category} {categoryCount && `(${categoryCount})`} +
+ + ) +} diff --git a/themes/magzine/components/Footer.js b/themes/magzine/components/Footer.js new file mode 100644 index 00000000000..0c5a9211229 --- /dev/null +++ b/themes/magzine/components/Footer.js @@ -0,0 +1,30 @@ +import DarkModeButton from '@/components/DarkModeButton' +import { siteConfig } from '@/lib/config' + +const Footer = ({ title }) => { + const d = new Date() + const currentYear = d.getFullYear() + const since = siteConfig('SINCE') + const copyrightDate = parseInt(since) < currentYear ? since + '-' + currentYear : currentYear + + return ( + + ) +} + +export default Footer diff --git a/themes/magzine/components/Header.js b/themes/magzine/components/Header.js new file mode 100644 index 00000000000..b4a8fd224dc --- /dev/null +++ b/themes/magzine/components/Header.js @@ -0,0 +1,136 @@ +import Collapse from '@/components/Collapse' +import { siteConfig } from '@/lib/config' +import { useGlobal } from '@/lib/global' +import throttle from 'lodash.throttle' +import { useEffect, useRef, useState } from 'react' +import CONFIG from '../config' +import LogoBar from './LogoBar' +import { MenuBarMobile } from './MenuBarMobile' +import { MenuItemDrop } from './MenuItemDrop' + +/** + * 顶部导航栏 + 菜单 + * @param {} param0 + * @returns + */ +export default function Header(props) { + const { customNav, customMenu } = props + const [isOpen, changeShow] = useState(false) + const collapseRef = useRef(null) + + const { locale } = useGlobal() + + const defaultLinks = [ + { + icon: 'fas fa-th', + name: locale.COMMON.CATEGORY, + href: '/category', + show: CONFIG.MENU_CATEGORY + }, + { + icon: 'fas fa-tag', + name: locale.COMMON.TAGS, + href: '/tag', + show: CONFIG.MENU_TAG + }, + { + icon: 'fas fa-archive', + name: locale.NAV.ARCHIVE, + href: '/archive', + show: CONFIG.MENU_ARCHIVE + }, + { + icon: 'fas fa-search', + name: locale.NAV.SEARCH, + href: '/search', + show: CONFIG.MENU_SEARCH + } + ] + + let links = defaultLinks.concat(customNav) + + const toggleMenuOpen = () => { + changeShow(!isOpen) + } + + // 向下滚动时,调整导航条高度 + useEffect(() => { + scrollTrigger() + window.addEventListener('scroll', scrollTrigger) + return () => { + window.removeEventListener('scroll', scrollTrigger) + } + }, []) + + const throttleMs = 150 + + const scrollTrigger = throttle(() => { + const scrollS = window.scrollY + const nav = document.querySelector('#top-navbar') + + const narrowNav = scrollS > 50 + if (narrowNav) { + nav && nav.classList.replace('h-20', 'h-14') + } else { + nav && nav.classList.replace('h-14', 'h-20') + } + }, throttleMs) + + // 如果 开启自定义菜单,则覆盖Page生成的菜单 + if (siteConfig('CUSTOM_MENU')) { + links = customMenu + } + + if (!links || links.length === 0) { + return null + } + + return ( +
+ {/* 导航栏菜单内容 */} +
+ {/* 左侧图标Logo */} + + + {/* 移动端折叠按钮 */} +
+
+ {isOpen ? ( + + ) : ( + + )} +
+
+ + {/* 桌面端顶部菜单 */} +
+ {links && + links?.map(link => )} +
+
+ + {/* 移动端折叠菜单 */} + +
+ + collapseRef.current?.updateCollapseHeight(param) + } + /> +
+
+
+ ) +} diff --git a/themes/magzine/components/InfoCard.js b/themes/magzine/components/InfoCard.js new file mode 100644 index 00000000000..abdc8862c89 --- /dev/null +++ b/themes/magzine/components/InfoCard.js @@ -0,0 +1,39 @@ +import LazyImage from '@/components/LazyImage' +import { siteConfig } from '@/lib/config' +import Router from 'next/router' +import SocialButton from './SocialButton' + +/** + * 用户信息卡 + * @param {*} props + * @returns + */ +const InfoCard = props => { + const { siteInfo } = props + return ( +
+
+
{ + Router.push('/about') + }}> + +
+
+ {siteConfig('AUTHOR')} +
+
+ {siteConfig('BIO')} +
+ +
+
+ ) +} + +export default InfoCard diff --git a/themes/magzine/components/JumpToTopButton.js b/themes/magzine/components/JumpToTopButton.js new file mode 100644 index 00000000000..6342bf78539 --- /dev/null +++ b/themes/magzine/components/JumpToTopButton.js @@ -0,0 +1,29 @@ +import CONFIG from '../config' +import { siteConfig } from '@/lib/config' + +/** + * 跳转到网页顶部 + * 当屏幕下滑500像素后会出现该控件 + * @param targetRef 关联高度的目标html标签 + * @param showPercent 是否显示百分比 + * @returns {JSX.Element} + * @constructor + */ +const JumpToTopButton = ({ showPercent = false, percent, className }) => { + if (!siteConfig('MEDIUM_WIDGET_TO_TOP', null, CONFIG)) { + return <> + } + return ( +
+ { window.scrollTo({ top: 0, behavior: 'smooth' }) }} /> +
+ ) +} + +export default JumpToTopButton diff --git a/themes/magzine/components/LeftMenuBar.js b/themes/magzine/components/LeftMenuBar.js new file mode 100644 index 00000000000..6bde6c51b85 --- /dev/null +++ b/themes/magzine/components/LeftMenuBar.js @@ -0,0 +1,15 @@ +import Link from 'next/link' + +export default function LeftMenuBar () { + return ( +
+
+ +
+ +
+ +
+
+ ); +} diff --git a/themes/magzine/components/LoadingCover.js b/themes/magzine/components/LoadingCover.js new file mode 100644 index 00000000000..4d8fa828c39 --- /dev/null +++ b/themes/magzine/components/LoadingCover.js @@ -0,0 +1,7 @@ +export default function LoadingCover() { + return
+
+ +
+
+} diff --git a/themes/magzine/components/LogoBar.js b/themes/magzine/components/LogoBar.js new file mode 100644 index 00000000000..dfe01f9a8e5 --- /dev/null +++ b/themes/magzine/components/LogoBar.js @@ -0,0 +1,20 @@ +import { siteConfig } from '@/lib/config' +import Link from 'next/link' + +export default function LogoBar(props) { + const { siteInfo } = props + return ( +
+ + {/* */} + {siteConfig('TITLE')} + +
+ ) +} diff --git a/themes/magzine/components/MenuBarMobile.js b/themes/magzine/components/MenuBarMobile.js new file mode 100644 index 00000000000..8e5051306f8 --- /dev/null +++ b/themes/magzine/components/MenuBarMobile.js @@ -0,0 +1,54 @@ +import { siteConfig } from '@/lib/config' +import { useGlobal } from '@/lib/global' +import CONFIG from '../config' +import { MenuItemCollapse } from './MenuItemCollapse' + +export const MenuBarMobile = props => { + const { customMenu, customNav } = props + const { locale } = useGlobal() + + let links = [ + // { name: locale.NAV.INDEX, href: '/' || '/', show: true }, + { + name: locale.COMMON.CATEGORY, + href: '/category', + show: siteConfig('MEDIUM_MENU_CATEGORY', null, CONFIG) + }, + { + name: locale.COMMON.TAGS, + href: '/tag', + show: siteConfig('MEDIUM_MENU_TAG', null, CONFIG) + }, + { + name: locale.NAV.ARCHIVE, + href: '/archive', + show: siteConfig('MEDIUM_MENU_ARCHIVE', null, CONFIG) + } + // { name: locale.NAV.SEARCH, href: '/search', show: siteConfig('MENU_SEARCH', null, CONFIG) } + ] + + if (customNav) { + links = links.concat(customNav) + } + + // 如果 开启自定义菜单,则不再使用 Page生成菜单。 + if (siteConfig('CUSTOM_MENU')) { + links = customMenu + } + + if (!links || links.length === 0) { + return null + } + + return ( + + ) +} diff --git a/themes/magzine/components/MenuItemCollapse.js b/themes/magzine/components/MenuItemCollapse.js new file mode 100644 index 00000000000..fcd8b75612b --- /dev/null +++ b/themes/magzine/components/MenuItemCollapse.js @@ -0,0 +1,97 @@ +import Collapse from '@/components/Collapse' +import Link from 'next/link' +import { useRouter } from 'next/router' +import { useState } from 'react' + +/** + * 折叠菜单 + * @param {*} param0 + * @returns + */ +export const MenuItemCollapse = props => { + const { link } = props + const [show, changeShow] = useState(false) + const hasSubMenu = link?.subMenus?.length > 0 + + const [isOpen, changeIsOpen] = useState(false) + + const router = useRouter() + + if (!link || !link.show) { + return null + } + + const selected = router.pathname === link.href || router.asPath === link.href + + const toggleShow = () => { + changeShow(!show) + } + + const toggleOpenSubMenu = () => { + changeIsOpen(!isOpen) + } + + return ( + <> +
+ {!hasSubMenu && ( + +
+
+ {link.name} +
+ + )} + + {hasSubMenu && ( +
+
+
+ {link.name} +
+
+ +
+
+ )} +
+ + {/* 折叠子菜单 */} + {hasSubMenu && ( + + {link?.subMenus?.map(sLink => { + return ( +
+ +
+
+ {sLink.title} +
+ +
+ ) + })} + + )} + + ) +} diff --git a/themes/magzine/components/MenuItemDrop.js b/themes/magzine/components/MenuItemDrop.js new file mode 100644 index 00000000000..38484029b44 --- /dev/null +++ b/themes/magzine/components/MenuItemDrop.js @@ -0,0 +1,76 @@ +import Link from 'next/link' +import { useRouter } from 'next/router' +import { useState } from 'react' + +export const MenuItemDrop = ({ link }) => { + const [show, changeShow] = useState(false) + // const show = true + // const changeShow = () => {} + const router = useRouter() + + if (!link || !link.show) { + return null + } + const hasSubMenu = link?.subMenus?.length > 0 + const selected = router.pathname === link.href || router.asPath === link.href + + return ( +
  • changeShow(true)} + onMouseOut={() => changeShow(false)}> + {hasSubMenu && ( +
    +
    + {link?.icon && } {link?.name} + {hasSubMenu && ( + + )} +
    +
    + )} + + {!hasSubMenu && ( +
    + + {link?.icon && } {link?.name} + +
    + )} + + {/* 子菜单 */} + {hasSubMenu && ( +
      + {link?.subMenus?.map(sLink => { + return ( +
    • + + + {link?.icon &&   } + {sLink.title} + + +
    • + ) + })} +
    + )} +
  • + ) +} diff --git a/themes/magzine/components/MenuItemMobileNormal.js b/themes/magzine/components/MenuItemMobileNormal.js new file mode 100644 index 00000000000..33569bfb5ca --- /dev/null +++ b/themes/magzine/components/MenuItemMobileNormal.js @@ -0,0 +1,29 @@ +import Link from 'next/link' +import { useRouter } from 'next/router' + +export const NormalMenu = props => { + const { link } = props + const router = useRouter() + + if (!link || !link.show) { + return null + } + + const selected = router.pathname === link.href || router.asPath === link.href + + return ( + +
    +
    {link.name}
    +
    + {link.slot} + + ) +} diff --git a/themes/magzine/components/MenuItemPCNormal.js b/themes/magzine/components/MenuItemPCNormal.js new file mode 100644 index 00000000000..e93ca07f070 --- /dev/null +++ b/themes/magzine/components/MenuItemPCNormal.js @@ -0,0 +1,30 @@ +import Link from 'next/link' +import { useRouter } from 'next/router' + +export const MenuItemPCNormal = props => { + const { link } = props + const router = useRouter() + const selected = router.pathname === link.href || router.asPath === link.href + if (!link || !link.show) { + return null + } + + return ( + +
    + +
    {link.name}
    +
    + {link.slot} + + ) +} diff --git a/themes/magzine/components/PaginationSimple.js b/themes/magzine/components/PaginationSimple.js new file mode 100644 index 00000000000..0fcbebab48e --- /dev/null +++ b/themes/magzine/components/PaginationSimple.js @@ -0,0 +1,55 @@ +import { useGlobal } from '@/lib/global' +import Link from 'next/link' +import { useRouter } from 'next/router' + +/** + * 简易翻页插件 + * @param page 当前页码 + * @param totalPage 是否有下一页 + * @returns {JSX.Element} + * @constructor + */ +const PaginationSimple = ({ page, totalPage }) => { + const { locale } = useGlobal() + const router = useRouter() + const currentPage = +page + const showNext = currentPage < totalPage + const pagePrefix = router.asPath + .split('?')[0] + .replace(/\/page\/[1-9]\d*/, '') + .replace(/\/$/, '') + + return ( +
    + + ←{locale.PAGINATION.PREV} + + + {locale.PAGINATION.NEXT}→ + +
    + ) +} + +export default PaginationSimple diff --git a/themes/magzine/components/Progress.js b/themes/magzine/components/Progress.js new file mode 100644 index 00000000000..f6fa94a680b --- /dev/null +++ b/themes/magzine/components/Progress.js @@ -0,0 +1,44 @@ +import { useEffect, useState } from 'react' +import { isBrowser } from '@/lib/utils' + +/** + * 顶部页面阅读进度条 + * @returns {JSX.Element} + * @constructor + */ +const Progress = ({ targetRef, showPercent = true }) => { + const currentRef = targetRef?.current || targetRef + const [percent, changePercent] = useState(0) + const scrollListener = () => { + const target = currentRef || (isBrowser && document.getElementById('article-wrapper')) + if (target) { + const clientHeight = target.clientHeight + const scrollY = window.pageYOffset + const fullHeight = clientHeight - window.outerHeight + let per = parseFloat(((scrollY / fullHeight) * 100).toFixed(0)) + if (per > 100) per = 100 + if (per < 0) per = 0 + changePercent(per) + } + } + + useEffect(() => { + document.addEventListener('scroll', scrollListener) + return () => document.removeEventListener('scroll', scrollListener) + }, []) + + return ( +
    +
    + {showPercent && ( +
    {percent}%
    + )} +
    +
    + ) +} + +export default Progress diff --git a/themes/magzine/components/RevolverMaps.js b/themes/magzine/components/RevolverMaps.js new file mode 100644 index 00000000000..a65fc4cf6de --- /dev/null +++ b/themes/magzine/components/RevolverMaps.js @@ -0,0 +1,36 @@ +import { useEffect, useState } from 'react' + +export default function RevolverMaps () { + const [load, changeLoad] = useState(false) + useEffect(() => { + if (!load) { + initRevolverMaps() + changeLoad(true) + } + }) + return
    +} + +function initRevolverMaps () { + if (screen.width >= 768) { + Promise.all([ + loadExternalResource('https://rf.revolvermaps.com/0/0/8.js?i=5jnp1havmh9&m=0&c=ff0000&cr1=ffffff&f=arial&l=33') + ]).then(() => { + // console.log('地图加载完成') + }) + } +} + +// 封装异步加载资源的方法 +function loadExternalResource (url) { + return new Promise((resolve, reject) => { + const container = document.getElementById('revolvermaps') + const tag = document.createElement('script') + tag.src = url + if (tag) { + tag.onload = () => resolve(url) + tag.onerror = () => reject(url) + container.appendChild(tag) + } + }) +} diff --git a/themes/magzine/components/SearchInput.js b/themes/magzine/components/SearchInput.js new file mode 100644 index 00000000000..f6c84d9c1b9 --- /dev/null +++ b/themes/magzine/components/SearchInput.js @@ -0,0 +1,86 @@ +import { useRouter } from 'next/router' +import { useImperativeHandle, useRef, useState } from 'react' +let lock = false + +const SearchInput = ({ currentTag, currentSearch, cRef, className }) => { + const [onLoading, setLoadingState] = useState(false) + const router = useRouter() + const searchInputRef = useRef() + useImperativeHandle(cRef, () => { + return { + focus: () => { + searchInputRef?.current?.focus() + } + } + }) + + const handleSearch = () => { + const key = searchInputRef.current.value + + if (key && key !== '') { + setLoadingState(true) + location.href = '/search/' + key + } else { + router.push({ pathname: '/' }).then(r => { + }) + } + } + const handleKeyUp = (e) => { + if (e.keyCode === 13) { // 回车 + handleSearch(searchInputRef.current.value) + } else if (e.keyCode === 27) { // ESC + cleanSearch() + } + } + const cleanSearch = () => { + searchInputRef.current.value = '' + } + + const [showClean, setShowClean] = useState(false) + const updateSearchKey = (val) => { + if (lock) { + return + } + searchInputRef.current.value = val + + if (val) { + setShowClean(true) + } else { + setShowClean(false) + } + } + function lockSearchInput () { + lock = true + } + + function unLockSearchInput () { + lock = false + } + + return
    + updateSearchKey(e.target.value)} + defaultValue={currentSearch} + /> + +
    + +
    + + {(showClean && +
    + +
    + )} +
    +} + +export default SearchInput diff --git a/themes/magzine/components/SocialButton.js b/themes/magzine/components/SocialButton.js new file mode 100644 index 00000000000..97aa6824e5e --- /dev/null +++ b/themes/magzine/components/SocialButton.js @@ -0,0 +1,104 @@ +import { siteConfig } from '@/lib/config' + +/** + * 社交联系方式按钮组 + * @returns {JSX.Element} + * @constructor + */ +const SocialButton = () => { + return ( +
    + {siteConfig('CONTACT_GITHUB') && ( + + + + )} + {siteConfig('CONTACT_TWITTER') && ( + + + + )} + {siteConfig('CONTACT_TELEGRAM') && ( + + + + )} + {siteConfig('CONTACT_LINKEDIN') && ( + + + + )} + {siteConfig('CONTACT_WEIBO') && ( + + + + )} + {siteConfig('CONTACT_INSTAGRAM') && ( + + + + )} + {siteConfig('CONTACT_EMAIL') && ( + + + + )} + {JSON.parse(siteConfig('ENABLE_RSS')) && ( + + + + )} + {siteConfig('CONTACT_BILIBILI') && ( + + + + )} + {siteConfig('CONTACT_YOUTUBE') && ( + + + + )} +
    + ) +} +export default SocialButton diff --git a/themes/magzine/components/TagGroups.js b/themes/magzine/components/TagGroups.js new file mode 100644 index 00000000000..dc0895f88a9 --- /dev/null +++ b/themes/magzine/components/TagGroups.js @@ -0,0 +1,30 @@ +import { useGlobal } from '@/lib/global' +import TagItemMini from './TagItemMini' + +/** + * 标签组 + * @param tags + * @param currentTag + * @returns {JSX.Element} + * @constructor + */ +const TagGroups = ({ tagOptions, currentTag }) => { + const { locale } = useGlobal() + if (!tagOptions) return <> + return ( +
    +
    + + {locale.COMMON.TAGS} +
    +
    + {tagOptions?.map(tag => { + const selected = tag.name === currentTag + return + })} +
    +
    + ) +} + +export default TagGroups diff --git a/themes/magzine/components/TagItemMini.js b/themes/magzine/components/TagItemMini.js new file mode 100644 index 00000000000..9922a069327 --- /dev/null +++ b/themes/magzine/components/TagItemMini.js @@ -0,0 +1,21 @@ +import Link from 'next/link' + +const TagItemMini = ({ tag, selected = false }) => { + return ( + + +
    {selected && } {tag.name + (tag.count ? `(${tag.count})` : '')}
    + + + ) +} + +export default TagItemMini diff --git a/themes/magzine/components/TocDrawer.js b/themes/magzine/components/TocDrawer.js new file mode 100644 index 00000000000..e8367486f7b --- /dev/null +++ b/themes/magzine/components/TocDrawer.js @@ -0,0 +1,48 @@ +import { useMagzineGlobal } from '..' +import Catalog from './Catalog' + +/** + * 悬浮抽屉目录 + * @param toc + * @param post + * @returns {JSX.Element} + * @constructor + */ +const TocDrawer = ({ post, cRef }) => { + const { tocVisible, changeTocVisible } = useMagzineGlobal() + const switchVisible = () => { + changeTocVisible(!tocVisible) + } + return ( + <> +
    + {/* 侧边菜单 */} +
    + {post && ( + <> +
    + +
    + + )} +
    +
    + {/* 背景蒙版 */} +
    + + ) +} +export default TocDrawer diff --git a/themes/magzine/components/TopNavBar.js b/themes/magzine/components/TopNavBar.js new file mode 100644 index 00000000000..244a02d780f --- /dev/null +++ b/themes/magzine/components/TopNavBar.js @@ -0,0 +1,110 @@ +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' + +/** + * 顶部导航栏 + 菜单 + * @param {} param0 + * @returns + */ +export default function TopNavBar(props) { + const { className, customNav, customMenu } = props + const [isOpen, changeShow] = useState(false) + const collapseRef = useRef(null) + + const { locale } = useGlobal() + + const defaultLinks = [ + { + icon: 'fas fa-th', + name: locale.COMMON.CATEGORY, + href: '/category', + show: siteConfig('MEDIUM_MENU_CATEGORY', null, CONFIG) + }, + { + icon: 'fas fa-tag', + name: locale.COMMON.TAGS, + href: '/tag', + show: siteConfig('MEDIUM_MENU_TAG', null, CONFIG) + }, + { + icon: 'fas fa-archive', + name: locale.NAV.ARCHIVE, + href: '/archive', + show: siteConfig('MEDIUM_MENU_ARCHIVE', null, CONFIG) + }, + { + icon: 'fas fa-search', + name: locale.NAV.SEARCH, + href: '/search', + show: siteConfig('MEDIUM_MENU_SEARCH', null, CONFIG) + } + ] + + let links = defaultLinks.concat(customNav) + + const toggleMenuOpen = () => { + changeShow(!isOpen) + } + + // 如果 开启自定义菜单,则覆盖Page生成的菜单 + if (siteConfig('CUSTOM_MENU')) { + links = customMenu + } + + if (!links || links.length === 0) { + return null + } + + return ( +
    + {/* 移动端折叠菜单 */} + +
    + + collapseRef.current?.updateCollapseHeight(param) + } + /> +
    +
    + + {/* 导航栏菜单 */} +
    + {/* 左侧图标Logo */} + + + {/* 折叠按钮、仅移动端显示 */} +
    +
    + {isOpen ? ( + + ) : ( + + )} +
    +
    + + {/* 桌面端顶部菜单 */} +
    + {links && + links?.map((link, index) => ( + + ))} +
    +
    +
    + ) +} diff --git a/themes/magzine/config.js b/themes/magzine/config.js new file mode 100644 index 00000000000..c29a2ef26c8 --- /dev/null +++ b/themes/magzine/config.js @@ -0,0 +1,24 @@ +const CONFIG = { + + // Style + MEDIUM_RIGHT_PANEL_DARK: process.env.NEXT_PUBLIC_MEDIUM_RIGHT_DARK || false, // 右侧面板深色模式 + + MEDIUM_POST_LIST_COVER: true, // 文章列表显示图片封面 + MEDIUM_POST_LIST_PREVIEW: true, // 列表显示文章预览 + MEDIUM_POST_LIST_CATEGORY: true, // 列表显示文章分类 + MEDIUM_POST_LIST_TAG: true, // 列表显示文章标签 + + MEDIUM_POST_DETAIL_CATEGORY: true, // 文章显示分类 + MEDIUM_POST_DETAIL_TAG: true, // 文章显示标签 + + // 菜单 + MEDIUM_MENU_CATEGORY: true, // 显示分类 + MEDIUM_MENU_TAG: true, // 显示标签 + MEDIUM_MENU_ARCHIVE: true, // 显示归档 + MEDIUM_MENU_SEARCH: true, // 显示搜索 + + // Widget + MEDIUM_WIDGET_REVOLVER_MAPS: process.env.NEXT_PUBLIC_WIDGET_REVOLVER_MAPS || 'false', // 地图插件 + MEDIUM_WIDGET_TO_TOP: true // 跳回顶部 +} +export default CONFIG diff --git a/themes/magzine/index.js b/themes/magzine/index.js new file mode 100644 index 00000000000..db46d13e036 --- /dev/null +++ b/themes/magzine/index.js @@ -0,0 +1,374 @@ +import Comment from '@/components/Comment' +import replaceSearchResult from '@/components/Mark' +import NotionPage from '@/components/NotionPage' +import ShareBar from '@/components/ShareBar' +import { siteConfig } from '@/lib/config' +import { useGlobal } from '@/lib/global' +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 ArticleAround from './components/ArticleAround' +import ArticleInfo from './components/ArticleInfo' +import { ArticleLock } from './components/ArticleLock' +import BlogArchiveItem from './components/BlogArchiveItem' +import BlogPostCardHorizontal from './components/BlogPostCardHorizontal' +import BlogPostCardTop from './components/BlogPostCardTop' +import BlogPostListPage from './components/BlogPostListPage' +import BlogPostListScroll from './components/BlogPostListScroll' +import Catalog from './components/Catalog' +import CategoryGroup from './components/CategoryGroup' +import CategoryItem from './components/CategoryItem' +import Footer from './components/Footer' +import Header from './components/Header' +import InfoCard from './components/InfoCard' +import SearchInput from './components/SearchInput' +import TagGroups from './components/TagGroups' +import TagItemMini from './components/TagItemMini' +import TocDrawer from './components/TocDrawer' +import CONFIG from './config' +import { Style } from './style' + +// 主题全局状态 +const ThemeGlobalMagzine = createContext() +export const useMagzineGlobal = () => useContext(ThemeGlobalMagzine) + +/** + * 基础布局 + * 采用左右两侧布局,移动端使用顶部导航栏 + * @returns {JSX.Element} + * @constructor + */ +const LayoutBase = props => { + const { children, showInfoCard = true, post, notice } = props + const { locale } = useGlobal() + const router = useRouter() + const [tocVisible, changeTocVisible] = useState(false) + const { onLoading, fullWidth } = useGlobal() + const [slotRight, setSlotRight] = useState(null) + + return ( + + {/* CSS样式 */} + +} + +export { Style } From 625b08b787f7a9f9fe2e8ae74ddbd6077f751bf2 Mon Sep 17 00:00:00 2001 From: "tangly1024.com" Date: Fri, 13 Sep 2024 12:54:25 +0800 Subject: [PATCH 3/8] =?UTF-8?q?magzine=E5=9F=BA=E6=9C=AC=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- styles/notion.css | 3 +- themes/magzine/components/Announcement.js | 2 +- .../{BlogArchiveItem.js => ArchiveItem.js} | 2 +- themes/magzine/components/ArticleInfo.js | 2 +- themes/magzine/components/ArticleLock.js | 2 +- .../magzine/components/BlogPostListEmpty.js | 14 --- themes/magzine/components/Catalog.js | 2 +- themes/magzine/components/CategoryItem.js | 8 +- themes/magzine/components/Footer.js | 58 ++++++--- themes/magzine/components/Header.js | 98 +++++++++++++--- themes/magzine/components/Hero.js | 62 ++++++++++ themes/magzine/components/InfoCard.js | 10 +- themes/magzine/components/JumpToTopButton.js | 23 ++-- themes/magzine/components/LogoBar.js | 4 +- themes/magzine/components/MenuBarMobile.js | 6 +- themes/magzine/components/MenuItemDrop.js | 16 +-- .../{BlogPostCard.js => PostItemCard.js} | 14 +-- .../magzine/components/PostItemCardSimple.js | 45 +++++++ ...{BlogPostCardTop.js => PostItemCardTop.js} | 22 ++-- ...tCardHorizontal.js => PostItemCardWide.js} | 47 ++++---- themes/magzine/components/PostListEmpty.js | 19 +++ .../magzine/components/PostListHorizontal.js | 38 ++++++ .../{BlogPostListPage.js => PostListPage.js} | 12 +- ...logPostListScroll.js => PostListScroll.js} | 12 +- .../components/PostListSimpleHorizontal.js | 37 ++++++ .../{BlogPostBar.js => PostListSlotBar.js} | 2 +- themes/magzine/components/SearchInput.js | 69 ++++++----- themes/magzine/components/TagItemMini.js | 15 ++- themes/magzine/components/TopNavBar.js | 8 +- themes/magzine/config.js | 37 +++--- themes/magzine/index.js | 110 ++++++++++++------ 31 files changed, 572 insertions(+), 227 deletions(-) rename themes/magzine/components/{BlogArchiveItem.js => ArchiveItem.js} (93%) delete mode 100644 themes/magzine/components/BlogPostListEmpty.js create mode 100644 themes/magzine/components/Hero.js rename themes/magzine/components/{BlogPostCard.js => PostItemCard.js} (88%) create mode 100644 themes/magzine/components/PostItemCardSimple.js rename themes/magzine/components/{BlogPostCardTop.js => PostItemCardTop.js} (77%) rename themes/magzine/components/{BlogPostCardHorizontal.js => PostItemCardWide.js} (77%) create mode 100644 themes/magzine/components/PostListEmpty.js create mode 100644 themes/magzine/components/PostListHorizontal.js rename themes/magzine/components/{BlogPostListPage.js => PostListPage.js} (73%) rename themes/magzine/components/{BlogPostListScroll.js => PostListScroll.js} (89%) create mode 100644 themes/magzine/components/PostListSimpleHorizontal.js rename themes/magzine/components/{BlogPostBar.js => PostListSlotBar.js} (92%) diff --git a/styles/notion.css b/styles/notion.css index ba794f88772..92c990fbf3c 100644 --- a/styles/notion.css +++ b/styles/notion.css @@ -1664,9 +1664,8 @@ code[class*='language-'] { } /* NOTION CSS OVERRIDE */ - .notion { - @apply dark:text-gray-300; + @apply dark:text-gray-100; overflow-wrap: break-word; } .notion, diff --git a/themes/magzine/components/Announcement.js b/themes/magzine/components/Announcement.js index 4796f99140b..522f078417c 100644 --- a/themes/magzine/components/Announcement.js +++ b/themes/magzine/components/Announcement.js @@ -10,7 +10,7 @@ const Announcement = ({ post, className }) => {
    + className='dark:text-gray-300 rounded-xl px-2'> {/*
    {locale.COMMON.ANNOUNCEMENT}
    */} {post && (
    diff --git a/themes/magzine/components/BlogArchiveItem.js b/themes/magzine/components/ArchiveItem.js similarity index 93% rename from themes/magzine/components/BlogArchiveItem.js rename to themes/magzine/components/ArchiveItem.js index 7d7b5a1c2e6..2dafd34c675 100644 --- a/themes/magzine/components/BlogArchiveItem.js +++ b/themes/magzine/components/ArchiveItem.js @@ -5,7 +5,7 @@ import Link from 'next/link' * @param {*} param0 * @returns */ -export default function BlogArchiveItem({ archiveTitle, archivePosts }) { +export default function ArchiveItem({ archiveTitle, archivePosts }) { return (
    diff --git a/themes/magzine/components/ArticleInfo.js b/themes/magzine/components/ArticleInfo.js index b5a71d26c9a..e2f79ea3043 100644 --- a/themes/magzine/components/ArticleInfo.js +++ b/themes/magzine/components/ArticleInfo.js @@ -32,7 +32,7 @@ export default function ArticleInfo(props) { {post?.lastEditedDay} -
    +
    diff --git a/themes/magzine/components/ArticleLock.js b/themes/magzine/components/ArticleLock.js index 6f2ca8cd46e..3047e7d24f6 100644 --- a/themes/magzine/components/ArticleLock.js +++ b/themes/magzine/components/ArticleLock.js @@ -45,7 +45,7 @@ export const ArticleLock = props => { } }} ref={passwordInputRef} // 绑定ref到passwordInputRef变量 - className='outline-none w-full text-sm pl-5 rounded-l transition focus:shadow-lg dark:text-gray-300 font-light leading-10 text-black bg-gray-100 dark:bg-gray-500'> + className='outline-none w-full text-sm pl-5 rounded-l transition focus:shadow-lg dark:text-gray-300 leading-10 text-black bg-gray-100 dark:bg-gray-500'>
    diff --git a/themes/magzine/components/BlogPostListEmpty.js b/themes/magzine/components/BlogPostListEmpty.js deleted file mode 100644 index a26cf292d3d..00000000000 --- a/themes/magzine/components/BlogPostListEmpty.js +++ /dev/null @@ -1,14 +0,0 @@ -import { useGlobal } from '@/lib/global' - -/** - * 空白博客 列表 - * @returns {JSX.Element} - * @constructor - */ -const BlogPostListEmpty = ({ currentSearch }) => { - const { locale } = useGlobal() - return
    -

    {locale.COMMON.NO_RESULTS_FOUND} {(currentSearch &&

    {currentSearch}
    )}

    -
    -} -export default BlogPostListEmpty diff --git a/themes/magzine/components/Catalog.js b/themes/magzine/components/Catalog.js index b390e68647f..4ee2c2822ef 100644 --- a/themes/magzine/components/Catalog.js +++ b/themes/magzine/components/Catalog.js @@ -77,7 +77,7 @@ const Catalog = ({ toc }) => {
    - + /> */} {category} {categoryCount && `(${categoryCount})`}
    diff --git a/themes/magzine/components/Footer.js b/themes/magzine/components/Footer.js index 0c5a9211229..aaf801f869f 100644 --- a/themes/magzine/components/Footer.js +++ b/themes/magzine/components/Footer.js @@ -1,28 +1,56 @@ import DarkModeButton from '@/components/DarkModeButton' import { siteConfig } from '@/lib/config' +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 copyrightDate = + parseInt(since) < currentYear ? since + '-' + currentYear : currentYear return ( -
    - - {`${copyrightDate}`} {siteConfig('AUTHOR')}.
    - - {siteConfig('BEI_AN') && <> {siteConfig('BEI_AN')}
    } - - - - - -
    + ) } diff --git a/themes/magzine/components/Header.js b/themes/magzine/components/Header.js index b4a8fd224dc..23985074402 100644 --- a/themes/magzine/components/Header.js +++ b/themes/magzine/components/Header.js @@ -17,6 +17,7 @@ export default function Header(props) { const { customNav, customMenu } = props const [isOpen, changeShow] = useState(false) const collapseRef = useRef(null) + const lastScrollY = useRef(0) // 用于存储上一次的滚动位置 const { locale } = useGlobal() @@ -66,16 +67,39 @@ export default function Header(props) { const scrollTrigger = throttle(() => { const scrollS = window.scrollY - const nav = document.querySelector('#top-navbar') + if (scrollS === lastScrollY.current) return // 如果滚动位置没有变化,则不做任何操作 - const narrowNav = scrollS > 50 + const nav = document.querySelector('#top-navbar') + const narrowNav = scrollS > 60 if (narrowNav) { nav && nav.classList.replace('h-20', 'h-14') } else { nav && nav.classList.replace('h-14', 'h-20') } + + lastScrollY.current = scrollS // 更新上一次的滚动位置 }, throttleMs) + const [showSearchInput, changeShowSearchInput] = useState(false) + + // 展示搜索框 + const toggleShowSearchInput = () => { + if (siteConfig('ALGOLIA_APP_ID')) { + searchModal.current.openSearch() + } else { + changeShowSearchInput(!showSearchInput) + } + } + + const onKeyUp = e => { + if (e.keyCode === 13) { + const search = document.getElementById('simple-search').value + if (search) { + router.push({ pathname: '/search/' + search }) + } + } + } + // 如果 开启自定义菜单,则覆盖Page生成的菜单 if (siteConfig('CUSTOM_MENU')) { links = customMenu @@ -94,25 +118,61 @@ export default function Header(props) { {/* 导航栏菜单内容 */}
    - {/* 左侧图标Logo */} - - - {/* 移动端折叠按钮 */} -
    -
    - {isOpen ? ( - - ) : ( - - )} + className='flex w-full mx-auto max-w-7xl h-20 transition-all duration-200 items-center justify-between'> + {/* 搜索栏 */} + {showSearchInput && ( + + )} + + {/* 默认菜单 */} + {!showSearchInput && ( + <> + {/* 左侧图标Logo */} +
    + + {/* 桌面端顶部菜单 */} +
    + {links && + links?.map(link => ( + + ))} +
    +
    + + )} + + {/* 右侧移动端折叠按钮 */} +
    +
    +
    + {isOpen ? ( + + ) : ( + + )} +
    -
    - {/* 桌面端顶部菜单 */} -
    - {links && - links?.map(link => )} + {/* 搜索按钮 */} +
    + +
    diff --git a/themes/magzine/components/Hero.js b/themes/magzine/components/Hero.js new file mode 100644 index 00000000000..590c948425c --- /dev/null +++ b/themes/magzine/components/Hero.js @@ -0,0 +1,62 @@ +// import { useGlobal } from '@/lib/global' +import { siteConfig } from '@/lib/config' +import Link from 'next/link' +import PostItemCardTop from './PostItemCardTop' +import PostItemCardWide from './PostItemCardWide' + +/** + * 首页主宣传 + * @param {*} param0 + * @returns + */ +const Hero = ({ posts }) => { + // 获取置顶文章与次要文章 + const postTop = posts[0] + const post1 = posts[1] + const post2 = posts[2] + // 首屏信息栏按钮文字 + const banner = siteConfig('MAGZINE_HOME_BANNER_ENABLE') + const button = siteConfig('MAGZINE_HOME_BUTTON') + const text = siteConfig('MAGZINE_HOME_BUTTON_TEXT') + const url = siteConfig('MAGZINE_HOME_BUTTON_URL') + const title = siteConfig('MAGZINE_HOME_TITLE') + const description = siteConfig('MAGZINE_HOME_DESCRIPTION') + const tips = siteConfig('MAGZINE_HOME_TIPS') + + return ( + <> +
    + {/* 左侧一篇主要置顶文章 */} +
    + +
    + {/* 右侧 */} +
    + {/* 首屏介绍 */} + {banner && ( +
    + {/* 首屏导航按钮 */} +

    {title}

    +

    {description}

    + {button && ( +
    + {text} +
    + )} + {tips} +
    + )} + + {/* 两篇次要文章 */} +
    +
    + +
    + +
    +
    +
    + + ) +} +export default Hero diff --git a/themes/magzine/components/InfoCard.js b/themes/magzine/components/InfoCard.js index abdc8862c89..507296646d5 100644 --- a/themes/magzine/components/InfoCard.js +++ b/themes/magzine/components/InfoCard.js @@ -1,7 +1,5 @@ import LazyImage from '@/components/LazyImage' import { siteConfig } from '@/lib/config' -import Router from 'next/router' -import SocialButton from './SocialButton' /** * 用户信息卡 @@ -10,8 +8,9 @@ import SocialButton from './SocialButton' */ const InfoCard = props => { const { siteInfo } = props + return ( -
    +
    { alt={siteConfig('AUTHOR')} />
    -
    +
    {siteConfig('AUTHOR')}
    -
    +
    {siteConfig('BIO')}
    -
    ) diff --git a/themes/magzine/components/JumpToTopButton.js b/themes/magzine/components/JumpToTopButton.js index 6342bf78539..1c30373b336 100644 --- a/themes/magzine/components/JumpToTopButton.js +++ b/themes/magzine/components/JumpToTopButton.js @@ -1,5 +1,5 @@ -import CONFIG from '../config' import { siteConfig } from '@/lib/config' +import CONFIG from '../config' /** * 跳转到网页顶部 @@ -10,18 +10,23 @@ import { siteConfig } from '@/lib/config' * @constructor */ const JumpToTopButton = ({ showPercent = false, percent, className }) => { - if (!siteConfig('MEDIUM_WIDGET_TO_TOP', null, CONFIG)) { + if (!siteConfig('MAGZINE_WIDGET_TO_TOP', null, CONFIG)) { return <> } return (
    - { window.scrollTo({ top: 0, behavior: 'smooth' }) }} /> + id='jump-to-top' + data-aos='fade-up' + data-aos-duration='300' + data-aos-once='false' + data-aos-anchor-placement='top-center' + className='fixed xl:right-80 right-2 mr-10 bottom-24 z-20'> + { + window.scrollTo({ top: 0, behavior: 'smooth' }) + }} + />
    ) } diff --git a/themes/magzine/components/LogoBar.js b/themes/magzine/components/LogoBar.js index dfe01f9a8e5..c484f34aebe 100644 --- a/themes/magzine/components/LogoBar.js +++ b/themes/magzine/components/LogoBar.js @@ -5,7 +5,9 @@ export default function LogoBar(props) { const { siteInfo } = props return (
    - + {/* { { name: locale.COMMON.CATEGORY, href: '/category', - show: siteConfig('MEDIUM_MENU_CATEGORY', null, CONFIG) + show: siteConfig('MAGZINE_MENU_CATEGORY', null, CONFIG) }, { name: locale.COMMON.TAGS, href: '/tag', - show: siteConfig('MEDIUM_MENU_TAG', null, CONFIG) + show: siteConfig('MAGZINE_MENU_TAG', null, CONFIG) }, { name: locale.NAV.ARCHIVE, href: '/archive', - show: siteConfig('MEDIUM_MENU_ARCHIVE', null, CONFIG) + show: siteConfig('MAGZINE_MENU_ARCHIVE', null, CONFIG) } // { name: locale.NAV.SEARCH, href: '/search', show: siteConfig('MENU_SEARCH', null, CONFIG) } ] diff --git a/themes/magzine/components/MenuItemDrop.js b/themes/magzine/components/MenuItemDrop.js index 38484029b44..1a629248b55 100644 --- a/themes/magzine/components/MenuItemDrop.js +++ b/themes/magzine/components/MenuItemDrop.js @@ -16,22 +16,22 @@ export const MenuItemDrop = ({ link }) => { return (
  • changeShow(true)} onMouseOut={() => changeShow(false)}> {hasSubMenu && (
    -
    +
    {link?.icon && } {link?.name} {hasSubMenu && ( + className={`px-1 fas fa-chevron-down duration-500 transition-all ${show ? ' rotate-180' : ''}`}> )}
    @@ -40,7 +40,7 @@ export const MenuItemDrop = ({ link }) => { {!hasSubMenu && (
    { {/* 子菜单 */} {hasSubMenu && (
      + className={`${show ? 'visible opacity-100 top-14 ' : 'invisible opacity-0 top-10 '} absolute border bg-white dark:bg-black dark:border-gray-800 transition-all duration-300 z-20 block rounded-lg drop-shadow-lg p-4 `}> {link?.subMenus?.map(sLink => { return (
    • + className='text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-900 tracking-widest transition-all duration-200 dark:border-gray-800 py-3 pr-6 pl-3'> - + {link?.icon &&   } {sLink.title} diff --git a/themes/magzine/components/BlogPostCard.js b/themes/magzine/components/PostItemCard.js similarity index 88% rename from themes/magzine/components/BlogPostCard.js rename to themes/magzine/components/PostItemCard.js index ac82bcc1a94..228db9a6708 100644 --- a/themes/magzine/components/BlogPostCard.js +++ b/themes/magzine/components/PostItemCard.js @@ -9,9 +9,9 @@ import CONFIG from '../config' import CategoryItem from './CategoryItem' import TagItemMini from './TagItemMini' -const BlogPostCard = ({ post, showSummary }) => { +const PostItemCard = ({ post, showSummary }) => { const showPreview = - siteConfig('MEDIUM_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap + siteConfig('MAGZINE_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap const { locale } = useGlobal() return (
      { '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' }>

      - {siteConfig('MEDIUM_POST_LIST_COVER', null, CONFIG) && ( + {siteConfig('MAGZINE_POST_LIST_COVER', null, CONFIG) && (
      { 'flex mt-2 items-center justify-start flex-wrap space-x-3 text-gray-400' }>
      {post.date?.start_date}
      - {siteConfig('MEDIUM_POST_LIST_CATEGORY', null, CONFIG) && ( + {siteConfig('MAGZINE_POST_LIST_CATEGORY', null, CONFIG) && ( )} - {siteConfig('MEDIUM_POST_LIST_TAG', null, CONFIG) && + {siteConfig('MAGZINE_POST_LIST_TAG', null, CONFIG) && post?.tagItems?.map(tag => ( ))} @@ -63,7 +63,7 @@ const BlogPostCard = ({ post, showSummary }) => {
      {(!showPreview || showSummary) && ( -
      +
      {post.summary}
      )} @@ -89,4 +89,4 @@ const BlogPostCard = ({ post, showSummary }) => { ) } -export default BlogPostCard +export default PostItemCard diff --git a/themes/magzine/components/PostItemCardSimple.js b/themes/magzine/components/PostItemCardSimple.js new file mode 100644 index 00000000000..69ef5556c7f --- /dev/null +++ b/themes/magzine/components/PostItemCardSimple.js @@ -0,0 +1,45 @@ +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' + +/** + * 不带图片 + * @param {*} param0 + * @returns + */ +const PostItemCardSimple = ({ post, showSummary }) => { + const showPreview = + siteConfig('MAGZINE_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap + const { locale } = useGlobal() + return ( +
      +
      + {siteConfig('MAGZINE_POST_LIST_CATEGORY', null, CONFIG) && ( + + )} +
      + + {/* 文章标题 */} + +

      + {siteConfig('POST_TITLE_ICON') && } + {post.title} +

      + + +
      {post.date?.start_date}
      +
      + ) +} + +export default PostItemCardSimple diff --git a/themes/magzine/components/BlogPostCardTop.js b/themes/magzine/components/PostItemCardTop.js similarity index 77% rename from themes/magzine/components/BlogPostCardTop.js rename to themes/magzine/components/PostItemCardTop.js index 2c02d02e6f3..b9d5756a3bf 100644 --- a/themes/magzine/components/BlogPostCardTop.js +++ b/themes/magzine/components/PostItemCardTop.js @@ -13,9 +13,9 @@ import TagItemMini from './TagItemMini' * @param {*} param0 * @returns */ -const BlogPostCardTop = ({ post, showSummary }) => { +const PostItemCardTop = ({ post, showSummary }) => { const showPreview = - siteConfig('MEDIUM_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap + siteConfig('MAGZINE_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap const { locale } = useGlobal() return (
      { data-aos-anchor-placement='top-bottom' className='mb-6 max-w-7xl '>
      - {siteConfig('MEDIUM_POST_LIST_COVER', null, CONFIG) && ( + {siteConfig('MAGZINE_POST_LIST_COVER', null, CONFIG) && (
      { )} -
      - {siteConfig('MEDIUM_POST_LIST_CATEGORY', null, CONFIG) && ( +
      + {siteConfig('MAGZINE_POST_LIST_CATEGORY', null, CONFIG) && ( )}
      - {siteConfig('MEDIUM_POST_LIST_TAG', null, CONFIG) && + {siteConfig('MAGZINE_POST_LIST_TAG', null, CONFIG) && post?.tagItems?.map(tag => ( ))} @@ -62,9 +62,9 @@ const BlogPostCardTop = ({ post, showSummary }) => { href={post?.href} passHref className={ - 'cursor-pointer hover:underline font-bold text-3xl leading-tight dark:text-gray-300 dark:hover:text-gray-400' + 'cursor-pointer hover:underline leading-tight dark:text-gray-300 dark:hover:text-gray-400' }> -

      +

      {siteConfig('POST_TITLE_ICON') && ( )} @@ -75,7 +75,7 @@ const BlogPostCardTop = ({ post, showSummary }) => {
      {(!showPreview || showSummary) && ( -
      +
      {post.summary}
      )} @@ -103,4 +103,4 @@ const BlogPostCardTop = ({ post, showSummary }) => { ) } -export default BlogPostCardTop +export default PostItemCardTop diff --git a/themes/magzine/components/BlogPostCardHorizontal.js b/themes/magzine/components/PostItemCardWide.js similarity index 77% rename from themes/magzine/components/BlogPostCardHorizontal.js rename to themes/magzine/components/PostItemCardWide.js index 076b2d897a5..0b250850646 100644 --- a/themes/magzine/components/BlogPostCardHorizontal.js +++ b/themes/magzine/components/PostItemCardWide.js @@ -8,21 +8,24 @@ import CONFIG from '../config' import CategoryItem from './CategoryItem' import TagItemMini from './TagItemMini' -const BlogPostCardHorizontal = ({ post, showSummary }) => { +/** + * 水平左右布局的博客卡片 + * @param {*} param0 + * @returns + */ +const PostItemCardWide = ({ post, showSummary }) => { const showPreview = - siteConfig('MEDIUM_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap + siteConfig('MAGZINE_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap const { locale } = useGlobal() return ( -
      +
      {/* 卡牌左侧 */}

      {siteConfig('POST_TITLE_ICON') && ( @@ -32,22 +35,8 @@ const BlogPostCardHorizontal = ({ post, showSummary }) => {

      -
      -
      {post.date?.start_date}
      - {siteConfig('MEDIUM_POST_LIST_CATEGORY', null, CONFIG) && ( - - )} - {siteConfig('MEDIUM_POST_LIST_TAG', null, CONFIG) && - post?.tagItems?.map(tag => ( - - ))} -
      - {(!showPreview || showSummary) && ( -
      +
      {post.summary}
      )} @@ -68,6 +57,20 @@ const BlogPostCardHorizontal = ({ post, showSummary }) => {
      )} + +
      + {siteConfig('MAGZINE_POST_LIST_CATEGORY', null, CONFIG) && ( + + )} + {siteConfig('MAGZINE_POST_LIST_TAG', null, CONFIG) && + post?.tagItems?.map(tag => ( + + ))} +
      {post.date?.start_date}
      +
      {/* 卡牌右侧图片 */} @@ -82,4 +85,4 @@ const BlogPostCardHorizontal = ({ post, showSummary }) => { ) } -export default BlogPostCardHorizontal +export default PostItemCardWide diff --git a/themes/magzine/components/PostListEmpty.js b/themes/magzine/components/PostListEmpty.js new file mode 100644 index 00000000000..cc037cea0da --- /dev/null +++ b/themes/magzine/components/PostListEmpty.js @@ -0,0 +1,19 @@ +import { useGlobal } from '@/lib/global' + +/** + * 空白博客 列表 + * @returns {JSX.Element} + * @constructor + */ +const PostListEmpty = ({ currentSearch }) => { + const { locale } = useGlobal() + return ( +
      +

      + {locale.COMMON.NO_RESULTS_FOUND}{' '} + {currentSearch &&

      {currentSearch}
      } +

      +
      + ) +} +export default PostListEmpty diff --git a/themes/magzine/components/PostListHorizontal.js b/themes/magzine/components/PostListHorizontal.js new file mode 100644 index 00000000000..41ef905d033 --- /dev/null +++ b/themes/magzine/components/PostListHorizontal.js @@ -0,0 +1,38 @@ +import Link from 'next/link' +import PostItemCardSimple from './PostItemCardSimple' +import PostListEmpty from './PostListEmpty' + +/** + * 博文水平列表 + * 含封面 + * @returns {JSX.Element} + * @constructor + */ +const PostListHorizontal = ({ title, href, posts }) => { + if (!posts || posts.length === 0) { + return + } + + return ( +
      +
      + {/* 标题 */} +
      +

      {title}

      + + 查看全部 + + +
      + {/* 列表 */} +
        + {posts?.map(p => { + return + })} +
      +
      +
      + ) +} + +export default PostListHorizontal diff --git a/themes/magzine/components/BlogPostListPage.js b/themes/magzine/components/PostListPage.js similarity index 73% rename from themes/magzine/components/BlogPostListPage.js rename to themes/magzine/components/PostListPage.js index 79e031dd63e..9486f6ec965 100644 --- a/themes/magzine/components/BlogPostListPage.js +++ b/themes/magzine/components/PostListPage.js @@ -1,8 +1,8 @@ import { siteConfig } from '@/lib/config' import { useGlobal } from '@/lib/global' -import BlogPostCard from './BlogPostCard' -import BlogPostListEmpty from './BlogPostListEmpty' import PaginationSimple from './PaginationSimple' +import PostItemCard from './PostItemCard' +import PostListEmpty from './PostListEmpty' /** * 文章列表分页表格 @@ -12,13 +12,13 @@ import PaginationSimple from './PaginationSimple' * @returns {JSX.Element} * @constructor */ -const BlogPostListPage = ({ page = 1, posts = [], postCount }) => { +const PostListPage = ({ page = 1, posts = [], postCount }) => { const { NOTION_CONFIG } = useGlobal() const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', null, NOTION_CONFIG) const totalPage = Math.ceil(postCount / POSTS_PER_PAGE) if (!posts || posts.length === 0) { - return + return } return ( @@ -26,7 +26,7 @@ const BlogPostListPage = ({ page = 1, posts = [], postCount }) => {
      {/* 文章列表 */} {posts?.map(post => ( - + ))}
      @@ -34,4 +34,4 @@ const BlogPostListPage = ({ page = 1, posts = [], postCount }) => { ) } -export default BlogPostListPage +export default PostListPage diff --git a/themes/magzine/components/BlogPostListScroll.js b/themes/magzine/components/PostListScroll.js similarity index 89% rename from themes/magzine/components/BlogPostListScroll.js rename to themes/magzine/components/PostListScroll.js index 22960779231..a33aa1e9166 100644 --- a/themes/magzine/components/BlogPostListScroll.js +++ b/themes/magzine/components/PostListScroll.js @@ -3,8 +3,8 @@ import { useGlobal } from '@/lib/global' import throttle from 'lodash.throttle' import { useRouter } from 'next/router' import { useCallback, useEffect, useRef, useState } from 'react' -import BlogPostCard from './BlogPostCard' -import BlogPostListEmpty from './BlogPostListEmpty' +import PostItemCard from './PostItemCard' +import PostListEmpty from './PostListEmpty' /** * 博客列表滚动分页 @@ -13,7 +13,7 @@ import BlogPostListEmpty from './BlogPostListEmpty' * @returns {JSX.Element} * @constructor */ -const BlogPostListScroll = ({ posts = [], currentSearch }) => { +const PostListScroll = ({ posts = [], currentSearch }) => { const { NOTION_CONFIG } = useGlobal() const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', null, NOTION_CONFIG) const [page, updatePage] = useState(1) @@ -67,14 +67,14 @@ const BlogPostListScroll = ({ posts = [], currentSearch }) => { const { locale } = useGlobal() if (!postsToShow || postsToShow.length === 0) { - return + return } else { return (
      {/* 文章列表 */}
      {postsToShow?.map(post => ( - + ))}
      @@ -104,4 +104,4 @@ const getPostByPage = function (page, totalPosts, POSTS_PER_PAGE) { return totalPosts.slice(0, POSTS_PER_PAGE * page) } -export default BlogPostListScroll +export default PostListScroll diff --git a/themes/magzine/components/PostListSimpleHorizontal.js b/themes/magzine/components/PostListSimpleHorizontal.js new file mode 100644 index 00000000000..5add570c757 --- /dev/null +++ b/themes/magzine/components/PostListSimpleHorizontal.js @@ -0,0 +1,37 @@ +import Link from 'next/link' +import PostItemCardSimple from './PostItemCardSimple' +import PostListEmpty from './PostListEmpty' + +/** + * 博文水平列表;不带封面图 + * @returns {JSX.Element} + * @constructor + */ +const PostSimpleListHorizontal = ({ title, href, posts }) => { + if (!posts || posts.length === 0) { + return + } + + return ( +
      +
      + {/* 标题 */} +
      +

      {title}

      + + 查看全部 + + +
      + {/* 列表 */} +
        + {posts?.map(p => { + return + })} +
      +
      +
      + ) +} + +export default PostSimpleListHorizontal diff --git a/themes/magzine/components/BlogPostBar.js b/themes/magzine/components/PostListSlotBar.js similarity index 92% rename from themes/magzine/components/BlogPostBar.js rename to themes/magzine/components/PostListSlotBar.js index 9f34aca5149..228d1f3c05f 100644 --- a/themes/magzine/components/BlogPostBar.js +++ b/themes/magzine/components/PostListSlotBar.js @@ -5,7 +5,7 @@ import { useGlobal } from '@/lib/global' * @param {*} props * @returns */ -export default function BlogPostBar(props) { +export default function PostListSlotBar(props) { const { tag, category } = props const { locale } = useGlobal() diff --git a/themes/magzine/components/SearchInput.js b/themes/magzine/components/SearchInput.js index f6c84d9c1b9..4ebcade0bd7 100644 --- a/themes/magzine/components/SearchInput.js +++ b/themes/magzine/components/SearchInput.js @@ -21,14 +21,15 @@ const SearchInput = ({ currentTag, currentSearch, cRef, className }) => { setLoadingState(true) location.href = '/search/' + key } else { - router.push({ pathname: '/' }).then(r => { - }) + router.push({ pathname: '/' }).then(r => {}) } } - const handleKeyUp = (e) => { - if (e.keyCode === 13) { // 回车 + const handleKeyUp = e => { + if (e.keyCode === 13) { + // 回车 handleSearch(searchInputRef.current.value) - } else if (e.keyCode === 27) { // ESC + } else if (e.keyCode === 27) { + // ESC cleanSearch() } } @@ -37,7 +38,7 @@ const SearchInput = ({ currentTag, currentSearch, cRef, className }) => { } const [showClean, setShowClean] = useState(false) - const updateSearchKey = (val) => { + const updateSearchKey = val => { if (lock) { return } @@ -49,38 +50,48 @@ const SearchInput = ({ currentTag, currentSearch, cRef, className }) => { setShowClean(false) } } - function lockSearchInput () { + function lockSearchInput() { lock = true } - function unLockSearchInput () { + function unLockSearchInput() { lock = false } - return
      - updateSearchKey(e.target.value)} - defaultValue={currentSearch} - /> + return ( +
      + updateSearchKey(e.target.value)} + defaultValue={currentSearch} + /> -
      - -
      - - {(showClean && -
      - +
      +
      + + {showClean && ( +
      + +
      )} -
      +
      + ) } export default SearchInput diff --git a/themes/magzine/components/TagItemMini.js b/themes/magzine/components/TagItemMini.js index 9922a069327..c08b33f1ce9 100644 --- a/themes/magzine/components/TagItemMini.js +++ b/themes/magzine/components/TagItemMini.js @@ -8,12 +8,15 @@ const TagItemMini = ({ tag, selected = false }) => { passHref className={`cursor-pointer inline-block rounded hover:bg-gray-500 hover:text-white duration-200 mr-2 py-1 px-2 text-xs whitespace-nowrap dark:hover:text-white - ${selected - ? '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`}` }> - -
      {selected && } {tag.name + (tag.count ? `(${tag.count})` : '')}
      - + ${ + selected + ? 'text-white dark:text-gray-300 dark:hover:bg-gray-900' + : `text-gray-900 hover:shadow-xl dark:border-gray-400 dark:bg-gray-800` + }`}> +
      + {/* {selected && } */}# + {tag.name + (tag.count ? `(${tag.count})` : '')}{' '} +
      ) } diff --git a/themes/magzine/components/TopNavBar.js b/themes/magzine/components/TopNavBar.js index 244a02d780f..ef22aa2d3d2 100644 --- a/themes/magzine/components/TopNavBar.js +++ b/themes/magzine/components/TopNavBar.js @@ -24,25 +24,25 @@ export default function TopNavBar(props) { icon: 'fas fa-th', name: locale.COMMON.CATEGORY, href: '/category', - show: siteConfig('MEDIUM_MENU_CATEGORY', null, CONFIG) + show: siteConfig('MAGZINE_MENU_CATEGORY', null, CONFIG) }, { icon: 'fas fa-tag', name: locale.COMMON.TAGS, href: '/tag', - show: siteConfig('MEDIUM_MENU_TAG', null, CONFIG) + show: siteConfig('MAGZINE_MENU_TAG', null, CONFIG) }, { icon: 'fas fa-archive', name: locale.NAV.ARCHIVE, href: '/archive', - show: siteConfig('MEDIUM_MENU_ARCHIVE', null, CONFIG) + show: siteConfig('MAGZINE_MENU_ARCHIVE', null, CONFIG) }, { icon: 'fas fa-search', name: locale.NAV.SEARCH, href: '/search', - show: siteConfig('MEDIUM_MENU_SEARCH', null, CONFIG) + show: siteConfig('MAGZINE_MENU_SEARCH', null, CONFIG) } ] diff --git a/themes/magzine/config.js b/themes/magzine/config.js index c29a2ef26c8..6ef5e66edff 100644 --- a/themes/magzine/config.js +++ b/themes/magzine/config.js @@ -1,24 +1,35 @@ const CONFIG = { + // 首屏信息栏按钮文字 + MAGZINE_HOME_BANNER_ENABLE: true, // 首屏右上角的宣传位 + MAGZINE_HOME_BUTTON: true, + MAGZINE_HOME_BUTTON_URL: '/about', + MAGZINE_HOME_BUTTON_TEXT: '了解更多', + + MAGZINE_HOME_TITLE: '立即开创您的在线业务。完全免费。', + MAGZINE_HOME_DESCRIPTION: + '借助NotionNext,获得助您开创、经营和扩展业务所需的全部工具和帮助。', + MAGZINE_HOME_TIPS: 'AI时代来临,这是属于超级个体的狂欢盛宴!', // Style - MEDIUM_RIGHT_PANEL_DARK: process.env.NEXT_PUBLIC_MEDIUM_RIGHT_DARK || false, // 右侧面板深色模式 + MAGZINE_RIGHT_PANEL_DARK: process.env.NEXT_PUBLIC_MAGZINE_RIGHT_DARK || false, // 右侧面板深色模式 - MEDIUM_POST_LIST_COVER: true, // 文章列表显示图片封面 - MEDIUM_POST_LIST_PREVIEW: true, // 列表显示文章预览 - MEDIUM_POST_LIST_CATEGORY: true, // 列表显示文章分类 - MEDIUM_POST_LIST_TAG: true, // 列表显示文章标签 + MAGZINE_POST_LIST_COVER: true, // 文章列表显示图片封面 + MAGZINE_POST_LIST_PREVIEW: true, // 列表显示文章预览 + MAGZINE_POST_LIST_CATEGORY: true, // 列表显示文章分类 + MAGZINE_POST_LIST_TAG: true, // 列表显示文章标签 - MEDIUM_POST_DETAIL_CATEGORY: true, // 文章显示分类 - MEDIUM_POST_DETAIL_TAG: true, // 文章显示标签 + MAGZINE_POST_DETAIL_CATEGORY: true, // 文章显示分类 + MAGZINE_POST_DETAIL_TAG: true, // 文章显示标签 // 菜单 - MEDIUM_MENU_CATEGORY: true, // 显示分类 - MEDIUM_MENU_TAG: true, // 显示标签 - MEDIUM_MENU_ARCHIVE: true, // 显示归档 - MEDIUM_MENU_SEARCH: true, // 显示搜索 + MAGZINE_MENU_CATEGORY: true, // 显示分类 + MAGZINE_MENU_TAG: true, // 显示标签 + MAGZINE_MENU_ARCHIVE: true, // 显示归档 + MAGZINE_MENU_SEARCH: true, // 显示搜索 // Widget - MEDIUM_WIDGET_REVOLVER_MAPS: process.env.NEXT_PUBLIC_WIDGET_REVOLVER_MAPS || 'false', // 地图插件 - MEDIUM_WIDGET_TO_TOP: true // 跳回顶部 + MAGZINE_WIDGET_REVOLVER_MAPS: + process.env.NEXT_PUBLIC_WIDGET_REVOLVER_MAPS || 'false', // 地图插件 + MAGZINE_WIDGET_TO_TOP: true // 跳回顶部 } export default CONFIG diff --git a/themes/magzine/index.js b/themes/magzine/index.js index db46d13e036..5845e01c8a2 100644 --- a/themes/magzine/index.js +++ b/themes/magzine/index.js @@ -8,21 +8,20 @@ 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' import { ArticleLock } from './components/ArticleLock' -import BlogArchiveItem from './components/BlogArchiveItem' -import BlogPostCardHorizontal from './components/BlogPostCardHorizontal' -import BlogPostCardTop from './components/BlogPostCardTop' -import BlogPostListPage from './components/BlogPostListPage' -import BlogPostListScroll from './components/BlogPostListScroll' import Catalog from './components/Catalog' import CategoryGroup from './components/CategoryGroup' import CategoryItem from './components/CategoryItem' import Footer from './components/Footer' import Header from './components/Header' -import InfoCard from './components/InfoCard' +import Hero from './components/Hero' +import PostListHorizontal from './components/PostListHorizontal' +import PostListPage from './components/PostListPage' +import PostListScroll from './components/PostListScroll' +import PostSimpleListHorizontal from './components/PostListSimpleHorizontal' import SearchInput from './components/SearchInput' import TagGroups from './components/TagGroups' import TagItemMini from './components/TagItemMini' @@ -81,33 +80,72 @@ const LayoutBase = props => { * @returns */ const LayoutIndex = props => { - const { posts, notice } = props - const top = posts[0] - const post1 = posts[1] - const post2 = posts[2] + const { posts, allNavPages } = props + // 最新文章 从第4个元素开始截取出4个 + const newPosts = posts.slice(3, 7) + + // 按分类将文章分组成文件夹 + const categoryFolders = groupArticles(allNavPages.slice(8)) + return ( -
      - {/* 首屏文章 */} +
      + {/* 首屏宣传区块 */} + -
      -
      - -
      -
      -
      - - -
      - {/* 两篇主要文章 */} -
      - - -
      -
      -
      + {/* 最新文章区块 */} + + + {/* 不同的分类文章列表 */} + {categoryFolders?.map((categoryGroup, index) => { + if ( + !categoryGroup || + !categoryGroup.items || + categoryGroup.items.length < 1 + ) { + return null + } + + return ( + + ) + })}
      ) } +// 按照分类将文章分组成文件夹 +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 +} /** * 博客列表 @@ -117,9 +155,9 @@ const LayoutPostList = props => { return ( <> {siteConfig('POST_LIST_STYLE') === 'page' ? ( - + ) : ( - + )} ) @@ -180,10 +218,10 @@ const LayoutSlug = props => { {/* 文章分类和标签信息 */}
      - {siteConfig('MEDIUM_POST_DETAIL_CATEGORY', null, CONFIG) && + {siteConfig('MAGZINE_POST_DETAIL_CATEGORY', null, CONFIG) && post?.category && }
      - {siteConfig('MEDIUM_POST_DETAIL_TAG', null, CONFIG) && + {siteConfig('MAGZINE_POST_DETAIL_TAG', null, CONFIG) && post?.tagItems?.map(tag => ( ))} @@ -245,9 +283,9 @@ const LayoutSearch = props => { {currentSearch && (
      {siteConfig('POST_LIST_STYLE') === 'page' ? ( - + ) : ( - + )}
      )} @@ -266,7 +304,7 @@ const LayoutArchive = props => { <>
      {Object.keys(archivePosts)?.map(archiveTitle => ( - Date: Fri, 13 Sep 2024 15:12:28 +0800 Subject: [PATCH 4/8] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E4=B8=80=E7=BA=A7?= =?UTF-8?q?=E6=A0=87=E9=A2=98=E4=B8=8B=E5=88=92=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- styles/notion.css | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/styles/notion.css b/styles/notion.css index 92c990fbf3c..0685e3042e9 100644 --- a/styles/notion.css +++ b/styles/notion.css @@ -403,7 +403,8 @@ summary > .notion-h { .notion-h1 { font-size: 1.575em; margin-top: 1.08em; - @apply border-b w-full; + @apply w-full; + /* @apply border-b w-full; */ } .notion-h2 { @apply w-full; @@ -554,7 +555,7 @@ summary > .notion-h { width: 100%; margin: 6px 0; padding: 0; - border-bottom-width: 1px; + /* border-bottom-width: 1px; */ } .notion-link { From 0dae01f5470d72c127b6f0815f189a776adbbeda Mon Sep 17 00:00:00 2001 From: "tangly1024.com" Date: Fri, 13 Sep 2024 17:07:09 +0800 Subject: [PATCH 5/8] =?UTF-8?q?Magzine=E4=B8=BB=E9=A2=98=E5=9F=BA=E7=A1=80?= =?UTF-8?q?=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/ExternalPlugins.js | 3 +- components/OpenWrite.js | 5 +- lib/cache/cache_manager.js | 2 +- themes/magzine/components/Announcement.js | 3 + themes/magzine/components/ArticleInfo.js | 43 +++++- themes/magzine/components/Footer.js | 137 +++++++++++++----- themes/magzine/components/Header.js | 2 +- themes/magzine/components/Hero.js | 2 +- themes/magzine/components/JumpToTopButton.js | 3 +- themes/magzine/components/LoadingCover.js | 7 - themes/magzine/components/MenuBarMobile.js | 9 +- .../components/PostBannerGroupByCategory.js | 87 +++++++++++ themes/magzine/components/PostItemCard.js | 96 ++++-------- .../magzine/components/PostItemCardSimple.js | 8 +- themes/magzine/components/PostItemCardTop.js | 12 +- themes/magzine/components/PostItemCardWide.js | 8 +- .../magzine/components/PostListHorizontal.js | 15 +- .../magzine/components/PostListRecommend.js | 79 ++++++++++ .../components/PostListSimpleHorizontal.js | 2 +- themes/magzine/components/SocialButton.js | 20 +-- themes/magzine/components/TopNavBar.js | 9 +- themes/magzine/config.js | 96 +++++++++++- themes/magzine/index.js | 80 +++------- 23 files changed, 499 insertions(+), 229 deletions(-) delete mode 100644 themes/magzine/components/LoadingCover.js create mode 100644 themes/magzine/components/PostBannerGroupByCategory.js create mode 100644 themes/magzine/components/PostListRecommend.js diff --git a/components/ExternalPlugins.js b/components/ExternalPlugins.js index ce0b5e63ab0..d798a940cdd 100644 --- a/components/ExternalPlugins.js +++ b/components/ExternalPlugins.js @@ -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) { diff --git a/components/OpenWrite.js b/components/OpenWrite.js index 973931a80b9..5caf5d7b105 100644 --- a/components/OpenWrite.js +++ b/components/OpenWrite.js @@ -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') diff --git a/lib/cache/cache_manager.js b/lib/cache/cache_manager.js index 6070958cc23..bbfbfdacb68 100644 --- a/lib/cache/cache_manager.js +++ b/lib/cache/cache_manager.js @@ -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 diff --git a/themes/magzine/components/Announcement.js b/themes/magzine/components/Announcement.js index 522f078417c..62ab01d00bc 100644 --- a/themes/magzine/components/Announcement.js +++ b/themes/magzine/components/Announcement.js @@ -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) { diff --git a/themes/magzine/components/ArticleInfo.js b/themes/magzine/components/ArticleInfo.js index e2f79ea3043..02461b8d7a6 100644 --- a/themes/magzine/components/ArticleInfo.js +++ b/themes/magzine/components/ArticleInfo.js @@ -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 */} -

      - {siteConfig('POST_TITLE_ICON') && } - {post?.title} -

      +
      +
      + {siteConfig('MAGZINE_POST_LIST_CATEGORY') && ( + + )} +
      + {siteConfig('MAGZINE_POST_LIST_TAG') && + post?.tagItems?.map(tag => ( + + ))} +
      +
      + + {/* title */} +

      + {siteConfig('POST_TITLE_ICON') && ( + + )} + {post?.title} +

      + +
      {post?.summary}
      +
      + + {post?.type && !post?.type !== 'Page' && post?.pageCover && ( +
      + +
      + )} {/* meta */}
      diff --git a/themes/magzine/components/Footer.js b/themes/magzine/components/Footer.js index aaf801f869f..b3672dda7f0 100644 --- a/themes/magzine/components/Footer.js +++ b/themes/magzine/components/Footer.js @@ -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 ( -
      - - {`${copyrightDate}`}{' '} - - {' '} - - {siteConfig('AUTHOR')} - - .
      - {siteConfig('BEI_AN') && ( - <> - {' '} - - {siteConfig('BEI_AN')} + ) } diff --git a/themes/magzine/components/Header.js b/themes/magzine/components/Header.js index 23985074402..1b44f9ccd9a 100644 --- a/themes/magzine/components/Header.js +++ b/themes/magzine/components/Header.js @@ -118,7 +118,7 @@ export default function Header(props) { {/* 导航栏菜单内容 */}
      + className='flex w-full mx-auto max-w-screen-2xl h-20 transition-all duration-200 items-center justify-between'> {/* 搜索栏 */} {showSearchInput && ( { return ( <> -
      +
      {/* 左侧一篇主要置顶文章 */}
      diff --git a/themes/magzine/components/JumpToTopButton.js b/themes/magzine/components/JumpToTopButton.js index 1c30373b336..5e8a5418d2a 100644 --- a/themes/magzine/components/JumpToTopButton.js +++ b/themes/magzine/components/JumpToTopButton.js @@ -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 ( diff --git a/themes/magzine/components/LoadingCover.js b/themes/magzine/components/LoadingCover.js deleted file mode 100644 index 4d8fa828c39..00000000000 --- a/themes/magzine/components/LoadingCover.js +++ /dev/null @@ -1,7 +0,0 @@ -export default function LoadingCover() { - return
      -
      - -
      -
      -} diff --git a/themes/magzine/components/MenuBarMobile.js b/themes/magzine/components/MenuBarMobile.js index 1322190b052..9e32e9f53b1 100644 --- a/themes/magzine/components/MenuBarMobile.js +++ b/themes/magzine/components/MenuBarMobile.js @@ -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) { diff --git a/themes/magzine/components/PostBannerGroupByCategory.js b/themes/magzine/components/PostBannerGroupByCategory.js new file mode 100644 index 00000000000..ee16008c435 --- /dev/null +++ b/themes/magzine/components/PostBannerGroupByCategory.js @@ -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 ( + + ) + })} + + ) +} + +// 按照分类将文章分组成文件夹 +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 diff --git a/themes/magzine/components/PostItemCard.js b/themes/magzine/components/PostItemCard.js index 228db9a6708..bac91ab0788 100644 --- a/themes/magzine/components/PostItemCard.js +++ b/themes/magzine/components/PostItemCard.js @@ -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 ( -
      -
      +
      +
      + {siteConfig('MAGZINE_POST_LIST_COVER') && ( + +
      + +
      + + )} + {siteConfig('MAGZINE_POST_LIST_CATEGORY') && ( + + )} +

      - {siteConfig('MAGZINE_POST_LIST_COVER', null, CONFIG) && ( -
      - -
      - )} {siteConfig('POST_TITLE_ICON') && ( )} @@ -45,46 +49,8 @@ const PostItemCard = ({ post, showSummary }) => {

      -
      -
      {post.date?.start_date}
      - {siteConfig('MAGZINE_POST_LIST_CATEGORY', null, CONFIG) && ( - - )} - {siteConfig('MAGZINE_POST_LIST_TAG', null, CONFIG) && - post?.tagItems?.map(tag => ( - - ))} - -
      - -
      - - {(!showPreview || showSummary) && ( -
      - {post.summary} -
      - )} - - {showPreview && ( -
      - -
      -
      - - {locale.COMMON.ARTICLE_DETAIL} - - -
      -
      -
      - )} -
      +
      {post.date?.start_date}
      +
      ) } diff --git a/themes/magzine/components/PostItemCardSimple.js b/themes/magzine/components/PostItemCardSimple.js index 69ef5556c7f..61d69465070 100644 --- a/themes/magzine/components/PostItemCardSimple.js +++ b/themes/magzine/components/PostItemCardSimple.js @@ -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 (
      + className='mb-6 max-w-screen-2xl border-t mr-8 py-2 gap-y-4 flex flex-col dark:border-gray-800 '>
      - {siteConfig('MAGZINE_POST_LIST_CATEGORY', null, CONFIG) && ( + {siteConfig('MAGZINE_POST_LIST_CATEGORY') && ( )}
      diff --git a/themes/magzine/components/PostItemCardTop.js b/themes/magzine/components/PostItemCardTop.js index b9d5756a3bf..24f2a00df2a 100644 --- a/themes/magzine/components/PostItemCardTop.js +++ b/themes/magzine/components/PostItemCardTop.js @@ -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 (
      { 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 '>
      - {siteConfig('MAGZINE_POST_LIST_COVER', null, CONFIG) && ( + {siteConfig('MAGZINE_POST_LIST_COVER') && ( { )}
      - {siteConfig('MAGZINE_POST_LIST_CATEGORY', null, CONFIG) && ( + {siteConfig('MAGZINE_POST_LIST_CATEGORY') && ( )}
      - {siteConfig('MAGZINE_POST_LIST_TAG', null, CONFIG) && + {siteConfig('MAGZINE_POST_LIST_TAG') && post?.tagItems?.map(tag => ( ))} diff --git a/themes/magzine/components/PostItemCardWide.js b/themes/magzine/components/PostItemCardWide.js index 0b250850646..11487e7f9a4 100644 --- a/themes/magzine/components/PostItemCardWide.js +++ b/themes/magzine/components/PostItemCardWide.js @@ -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 (
      @@ -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') && ( )} - {siteConfig('MAGZINE_POST_LIST_TAG', null, CONFIG) && + {siteConfig('MAGZINE_POST_LIST_TAG') && post?.tagItems?.map(tag => ( ))} diff --git a/themes/magzine/components/PostListHorizontal.js b/themes/magzine/components/PostListHorizontal.js index 41ef905d033..0976033b47d 100644 --- a/themes/magzine/components/PostListHorizontal.js +++ b/themes/magzine/components/PostListHorizontal.js @@ -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 } return ( -
      -
      +
      +
      {/* 标题 */}

      {title}

      @@ -25,9 +26,9 @@ const PostListHorizontal = ({ title, href, posts }) => {
      {/* 列表 */} -
        - {posts?.map(p => { - return +
          + {posts?.map((p, index) => { + return })}
      diff --git a/themes/magzine/components/PostListRecommend.js b/themes/magzine/components/PostListRecommend.js new file mode 100644 index 00000000000..4335b579f34 --- /dev/null +++ b/themes/magzine/components/PostListRecommend.js @@ -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 + } + const title = siteConfig('MAGZINE_RECOMMEND_POST_TITLE') + + return ( +
      +
      + {/* 标题 */} +
      +

      {title}

      +
      + {/* 列表 */} +
        + {recommendPosts?.map(p => { + return + })} +
      +
      +
      + ) +} + +/** + * 获取推荐置顶文章 + */ +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 diff --git a/themes/magzine/components/PostListSimpleHorizontal.js b/themes/magzine/components/PostListSimpleHorizontal.js index 5add570c757..62303ec3e81 100644 --- a/themes/magzine/components/PostListSimpleHorizontal.js +++ b/themes/magzine/components/PostListSimpleHorizontal.js @@ -14,7 +14,7 @@ const PostSimpleListHorizontal = ({ title, href, posts }) => { return (
      -
      +
      {/* 标题 */}

      {title}

      diff --git a/themes/magzine/components/SocialButton.js b/themes/magzine/components/SocialButton.js index 97aa6824e5e..5ef31889296 100644 --- a/themes/magzine/components/SocialButton.js +++ b/themes/magzine/components/SocialButton.js @@ -7,14 +7,14 @@ import { siteConfig } from '@/lib/config' */ const SocialButton = () => { return ( -
      +
      {siteConfig('CONTACT_GITHUB') && ( - + )} {siteConfig('CONTACT_TWITTER') && ( @@ -23,7 +23,7 @@ const SocialButton = () => { rel='noreferrer' title={'twitter'} href={siteConfig('CONTACT_TWITTER')}> - + )} {siteConfig('CONTACT_TELEGRAM') && ( @@ -32,7 +32,7 @@ const SocialButton = () => { rel='noreferrer' href={siteConfig('CONTACT_TELEGRAM')} title={'telegram'}> - + )} {siteConfig('CONTACT_LINKEDIN') && ( @@ -50,7 +50,7 @@ const SocialButton = () => { rel='noreferrer' title={'weibo'} href={siteConfig('CONTACT_WEIBO')}> - + )} {siteConfig('CONTACT_INSTAGRAM') && ( @@ -59,7 +59,7 @@ const SocialButton = () => { rel='noreferrer' title={'instagram'} href={siteConfig('CONTACT_INSTAGRAM')}> - + )} {siteConfig('CONTACT_EMAIL') && ( @@ -68,7 +68,7 @@ const SocialButton = () => { rel='noreferrer' title={'email'} href={`mailto:${siteConfig('CONTACT_EMAIL')}`}> - + )} {JSON.parse(siteConfig('ENABLE_RSS')) && ( @@ -77,7 +77,7 @@ const SocialButton = () => { rel='noreferrer' title={'RSS'} href={'/rss/feed.xml'}> - + )} {siteConfig('CONTACT_BILIBILI') && ( @@ -86,7 +86,7 @@ const SocialButton = () => { rel='noreferrer' title={'bilibili'} href={siteConfig('CONTACT_BILIBILI')}> - + )} {siteConfig('CONTACT_YOUTUBE') && ( @@ -95,7 +95,7 @@ const SocialButton = () => { rel='noreferrer' title={'youtube'} href={siteConfig('CONTACT_YOUTUBE')}> - + )}
      diff --git a/themes/magzine/components/TopNavBar.js b/themes/magzine/components/TopNavBar.js index ef22aa2d3d2..370e542abd0 100644 --- a/themes/magzine/components/TopNavBar.js +++ b/themes/magzine/components/TopNavBar.js @@ -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') } ] diff --git a/themes/magzine/config.js b/themes/magzine/config.js index 6ef5e66edff..201d2a18e1f 100644 --- a/themes/magzine/config.js +++ b/themes/magzine/config.js @@ -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 diff --git a/themes/magzine/index.js b/themes/magzine/index.js index 5845e01c8a2..14b737e12f5 100644 --- a/themes/magzine/index.js +++ b/themes/magzine/index.js @@ -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}
      {/* 底部 */} +
      +

      ) @@ -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 ( -
      +
      {/* 首屏宣传区块 */} @@ -99,53 +104,14 @@ const LayoutIndex = props => { posts={newPosts} /> - {/* 不同的分类文章列表 */} - {categoryFolders?.map((categoryGroup, index) => { - if ( - !categoryGroup || - !categoryGroup.items || - categoryGroup.items.length < 1 - ) { - return null - } + {/* 文章分类陈列区 */} + - return ( - - ) - })} + {/* 文章推荐 */} +
      ) } -// 按照分类将文章分组成文件夹 -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 && (
      ) + console.log('post-文章', post) - const router = useRouter() useEffect(() => { // 404 if (!post) { @@ -198,7 +165,7 @@ const LayoutSlug = props => { }, [post]) return ( -
      +
      {/* 文章锁 */} {lock && } @@ -209,7 +176,7 @@ const LayoutSlug = props => { {/* Notion文章主体 */}
      - {post && } +
      {/* 文章底部区域 */} @@ -218,10 +185,11 @@ const LayoutSlug = props => { {/* 文章分类和标签信息 */}
      - {siteConfig('MAGZINE_POST_DETAIL_CATEGORY', null, CONFIG) && - post?.category && } + {siteConfig('MAGZINE_POST_DETAIL_CATEGORY') && post?.category && ( + + )}
      - {siteConfig('MAGZINE_POST_DETAIL_TAG', null, CONFIG) && + {siteConfig('MAGZINE_POST_DETAIL_TAG') && post?.tagItems?.map(tag => ( ))} From d01cffb63bacb3604bc90643c5b0d37ccea33891 Mon Sep 17 00:00:00 2001 From: "tangly1024.com" Date: Fri, 13 Sep 2024 19:05:21 +0800 Subject: [PATCH 6/8] =?UTF-8?q?Magzine=E4=B8=BB=E9=A2=98=E5=9F=BA=E6=9C=AC?= =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/ShareBar.js | 20 +- themes/magzine/components/ArchiveItem.js | 36 ---- themes/magzine/components/ArticleInfo.js | 41 +--- themes/magzine/components/BannerFullWidth.js | 30 +++ themes/magzine/components/BannerItem.js | 35 ++++ themes/magzine/components/Catalog.js | 4 +- themes/magzine/components/CategoryGroup.js | 7 +- themes/magzine/components/CategoryItem.js | 5 +- themes/magzine/components/Footer.js | 11 +- themes/magzine/components/Header.js | 28 +-- themes/magzine/components/Hero.js | 32 +-- themes/magzine/components/InfoCard.js | 3 +- themes/magzine/components/PostGroupArchive.js | 34 ++++ themes/magzine/components/PostGroupLates.js | 66 +++++++ themes/magzine/components/PostItemCard.js | 4 +- .../magzine/components/PostItemCardSimple.js | 2 +- .../magzine/components/PostListHorizontal.js | 4 +- themes/magzine/components/PostListPage.js | 10 +- .../magzine/components/PostListRecommend.js | 4 +- .../components/PostListSimpleHorizontal.js | 4 +- themes/magzine/components/TouchMeCard.js | 39 ++++ themes/magzine/config.js | 7 + themes/magzine/index.js | 185 ++++++++++++------ 23 files changed, 394 insertions(+), 217 deletions(-) delete mode 100644 themes/magzine/components/ArchiveItem.js create mode 100644 themes/magzine/components/BannerFullWidth.js create mode 100644 themes/magzine/components/BannerItem.js create mode 100644 themes/magzine/components/PostGroupArchive.js create mode 100644 themes/magzine/components/PostGroupLates.js create mode 100644 themes/magzine/components/TouchMeCard.js diff --git a/components/ShareBar.js b/components/ShareBar.js index 334a5f128c2..1acbef4e991 100644 --- a/components/ShareBar.js +++ b/components/ShareBar.js @@ -1,7 +1,9 @@ import { siteConfig } from '@/lib/config' import dynamic from 'next/dynamic' -const ShareButtons = dynamic(() => import('@/components/ShareButtons'), { ssr: false }) +const ShareButtons = dynamic(() => import('@/components/ShareButtons'), { + ssr: false +}) /** * 分享栏 @@ -9,14 +11,20 @@ const ShareButtons = dynamic(() => import('@/components/ShareButtons'), { ssr: f * @returns */ const ShareBar = ({ post }) => { - if (!JSON.parse(siteConfig('POST_SHARE_BAR_ENABLE')) || !post || post?.type !== 'Post') { + if ( + !JSON.parse(siteConfig('POST_SHARE_BAR_ENABLE')) || + !post || + post?.type !== 'Post' + ) { return <> } - return
      -
      - -
      + return ( +
      +
      + +
      + ) } export default ShareBar diff --git a/themes/magzine/components/ArchiveItem.js b/themes/magzine/components/ArchiveItem.js deleted file mode 100644 index 2dafd34c675..00000000000 --- a/themes/magzine/components/ArchiveItem.js +++ /dev/null @@ -1,36 +0,0 @@ -import Link from 'next/link' - -/** - * 归档分组 - * @param {*} param0 - * @returns - */ -export default function ArchiveItem({ archiveTitle, archivePosts }) { - return ( -
      -
      - {archiveTitle} -
      -
        - {archivePosts[archiveTitle]?.map(post => { - return ( -
      • -
        - {post.date?.start_date}{' '} -   - - {post.title} - -
        -
      • - ) - })} -
      -
      - ) -} diff --git a/themes/magzine/components/ArticleInfo.js b/themes/magzine/components/ArticleInfo.js index 02461b8d7a6..5bedfbeca8d 100644 --- a/themes/magzine/components/ArticleInfo.js +++ b/themes/magzine/components/ArticleInfo.js @@ -1,7 +1,6 @@ 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' @@ -15,8 +14,8 @@ export default function ArticleInfo(props) { return ( <> -
      -
      +
      +
      {siteConfig('MAGZINE_POST_LIST_CATEGORY') && ( )} @@ -32,7 +31,7 @@ export default function ArticleInfo(props) {
      {/* title */} -

      +

      {siteConfig('POST_TITLE_ICON') && ( )} @@ -51,40 +50,6 @@ export default function ArticleInfo(props) { />

      )} - - {/* meta */} -
      -
      - - {' '} - - {post?.publishDay} - - | - - - {post?.lastEditedDay} - -
      - - -
      -
      - -
      - - -
      - {siteConfig('AUTHOR')} -
      -
      - -
      ) } diff --git a/themes/magzine/components/BannerFullWidth.js b/themes/magzine/components/BannerFullWidth.js new file mode 100644 index 00000000000..fadebaa6008 --- /dev/null +++ b/themes/magzine/components/BannerFullWidth.js @@ -0,0 +1,30 @@ +import LazyImage from '@/components/LazyImage' +import { siteConfig } from '@/lib/config' +import { useGlobal } from '@/lib/global' +import BannerItem from './BannerItem' + +/** + * 全宽 + * @param {*} props + * @returns + */ +export default function BannerFullWidth() { + const { siteInfo } = useGlobal() + const banner = siteConfig('MAGZINE_HOME_BANNER_ENABLE') + if (!banner) { + return null + } + return ( +
      + + +
      + +
      +
      + ) +} diff --git a/themes/magzine/components/BannerItem.js b/themes/magzine/components/BannerItem.js new file mode 100644 index 00000000000..3e77271a010 --- /dev/null +++ b/themes/magzine/components/BannerItem.js @@ -0,0 +1,35 @@ +import { siteConfig } from '@/lib/config' +import Link from 'next/link' + +/** + * 文字广告Banner + * @param {*} props + * @returns + */ +export default function BannerItem() { + // 首屏信息栏按钮文字 + const banner = siteConfig('MAGZINE_HOME_BANNER_ENABLE') + const button = siteConfig('MAGZINE_HOME_BUTTON') + const text = siteConfig('MAGZINE_HOME_BUTTON_TEXT') + const url = siteConfig('MAGZINE_HOME_BUTTON_URL') + const title = siteConfig('MAGZINE_HOME_TITLE') + const description = siteConfig('MAGZINE_HOME_DESCRIPTION') + const tips = siteConfig('MAGZINE_HOME_TIPS') + if (!banner) { + return null + } + + return ( +
      + {/* 首屏导航按钮 */} +

      {title}

      +

      {description}

      + {button && ( +
      + {text} +
      + )} + {tips} +
      + ) +} diff --git a/themes/magzine/components/Catalog.js b/themes/magzine/components/Catalog.js index 4ee2c2822ef..b127d24aad2 100644 --- a/themes/magzine/components/Catalog.js +++ b/themes/magzine/components/Catalog.js @@ -9,7 +9,7 @@ import Progress from './Progress' * @returns {JSX.Element} * @constructor */ -const Catalog = ({ toc }) => { +const Catalog = ({ toc, className }) => { const tocIds = [] // 目录自动滚动 @@ -62,7 +62,7 @@ const Catalog = ({ toc }) => { } return ( -
      +
      diff --git a/themes/magzine/components/CategoryGroup.js b/themes/magzine/components/CategoryGroup.js index 3fd6b67d716..063eb58cbb9 100644 --- a/themes/magzine/components/CategoryGroup.js +++ b/themes/magzine/components/CategoryGroup.js @@ -13,11 +13,8 @@ const CategoryGroup = ({ currentCategory, categoryOptions }) => { } return (
      -
      - - {locale.COMMON.CATEGORY} -
      -
      +
      {locale.COMMON.CATEGORY}
      +
      {categoryOptions?.map(category => { const selected = currentCategory === category.name return ( diff --git a/themes/magzine/components/CategoryItem.js b/themes/magzine/components/CategoryItem.js index 1286d35ed74..44fd3845f82 100644 --- a/themes/magzine/components/CategoryItem.js +++ b/themes/magzine/components/CategoryItem.js @@ -9,12 +9,9 @@ export default function CategoryItem({ selected, category, categoryCount }) { (selected ? ' bg-gray-600 text-white ' : 'dark:text-gray-400 text-gray-900 ') + - ' hover:underline flex text-sm items-center duration-300 cursor-pointer py-1 whitespace-nowrap' + 'text-sm hover:underline flex text-md items-center duration-300 cursor-pointer py-1 whitespace-nowrap' }>
      - {/* */} {category} {categoryCount && `(${categoryCount})`}
      diff --git a/themes/magzine/components/Footer.js b/themes/magzine/components/Footer.js index b3672dda7f0..4d20657d668 100644 --- a/themes/magzine/components/Footer.js +++ b/themes/magzine/components/Footer.js @@ -16,14 +16,13 @@ const Footer = ({ title }) => { parseInt(since) < currentYear ? since + '-' + currentYear : currentYear const { siteInfo } = useGlobal() const MAGZINE_FOOTER_LINKS = siteConfig('MAGZINE_FOOTER_LINKS', []) - console.log('菜单', MAGZINE_FOOTER_LINKS) return (
      -
      +
      {/* 信息与链接区块 */} -
      -
      +
      +
      {/* 站长信息 */} {
      {/* 右侧链接区块 */} -
      +
      {MAGZINE_FOOTER_LINKS?.map((group, index) => { return (
      -
      +
      {group.name}
      diff --git a/themes/magzine/components/Header.js b/themes/magzine/components/Header.js index 1b44f9ccd9a..73a3627bb35 100644 --- a/themes/magzine/components/Header.js +++ b/themes/magzine/components/Header.js @@ -2,6 +2,7 @@ import Collapse from '@/components/Collapse' import { siteConfig } from '@/lib/config' import { useGlobal } from '@/lib/global' import throttle from 'lodash.throttle' +import { useRouter } from 'next/router' import { useEffect, useRef, useState } from 'react' import CONFIG from '../config' import LogoBar from './LogoBar' @@ -18,8 +19,8 @@ export default function Header(props) { const [isOpen, changeShow] = useState(false) const collapseRef = useRef(null) const lastScrollY = useRef(0) // 用于存储上一次的滚动位置 - const { locale } = useGlobal() + const router = useRouter() const defaultLinks = [ { @@ -118,7 +119,7 @@ export default function Header(props) { {/* 导航栏菜单内容 */}
      + className='px-2 lg:px-0 flex w-full mx-auto max-w-screen-2xl h-20 transition-all duration-200 items-center justify-between'> {/* 搜索栏 */} {showSearchInput && ( {/* 桌面端顶部菜单 */} -
      +
      {links && links?.map(link => ( @@ -153,18 +154,8 @@ export default function Header(props) { {/* 右侧移动端折叠按钮 */}
      -
      -
      - {isOpen ? ( - - ) : ( - - )} -
      -
      - {/* 搜索按钮 */} -
      +
      +
      +
      + {isOpen ? ( + + ) : ( + + )} +
      +
      diff --git a/themes/magzine/components/Hero.js b/themes/magzine/components/Hero.js index 18e8ff3d258..2e463a61f96 100644 --- a/themes/magzine/components/Hero.js +++ b/themes/magzine/components/Hero.js @@ -1,6 +1,5 @@ // import { useGlobal } from '@/lib/global' -import { siteConfig } from '@/lib/config' -import Link from 'next/link' +import BannerItem from './BannerItem' import PostItemCardTop from './PostItemCardTop' import PostItemCardWide from './PostItemCardWide' @@ -14,41 +13,20 @@ const Hero = ({ posts }) => { const postTop = posts[0] const post1 = posts[1] const post2 = posts[2] - // 首屏信息栏按钮文字 - const banner = siteConfig('MAGZINE_HOME_BANNER_ENABLE') - const button = siteConfig('MAGZINE_HOME_BUTTON') - const text = siteConfig('MAGZINE_HOME_BUTTON_TEXT') - const url = siteConfig('MAGZINE_HOME_BUTTON_URL') - const title = siteConfig('MAGZINE_HOME_TITLE') - const description = siteConfig('MAGZINE_HOME_DESCRIPTION') - const tips = siteConfig('MAGZINE_HOME_TIPS') - return ( <> -
      +
      {/* 左侧一篇主要置顶文章 */} -
      +
      {/* 右侧 */}
      {/* 首屏介绍 */} - {banner && ( -
      - {/* 首屏导航按钮 */} -

      {title}

      -

      {description}

      - {button && ( -
      - {text} -
      - )} - {tips} -
      - )} + {/* 两篇次要文章 */} -
      +


      diff --git a/themes/magzine/components/InfoCard.js b/themes/magzine/components/InfoCard.js index 507296646d5..e6009de1e79 100644 --- a/themes/magzine/components/InfoCard.js +++ b/themes/magzine/components/InfoCard.js @@ -1,5 +1,6 @@ import LazyImage from '@/components/LazyImage' import { siteConfig } from '@/lib/config' +import { useGlobal } from '@/lib/global' /** * 用户信息卡 @@ -7,7 +8,7 @@ import { siteConfig } from '@/lib/config' * @returns */ const InfoCard = props => { - const { siteInfo } = props + const { siteInfo } = useGlobal() return (
      diff --git a/themes/magzine/components/PostGroupArchive.js b/themes/magzine/components/PostGroupArchive.js new file mode 100644 index 00000000000..c4369e9a2c1 --- /dev/null +++ b/themes/magzine/components/PostGroupArchive.js @@ -0,0 +1,34 @@ +import PostItemCard from './PostItemCard' + +/** + * 博客归档列表 + * @param posts 所有文章 + * @param archiveTitle 归档标题 + * @returns {JSX.Element} + * @constructor + */ +const PostGroupArchive = ({ posts = [], archiveTitle }) => { + if (!posts || posts.length === 0) { + return <> + } + + return ( +
      + {/* 分组标题 */} +
      + {archiveTitle} +
      + + {/* 列表 */} +
        + {posts?.map((p, index) => { + return + })} +
      +
      + ) +} + +export default PostGroupArchive diff --git a/themes/magzine/components/PostGroupLates.js b/themes/magzine/components/PostGroupLates.js new file mode 100644 index 00000000000..397de795845 --- /dev/null +++ b/themes/magzine/components/PostGroupLates.js @@ -0,0 +1,66 @@ +import LazyImage from '@/components/LazyImage' +import { siteConfig } from '@/lib/config' +import { useGlobal } from '@/lib/global' +// import Image from 'next/image' +import Link from 'next/link' +import { useRouter } from 'next/router' + +/** + * 最新文章列表 + * @param posts 所有文章数据 + * @param sliceCount 截取展示的数量 默认6 + * @constructor + */ +const PostGroupLatest = props => { + const { latestPosts } = props + // 获取当前路径 + const currentPath = useRouter().asPath + const { locale, siteInfo } = useGlobal() + if (!latestPosts) { + return <> + } + + return ( + <> +
      +
      {locale.COMMON.LATEST_POSTS}
      +
      + {latestPosts.map(post => { + const selected = + currentPath === `${siteConfig('SUB_PATH', '')}/${post.slug}` + + const headerImage = post?.pageCoverThumbnail + ? post.pageCoverThumbnail + : siteInfo?.pageCover + + return ( + +
      + +
      +
      +
      +
      {post.title}
      +
      {post.lastEditedDay}
      +
      +
      + + ) + })} + + ) +} +export default PostGroupLatest diff --git a/themes/magzine/components/PostItemCard.js b/themes/magzine/components/PostItemCard.js index bac91ab0788..6b4f811ad53 100644 --- a/themes/magzine/components/PostItemCard.js +++ b/themes/magzine/components/PostItemCard.js @@ -9,12 +9,12 @@ import CategoryItem from './CategoryItem' * 普通的博客卡牌 * 带封面图 */ -const PostItemCard = ({ post, showSummary }) => { +const PostItemCard = ({ post }) => { const { siteInfo } = useGlobal() const cover = post?.pageCoverThumbnail || siteInfo?.pageCover return (
      -
      +
      {siteConfig('MAGZINE_POST_LIST_COVER') && ( { return (
      + className='lg:mb-6 max-w-screen-2xl border-t mr-8 py-2 gap-y-4 flex flex-col dark:border-gray-800 '>
      {siteConfig('MAGZINE_POST_LIST_CATEGORY') && ( diff --git a/themes/magzine/components/PostListHorizontal.js b/themes/magzine/components/PostListHorizontal.js index 0976033b47d..a857af617b9 100644 --- a/themes/magzine/components/PostListHorizontal.js +++ b/themes/magzine/components/PostListHorizontal.js @@ -15,7 +15,7 @@ const PostListHorizontal = ({ title, href, posts, hasBg }) => { } return ( -
      +
      {/* 标题 */}
      @@ -26,7 +26,7 @@ const PostListHorizontal = ({ title, href, posts, hasBg }) => {
      {/* 列表 */} -
        +
          {posts?.map((p, index) => { return })} diff --git a/themes/magzine/components/PostListPage.js b/themes/magzine/components/PostListPage.js index 9486f6ec965..ba35d0d50ab 100644 --- a/themes/magzine/components/PostListPage.js +++ b/themes/magzine/components/PostListPage.js @@ -24,10 +24,12 @@ const PostListPage = ({ page = 1, posts = [], postCount }) => { return (
          - {/* 文章列表 */} - {posts?.map(post => ( - - ))} + {/* 列表 */} +
            + {posts?.map((p, index) => { + return + })} +
          diff --git a/themes/magzine/components/PostListRecommend.js b/themes/magzine/components/PostListRecommend.js index 4335b579f34..84025732432 100644 --- a/themes/magzine/components/PostListRecommend.js +++ b/themes/magzine/components/PostListRecommend.js @@ -18,14 +18,14 @@ const PostListRecommend = ({ latestPosts, allNavPages }) => { const title = siteConfig('MAGZINE_RECOMMEND_POST_TITLE') return ( -
          +
          {/* 标题 */}

          {title}

          {/* 列表 */} -
            +
              {recommendPosts?.map(p => { return })} diff --git a/themes/magzine/components/PostListSimpleHorizontal.js b/themes/magzine/components/PostListSimpleHorizontal.js index 62303ec3e81..e611f4b7a41 100644 --- a/themes/magzine/components/PostListSimpleHorizontal.js +++ b/themes/magzine/components/PostListSimpleHorizontal.js @@ -14,7 +14,7 @@ const PostSimpleListHorizontal = ({ title, href, posts }) => { return (
              -
              +
              {/* 标题 */}

              {title}

              @@ -24,7 +24,7 @@ const PostSimpleListHorizontal = ({ title, href, posts }) => {
              {/* 列表 */} -
                +
                  {posts?.map(p => { return })} diff --git a/themes/magzine/components/TouchMeCard.js b/themes/magzine/components/TouchMeCard.js new file mode 100644 index 00000000000..767ccf4ee97 --- /dev/null +++ b/themes/magzine/components/TouchMeCard.js @@ -0,0 +1,39 @@ +import FlipCard from '@/components/FlipCard' +import { siteConfig } from '@/lib/config' +import Link from 'next/link' + +/** + * 交流频道 + * @returns + */ +export default function TouchMeCard() { + // 开关 + if (!siteConfig('MAGZINE_SOCIAL_CARD', null)) { + return <> + } + + return ( +
                  + +

                  + {siteConfig('MAGZINE_SOCIAL_CARD_TITLE_1')} +

                  +

                  + {siteConfig('MAGZINE_SOCIAL_CARD_TITLE_2')} +

                  +
                  + } + backContent={ + +
                  + {siteConfig('MAGZINE_SOCIAL_CARD_TITLE_3')} +
                  + + } + /> +
              + ) +} diff --git a/themes/magzine/config.js b/themes/magzine/config.js index 201d2a18e1f..f49dc000dfb 100644 --- a/themes/magzine/config.js +++ b/themes/magzine/config.js @@ -29,6 +29,13 @@ const CONFIG = { MAGZINE_POST_DETAIL_CATEGORY: true, // 文章显示分类 MAGZINE_POST_DETAIL_TAG: true, // 文章显示标签 + // 文章页面联系卡 + MAGZINE_SOCIAL_CARD: true, // 是否显示右侧,点击加入社群按钮 + MAGZINE_SOCIAL_CARD_TITLE_1: '交流频道', + MAGZINE_SOCIAL_CARD_TITLE_2: '加入社群讨论分享', + MAGZINE_SOCIAL_CARD_TITLE_3: '点击加入社群', + MAGZINE_SOCIAL_CARD_URL: 'https://docs.tangly1024.com/article/chat-community', + // 页脚菜单 MAGZINE_FOOTER_LINKS: [ { diff --git a/themes/magzine/index.js b/themes/magzine/index.js index 14b737e12f5..65ec10cdf2e 100644 --- a/themes/magzine/index.js +++ b/themes/magzine/index.js @@ -10,10 +10,9 @@ 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' import { ArticleLock } from './components/ArticleLock' +import BannerFullWidth from './components/BannerFullWidth' import Catalog from './components/Catalog' import CategoryGroup from './components/CategoryGroup' import CategoryItem from './components/CategoryItem' @@ -21,14 +20,16 @@ import Footer from './components/Footer' import Header from './components/Header' import Hero from './components/Hero' import PostBannerGroupByCategory from './components/PostBannerGroupByCategory' +import PostGroupArchive from './components/PostGroupArchive' +import PostGroupLatest from './components/PostGroupLates' 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' import TagGroups from './components/TagGroups' import TagItemMini from './components/TagItemMini' import TocDrawer from './components/TocDrawer' +import TouchMeCard from './components/TouchMeCard' import CONFIG from './config' import { Style } from './style' @@ -118,14 +119,20 @@ const LayoutIndex = props => { * @returns */ const LayoutPostList = props => { + // 当前筛选的分类或标签 + const { category, tag } = props + return ( - <> +
              + {/* 一个顶部条 */} +

              {category || tag}

              + {siteConfig('POST_LIST_STYLE') === 'page' ? ( ) : ( )} - +
              ) } @@ -135,15 +142,9 @@ const LayoutPostList = props => { * @returns */ const LayoutSlug = props => { - const { post, prev, next, lock, validPassword } = props + const { post, recommendPosts, prev, next, lock, validPassword } = props const { locale } = useGlobal() const router = useRouter() - const slotRight = post?.toc && post?.toc?.length >= 3 && ( -
              - -
              - ) - console.log('post-文章', post) useEffect(() => { // 404 @@ -165,47 +166,102 @@ const LayoutSlug = props => { }, [post]) return ( -
              - {/* 文章锁 */} - {lock && } + <> +
              + {/* 文章锁 */} + {lock && } - {!lock && ( -
              - {/* 文章信息 */} - - - {/* Notion文章主体 */} -
              - -
              - - {/* 文章底部区域 */} -
              - {/* 分享 */} - - {/* 文章分类和标签信息 */} -
              - {siteConfig('MAGZINE_POST_DETAIL_CATEGORY') && post?.category && ( - - )} -
              - {siteConfig('MAGZINE_POST_DETAIL_TAG') && - post?.tagItems?.map(tag => ( - - ))} + {!lock && ( +
              + {/* 文章信息 */} + + + {/* 文章区块分为三列 */} +
              +
              + +
              + + {/* Notion文章主体 */} +
              + + + {/* 文章底部区域 */} +
              + {/* 分享 */} + + {/* 文章分类和标签信息 */} +
              + {siteConfig('MAGZINE_POST_DETAIL_CATEGORY') && + post?.category && ( + + )} +
              + {siteConfig('MAGZINE_POST_DETAIL_TAG') && + post?.tagItems?.map(tag => ( + + ))} +
              +
              + {/* 评论区 */} + +
              +
              + +
              + {/* meta信息 */} +
              +
              + {/*
              + + {post?.publishDay} +
              */} +
              + + {post?.lastEditedDay} +
              +
              + + +
              +
              +
              + + {/* 最新文章区块 */} +
              + +
              + + {/* 文章分类区块 */} +
              + +
              + +
              + +
              + + {/* 底部留白 */} +
              - {/* 上一篇下一篇文章 */} - {post?.type === 'Post' && } - {/* 评论区 */} - -
              - - {/* 移动端目录 */} - -
              - )} -
              + + {/* 移动端目录 */} + +
              + )} +
              + {/* 广告醒图 */} + + {/* 最新文章区块 */} + + ) } @@ -234,11 +290,10 @@ const LayoutSearch = props => { }, []) return ( - <> +
              {/* 搜索导航栏 */}
              {locale.NAV.SEARCH}
              - {!currentSearch && ( <> @@ -257,7 +312,7 @@ const LayoutSearch = props => { )}
              )} - +
              ) } @@ -270,12 +325,12 @@ const LayoutArchive = props => { const { archivePosts } = props return ( <> -
              +
              {Object.keys(archivePosts)?.map(archiveTitle => ( - ))}
              @@ -307,10 +362,10 @@ const LayoutCategoryIndex = props => { const { categoryOptions } = props const { locale } = useGlobal() return ( - <> +
              -
              - +
              + {/* */} {locale.COMMON.CATEGORY}:
              @@ -325,7 +380,7 @@ const LayoutCategoryIndex = props => { 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' }> - + {/* */} {category.name}({category.count})
              @@ -333,7 +388,7 @@ const LayoutCategoryIndex = props => { })}
              - +
              ) } @@ -346,10 +401,10 @@ const LayoutTagIndex = props => { const { tagOptions } = props const { locale } = useGlobal() return ( - <> +
              -
              - +
              + {/* */} {locale.COMMON.TAGS}:
              @@ -362,7 +417,7 @@ const LayoutTagIndex = props => { })}
              - +
              ) } From c24d38eaef17affe0a0ae761d9364e56fe236346 Mon Sep 17 00:00:00 2001 From: "tangly1024.com" Date: Fri, 13 Sep 2024 19:05:28 +0800 Subject: [PATCH 7/8] 4.7.1 --- .env.local | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.local b/.env.local index 4d4824d5bb6..63ecde97f4c 100644 --- a/.env.local +++ b/.env.local @@ -1,5 +1,5 @@ # 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables -NEXT_PUBLIC_VERSION=4.7.0 +NEXT_PUBLIC_VERSION=4.7.1 # 可在此添加环境变量,去掉最左边的(# )注释即可 diff --git a/package.json b/package.json index 2e523fbcd40..cb5c337f52f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "notion-next", - "version": "4.7.0", + "version": "4.7.1", "homepage": "https://github.com/tangly1024/NotionNext.git", "license": "MIT", "repository": { From e32ca96bdbd3fe4d321fd2aa6989bf9632ed607e Mon Sep 17 00:00:00 2001 From: "tangly1024.com" Date: Fri, 13 Sep 2024 19:17:22 +0800 Subject: [PATCH 8/8] =?UTF-8?q?Magzine=20=E6=A0=B7=E5=BC=8F=E5=BE=AE?= =?UTF-8?q?=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- themes/magzine/components/ArticleInfo.js | 2 +- themes/magzine/components/Header.js | 4 +- themes/magzine/components/PostGroupLates.js | 66 ----------------- themes/magzine/components/PostGroupLatest.js | 71 +++++++++++++++++++ .../components/PostListSimpleHorizontal.js | 2 +- themes/magzine/index.js | 8 +-- 6 files changed, 79 insertions(+), 74 deletions(-) delete mode 100644 themes/magzine/components/PostGroupLates.js create mode 100644 themes/magzine/components/PostGroupLatest.js diff --git a/themes/magzine/components/ArticleInfo.js b/themes/magzine/components/ArticleInfo.js index 5bedfbeca8d..f41654b0a3a 100644 --- a/themes/magzine/components/ArticleInfo.js +++ b/themes/magzine/components/ArticleInfo.js @@ -14,7 +14,7 @@ export default function ArticleInfo(props) { return ( <> -
              +
              {siteConfig('MAGZINE_POST_LIST_CATEGORY') && ( diff --git a/themes/magzine/components/Header.js b/themes/magzine/components/Header.js index 73a3627bb35..a7c4afdebd0 100644 --- a/themes/magzine/components/Header.js +++ b/themes/magzine/components/Header.js @@ -144,8 +144,8 @@ export default function Header(props) { {/* 桌面端顶部菜单 */}
              {links && - links?.map(link => ( - + links?.map((link, index) => ( + ))}
              diff --git a/themes/magzine/components/PostGroupLates.js b/themes/magzine/components/PostGroupLates.js deleted file mode 100644 index 397de795845..00000000000 --- a/themes/magzine/components/PostGroupLates.js +++ /dev/null @@ -1,66 +0,0 @@ -import LazyImage from '@/components/LazyImage' -import { siteConfig } from '@/lib/config' -import { useGlobal } from '@/lib/global' -// import Image from 'next/image' -import Link from 'next/link' -import { useRouter } from 'next/router' - -/** - * 最新文章列表 - * @param posts 所有文章数据 - * @param sliceCount 截取展示的数量 默认6 - * @constructor - */ -const PostGroupLatest = props => { - const { latestPosts } = props - // 获取当前路径 - const currentPath = useRouter().asPath - const { locale, siteInfo } = useGlobal() - if (!latestPosts) { - return <> - } - - return ( - <> -
              -
              {locale.COMMON.LATEST_POSTS}
              -
              - {latestPosts.map(post => { - const selected = - currentPath === `${siteConfig('SUB_PATH', '')}/${post.slug}` - - const headerImage = post?.pageCoverThumbnail - ? post.pageCoverThumbnail - : siteInfo?.pageCover - - return ( - -
              - -
              -
              -
              -
              {post.title}
              -
              {post.lastEditedDay}
              -
              -
              - - ) - })} - - ) -} -export default PostGroupLatest diff --git a/themes/magzine/components/PostGroupLatest.js b/themes/magzine/components/PostGroupLatest.js new file mode 100644 index 00000000000..8731e7d6317 --- /dev/null +++ b/themes/magzine/components/PostGroupLatest.js @@ -0,0 +1,71 @@ +import LazyImage from '@/components/LazyImage' +import { siteConfig } from '@/lib/config' +import { useGlobal } from '@/lib/global' +// import Image from 'next/image' +import Link from 'next/link' +import { useRouter } from 'next/router' + +/** + * 最新文章列表 + * @param posts 所有文章数据 + * @param sliceCount 截取展示的数量 默认6 + * @constructor + */ +const PostGroupLatest = props => { + const { latestPosts } = props + // 获取当前路径 + const currentPath = useRouter().asPath + const { locale, siteInfo } = useGlobal() + if (!latestPosts) { + return <> + } + + return ( + <> + {/* 标题 */} +
              +
              {locale.COMMON.LATEST_POSTS}
              +
              + + {/* 文章列表 */} +
              + {latestPosts.map(post => { + const selected = + currentPath === `${siteConfig('SUB_PATH', '')}/${post.slug}` + + const headerImage = post?.pageCoverThumbnail + ? post.pageCoverThumbnail + : siteInfo?.pageCover + + return ( + +
              + +
              +
              +
              +
              {post.title}
              +
              {post.lastEditedDay}
              +
              +
              + + ) + })} +
              + + ) +} +export default PostGroupLatest diff --git a/themes/magzine/components/PostListSimpleHorizontal.js b/themes/magzine/components/PostListSimpleHorizontal.js index e611f4b7a41..af1ece3a17c 100644 --- a/themes/magzine/components/PostListSimpleHorizontal.js +++ b/themes/magzine/components/PostListSimpleHorizontal.js @@ -24,7 +24,7 @@ const PostSimpleListHorizontal = ({ title, href, posts }) => {
              {/* 列表 */} -
                +
                  {posts?.map(p => { return })} diff --git a/themes/magzine/index.js b/themes/magzine/index.js index 65ec10cdf2e..431f8ca8268 100644 --- a/themes/magzine/index.js +++ b/themes/magzine/index.js @@ -21,7 +21,7 @@ import Header from './components/Header' import Hero from './components/Hero' import PostBannerGroupByCategory from './components/PostBannerGroupByCategory' import PostGroupArchive from './components/PostGroupArchive' -import PostGroupLatest from './components/PostGroupLates' +import PostGroupLatest from './components/PostGroupLatest' import PostListPage from './components/PostListPage' import PostListRecommend from './components/PostListRecommend' import PostListScroll from './components/PostListScroll' @@ -178,14 +178,14 @@ const LayoutSlug = props => { {/* 文章区块分为三列 */}
                  -
                  +
                  {/* Notion文章主体 */}
                  + className='max-w-3xl lg:col-span-3 w-full mx-auto px-2 lg:px-0'> {/* 文章底部区域 */} @@ -210,7 +210,7 @@ const LayoutSlug = props => {

  • -
    +
    {/* meta信息 */}