diff --git a/lib/lang.js b/lib/lang.js index ff2201b8365..a6ef7b57a57 100644 --- a/lib/lang.js +++ b/lib/lang.js @@ -69,13 +69,22 @@ export function generateLocaleDict(langString) { */ export function initLocale(lang, locale, changeLang, changeLocale) { if (isBrowser) { - // 用户请求的预研 - const queryLang = + // 用户请求的语言 + let queryLang = getQueryVariable('locale') || getQueryVariable('lang') || loadLangFromLocalStorage() + + if (queryLang) { + // 用正则表达式匹配有效的语言标识符例如zh-CN(可选的 -CN 部分) + queryLang = queryLang.match(/[a-zA-Z]{2}(?:-[a-zA-Z]{2})?/) + if (queryLang) { + queryLang = queryLang[0] + } + } + let currentLang = lang - if (queryLang && queryLang !== 'undefined' && queryLang !== lang) { + if (queryLang && queryLang !== lang) { currentLang = queryLang } diff --git a/lib/notion/mapImage.js b/lib/notion/mapImage.js index 1df9f9115e1..491632bc1b9 100644 --- a/lib/notion/mapImage.js +++ b/lib/notion/mapImage.js @@ -24,13 +24,15 @@ const mapImgUrl = (img, block, type = 'block', needCompress = true) => { } // Notion 图床转换为永久地址 - const hasConverted = ret.indexOf('https://www.notion.so/image') === 0 + const hasConverted = + ret.indexOf('https://www.notion.so/image') === 0 || + ret.includes('notion.site/images/page-cover/') // 需要转化的URL ; 识别aws图床地址,或者bookmark类型的外链图片 const needConvert = !hasConverted && - (ret.indexOf('secure.notion-static.com') > 0 || - ret.indexOf('prod-files-secure') > 0 || - block.type === 'bookmark') + (block.type === 'bookmark' || + ret.includes('secure.notion-static.com') || + ret.includes('prod-files-secure')) // 使用Notion图传 if (needConvert) { diff --git a/pages/[prefix]/[slug]/index.js b/pages/[prefix]/[slug]/index.js index 4d889d647b5..072a932c71b 100644 --- a/pages/[prefix]/[slug]/index.js +++ b/pages/[prefix]/[slug]/index.js @@ -26,6 +26,7 @@ export async function getStaticPaths() { const from = 'slug-paths' const { allPages } = await getGlobalData({ from }) + // 根据slug中的 / 分割成prefix和slug两个字段 ; 例如 article/test const paths = allPages ?.filter(row => checkSlug(row)) .map(row => ({ diff --git a/themes/commerce/index.js b/themes/commerce/index.js index 0500b63c6ca..4e8c76c04dc 100644 --- a/themes/commerce/index.js +++ b/themes/commerce/index.js @@ -1,32 +1,32 @@ import CONFIG from './config' -import { useEffect, useRef } from 'react' -import Footer from './components/Footer' +import LazyImage from '@/components/LazyImage' +import replaceSearchResult from '@/components/Mark' +import NotionPage from '@/components/NotionPage' +import { siteConfig } from '@/lib/config' import { useGlobal } from '@/lib/global' import { isBrowser, scanAndConvertToLinks } from '@/lib/utils' +import { Transition } from '@headlessui/react' +import Link from 'next/link' +import { useRouter } from 'next/router' +import { useEffect, useRef } from 'react' +import { ArticleLock } from './components/ArticleLock' +import BlogPostArchive from './components/BlogPostArchive' import BlogPostListPage from './components/BlogPostListPage' import BlogPostListScroll from './components/BlogPostListScroll' -import Hero from './components/Hero' -import { useRouter } from 'next/router' import Card from './components/Card' +import Footer from './components/Footer' +import Header from './components/Header' +import Hero from './components/Hero' +import PostHeader from './components/PostHeader' +import ProductCategories from './components/ProductCategories' +import ProductCenter from './components/ProductCenter' import RightFloatArea from './components/RightFloatArea' import SearchNav from './components/SearchNav' -import BlogPostArchive from './components/BlogPostArchive' -import { ArticleLock } from './components/ArticleLock' -import PostHeader from './components/PostHeader' -import TocDrawer from './components/TocDrawer' -import NotionPage from '@/components/NotionPage' -import TagItemMini from './components/TagItemMini' -import Link from 'next/link' import SlotBar from './components/SlotBar' -import { Transition } from '@headlessui/react' +import TagItemMini from './components/TagItemMini' +import TocDrawer from './components/TocDrawer' import { Style } from './style' -import replaceSearchResult from '@/components/Mark' -import { siteConfig } from '@/lib/config' -import Header from './components/Header' -import ProductCenter from './components/ProductCenter' -import LazyImage from '@/components/LazyImage' -import ProductCategories from './components/ProductCategories' /** * 基础布局 采用左右两侧布局,移动端使用顶部导航栏 @@ -35,17 +35,19 @@ import ProductCategories from './components/ProductCategories' * @constructor */ const LayoutBase = props => { - const { children, post, floatSlot, slotTop, slotRight, meta, className } = - props + const { children, post, floatSlot, slotTop, className } = props const { onLoading } = useGlobal() - + const router = useRouter() // 查找页面上的 链接,并便成为可点击 useEffect(() => { scanAndConvertToLinks(document.getElementById('theme-commerce')) - }) + }, [router]) + + const slotRight = router.route !== '/' && !post && ( + + ) let headerSlot = null - const router = useRouter() if (router.route === '/' && !post) { headerSlot = JSON.parse(siteConfig('COMMERCE_HOME_BANNER_ENABLE', true)) ? ( @@ -146,18 +148,15 @@ const LayoutIndex = props => { * @returns */ const LayoutPostList = props => { - const slotRight = return ( - -
- - {siteConfig('POST_LIST_STYLE') === 'page' ? ( - - ) : ( - - )} -
-
+
+ + {siteConfig('POST_LIST_STYLE') === 'page' ? ( + + ) : ( + + )} +
) } @@ -241,7 +240,6 @@ const LayoutSlug = props => { const headerImage = post?.pageCover ? post.pageCover : siteConfig('HOME_BANNER_IMAGE') - const floatSlot = <> return ( <> @@ -395,14 +393,14 @@ const LayoutTagIndex = props => { } export { - CONFIG as THEME_CONFIG, + Layout404, + LayoutArchive, LayoutBase, + LayoutCategoryIndex, LayoutIndex, + LayoutPostList, LayoutSearch, - LayoutArchive, LayoutSlug, - Layout404, - LayoutCategoryIndex, - LayoutPostList, - LayoutTagIndex + LayoutTagIndex, + CONFIG as THEME_CONFIG } diff --git a/themes/gitbook/components/ArticleLock.js b/themes/gitbook/components/ArticleLock.js index 4ba5a3b91eb..dd63992c1c6 100644 --- a/themes/gitbook/components/ArticleLock.js +++ b/themes/gitbook/components/ArticleLock.js @@ -11,6 +11,7 @@ import { useEffect, useRef } from 'react' export const ArticleLock = props => { const { validPassword } = props const { locale } = useGlobal() + console.log('locale', locale) const submitPassword = () => { const p = document.getElementById('password') @@ -29,25 +30,33 @@ export const ArticleLock = props => { passwordInputRef.current.focus() }, []) - return
-
-
{locale.COMMON.ARTICLE_LOCK_TIPS}
-
- { + 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} + 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/gitbook/components/BlogPostCard.js b/themes/gitbook/components/BlogPostCard.js index 352d098812c..8ce99f0921f 100644 --- a/themes/gitbook/components/BlogPostCard.js +++ b/themes/gitbook/components/BlogPostCard.js @@ -1,25 +1,36 @@ +import Badge from '@/components/Badge' +import NotionIcon from '@/components/NotionIcon' import { siteConfig } from '@/lib/config' +import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils' import Link from 'next/link' import { useRouter } from 'next/router' -import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils' -import NotionIcon from '@/components/NotionIcon' -import Badge from '@/components/Badge' import CONFIG from '../config' const BlogPostCard = ({ post, className }) => { const router = useRouter() const currentSelected = router.asPath.split('?')[0] === '/' + post.slug - const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}` + const url = checkContainHttp(post.slug) + ? sliceUrlFromHttp(post.slug) + : `${siteConfig('SUB_PATH', '')}/${post.slug}` return ( - -
-
- {siteConfig('POST_TITLE_ICON') && } {post.title} -
- {/* 最新文章加个红点 */} - {post?.isLatest && siteConfig('GITBOOK_LATEST_POST_RED_BADGE', false, CONFIG) && } -
- + +
+
+ {siteConfig('POST_TITLE_ICON') && ( + + )}{' '} + {post.title} +
+ {/* 最新文章加个红点 */} + {post?.isLatest && + siteConfig('GITBOOK_LATEST_POST_RED_BADGE', false, CONFIG) && ( + + )} +
+ ) } diff --git a/themes/gitbook/components/Header.js b/themes/gitbook/components/Header.js new file mode 100644 index 00000000000..757d4ea041c --- /dev/null +++ b/themes/gitbook/components/Header.js @@ -0,0 +1,109 @@ +import Collapse from '@/components/Collapse' +import DarkModeButton from '@/components/DarkModeButton' +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 Header(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, + to: '/category', + show: siteConfig('GITBOOK_MENU_CATEGORY', null, CONFIG) + }, + { + icon: 'fas fa-tag', + name: locale.COMMON.TAGS, + to: '/tag', + show: siteConfig('GITBOOK_BOOK_MENU_TAG', null, CONFIG) + }, + { + icon: 'fas fa-archive', + name: locale.NAV.ARCHIVE, + to: '/archive', + show: siteConfig('GITBOOK_MENU_ARCHIVE', null, CONFIG) + }, + { + icon: 'fas fa-search', + name: locale.NAV.SEARCH, + to: '/search', + show: siteConfig('GITBOOK_MENU_SEARCH', null, CONFIG) + } + ] + + let links = defaultLinks.concat(customNav) + + const toggleMenuOpen = () => { + changeShow(!isOpen) + } + + // 如果 开启自定义菜单,则覆盖Page生成的菜单 + if (siteConfig('CUSTOM_MENU')) { + links = customMenu + } + + return ( +
+ {/* 移动端折叠菜单 */} + +
+ + collapseRef.current?.updateCollapseHeight(param) + } + /> +
+
+ + {/* 导航栏菜单 */} +
+ {/* 左侧图标Logo */} + + + {/* 折叠按钮、仅移动端显示 */} +
+ +
+ {isOpen ? ( + + ) : ( + + )} +
+
+ + {/* 桌面端顶部菜单 */} +
+ {links && + links?.map((link, index) => ( + + ))} + +
+
+
+ ) +} diff --git a/themes/gitbook/components/LogoBar.js b/themes/gitbook/components/LogoBar.js index 5b6a0c8798a..c2d1c453e86 100644 --- a/themes/gitbook/components/LogoBar.js +++ b/themes/gitbook/components/LogoBar.js @@ -1,7 +1,7 @@ import LazyImage from '@/components/LazyImage' +import { siteConfig } from '@/lib/config' import { useGitBookGlobal } from '@/themes/gitbook' import Link from 'next/link' -import { siteConfig } from '@/lib/config' import CONFIG from '../config' /** @@ -17,14 +17,25 @@ export default function LogoBar(props) { changePageNavVisible(!pageNavVisible) } return ( -
-
- -
- - - {siteConfig('TITLE')} - -
+
+
+ +
+ + + {siteInfo?.title || siteConfig('TITLE')} + +
) } diff --git a/themes/gitbook/components/NavPostItem.js b/themes/gitbook/components/NavPostItem.js index 409531a8ea6..cd0c17424f0 100644 --- a/themes/gitbook/components/NavPostItem.js +++ b/themes/gitbook/components/NavPostItem.js @@ -28,7 +28,7 @@ const NavPostItem = props => { <>
{group?.category}
diff --git a/themes/gitbook/components/PageNavDrawer.js b/themes/gitbook/components/PageNavDrawer.js index 14846699db0..b5657d18ff6 100644 --- a/themes/gitbook/components/PageNavDrawer.js +++ b/themes/gitbook/components/PageNavDrawer.js @@ -8,7 +8,7 @@ import NavPostList from './NavPostList' * @returns {JSX.Element} * @constructor */ -const PageNavDrawer = (props) => { +const PageNavDrawer = props => { const { pageNavVisible, changePageNavVisible } = useGitBookGlobal() const { filteredNavPages } = props @@ -16,21 +16,29 @@ const PageNavDrawer = (props) => { changePageNavVisible(!pageNavVisible) } - return <> -
- {/* 侧边菜单 */} -
-
- {/* 所有文章列表 */} - -
-
+ return ( + <> +
+ {/* 侧边菜单 */} +
+ {/* 所有文章列表 */} +
+ +
- {/* 背景蒙版 */} -
+
+ + {/* 背景蒙版 */} +
+ ) } export default PageNavDrawer diff --git a/themes/gitbook/components/TopNavBar.js b/themes/gitbook/components/TopNavBar.js deleted file mode 100644 index c92df55d480..00000000000 --- a/themes/gitbook/components/TopNavBar.js +++ /dev/null @@ -1,73 +0,0 @@ -import LogoBar from './LogoBar' -import { useRef, useState } from 'react' -import Collapse from '@/components/Collapse' -import { MenuBarMobile } from './MenuBarMobile' -import { useGlobal } from '@/lib/global' -import CONFIG from '../config' -import { siteConfig } from '@/lib/config' -import { MenuItemDrop } from './MenuItemDrop' -import DarkModeButton from '@/components/DarkModeButton' - -/** - * 顶部导航栏 + 菜单 - * @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, to: '/category', show: siteConfig('GITBOOK_MENU_CATEGORY', null, CONFIG) }, - { icon: 'fas fa-tag', name: locale.COMMON.TAGS, to: '/tag', show: siteConfig('GITBOOK_BOOK_MENU_TAG', null, CONFIG) }, - { icon: 'fas fa-archive', name: locale.NAV.ARCHIVE, to: '/archive', show: siteConfig('GITBOOK_MENU_ARCHIVE', null, CONFIG) }, - { icon: 'fas fa-search', name: locale.NAV.SEARCH, to: '/search', show: siteConfig('GITBOOK_MENU_SEARCH', null, CONFIG) } - ] - - let links = defaultLinks.concat(customNav) - - const toggleMenuOpen = () => { - changeShow(!isOpen) - } - - // 如果 开启自定义菜单,则覆盖Page生成的菜单 - if (siteConfig('CUSTOM_MENU')) { - links = customMenu - } - - return ( -
- - {/* 移动端折叠菜单 */} - -
- collapseRef.current?.updateCollapseHeight(param)} /> -
-
- - {/* 导航栏菜单 */} -
- - {/* 左侧图标Logo */} - - - {/* 折叠按钮、仅移动端显示 */} -
- -
- {isOpen ? : } -
-
- - {/* 桌面端顶部菜单 */} -
- {links && links?.map((link, index) => )} - -
-
-
- ) -} diff --git a/themes/gitbook/index.js b/themes/gitbook/index.js index 7d52f5a743d..68940b59902 100644 --- a/themes/gitbook/index.js +++ b/themes/gitbook/index.js @@ -1,41 +1,44 @@ 'use client' -import CONFIG from './config' -import { useRouter } from 'next/router' -import { useEffect, useState, createContext, useContext, useRef } from 'react' -import { isBrowser } from '@/lib/utils' -import Footer from './components/Footer' -import InfoCard from './components/InfoCard' -import RevolverMaps from './components/RevolverMaps' -import TopNavBar from './components/TopNavBar' -import SearchInput from './components/SearchInput' -import { useGlobal } from '@/lib/global' +import Comment from '@/components/Comment' +import { AdSlot } from '@/components/GoogleAdsense' import Live2D from '@/components/Live2D' -import NavPostList from './components/NavPostList' +import NotionIcon from '@/components/NotionIcon' +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 { Transition } from '@headlessui/react' +import dynamic from 'next/dynamic' +import Link from 'next/link' +import { useRouter } from 'next/router' +import { createContext, useContext, useEffect, useRef, 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 Catalog from './components/Catalog' -import Announcement from './components/Announcement' -import PageNavDrawer from './components/PageNavDrawer' +import CategoryItem from './components/CategoryItem' import FloatTocButton from './components/FloatTocButton' -import { AdSlot } from '@/components/GoogleAdsense' +import Footer from './components/Footer' +import Header from './components/Header' +import InfoCard from './components/InfoCard' import JumpToTopButton from './components/JumpToTopButton' -import ShareBar from '@/components/ShareBar' -import CategoryItem from './components/CategoryItem' +import NavPostList from './components/NavPostList' +import PageNavDrawer from './components/PageNavDrawer' +import RevolverMaps from './components/RevolverMaps' +import SearchInput from './components/SearchInput' import TagItemMini from './components/TagItemMini' -import ArticleAround from './components/ArticleAround' -import Comment from '@/components/Comment' import TocDrawer from './components/TocDrawer' -import NotionPage from '@/components/NotionPage' -import { ArticleLock } from './components/ArticleLock' -import { Transition } from '@headlessui/react' +import CONFIG from './config' import { Style } from './style' -import BlogArchiveItem from './components/BlogArchiveItem' -import Link from 'next/link' -import dynamic from 'next/dynamic' -import { siteConfig } from '@/lib/config' -import NotionIcon from '@/components/NotionIcon' -const AlgoliaSearchModal = dynamic(() => import('@/components/AlgoliaSearchModal'), { ssr: false }) +const AlgoliaSearchModal = dynamic( + () => import('@/components/AlgoliaSearchModal'), + { ssr: false } +) const WWAds = dynamic(() => import('@/components/WWAds'), { ssr: false }) // 主题全局变量 @@ -47,12 +50,14 @@ export const useGitBookGlobal = () => useContext(ThemeGlobalGitbook) */ function getNavPagesWithLatest(allNavPages, latestPosts, post) { // localStorage 保存id和上次阅读时间戳: posts_read_time = {"${post.id}":"Date()"} - const postReadTime = JSON.parse(localStorage.getItem('post_read_time') || '{}'); + const postReadTime = JSON.parse( + localStorage.getItem('post_read_time') || '{}' + ) if (post) { - postReadTime[post.id] = new Date().getTime(); + postReadTime[post.id] = new Date().getTime() } // 更新 - localStorage.setItem('post_read_time', JSON.stringify(postReadTime)); + localStorage.setItem('post_read_time', JSON.stringify(postReadTime)) return allNavPages?.map(item => { const res = { @@ -67,12 +72,14 @@ function getNavPagesWithLatest(allNavPages, latestPosts, post) { lastEditedDate: item.lastEditedDate } // 属于最新文章通常6篇 && (无阅读记录 || 最近更新时间大于上次阅读时间) - if (latestPosts.some(post => post.id === item.id) && - (!postReadTime[item.id] || postReadTime[item.id] < new Date(item.lastEditedDate).getTime()) + if ( + latestPosts.some(post => post.id === item.id) && + (!postReadTime[item.id] || + postReadTime[item.id] < new Date(item.lastEditedDate).getTime()) ) { - return { ...res, isLatest: true }; + return { ...res, isLatest: true } } else { - return res; + return res } }) } @@ -83,8 +90,16 @@ function getNavPagesWithLatest(allNavPages, latestPosts, post) { * @returns {JSX.Element} * @constructor */ -const LayoutBase = (props) => { - const { children, post, allNavPages, latestPosts, slotLeft, slotRight, slotTop } = props +const LayoutBase = props => { + const { + children, + post, + allNavPages, + latestPosts, + slotLeft, + slotRight, + slotTop + } = props const { onLoading, fullWidth } = useGlobal() const router = useRouter() const [tocVisible, changeTocVisible] = useState(false) @@ -99,110 +114,140 @@ const LayoutBase = (props) => { }, [router]) return ( - -