magzine 微调

This commit is contained in:
tangly1024
2024-09-13 22:27:45 +08:00
parent 09f4e091a7
commit 3c4658baf5
8 changed files with 180 additions and 26 deletions

View File

@@ -7,9 +7,9 @@ export default function CategoryItem({ selected, category, categoryCount }) {
passHref
className={
(selected
? ' bg-gray-600 text-white '
? 'bg-gray-600 text-white '
: 'dark:text-gray-400 text-gray-900 ') +
'text-sm hover:underline flex text-md items-center duration-300 cursor-pointer py-1 whitespace-nowrap'
'text-sm font-semibold hover:underline flex text-md items-center duration-300 cursor-pointer py-1 whitespace-nowrap'
}>
<div>
{category} {categoryCount && `(${categoryCount})`}

View File

@@ -12,7 +12,7 @@ import { useRouter } from 'next/router'
* @constructor
*/
const PostGroupLatest = props => {
const { latestPosts } = props
const { latestPosts, vertical } = props
// 获取当前路径
const currentPath = useRouter().asPath
const { locale, siteInfo } = useGlobal()
@@ -23,12 +23,12 @@ const PostGroupLatest = props => {
return (
<>
{/* 标题 */}
<div className=' mb-2 px-1 flex flex-nowrap justify-between'>
<div className='mb-2 px-1 flex flex-nowrap justify-between'>
<div className='font-bold text-lg'>{locale.COMMON.LATEST_POSTS}</div>
</div>
{/* 文章列表 */}
<div className='grid grid-cols-1 lg:grid-cols-4'>
<div className={`grid grid-cols-1 ${!vertical ? 'lg:grid-cols-4' : ''}`}>
{latestPosts.map(post => {
const selected =
currentPath === `${siteConfig('SUB_PATH', '')}/${post.slug}`

View File

@@ -2,6 +2,7 @@ import LazyImage from '@/components/LazyImage'
import NotionIcon from '@/components/NotionIcon'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import { formatDateFmt } from '@/lib/utils/formatDate'
import Link from 'next/link'
import CategoryItem from './CategoryItem'
@@ -14,19 +15,19 @@ const PostItemCard = ({ post }) => {
const cover = post?.pageCoverThumbnail || siteInfo?.pageCover
return (
<div key={post.id} className='mb-6 max-w-screen-2xl'>
<div className='flex flex-col'>
<div className='flex flex-col space-y-3'>
{siteConfig('MAGZINE_POST_LIST_COVER') && (
<Link
href={post?.href}
passHref
className={
'cursor-pointer hover:underline leading-tight text-gray-700 dark:text-gray-300 hover:text-gray-500 dark:hover:text-gray-400'
'cursor-pointer hover:underline leading-tight text-gray-700 dark:text-gray-300 hover:text-gray-500 dark:hover:text-gray-400'
}>
<div className='w-full h-40 aspect-video overflow-hidden mb-2'>
<LazyImage
src={cover}
style={cover ? {} : { height: '0px' }}
className='w-full h-40 aspect-video object-cover hover:scale-125 duration-150'
className='w-full h-40 aspect-video object-cover'
/>
</div>
</Link>
@@ -39,7 +40,7 @@ const PostItemCard = ({ post }) => {
href={post?.href}
passHref
className={
'text-lg cursor-pointer hover:underline leading-tight text-gray-700 dark:text-gray-300 hover:text-gray-500 dark:hover:text-gray-400'
'text-xl cursor-pointer hover:underline leading-tight text-gray-700 dark:text-gray-300 hover:text-gray-500 dark:hover:text-gray-400'
}>
<h2>
{siteConfig('POST_TITLE_ICON') && (
@@ -49,7 +50,9 @@ const PostItemCard = ({ post }) => {
</h2>
</Link>
<div className='text-sm py-1'>{post.date?.start_date}</div>
<div className='text-sm'>
{formatDateFmt(post.publishDate, 'yyyy-MM')}
</div>
</div>
</div>
)

View File

@@ -1,6 +1,5 @@
import NotionIcon from '@/components/NotionIcon'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import Link from 'next/link'
import CategoryItem from './CategoryItem'
@@ -10,12 +9,10 @@ import CategoryItem from './CategoryItem'
* @returns
*/
const PostItemCardSimple = ({ post, showSummary }) => {
const showPreview = siteConfig('MAGZINE_POST_LIST_PREVIEW') && post.blockMap
const { locale } = useGlobal()
return (
<div
key={post.id}
className='lg:mb-6 max-w-screen-2xl border-t mr-8 py-2 gap-y-4 flex flex-col dark:border-gray-800 '>
className='lg:mb-6 max-w-screen-2xl border-t border-gray-300 mr-8 py-2 gap-y-3 flex flex-col dark:border-gray-800 '>
<div className='flex mr-2 items-center'>
{siteConfig('MAGZINE_POST_LIST_CATEGORY') && (
<CategoryItem category={post.category} />
@@ -35,7 +32,7 @@ const PostItemCardSimple = ({ post, showSummary }) => {
</h2>
</Link>
<div className='text-sm py-2 text-gray-700'>{post.date?.start_date}</div>
<div className='text-sm text-gray-700'>{post.date?.start_date}</div>
</div>
)
}

View File

@@ -1,6 +1,7 @@
import Link from 'next/link'
import PostItemCard from './PostItemCard'
import PostListEmpty from './PostListEmpty'
import Swiper from './Swiper'
/**
* 博文水平列表
@@ -15,22 +16,34 @@ const PostListHorizontal = ({ title, href, posts, hasBg }) => {
}
return (
<div className={`w-full py-10 px-2 lg:px-0 ${hasBg ? 'bg-[#F6F6F1] dark:bg-black' : ''}`}>
<div
className={`w-full py-10 px-2 lg:px-0 ${hasBg ? 'bg-[#F6F6F1] dark:bg-black' : ''}`}>
<div className='max-w-screen-2xl w-full mx-auto'>
{/* 标题 */}
<div className='flex justify-between items-center py-6'>
<h3 className='text-2xl'>{title}</h3>
<Link className='text-lg underline' href={href}>
<span>查看全部</span>
<i className='ml-2 fas fa-arrow-right' />
</Link>
{href && (
<Link className='hidden lg:block text-lg underline' href={href}>
<span>查看全部</span>
<i className='ml-2 fas fa-arrow-right' />
</Link>
)}
</div>
{/* 列表 */}
<ul className='grid grid-cols-1 lg:grid-cols-4 gap-4'>
<ul className='hidden lg:grid grid-cols-1 lg:grid-cols-4 gap-4'>
{posts?.map((p, index) => {
return <PostItemCard key={index} post={p} />
})}
</ul>
<div className='block lg:hidden px-2'>
<Swiper posts={posts} />
{href && (
<Link className='lg:hidden block text-lg underline' href={href}>
<span>查看全部</span>
<i className='ml-2 fas fa-arrow-right' />
</Link>
)}
</div>
</div>
</div>
)

View File

@@ -1,6 +1,7 @@
import { siteConfig } from '@/lib/config'
import PostItemCard from './PostItemCard'
import PostListEmpty from './PostListEmpty'
import Swiper from './Swiper'
/**
* 博文水平列表
@@ -25,11 +26,14 @@ const PostListRecommend = ({ latestPosts, allNavPages }) => {
<h3 className='text-4xl font-bold'>{title}</h3>
</div>
{/* 列表 */}
<ul className='flex flex-col lg:flex-row gap-4 lg:overflow-x-scroll'>
{recommendPosts?.map(p => {
return <PostItemCard key={p.id} post={p} />
<ul className='hidden lg:grid grid-cols-1 lg:grid-cols-4 gap-4'>
{recommendPosts?.map((p, index) => {
return <PostItemCard key={index} post={p} />
})}
</ul>
<div className='block lg:hidden px-2'>
<Swiper posts={recommendPosts} />
</div>
</div>
</div>
)

View File

@@ -0,0 +1,137 @@
import { useRef, useState } from 'react'
import PostItemCard from './PostItemCard'
const Swiper = ({ posts }) => {
const [currentIndex, setCurrentIndex] = useState(0)
const containerRef = useRef(null)
// 用于记录触摸开始和结束的水平位置
const touchStartPos = useRef({ x: 0, y: 0 })
const touchEndPos = useRef({ x: 0, y: 0 })
const isHorizontalSwipe = useRef(false)
const handleTouchStart = e => {
// 记录初始触摸位置
touchStartPos.current = {
x: e.touches[0].clientX,
y: e.touches[0].clientY
}
isHorizontalSwipe.current = false // 重置滑动方向标志
}
const handleTouchMove = e => {
const touch = e.touches[0]
const deltaX = touch.clientX - touchStartPos.current.x
const deltaY = touch.clientY - touchStartPos.current.y
// 判断是否为水平滑动(避免垂直滑动干扰)
if (!isHorizontalSwipe.current) {
isHorizontalSwipe.current = Math.abs(deltaX) > Math.abs(deltaY)
}
// 如果是水平滑动,阻止垂直滚动
if (isHorizontalSwipe.current) {
e.preventDefault() // 阻止垂直方向的默认滚动行为
}
}
const handleTouchEnd = e => {
if (isHorizontalSwipe.current) {
// 记录触摸结束位置
touchEndPos.current = {
x: e.changedTouches[0].clientX,
y: e.changedTouches[0].clientY
}
// 计算滑动距离
const deltaX = touchEndPos.current.x - touchStartPos.current.x
// 如果滑动距离足够大,则决定滑动到下一张或上一张卡片
const swipeThreshold = 50 // 设置滑动的阈值
if (deltaX > swipeThreshold) {
goToPrevious() // 向右滑动,上一张
} else if (deltaX < -swipeThreshold) {
goToNext() // 向左滑动,下一张
} else {
// 滑动距离不够,回到当前卡片
scrollToCard(currentIndex)
}
}
}
const goToPrevious = () => {
const newIndex = currentIndex === 0 ? posts.length - 1 : currentIndex - 1
setCurrentIndex(newIndex)
scrollToCard(newIndex)
}
const goToNext = () => {
const newIndex = currentIndex === posts.length - 1 ? 0 : currentIndex + 1
setCurrentIndex(newIndex)
scrollToCard(newIndex)
}
const scrollToCard = index => {
const container = containerRef.current
if (!container) return
const cardWidth = container.scrollWidth / posts.length
container.scrollTo({
left: index * cardWidth,
behavior: 'smooth'
})
}
const handleIndicatorClick = index => {
setCurrentIndex(index)
scrollToCard(index)
}
return (
<div className='relative w-full mx-auto'>
{/* 左侧点击区域 */}
<div
className='absolute inset-y-0 left-0 w-1/5 z-10'
onClick={goToPrevious}></div>
{/* 右侧点击区域 */}
<div
className='absolute inset-y-0 right-0 w-1/5 z-10'
onClick={goToNext}></div>
{/* Swiper Container */}
<div
ref={containerRef}
className='relative w-full overflow-x-scroll scroll-smooth py-4'
onTouchStart={handleTouchStart}
onTouchMove={handleTouchMove}
onTouchEnd={handleTouchEnd}
style={{ WebkitOverflowScrolling: 'touch' }} // iOS自然滚动支持
>
<div className='flex gap-x-4'>
{posts.map((item, index) => (
<div key={index} className='w-5/6 flex-shrink-0'>
<PostItemCard key={index} post={item} />
</div>
))}
</div>
</div>
{/* Indicator Dots */}
<div className='absolute bottom-0 left-0 right-0 flex justify-center space-x-2'>
{posts.map((_, index) => (
<button
key={index}
onClick={() => handleIndicatorClick(index)}
className={`w-3 h-3 rounded-full ${
currentIndex === index
? 'bg-black dark:bg-white'
: 'bg-gray-300 dark:bg-gray-700'
}`}></button>
))}
</div>
</div>
)
}
export default Swiper

View File

@@ -178,7 +178,7 @@ const LayoutSlug = props => {
{/* 文章区块分为三列 */}
<div className='grid grid-cols-1 lg:grid-cols-5 gap-8 py-12'>
<div className='h-full lg:col-span-1 hidden lg:contents'>
<div className='h-full lg:col-span-1 hidden lg:block'>
<Catalog toc={post?.toc} className='sticky top-20' />
</div>
@@ -231,7 +231,7 @@ const LayoutSlug = props => {
{/* 最新文章区块 */}
<div>
<PostGroupLatest {...props} />
<PostGroupLatest {...props} vertical={true} />
</div>
{/* 文章分类区块 */}