mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-14 15:09:22 +00:00
Merge branch 'tangly1024:main' into main
This commit is contained in:
@@ -84,8 +84,9 @@
|
||||
<td align="center"><a href="https://github.com/SkysCrystal"><img src="https://avatars.githubusercontent.com/u/49473463" width="64px;" alt="SkysCrystal"/><br/><sub><b>Simon Shi</b></sub></a><br/><a href="https://github.com/tangly1024/NotionNext/commits?author=SkysCrystal" title="SkysCrystal" >🔧 🐛</a></td>
|
||||
|
||||
<td align="center"><a href="https://github.com/siygle"><img src="https://avatars.githubusercontent.com/u/173408" width="64px;" alt="S.Y. Lee"/><br/><sub><b>S.Y. Lee</b></sub></a><br/><a href="https://github.com/tangly1024/NotionNext/commits?author=siygle" title="siygle" >🔧 🐛</a></td>
|
||||
|
||||
|
||||
|
||||
<td align="center"><a href="https://github.com/fighting-bug"><img src="https://avatars.githubusercontent.com/u/56441589" width="64px;" alt="fighting-buf"/><br/><sub><b>fighting-buf</b></sub></a><br/><a href="https://github.com/tangly1024/NotionNext/commits?author=fighting-bug" title="fighting-buf" >🔧 🐛</a></td>
|
||||
|
||||
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -2,10 +2,31 @@ import { useGlobal } from '@/lib/global'
|
||||
import { ReactCusdis } from 'react-cusdis'
|
||||
import BLOG from '@/blog.config'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
const CusdisComponent = ({ frontMatter }) => {
|
||||
const { locale } = useGlobal()
|
||||
const router = useRouter()
|
||||
const { isDarkMode } = useGlobal()
|
||||
|
||||
// 处理cusdis主题
|
||||
useEffect(() => {
|
||||
const cusdisThread = document?.getElementById('cusdis_thread')
|
||||
const cusdisIframe = cusdisThread?.getElementsByTagName('iframe')
|
||||
if (cusdisIframe) {
|
||||
const cusdisWrapper = cusdisIframe[0]?.contentDocument?.getElementById('root')
|
||||
if (isDarkMode) {
|
||||
cusdisWrapper?.classList?.remove('light')
|
||||
cusdisWrapper?.classList?.add('dark')
|
||||
} else {
|
||||
cusdisWrapper?.classList?.remove('dark')
|
||||
cusdisWrapper?.classList?.add('light')
|
||||
}
|
||||
if (!cusdisWrapper?.firstElementChild?.classList?.contains('dark:text-gray-100')) {
|
||||
cusdisWrapper?.firstElementChild?.classList?.add('dark:text-gray-100')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return <ReactCusdis
|
||||
lang={locale.LOCALE.toLowerCase()}
|
||||
|
||||
29
public/css/theme-fukasawa.css
Normal file
29
public/css/theme-fukasawa.css
Normal file
@@ -0,0 +1,29 @@
|
||||
#theme-fukasawa .grid-item {
|
||||
height: auto;
|
||||
break-inside: avoid-column;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
/* 大屏幕(宽度≥1024px)下显示3列 */
|
||||
@media (min-width: 1024px) {
|
||||
#theme-fukasawa .grid-container {
|
||||
column-count: 3;
|
||||
column-gap: .5rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* 小屏幕(宽度≥640px)下显示2列 */
|
||||
@media (min-width: 640px) and (max-width: 1023px) {
|
||||
#theme-fukasawa .grid-container {
|
||||
column-count: 2;
|
||||
column-gap: .5rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* 移动端(宽度<640px)下显示1列 */
|
||||
@media (max-width: 639px) {
|
||||
#theme-fukasawa .grid-container {
|
||||
column-count: 1;
|
||||
column-gap: .5rem;
|
||||
}
|
||||
}
|
||||
@@ -2010,4 +2010,11 @@ code.language-mermaid {
|
||||
|
||||
.notion-equation-inline .katex-display {
|
||||
margin: 0 0 !important;
|
||||
}
|
||||
|
||||
.two-line-clamp {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import TopNav from './components/TopNav'
|
||||
import AsideLeft from './components/AsideLeft'
|
||||
import Live2D from '@/components/Live2D'
|
||||
import BLOG from '@/blog.config'
|
||||
import { isBrowser, loadExternalResource } from '@/lib/utils'
|
||||
|
||||
/**
|
||||
* 基础布局 采用左右两侧布局,移动端使用顶部导航栏
|
||||
@@ -25,6 +26,11 @@ const LayoutBase = (props) => {
|
||||
meta
|
||||
} = props
|
||||
const leftAreaSlot = <Live2D/>
|
||||
|
||||
if (isBrowser()) {
|
||||
loadExternalResource('/css/theme-fukasawa.css', 'css')
|
||||
}
|
||||
|
||||
return (<div id='theme-fukasawa' >
|
||||
<CommonHead meta={meta} />
|
||||
<TopNav {...props}/>
|
||||
|
||||
@@ -2,9 +2,8 @@ import BLOG from '@/blog.config'
|
||||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
import CONFIG_FUKA from '../config_fuka'
|
||||
import Card from './Card'
|
||||
|
||||
const BlogCard = ({ post, showSummary, siteInfo }) => {
|
||||
const BlogCard = ({ index, post, showSummary, siteInfo }) => {
|
||||
const showPreview = CONFIG_FUKA.POST_LIST_PREVIEW && post.blockMap
|
||||
// matery 主题默认强制显示图片
|
||||
if (post && !post.page_cover) {
|
||||
@@ -13,44 +12,45 @@ const BlogCard = ({ post, showSummary, siteInfo }) => {
|
||||
const showPageCover = CONFIG_FUKA.POST_LIST_COVER && post?.page_cover
|
||||
|
||||
return (
|
||||
<Card className="w-full lg:max-w-sm p-2 h-full overflow-auto">
|
||||
<div
|
||||
key={post.id}
|
||||
className="flex flex-col-reverse justify-between duration-300"
|
||||
>
|
||||
<div className="p-2 flex flex-col w-full">
|
||||
<Link
|
||||
href={`${BLOG.SUB_PATH}/${post.slug}`}
|
||||
passHref
|
||||
className={`break-words cursor-pointer font-bold hover:underline text-xl ${showPreview ? 'justify-center' : 'justify-start'
|
||||
} leading-tight text-gray-700 dark:text-gray-100 hover:text-blue-500 dark:hover:text-blue-400`}>
|
||||
<div data-aos="fade-up" data-aos-duration="500" data-aos-once="true"
|
||||
className='w-full lg:max-w-sm p-2 h-full overflow-auto'>
|
||||
<section className="shadow mb-4 p-2 bg-white dark:bg-hexo-black-gray hover:shadow-lg duration-200">
|
||||
<div className="flex flex-col-reverse justify-between duration-300">
|
||||
<div className="p-2 flex flex-col w-full">
|
||||
<Link
|
||||
href={`${BLOG.SUB_PATH}/${post.slug}`}
|
||||
passHref
|
||||
className={`break-words cursor-pointer font-bold hover:underline text-xl ${showPreview ? 'justify-center' : 'justify-start'}
|
||||
leading-tight text-gray-700 dark:text-gray-100 hover:text-blue-500 dark:hover:text-blue-400`}>
|
||||
|
||||
{post.title}
|
||||
{post.title}
|
||||
|
||||
</Link>
|
||||
</Link>
|
||||
|
||||
{(!showPreview || showSummary) && (
|
||||
<p className="mt-4 mb-4 text-gray-700 dark:text-gray-300 text-sm font-light leading-7 overflow-hidden">
|
||||
{post.summary}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{showPageCover && (
|
||||
<Link href={`${BLOG.SUB_PATH}/${post.slug}`} passHref legacyBehavior>
|
||||
<div className="h-40 w-full relative duration-200 cursor-pointer transform overflow-hidden">
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src={post?.page_cover}
|
||||
alt={post.title}
|
||||
className="w-full hover:scale-125 transform duration-500"
|
||||
></img>
|
||||
{/* <Image className='hover:scale-105 transform duration-500' src={post?.page_cover} alt={post.title} layout='fill' objectFit='cover' loading='lazy' /> */}
|
||||
{(!showPreview || showSummary) && (
|
||||
<p className="mt-4 mb-4 text-gray-700 dark:text-gray-300 text-sm font-light leading-7 overflow-hidden">
|
||||
{post.summary}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{showPageCover && (
|
||||
<Link href={`${BLOG.SUB_PATH}/${post.slug}`} passHref legacyBehavior>
|
||||
<div className="h-40 w-full relative duration-200 cursor-pointer transform overflow-hidden">
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src={post?.page_cover}
|
||||
alt={post.title}
|
||||
className="w-full hover:scale-125 transform duration-500"
|
||||
></img>
|
||||
{/* <Image className='hover:scale-105 transform duration-500' src={post?.page_cover} alt={post.title} layout='fill' objectFit='cover' loading='lazy' /> */}
|
||||
</div>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import BLOG from '@/blog.config'
|
||||
import { useEffect, useState } from 'react'
|
||||
import BlogCard from './BlogCard'
|
||||
import BlogPostListEmpty from './BlogListEmpty'
|
||||
import PaginationSimple from './PaginationSimple'
|
||||
@@ -15,25 +14,6 @@ import PaginationSimple from './PaginationSimple'
|
||||
const BlogListPage = ({ page = 1, posts = [], postCount, siteInfo }) => {
|
||||
const totalPage = Math.ceil(postCount / BLOG.POSTS_PER_PAGE)
|
||||
const showNext = page < totalPage
|
||||
const [colCount, changeCol] = useState(1)
|
||||
|
||||
function updateCol() {
|
||||
if (window.outerWidth > 1200) {
|
||||
changeCol(3)
|
||||
} else if (window.outerWidth > 900) {
|
||||
changeCol(2)
|
||||
} else {
|
||||
changeCol(1)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
updateCol()
|
||||
window.addEventListener('resize', updateCol)
|
||||
return () => {
|
||||
window.removeEventListener('resize', updateCol)
|
||||
}
|
||||
})
|
||||
|
||||
if (!posts || posts.length === 0) {
|
||||
return <BlogPostListEmpty />
|
||||
@@ -41,10 +21,10 @@ const BlogListPage = ({ page = 1, posts = [], postCount, siteInfo }) => {
|
||||
return (
|
||||
<div>
|
||||
{/* 文章列表 */}
|
||||
<div id="container" style={{ columnCount: colCount }}>
|
||||
<div id="container" className='grid-container'>
|
||||
{posts?.map(post => (
|
||||
<div key={post.id} className='justify-center flex' style={{ breakInside: 'avoid' }}>
|
||||
<BlogCard key={post.id} post={post} siteInfo={siteInfo} />
|
||||
<div key={post.id} className='grid-item justify-center flex' style={{ breakInside: 'avoid' }}>
|
||||
<BlogCard index={posts.indexOf(post)} key={post.id} post={post} siteInfo={siteInfo} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -14,18 +14,7 @@ import { useGlobal } from '@/lib/global'
|
||||
*/
|
||||
const BlogListScroll = props => {
|
||||
const { posts = [], siteInfo } = props
|
||||
const [colCount, changeCol] = React.useState(1)
|
||||
const { locale } = useGlobal()
|
||||
|
||||
function updateCol() {
|
||||
if (window.outerWidth > 1200) {
|
||||
changeCol(3)
|
||||
} else if (window.outerWidth > 900) {
|
||||
changeCol(2)
|
||||
} else {
|
||||
changeCol(1)
|
||||
}
|
||||
}
|
||||
const targetRef = React.useRef(null)
|
||||
|
||||
const [page, updatePage] = React.useState(1)
|
||||
@@ -56,29 +45,23 @@ const BlogListScroll = props => {
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
updateCol()
|
||||
window.addEventListener('scroll', scrollTrigger)
|
||||
|
||||
window.addEventListener('resize', updateCol)
|
||||
return () => {
|
||||
window.removeEventListener('resize', updateCol)
|
||||
window.removeEventListener('scroll', scrollTrigger)
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
|
||||
if (!posts || posts.length === 0) {
|
||||
return <BlogPostListEmpty />
|
||||
} else {
|
||||
return (
|
||||
<div id="container" ref={targetRef} >
|
||||
<div id="container" ref={targetRef} className='grid-container' >
|
||||
{/* 文章列表 */}
|
||||
<div style={{ columnCount: colCount }}>
|
||||
{postsToShow?.map(post => (
|
||||
<div key={post.id} className='justify-center flex' style={{ breakInside: 'avoid' }}>
|
||||
<BlogCard key={post.id} post={post} siteInfo={siteInfo} />
|
||||
<div key={post.id} className='grid-item justify-center flex' style={{ breakInside: 'avoid' }}>
|
||||
<BlogCard index={posts.indexOf(post)} key={post.id} post={post} siteInfo={siteInfo} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="w-full my-4 py-4 text-center cursor-pointer "
|
||||
onClick={handleGetMore}>
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
const Card = ({ children, headerSlot, className }) => {
|
||||
return <div className={className}
|
||||
data-aos="fade-up"
|
||||
data-aos-duration="300"
|
||||
data-aos-once="false"
|
||||
data-aos-anchor-placement="top-bottom"
|
||||
>
|
||||
return <div data-aos="fade-in" data-aos-duration="1000" className={className}>
|
||||
<>{headerSlot}</>
|
||||
<section className="shadow mb-4 p-2 bg-white dark:bg-hexo-black-gray hover:shadow-lg duration-200">
|
||||
{children}
|
||||
|
||||
@@ -41,15 +41,14 @@ export const BlogPostCardInfo = ({ post, showPreview, showPageCover, showSummary
|
||||
|
||||
{/* 摘要 */}
|
||||
{(!showPreview || showSummary) && !post.results && (
|
||||
<p style={{ overflow: 'hidden', textOverflow: 'ellipsis', display: '-webkit-box', WebkitLineClamp: '3', WebkitBoxOrient: 'vertical' }}
|
||||
className="replace my-3 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
|
||||
<p className="two-line-clamp replace my-3 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
|
||||
{post.summary}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* 搜索结果 */}
|
||||
{post.results && (
|
||||
<p className="mt-4 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
|
||||
<p className="two-line-clamp mt-4 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
|
||||
{post.results.map(r => (
|
||||
<span key={r}>{r}</span>
|
||||
))}
|
||||
|
||||
@@ -8,6 +8,7 @@ const MenuButtonGroupTop = (props) => {
|
||||
const { locale } = useGlobal()
|
||||
|
||||
let links = [
|
||||
{ icon: 'fa-solid fa-house', name: locale.NAV.INDEX, to: '/', show: CONFIG_HEXO.MENU_INDEX },
|
||||
{ icon: 'fas fa-search', name: locale.NAV.SEARCH, to: '/search', show: CONFIG_HEXO.MENU_SEARCH },
|
||||
{ icon: 'fas fa-archive', name: locale.NAV.ARCHIVE, to: '/archive', show: CONFIG_HEXO.MENU_ARCHIVE }
|
||||
// { icon: 'fas fa-folder', name: locale.COMMON.CATEGORY, to: '/category', show: CONFIG_HEXO.MENU_CATEGORY },
|
||||
@@ -36,12 +37,12 @@ const MenuButtonGroupTop = (props) => {
|
||||
</div>
|
||||
|
||||
</Link>
|
||||
);
|
||||
)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
})}
|
||||
</nav>
|
||||
);
|
||||
)
|
||||
}
|
||||
export default MenuButtonGroupTop
|
||||
|
||||
@@ -6,6 +6,7 @@ const CONFIG_HEXO = {
|
||||
HOME_NAV_BACKGROUND_IMG_FIXED: true, // 首页背景图滚动时是否固定,true 则滚动时图片不懂; false则随鼠标滚动
|
||||
|
||||
// 菜单配置
|
||||
MENU_INDEX: true, // 显示首页
|
||||
MENU_CATEGORY: true, // 显示分类
|
||||
MENU_TAG: true, // 显示标签
|
||||
MENU_ARCHIVE: true, // 显示归档
|
||||
|
||||
@@ -20,10 +20,10 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
|
||||
data-aos-delay={delay}
|
||||
data-aos-once="true"
|
||||
data-aos-anchor-placement="top-bottom"
|
||||
className="w-full mb-4 h-full overflow-auto shadow-md border dark:border-black rounded-xl bg-white dark:bg-hexo-black-gray">
|
||||
className="w-full mb-4 overflow-auto shadow-md border dark:border-black rounded-xl bg-white dark:bg-hexo-black-gray">
|
||||
|
||||
{/* 固定高度 ,空白用图片拉升填充 */}
|
||||
<div key={post.id} className="flex flex-col h-96 justify-between">
|
||||
<div className="flex flex-col h-80 justify-between">
|
||||
|
||||
{/* 头部图片 填充卡片 */}
|
||||
{showPageCover && (
|
||||
@@ -36,22 +36,12 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
|
||||
alt={post.title}
|
||||
className="opacity-50 h-full w-full hover:scale-125 rounded-t-md transform object-cover duration-500"
|
||||
/>
|
||||
{/* <div className='relative w-full'>
|
||||
<Image
|
||||
className='hover:scale-125 opacity-50 transition cursor-pointer duration-500'
|
||||
src={post?.page_cover}
|
||||
alt={post.title}
|
||||
quality={30}
|
||||
placeholder='blur'
|
||||
blurDataURL='/bg_image.jpg'
|
||||
style={{ objectFit: 'cover' }}
|
||||
fill/>
|
||||
</div> */}
|
||||
<span className='absolute bottom-0 left-0 text-white p-6 text-2xl replace' > {post.title}</span>
|
||||
<span className='absolute bottom-0 left-0 text-white p-6 text-2xl replace break-words w-full' > {post.title}</span>
|
||||
</div>
|
||||
</Link>
|
||||
)}
|
||||
|
||||
{/* 文字描述 */}
|
||||
<div >
|
||||
{/* 描述 */}
|
||||
<div className="px-4 flex flex-col w-full text-gray-700 dark:text-gray-300">
|
||||
|
||||
@@ -21,9 +21,9 @@ const BlogPostListPage = ({ page = 1, posts = [], postCount, siteInfo }) => {
|
||||
<div id="container" className='w-full'>
|
||||
<div className='pt-6'></div>
|
||||
{/* 文章列表 */}
|
||||
<div className="px-4 pt-4 xl:columns-3 md:columns-2 pb-24" >
|
||||
<div className="px-4 pt-4 flex flex-wrap pb-24" >
|
||||
{posts.map(post => (
|
||||
<BlogPostCard index={posts.indexOf(post)} key={post.id} post={post} siteInfo={siteInfo} />
|
||||
<div key={post.id} className='xl:w-1/3 md:w-1/2 w-full p-4'> <BlogPostCard index={posts.indexOf(post)} post={post} siteInfo={siteInfo} /></div>
|
||||
))}
|
||||
</div>
|
||||
{showPagination && <PaginationSimple page={page} totalPage={totalPage} />}
|
||||
|
||||
@@ -57,9 +57,11 @@ const BlogPostListScroll = ({ posts = [], currentSearch, showSummary = CONFIG_MA
|
||||
return <div id='container' ref={targetRef} className='w-full'>
|
||||
|
||||
{/* 文章列表 */}
|
||||
<div className='flex flex-wrap space-y-1 lg:space-y-4 px-2'>
|
||||
<div className="px-4 pt-4 flex flex-wrap pb-24" >
|
||||
{postsToShow.map(post => (
|
||||
<BlogPostCard index={posts.indexOf(post)} key={post.id} post={post} showSummary={showSummary} siteInfo={siteInfo}/>
|
||||
<div key={post.id} className='xl:w-1/3 md:w-1/2 w-full p-4'>
|
||||
<BlogPostCard index={posts.indexOf(post)} post={post} siteInfo={siteInfo} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user