mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-17 15:09:31 +00:00
mattery主题
This commit is contained in:
@@ -13,7 +13,8 @@ export function ThemeSwitch() {
|
||||
<div id="draggableBox" style={{ left: '10px', top: '90vh' }} className="fixed text-white bg-black z-50 rounded-lg shadow-card">
|
||||
<div className="p-2 flex items-center">
|
||||
<i className="fas fa-palette mr-1 cursor-move" />
|
||||
<div className='uppercase font-sans whitespace-nowrap' >{theme} <i className='fas fa-sync cursor-pointer border-l pl-2' title='click to change theme' alt='click to change theme' onClick={switchTheme} /></div>
|
||||
<div className='uppercase font-sans whitespace-nowrap cursor-pointer ' onClick={switchTheme}> {theme}
|
||||
<i className='fas fa-arrows cursor-move pl-2' title='click to change theme' alt='click to change theme' /></div>
|
||||
</div>
|
||||
</div>
|
||||
</Draggable>
|
||||
|
||||
@@ -11,6 +11,7 @@ import { useGlobal } from '@/lib/global'
|
||||
import BLOG from '@/blog.config'
|
||||
import AOS from 'aos'
|
||||
import 'aos/dist/aos.css' // You can also use <link> for styles
|
||||
import FloatDarkModeButton from './components/FloatDarkModeButton'
|
||||
|
||||
/**
|
||||
* 基础布局 采用左右两侧布局,移动端使用顶部导航栏
|
||||
@@ -46,39 +47,41 @@ const LayoutBase = props => {
|
||||
AOS.init()
|
||||
|
||||
return (
|
||||
<div id="outer-wrapper" className="min-h-screen flex flex-col justify-between bg-hexo-background-gray dark:bg-black w-full overflow-hidden">
|
||||
<div id="outer-wrapper" className="min-h-screen flex flex-col justify-between bg-hexo-background-gray dark:bg-black w-full overflow-hidden">
|
||||
|
||||
<CommonHead meta={meta} siteInfo={siteInfo}/>
|
||||
<CommonHead meta={meta} siteInfo={siteInfo} />
|
||||
|
||||
<TopNav {...props} />
|
||||
<TopNav {...props} />
|
||||
|
||||
{headerSlot}
|
||||
{headerSlot}
|
||||
|
||||
<main id="wrapper" className="flex-1 w-full py-8 md:px-8 lg:px-24">
|
||||
<div id="container-inner" className="w-full mx-auto lg:flex lg:space-x-4 justify-center">
|
||||
{onLoading ? <LoadingCover /> : children}
|
||||
<main id="wrapper" className="flex-1 w-full py-8 md:px-8 lg:px-24">
|
||||
<div id="container-inner" className="w-full max-w-4xl mx-auto lg:flex lg:space-x-4 justify-center">
|
||||
{onLoading ? <LoadingCover /> : children}
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* 左下角悬浮 */}
|
||||
<div className="bottom-4 -left-14 fixed justify-end z-40">
|
||||
<Live2D />
|
||||
</div>
|
||||
|
||||
<div className="bottom-24 right-2 fixed justify-end z-20">
|
||||
<FloatDarkModeButton />
|
||||
</div>
|
||||
{/* 右下角悬浮 */}
|
||||
<div className="bottom-12 right-2 fixed justify-end z-20">
|
||||
<div className={
|
||||
(show ? 'animate__animated ' : 'hidden') +
|
||||
' animate__fadeInUp justify-center duration-300 animate__faster flex flex-col items-center cursor-pointer '
|
||||
}
|
||||
>
|
||||
<JumpToTopButton />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Footer title={siteInfo?.title || BLOG.TITLE} />
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* 左下角悬浮 */}
|
||||
<div className="bottom-4 -left-14 fixed justify-end z-40">
|
||||
<Live2D />
|
||||
</div>
|
||||
|
||||
{/* 右下角悬浮 */}
|
||||
<div className="bottom-12 right-2 fixed justify-end z-20">
|
||||
<div
|
||||
className={
|
||||
(show ? 'animate__animated ' : 'hidden') +
|
||||
' animate__fadeInUp justify-center duration-300 animate__faster flex flex-col items-center cursor-pointer '
|
||||
}
|
||||
>
|
||||
<JumpToTopButton />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Footer title={siteInfo?.title || BLOG.TITLE} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ export const LayoutSearch = props => {
|
||||
return (
|
||||
<LayoutBase {...props} currentSearch={currentSearch}>
|
||||
{!currentSearch && <>
|
||||
<div className="my-6 px-2">
|
||||
<div className="my-6 px-2 mt-12">
|
||||
<SearchInput cRef={cRef} {...props} />
|
||||
{/* 分类 */}
|
||||
<Card className="w-full mt-4">
|
||||
|
||||
@@ -10,6 +10,7 @@ import NotionPage from '@/components/NotionPage'
|
||||
import ArticleAdjacent from './components/ArticleAdjacent'
|
||||
import ArticleCopyright from './components/ArticleCopyright'
|
||||
import { isBrowser } from '@/lib/utils'
|
||||
import { ArticleInfo } from './components/ArticleInfo'
|
||||
|
||||
export const LayoutSlug = props => {
|
||||
const { post, lock, validPassword } = props
|
||||
@@ -17,79 +18,83 @@ export const LayoutSlug = props => {
|
||||
|
||||
if (!post) {
|
||||
return <LayoutBase
|
||||
headerSlot={<HeaderArticle {...props} />}
|
||||
{...props}
|
||||
showCategory={false}
|
||||
showTag={false}
|
||||
></LayoutBase>
|
||||
headerSlot={<HeaderArticle {...props} />}
|
||||
{...props}
|
||||
showCategory={false}
|
||||
showTag={false}
|
||||
></LayoutBase>
|
||||
}
|
||||
|
||||
const targetRef = isBrowser() ? document.getElementById('container') : null
|
||||
|
||||
const floatSlot = <>
|
||||
{post?.toc?.length > 1 && <div className="block lg:hidden">
|
||||
<TocDrawerButton
|
||||
onClick={() => {
|
||||
drawerRight?.current?.handleSwitchVisible()
|
||||
}}
|
||||
/>
|
||||
</div>}
|
||||
<JumpToCommentButton />
|
||||
</>
|
||||
{post?.toc?.length > 1 && <div className="block lg:hidden">
|
||||
<TocDrawerButton
|
||||
onClick={() => {
|
||||
drawerRight?.current?.handleSwitchVisible()
|
||||
}}
|
||||
/>
|
||||
</div>}
|
||||
<JumpToCommentButton />
|
||||
</>
|
||||
|
||||
return (
|
||||
<LayoutBase
|
||||
headerSlot={<HeaderArticle {...props} />}
|
||||
{...props}
|
||||
showCategory={false}
|
||||
showTag={false}
|
||||
floatSlot={floatSlot}
|
||||
>
|
||||
<div>
|
||||
<div className="-mt-32 rounded-md mx-3 lg:shadow-sm lg:hover:shadow lg:border lg:rounded-xl lg:px-2 lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black">
|
||||
{lock && <ArticleLock validPassword={validPassword} />}
|
||||
<LayoutBase
|
||||
headerSlot={<HeaderArticle {...props} />}
|
||||
{...props}
|
||||
showCategory={false}
|
||||
showTag={false}
|
||||
floatSlot={floatSlot}
|
||||
>
|
||||
<div className='inner-wrapper drop-shadow-xl'>
|
||||
<div className="-mt-32 rounded-md mx-3 lg:border lg:rounded-xl lg:px-2 lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black">
|
||||
{lock && <ArticleLock validPassword={validPassword} />}
|
||||
|
||||
{!lock && <div id="container" className="overflow-x-auto flex-grow md:w-full ">
|
||||
{!lock && <div id="container" className="overflow-x-auto flex-grow md:w-full ">
|
||||
{/* <ArticleInfo */}
|
||||
<div className='px-5'>
|
||||
<ArticleInfo post={post} />
|
||||
</div>
|
||||
|
||||
<article itemScope itemType="https://schema.org/Movie" className="subpixel-antialiased" >
|
||||
{/* Notion文章主体 */}
|
||||
<section id='notion-article' className='px-5 justify-center mx-auto max-w-2xl lg:max-w-full'>
|
||||
{post && <NotionPage post={post} />}
|
||||
</section>
|
||||
<hr />
|
||||
|
||||
<section className="px-1 py-2 my-1 text-sm font-light overflow-auto text-gray-600 dark:text-gray-400">
|
||||
{/* 文章内嵌广告 */}
|
||||
<ins className="adsbygoogle"
|
||||
style={{ display: 'block', textAlign: 'center' }}
|
||||
data-adtest="on"
|
||||
data-ad-layout="in-article"
|
||||
data-ad-format="fluid"
|
||||
data-ad-client="ca-pub-2708419466378217"
|
||||
data-ad-slot="3806269138" />
|
||||
</section>
|
||||
<article itemScope itemType="https://schema.org/Movie" className="subpixel-antialiased" >
|
||||
{/* Notion文章主体 */}
|
||||
<section id='notion-article' className='px-5 justify-center mx-auto max-w-2xl lg:max-w-full'>
|
||||
{post && <NotionPage post={post} />}
|
||||
</section>
|
||||
|
||||
{post.type === 'Post' && <ArticleCopyright {...props} /> }
|
||||
<section className="px-1 py-2 my-1 text-sm font-light overflow-auto text-gray-600 dark:text-gray-400">
|
||||
{/* 文章内嵌广告 */}
|
||||
<ins className="adsbygoogle"
|
||||
style={{ display: 'block', textAlign: 'center' }}
|
||||
data-adtest="on"
|
||||
data-ad-layout="in-article"
|
||||
data-ad-format="fluid"
|
||||
data-ad-client="ca-pub-2708419466378217"
|
||||
data-ad-slot="3806269138" />
|
||||
</section>
|
||||
|
||||
</article>
|
||||
{post.type === 'Post' && <ArticleCopyright {...props} />}
|
||||
|
||||
<hr className='border-dashed' />
|
||||
</article>
|
||||
|
||||
{/* 评论互动 */}
|
||||
<div className="duration-200 overflow-x-auto dark:bg-hexo-black-gray px-3">
|
||||
<Comment frontMatter={post} />
|
||||
</div>
|
||||
</div>}
|
||||
</div>
|
||||
<hr className='border-dashed' />
|
||||
|
||||
<div className='px-3'>
|
||||
{post.type === 'Post' && <ArticleAdjacent {...props} /> }
|
||||
</div>
|
||||
{/* 评论互动 */}
|
||||
<div className="duration-200 overflow-x-auto dark:bg-hexo-black-gray px-3">
|
||||
<Comment frontMatter={post} />
|
||||
</div>
|
||||
</div>}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className='block lg:hidden'>
|
||||
<TocDrawer post={post} cRef={drawerRight} targetRef={targetRef} />
|
||||
</div>
|
||||
{post.type === 'Post' && <ArticleAdjacent {...props} />}
|
||||
|
||||
</LayoutBase>
|
||||
</div>
|
||||
<div className='block lg:hidden'>
|
||||
<TocDrawer post={post} cRef={drawerRight} targetRef={targetRef} />
|
||||
</div>
|
||||
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,24 +3,38 @@ import BlogPostListScroll from './components/BlogPostListScroll'
|
||||
import BlogPostListPage from './components/BlogPostListPage'
|
||||
import LayoutBase from './LayoutBase'
|
||||
import React from 'react'
|
||||
import Link from 'next/link'
|
||||
import HeaderArticle from './components/HeaderArticle'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import TagItemMiddle from './components/TagItemMiddle'
|
||||
|
||||
export const LayoutTag = (props) => {
|
||||
const tag = props.tags.find((t) => {
|
||||
return t.name === props.tag
|
||||
})
|
||||
const { tags, tag } = props
|
||||
|
||||
return <LayoutBase {...props}>
|
||||
{tag && (
|
||||
<div className="cursor-pointer px-3 py-2 mb-2 font-light hover:text-indigo-700 dark:hover:text-indigo-400 transform dark:text-white">
|
||||
<Link key={tag} href={`/tag/${encodeURIComponent(tag.name)}`} passHref>
|
||||
<a className={`cursor-pointer inline-block rounded duration-200
|
||||
mr-2 py-0.5 px-1 text-xl whitespace-nowrap ` }>
|
||||
<div className='font-light dark:text-gray-400 dark:hover:text-white'> #{tag.name + (tag.count ? `(${tag.count})` : '')} </div>
|
||||
</a>
|
||||
</Link>
|
||||
const { locale } = useGlobal()
|
||||
|
||||
return <LayoutBase {...props} headerSlot={<HeaderArticle {...props} />} >
|
||||
|
||||
<div className='inner-wrapper drop-shadow-xl'>
|
||||
|
||||
<div className="-mt-32 rounded-md mx-3 px-5 lg:border lg:rounded-xl lg:px-2 lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black">
|
||||
|
||||
<div className="dark:text-gray-200 py-5 text-center text-2xl">
|
||||
<i className="fas fa-tags" /> {locale.COMMON.TAGS}
|
||||
</div>
|
||||
|
||||
<div id="tags-list" className="duration-200 flex flex-wrap justify-center pb-12">
|
||||
{tags.map(e => {
|
||||
const selected = tag === e.name
|
||||
return (
|
||||
<div key={e.id} className="p-2">
|
||||
<TagItemMiddle key={e.id} tag={e} selected={selected} />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{BLOG.POST_LIST_STYLE === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />}
|
||||
</LayoutBase>
|
||||
}
|
||||
|
||||
@@ -1,28 +1,32 @@
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import Card from './components/Card'
|
||||
import TagItemMini from './components/TagItemMini'
|
||||
import HeaderArticle from './components/HeaderArticle'
|
||||
import TagItemMiddle from './components/TagItemMiddle'
|
||||
import LayoutBase from './LayoutBase'
|
||||
|
||||
export const LayoutTagIndex = props => {
|
||||
const { tags } = props
|
||||
const { locale } = useGlobal()
|
||||
return (
|
||||
<LayoutBase {...props}>
|
||||
<Card className='w-full'>
|
||||
<div className="dark:text-gray-200 mb-5 ml-4">
|
||||
<i className="mr-4 fas fa-tag" />
|
||||
{locale.COMMON.TAGS}:
|
||||
</div>
|
||||
<div id="tags-list" className="duration-200 flex flex-wrap ml-8">
|
||||
{tags.map(tag => {
|
||||
return (
|
||||
<div key={tag.name} className="p-2">
|
||||
<TagItemMini key={tag.name} tag={tag} />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</Card>
|
||||
</LayoutBase>
|
||||
<LayoutBase {...props} headerSlot={<HeaderArticle {...props} />} >
|
||||
<div className='inner-wrapper drop-shadow-xl'>
|
||||
|
||||
<div className="-mt-32 rounded-md mx-3 px-5 lg:border lg:rounded-xl lg:px-2 lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black">
|
||||
|
||||
<div className="dark:text-gray-200 py-5 text-center text-2xl">
|
||||
<i className="fas fa-tags" /> {locale.COMMON.TAGS}
|
||||
</div>
|
||||
|
||||
<div id="tags-list" className="duration-200 flex flex-wrap justify-center pb-12">
|
||||
{tags.map(tag => {
|
||||
return (
|
||||
<div key={tag.name} className="p-2">
|
||||
<TagItemMiddle key={tag.name} tag={tag} />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ export default function ArticleAdjacent ({ prev, next }) {
|
||||
if (!prev || !next || !CONFIG_MATERY.ARTICLE_ADJACENT) {
|
||||
return <></>
|
||||
}
|
||||
return <section className='flex-col py-3 space-y-3 text-gray-800 items-center text-xs md:text-sm md:flex md:flex-row md:space-y-0 md:space-x-4 justify-between m-1 '>
|
||||
return <section className='flex flex-col justify-between p-3 text-gray-800 items-center text-xs md:text-sm md:flex-row md:gap-2 '>
|
||||
|
||||
<BlogPostCard post={prev}/>
|
||||
<BlogPostCard post={next}/>
|
||||
|
||||
46
themes/matery/components/ArticleInfo.js
Normal file
46
themes/matery/components/ArticleInfo.js
Normal file
@@ -0,0 +1,46 @@
|
||||
import Link from 'next/link'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import formatDate from '@/lib/formatDate'
|
||||
import TagItemMiddle from './TagItemMiddle'
|
||||
import WordCount from './WordCount'
|
||||
|
||||
export const ArticleInfo = (props) => {
|
||||
const { post } = props
|
||||
|
||||
const { locale } = useGlobal()
|
||||
const date = formatDate(post?.date?.start_date || post?.createdTime, locale.LOCALE)
|
||||
|
||||
return <section className='mb-3'>
|
||||
<div className='my-3'>
|
||||
{post.tagItems && (
|
||||
<div className="flex flex-nowrap overflow-x-auto">
|
||||
{post.tagItems.map(tag => (
|
||||
<TagItemMiddle key={tag.name} tag={tag} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className='flex flex-wrap gap-3 mt-5 text-sm'>
|
||||
{post?.type !== 'Page' && (<>
|
||||
<Link
|
||||
href={`/archive#${post?.date?.start_date?.substr(0, 7)}`}
|
||||
passHref
|
||||
>
|
||||
<a className="cursor-pointer whitespace-nowrap">
|
||||
<i className='far fa-calendar-minus fa-fw'/>发布日期: {date}
|
||||
</a>
|
||||
</Link>
|
||||
<span className='whitespace-nowrap'>
|
||||
<i className='far fa-calendar-check fa-fw' /> 更新日期: {post.lastEditedTime}
|
||||
</span>
|
||||
<span className="hidden busuanzi_container_page_pv font-light mr-2">
|
||||
<i className='mr-1 fas fa-eye' />
|
||||
<span className="busuanzi_value_page_pv" />
|
||||
</span>
|
||||
<WordCount />
|
||||
</>)}
|
||||
</div>
|
||||
|
||||
</section>
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import CONFIG_MATERY from '../config_matery'
|
||||
|
||||
const BlogPostCard = ({ post, showSummary }) => {
|
||||
const showPreview = CONFIG_MATERY.POST_LIST_PREVIEW && post.blockMap
|
||||
console.log('文章', post)
|
||||
return (
|
||||
<div
|
||||
data-aos="fade-up"
|
||||
@@ -22,7 +23,7 @@ const BlogPostCard = ({ post, showSummary }) => {
|
||||
<div key={post.id} className="flex flex-col justify-between h-96">
|
||||
|
||||
{/* 头部图片 填充卡片 */}
|
||||
{CONFIG_MATERY.POST_LIST_COVER && !showPreview && post?.page_cover && !post.results && (
|
||||
{CONFIG_MATERY.POST_LIST_COVER && !showPreview && post?.page_cover && (
|
||||
<Link href={`${BLOG.SUB_PATH}/${post.slug}`} passHref>
|
||||
<div className="flex flex-grow w-full relative duration-200 bg-black rounded-t-md cursor-pointer transform overflow-hidden">
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
@@ -31,7 +32,7 @@ const BlogPostCard = ({ post, showSummary }) => {
|
||||
alt={post.title}
|
||||
className="opacity-50 h-full w-full hover:scale-125 rounded-t-md transform object-cover duration-500"
|
||||
/>
|
||||
<span className='absolute bottom-0 left-0 text-white p-6 text-2xl' > {post.title}</span>
|
||||
<span className='absolute bottom-0 left-0 text-white p-6 text-2xl replace' > {post.title}</span>
|
||||
</div>
|
||||
</Link>
|
||||
)}
|
||||
@@ -46,6 +47,14 @@ const BlogPostCard = ({ post, showSummary }) => {
|
||||
{post.summary}
|
||||
</p>
|
||||
)}
|
||||
{/* 搜索结果 */}
|
||||
{post.results && (
|
||||
<p className="mt-4 replace text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
|
||||
{post.results.map(r => (
|
||||
<span key={r}>{r}</span>
|
||||
))}
|
||||
</p>
|
||||
)}
|
||||
|
||||
<div className='text-gray-800 justify-between flex my-2'>
|
||||
<Link
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const Card = ({ children, headerSlot, className }) => {
|
||||
return <div className={className}>
|
||||
<>{headerSlot}</>
|
||||
<section className="shadow hover:shadow dark:text-gray-300 border dark:border-black rounded-xl px-2 py-4 bg-white dark:bg-hexo-black-gray lg:duration-100">
|
||||
<section className="drop-shadow-xl dark:text-gray-300 border dark:border-black rounded-xl px-2 py-4 bg-white dark:bg-hexo-black-gray lg:duration-100">
|
||||
{children}
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -2,12 +2,13 @@ import { useGlobal } from '@/lib/global'
|
||||
import { saveDarkModeToCookies } from '@/lib/theme'
|
||||
import CONFIG_MATERY from '../config_matery'
|
||||
|
||||
export default function FloatDarkModeButton () {
|
||||
export default function FloatDarkModeButton() {
|
||||
const { isDarkMode, updateDarkMode } = useGlobal()
|
||||
|
||||
if (!CONFIG_MATERY.WIDGET_DARK_MODE) {
|
||||
return <></>
|
||||
}
|
||||
|
||||
const { isDarkMode, updateDarkMode } = useGlobal()
|
||||
// 用户手动设置主题
|
||||
const handleChangeDarkMode = () => {
|
||||
const newStatus = !isDarkMode
|
||||
@@ -19,12 +20,13 @@ export default function FloatDarkModeButton () {
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
onClick={handleChangeDarkMode}
|
||||
className={'justify-center items-center w-7 h-7 text-center transform hover:scale-105 duration-200'
|
||||
}
|
||||
>
|
||||
<i id="darkModeButton" className={`${isDarkMode ? 'fa-sun' : 'fa-moon'} fas text-xs`}/>
|
||||
</div>
|
||||
<div
|
||||
onClick={handleChangeDarkMode}
|
||||
className={'justify-center items-center text-center'
|
||||
}
|
||||
>
|
||||
<i id="darkModeButton" className={`${isDarkMode ? 'fa-sun' : 'fa-moon'} fas
|
||||
text-2xl text-white bg-indigo-700 px-3 py-2.5 rounded-full dark:bg-black cursor-pointer`} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
export default function HeaderArticle({ post, siteInfo }) {
|
||||
if (!post) {
|
||||
return <></>
|
||||
}
|
||||
const headerImage = post?.page_cover ? `url("${post.page_cover}")` : `url("${siteInfo?.pageCover}")`
|
||||
const headerImage = post?.page_cover ? `url("${post?.page_cover}")` : `url("${siteInfo?.pageCover}")`
|
||||
const title = post?.title
|
||||
return (
|
||||
<div
|
||||
id="header"
|
||||
@@ -10,9 +8,8 @@ export default function HeaderArticle({ post, siteInfo }) {
|
||||
style={{ backgroundImage: headerImage }}
|
||||
>
|
||||
<div className="flex flex-col h-80 justify-center ">
|
||||
{/* 文章Title */}
|
||||
<div className="font-bold text-xl shadow-text flex justify-center text-center text-white dark:text-white ">
|
||||
{post.title}
|
||||
{title}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -30,7 +30,7 @@ const SideBar = (props) => {
|
||||
<div className="h-48 w-full bg-indigo-700">
|
||||
<div className='mx-5 pt-6'>
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img src={siteInfo?.icon} className='rounded-full' width={80} alt={BLOG.AUTHOR} />
|
||||
<img src={siteInfo?.icon} className='cursor-pointer rounded-full' width={80} alt={BLOG.AUTHOR} />
|
||||
<div className='text-white text-xl my-1'>{siteInfo?.title}</div>
|
||||
<div className='text-xs my-1 text-gray-300'>{siteInfo?.description}</div>
|
||||
</div>
|
||||
|
||||
14
themes/matery/components/TagItemMiddle.js
Normal file
14
themes/matery/components/TagItemMiddle.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import Link from 'next/link'
|
||||
|
||||
const TagItemMiddle = ({ tag, selected = false }) => {
|
||||
return <Link key={tag} href={selected ? '/' : `/tag/${encodeURIComponent(tag.name)}`} passHref>
|
||||
<a className={`cursor-pointer inline-block rounded-xl hover:text-white duration-200
|
||||
mr-2 py-0.5 px-2 text-md whitespace-nowrap text-white ${selected ? 'bg-black' : 'bg-indigo-700'}`}>
|
||||
<div className='font-light'>
|
||||
{selected && <i className='mr-1 fas fa-tag' />}
|
||||
{tag.name + (tag.count ? `(${tag.count})` : '')} </div>
|
||||
</a>
|
||||
</Link>
|
||||
}
|
||||
|
||||
export default TagItemMiddle
|
||||
65
themes/matery/components/WordCount.js
Normal file
65
themes/matery/components/WordCount.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import { useEffect } from 'react'
|
||||
|
||||
/**
|
||||
* 字数统计
|
||||
* @returns
|
||||
*/
|
||||
export default function WordCount() {
|
||||
useEffect(() => {
|
||||
countWords()
|
||||
})
|
||||
|
||||
return <span id='wordCountWrapper' className='flex gap-3 font-light'>
|
||||
<span className='flex whitespace-nowrap'>
|
||||
<i className='mr-1 fas fa-file-word' />
|
||||
<span>文章字数</span>
|
||||
<span id='wordCount'>0</span></span>
|
||||
<span className='flex whitespace-nowrap'>
|
||||
<i className='mr-1 fas fa-clock' />
|
||||
<span>阅读时长:</span>
|
||||
<span id='readTime'>0</span> 分钟
|
||||
</span>
|
||||
</span>
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新字数统计和阅读时间
|
||||
*/
|
||||
function countWords() {
|
||||
const articleText = deleteHtmlTag(document.getElementById('notion-article')?.innerHTML)
|
||||
const wordCount = fnGetCpmisWords(articleText)
|
||||
// 阅读速度 300-500每分钟
|
||||
document.getElementById('wordCount').innerHTML = wordCount
|
||||
document.getElementById('readTime').innerHTML = Math.floor(wordCount / 400) + 1
|
||||
const wordCountWrapper = document.getElementById('wordCountWrapper')
|
||||
wordCountWrapper.classList.remove('hidden')
|
||||
}
|
||||
|
||||
// 去除html标签
|
||||
function deleteHtmlTag(str) {
|
||||
if (!str) {
|
||||
return ''
|
||||
}
|
||||
str = str.replace(/<[^>]+>|&[^>]+;/g, '').trim()// 去掉所有的html标签和 之类的特殊符合
|
||||
return str
|
||||
}
|
||||
|
||||
// 用word方式计算正文字数
|
||||
function fnGetCpmisWords(str) {
|
||||
if (!str) {
|
||||
return 0
|
||||
}
|
||||
let sLen = 0
|
||||
try {
|
||||
// eslint-disable-next-line no-irregular-whitespace
|
||||
str = str.replace(/(\r\n+|\s+| +)/g, '龘')
|
||||
// eslint-disable-next-line no-control-regex
|
||||
str = str.replace(/[\x00-\xff]/g, 'm')
|
||||
str = str.replace(/m+/g, '*')
|
||||
str = str.replace(/龘+/g, '')
|
||||
sLen = str.length
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
return sLen
|
||||
}
|
||||
Reference in New Issue
Block a user