fukasawa 一点微调

This commit is contained in:
tangly1024.com
2024-06-03 18:47:52 +08:00
parent 3a62c47127
commit dc7e53343c
4 changed files with 321 additions and 233 deletions

View File

@@ -1,22 +1,22 @@
import Logo from './Logo'
import GroupCategory from './GroupCategory'
import { MenuList } from './MenuList'
import GroupTag from './GroupTag'
import SearchInput from './SearchInput'
import SiteInfo from './SiteInfo'
import Catalog from './Catalog'
import Announcement from './Announcement'
import { useRouter } from 'next/router'
import DarkModeButton from '@/components/DarkModeButton'
import SocialButton from './SocialButton'
import CONFIG from '@/themes/fukasawa/config'
import { AdSlot } from '@/components/GoogleAdsense'
import { siteConfig } from '@/lib/config'
import MailChimpForm from './MailChimpForm'
import { useGlobal } from '@/lib/global'
import { useEffect, useMemo, useState } from 'react'
import { isBrowser } from '@/lib/utils'
import CONFIG from '@/themes/fukasawa/config'
import { debounce } from 'lodash'
import { useRouter } from 'next/router'
import { useEffect, useMemo, useState } from 'react'
import Announcement from './Announcement'
import Catalog from './Catalog'
import GroupCategory from './GroupCategory'
import GroupTag from './GroupTag'
import Logo from './Logo'
import MailChimpForm from './MailChimpForm'
import { MenuList } from './MenuList'
import SearchInput from './SearchInput'
import SiteInfo from './SiteInfo'
import SocialButton from './SocialButton'
/**
* 侧边栏
@@ -24,16 +24,41 @@ import { debounce } from 'lodash'
* @returns
*/
function AsideLeft(props) {
const { tagOptions, currentTag, categoryOptions, currentCategory, post, slot, notice } = props
const {
tagOptions,
currentTag,
categoryOptions,
currentCategory,
post,
slot,
notice
} = props
const router = useRouter()
const { fullWidth } = useGlobal()
const FUKASAWA_SIDEBAR_COLLAPSE_SATUS_DEFAULT = fullWidth || siteConfig('FUKASAWA_SIDEBAR_COLLAPSE_SATUS_DEFAULT', null, CONFIG)
const FUKASAWA_SIDEBAR_COLLAPSE_SATUS_DEFAULT =
fullWidth ||
siteConfig('FUKASAWA_SIDEBAR_COLLAPSE_SATUS_DEFAULT', null, CONFIG)
const FUKASAWA_SIDEBAR_COLLAPSE_ON_SCROLL = siteConfig(
'FUKASAWA_SIDEBAR_COLLAPSE_ON_SCROLL',
false,
CONFIG
)
const FUKASAWA_SIDEBAR_COLLAPSE_BUTTON = siteConfig(
'FUKASAWA_SIDEBAR_COLLAPSE_BUTTON',
null,
CONFIG
)
// 侧边栏折叠从 本地存储中获取 open 状态的初始值
const [isCollapsed, setIsCollapse] = useState(() => {
if (typeof window !== 'undefined') {
return localStorage.getItem('fukasawa-sidebar-collapse') === 'true' || FUKASAWA_SIDEBAR_COLLAPSE_SATUS_DEFAULT
return (
localStorage.getItem('fukasawa-sidebar-collapse') === 'true' ||
FUKASAWA_SIDEBAR_COLLAPSE_SATUS_DEFAULT
)
}
return FUKASAWA_SIDEBAR_COLLAPSE_SATUS_DEFAULT
})
@@ -69,7 +94,7 @@ function AsideLeft(props) {
// 自动折叠侧边栏 onResize 窗口宽度小于1366 || 滚动条滚动至页面的300px时 ; 将open设置为false
useEffect(() => {
if (!siteConfig('FUKASAWA_SIDEBAR_COLLAPSE_ON_SCROLL', false, CONFIG)) {
if (!FUKASAWA_SIDEBAR_COLLAPSE_ON_SCROLL) {
return
}
const handleResize = debounce(() => {
@@ -92,73 +117,89 @@ function AsideLeft(props) {
}
}
}, [])
return <div className={`sideLeft relative ${isCollapsed ? 'w-0' : 'w-80'} duration-300 transition-all bg-white dark:bg-hexo-black-gray min-h-screen hidden lg:block z-20`}>
{/* 折叠按钮 */}
{siteConfig('FUKASAWA_SIDEBAR_COLLAPSE_BUTTON', null, CONFIG) && <div className={`${position} hidden lg:block fixed top-0 cursor-pointer hover:scale-110 duration-300 px-3 py-2 dark:text-white`} onClick={toggleOpen}>
{isCollapsed ? <i className="fa-solid fa-indent text-xl"></i> : <i className='fas fa-bars text-xl'></i>}
</div>}
<div className={`h-full ${isCollapsed ? 'hidden' : 'p-8'}`}>
<Logo {...props} />
<section className='siteInfo flex flex-col dark:text-gray-300 pt-8'>
{siteConfig('DESCRIPTION')}
</section>
<section className='flex flex-col text-gray-600'>
<div className='w-12 my-4' />
<MenuList {...props} />
</section>
<section className='flex flex-col text-gray-600'>
<div className='w-12 my-4' />
<SearchInput {...props} />
</section>
<section className='flex flex-col dark:text-gray-300'>
<div className='w-12 my-4' />
<Announcement post={notice} />
</section>
<section>
<MailChimpForm />
</section>
<section>
<AdSlot type='in-article' />
</section>
{router.asPath !== '/tag' && <section className='flex flex-col'>
<div className='w-12 my-4' />
<GroupTag tags={tagOptions} currentTag={currentTag} />
</section>}
{router.asPath !== '/category' && <section className='flex flex-col'>
<div className='w-12 my-4' />
<GroupCategory categories={categoryOptions} currentCategory={currentCategory} />
</section>}
<section className='flex flex-col'>
<div className='w-12 my-4' />
<SocialButton />
<SiteInfo />
</section>
<section className='flex justify-center dark:text-gray-200 pt-4'>
<DarkModeButton />
</section>
<section className='sticky top-0 pt-12 flex flex-col max-h-screen '>
<Catalog toc={post?.toc} />
<div className='flex justify-center'>
<div>{slot}</div>
</div>
</section>
return (
<div
className={`sideLeft relative ${isCollapsed ? 'w-0' : 'w-80'} duration-300 transition-all bg-white dark:bg-hexo-black-gray min-h-screen hidden lg:block z-20`}>
{/* 悬浮的折叠按钮 */}
{FUKASAWA_SIDEBAR_COLLAPSE_BUTTON && (
<div
className={`${position} hidden lg:block fixed top-0 cursor-pointer hover:scale-110 duration-300 px-3 py-2 dark:text-white`}
onClick={toggleOpen}>
{isCollapsed ? (
<i className='fa-solid fa-indent text-xl'></i>
) : (
<i className='fas fa-bars text-xl'></i>
)}
</div>
)}
<div className={`h-full ${isCollapsed ? 'hidden' : 'p-8'}`}>
<Logo {...props} />
<section className='siteInfo flex flex-col dark:text-gray-300 pt-8'>
{siteConfig('DESCRIPTION')}
</section>
<section className='flex flex-col text-gray-600'>
<div className='w-12 my-4' />
<MenuList {...props} />
</section>
<section className='flex flex-col text-gray-600'>
<div className='w-12 my-4' />
<SearchInput {...props} />
</section>
<section className='flex flex-col dark:text-gray-300'>
<div className='w-12 my-4' />
<Announcement post={notice} />
</section>
<section>
<MailChimpForm />
</section>
<section>
<AdSlot type='in-article' />
</section>
{router.asPath !== '/tag' && (
<section className='flex flex-col'>
<div className='w-12 my-4' />
<GroupTag tags={tagOptions} currentTag={currentTag} />
</section>
)}
{router.asPath !== '/category' && (
<section className='flex flex-col'>
<div className='w-12 my-4' />
<GroupCategory
categories={categoryOptions}
currentCategory={currentCategory}
/>
</section>
)}
<section className='flex flex-col'>
<div className='w-12 my-4' />
<SocialButton />
<SiteInfo />
</section>
<section className='flex justify-center dark:text-gray-200 pt-4'>
<DarkModeButton />
</section>
<section className='sticky top-0 pt-12 flex flex-col max-h-screen '>
<Catalog toc={post?.toc} />
<div className='flex justify-center'>
<div>{slot}</div>
</div>
</section>
</div>
</div>
)
}
export default AsideLeft

View File

@@ -0,0 +1,64 @@
import Collapse from '@/components/Collapse'
import { useRef, useState } from 'react'
import Logo from './Logo'
import { MenuList } from './MenuList'
import SearchInput from './SearchInput'
/**
* 顶部导航
* @param {*} param0
* @returns
*/
const Header = props => {
const [isOpen, changeShow] = useState(false)
const collapseRef = useRef(null)
const toggleMenuOpen = () => {
changeShow(!isOpen)
}
return (
<div id='top-nav' className='z-40 block lg:hidden'>
{/* 导航栏 */}
<div
id='sticky-nav'
className={
'relative w-full top-0 z-20 transform duration-500 bg-white dark:bg-black'
}>
<Collapse type='vertical' isOpen={isOpen} collapseRef={collapseRef}>
<div className='py-1 px-5'>
<MenuList
{...props}
onHeightChange={param =>
collapseRef.current?.updateCollapseHeight(param)
}
/>
<SearchInput {...props} />
</div>
</Collapse>
<div className='w-full flex justify-between items-center p-4 '>
{/* 左侧LOGO 标题 */}
<div className='flex flex-none flex-grow-0'>
<Logo {...props} />
</div>
<div className='flex'></div>
{/* 右侧功能 */}
<div className='mr-1 flex justify-end items-center text-sm space-x-4 font-serif dark:text-gray-200'>
<div
onClick={toggleMenuOpen}
className='cursor-pointer text-lg p-2'>
{isOpen ? (
<i className='fas fa-times' />
) : (
<i className='fas fa-bars' />
)}
</div>
</div>
</div>
</div>
</div>
)
}
export default Header

View File

@@ -1,50 +0,0 @@
import { useState, useRef } from 'react'
import Collapse from '@/components/Collapse'
import { MenuList } from './MenuList'
import Logo from './Logo'
import SearchInput from './SearchInput'
/**
* 顶部导航
* @param {*} param0
* @returns
*/
const TopNav = props => {
const [isOpen, changeShow] = useState(false)
const collapseRef = useRef(null)
const toggleMenuOpen = () => {
changeShow(!isOpen)
}
return (<div id='top-nav' className='z-40 block lg:hidden'>
{/* 导航栏 */}
<div id='sticky-nav' className={'relative w-full top-0 z-20 transform duration-500 bg-white dark:bg-black'}>
<Collapse type='vertical' isOpen={isOpen} collapseRef={collapseRef}>
<div className='py-1 px-5'>
<MenuList {...props} onHeightChange={(param) => collapseRef.current?.updateCollapseHeight(param)} />
<SearchInput {...props} />
</div>
</Collapse>
<div className='w-full flex justify-between items-center p-4 '>
{/* 左侧LOGO 标题 */}
<div className='flex flex-none flex-grow-0'>
<Logo {...props} />
</div>
<div className='flex'>
</div>
{/* 右侧功能 */}
<div className='mr-1 flex justify-end items-center text-sm space-x-4 font-serif dark:text-gray-200'>
<div onClick={toggleMenuOpen} className='cursor-pointer text-lg p-2'>
{isOpen ? <i className='fas fa-times' /> : <i className='fas fa-bars' />}
</div>
</div>
</div>
</div>
</div>)
}
export default TopNav

View File

@@ -1,27 +1,27 @@
'use client'
import CONFIG from './config'
import TopNav from './components/TopNav'
import AsideLeft from './components/AsideLeft'
import { isBrowser } from '@/lib/utils'
import AlgoliaSearchModal from '@/components/AlgoliaSearchModal'
import { AdSlot } from '@/components/GoogleAdsense'
import replaceSearchResult from '@/components/Mark'
import WWAds from '@/components/WWAds'
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 } from 'react'
import ArticleDetail from './components/ArticleDetail'
import ArticleLock from './components/ArticleLock'
import AsideLeft from './components/AsideLeft'
import BlogListPage from './components/BlogListPage'
import BlogListScroll from './components/BlogListScroll'
import BlogArchiveItem from './components/BlogPostArchive'
import ArticleDetail from './components/ArticleDetail'
import ArticleLock from './components/ArticleLock'
import Header from './components/Header'
import TagItemMini from './components/TagItemMini'
import { useRouter } from 'next/router'
import { createContext, useContext, useEffect, useRef } from 'react'
import Link from 'next/link'
import { Transition } from '@headlessui/react'
import dynamic from 'next/dynamic'
import { AdSlot } from '@/components/GoogleAdsense'
import CONFIG from './config'
import { Style } from './style'
import replaceSearchResult from '@/components/Mark'
import { siteConfig } from '@/lib/config'
import WWAds from '@/components/WWAds'
import AlgoliaSearchModal from '@/components/AlgoliaSearchModal'
const Live2D = dynamic(() => import('@/components/Live2D'))
@@ -43,51 +43,58 @@ export const useFukasawaGlobal = () => useContext(ThemeGlobalFukasawa)
* @returns {JSX.Element}
* @constructor
*/
const LayoutBase = (props) => {
const LayoutBase = props => {
const { children, headerSlot } = props
const leftAreaSlot = <Live2D />
const { onLoading, fullWidth } = useGlobal()
const searchModal = useRef(null)
return (
<ThemeGlobalFukasawa.Provider value={{ searchModal }}>
<div id='theme-fukasawa' className={`${siteConfig('FONT_STYLE')} dark:bg-black scroll-smooth`}>
<AlgoliaSearchModal cRef={searchModal} {...props} />
<div
id='theme-fukasawa'
className={`${siteConfig('FONT_STYLE')} dark:bg-black scroll-smooth`}>
<Style />
{/* 页头导航,此主题只在移动端生效 */}
<Header {...props} />
<TopNav {...props} />
<div className={(JSON.parse(siteConfig('LAYOUT_SIDEBAR_REVERSE')) ? 'flex-row-reverse' : '') + ' flex'}>
<div
className={
(JSON.parse(siteConfig('LAYOUT_SIDEBAR_REVERSE'))
? 'flex-row-reverse'
: '') + ' flex'
}>
{/* 侧边抽屉 */}
<AsideLeft {...props} slot={leftAreaSlot} />
<main id='wrapper' className='relative flex w-full py-8 justify-center bg-day dark:bg-night'>
<div id='container-inner' className={`${fullWidth ? '' : '2xl:max-w-6xl md:max-w-4xl'} w-full relative z-10`}>
<main
id='wrapper'
className='relative flex w-full py-8 justify-center bg-day dark:bg-night'>
<div
id='container-inner'
className={`${fullWidth ? '' : '2xl:max-w-6xl md:max-w-4xl'} w-full relative z-10`}>
<Transition
show={!onLoading}
appear={true}
className="w-full"
enter="transition ease-in-out duration-700 transform order-first"
enterFrom="opacity-0 translate-y-16"
enterTo="opacity-100"
leave="transition ease-in-out duration-300 transform"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 -translate-y-16"
unmount={false}
>
className='w-full'
enter='transition ease-in-out duration-700 transform order-first'
enterFrom='opacity-0 translate-y-16'
enterTo='opacity-100'
leave='transition ease-in-out duration-300 transform'
leaveFrom='opacity-100 translate-y-0'
leaveTo='opacity-0 -translate-y-16'
unmount={false}>
<div> {headerSlot} </div>
<div> {children} </div>
</Transition>
<div className='mt-2'>
<AdSlot type='native' />
</div>
</div>
</main>
</div>
<AlgoliaSearchModal cRef={searchModal} {...props} />
</div>
</ThemeGlobalFukasawa.Provider>
)
@@ -96,49 +103,64 @@ const LayoutBase = (props) => {
/**
* 首页
* @param {*} props notion数据
* @returns 首页就是一个博客列表
*/
const LayoutIndex = (props) => {
* @returns 首页就是一个博客列表
*/
const LayoutIndex = props => {
return <LayoutPostList {...props} />
}
/**
* 博客列表
* @param {*} props
*/
const LayoutPostList = (props) => {
return <>
<div className='w-full p-2'><WWAds className='w-full' orientation='horizontal' /></div>
{siteConfig('POST_LIST_STYLE') === 'page' ? <BlogListPage {...props} /> : <BlogListScroll {...props} />}
</>
*/
const LayoutPostList = props => {
return (
<>
<div className='w-full p-2'>
<WWAds className='w-full' orientation='horizontal' />
</div>
{siteConfig('POST_LIST_STYLE') === 'page' ? (
<BlogListPage {...props} />
) : (
<BlogListScroll {...props} />
)}
</>
)
}
/**
* 文章详情
* @param {*} props
* @returns
*/
const LayoutSlug = (props) => {
* @returns
*/
const LayoutSlug = props => {
const { post, lock, validPassword } = props
const router = useRouter()
useEffect(() => {
// 404
if (!post) {
setTimeout(() => {
if (isBrowser) {
const article = document.getElementById('notion-article')
if (!article) {
router.push('/404').then(() => {
console.warn('找不到页面', router.asPath)
})
setTimeout(
() => {
if (isBrowser) {
const article = document.getElementById('notion-article')
if (!article) {
router.push('/404').then(() => {
console.warn('找不到页面', router.asPath)
})
}
}
}
}, siteConfig('POST_WAITING_TIME_FOR_404') * 1000)
},
siteConfig('POST_WAITING_TIME_FOR_404') * 1000
)
}
}, [post])
return (
<>
{lock ? <ArticleLock validPassword={validPassword} /> : <ArticleDetail {...props} />}
{lock ? (
<ArticleLock validPassword={validPassword} />
) : (
<ArticleDetail {...props} />
)}
</>
)
}
@@ -167,26 +189,28 @@ const LayoutSearch = props => {
/**
* 归档页面
*/
const LayoutArchive = (props) => {
const LayoutArchive = props => {
const { archivePosts } = props
return <>
<div className="mb-10 pb-20 bg-white md:p-12 p-3 dark:bg-gray-800 shadow-md min-h-full">
{Object.keys(archivePosts).map(archiveTitle => (
<BlogArchiveItem
key={archiveTitle}
posts={archivePosts[archiveTitle]}
archiveTitle={archiveTitle}
/>
))}
</div>
</>
return (
<>
<div className='mb-10 pb-20 bg-white md:p-12 p-3 dark:bg-gray-800 shadow-md min-h-full'>
{Object.keys(archivePosts).map(archiveTitle => (
<BlogArchiveItem
key={archiveTitle}
posts={archivePosts[archiveTitle]}
archiveTitle={archiveTitle}
/>
))}
</div>
</>
)
}
/**
* 404
* @param {*} props
* @returns
*/
* @returns
*/
const Layout404 = props => {
return <>404</>
}
@@ -194,16 +218,17 @@ const Layout404 = props => {
/**
* 分类列表
* @param {*} props
* @returns
*/
const LayoutCategoryIndex = (props) => {
* @returns
*/
const LayoutCategoryIndex = props => {
const { locale } = useGlobal()
const { categoryOptions } = props
return (
<>
<div className='bg-white dark:bg-gray-700 px-10 py-10 shadow'>
<div className='dark:text-gray-200 mb-5'>
<i className='mr-4 fas fa-th' />{locale.COMMON.CATEGORY}:
<i className='mr-4 fas fa-th' />
{locale.COMMON.CATEGORY}:
</div>
<div id='category-list' className='duration-200 flex flex-wrap'>
{categoryOptions?.map(category => {
@@ -214,8 +239,11 @@ const LayoutCategoryIndex = (props) => {
passHref
legacyBehavior>
<div
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'}>
<i className='mr-4 fas fa-folder' />{category.name}({category.count})
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'
}>
<i className='mr-4 fas fa-folder' />
{category.name}({category.count})
</div>
</Link>
)
@@ -229,36 +257,41 @@ const LayoutCategoryIndex = (props) => {
/**
* 标签列表
* @param {*} props
* @returns
*/
const LayoutTagIndex = (props) => {
* @returns
*/
const LayoutTagIndex = props => {
const { locale } = useGlobal()
const { tagOptions } = props
return <>
<div className='bg-white dark:bg-gray-700 px-10 py-10 shadow'>
<div className='dark:text-gray-200 mb-5'><i className='mr-4 fas fa-tag' />{locale.COMMON.TAGS}:</div>
<div id="tags-list" className="duration-200 flex flex-wrap ml-8">
{tagOptions.map(tag => {
return (
<div key={tag.name} className="p-2">
<TagItemMini key={tag.name} tag={tag} />
</div>
)
})}
return (
<>
<div className='bg-white dark:bg-gray-700 px-10 py-10 shadow'>
<div className='dark:text-gray-200 mb-5'>
<i className='mr-4 fas fa-tag' />
{locale.COMMON.TAGS}:
</div>
<div id='tags-list' className='duration-200 flex flex-wrap ml-8'>
{tagOptions.map(tag => {
return (
<div key={tag.name} className='p-2'>
<TagItemMini key={tag.name} tag={tag} />
</div>
)
})}
</div>
</div>
</div>
</>
</>
)
}
export {
CONFIG as THEME_CONFIG,
LayoutBase,
LayoutIndex,
LayoutSearch,
LayoutArchive,
LayoutSlug,
Layout404,
LayoutPostList,
LayoutArchive,
LayoutBase,
LayoutCategoryIndex,
LayoutTagIndex
LayoutIndex,
LayoutPostList,
LayoutSearch,
LayoutSlug,
LayoutTagIndex,
CONFIG as THEME_CONFIG
}