This commit is contained in:
tangly1024
2024-02-01 20:43:34 +08:00
47 changed files with 319 additions and 235 deletions

View File

@@ -37,6 +37,8 @@ const BLOG = {
BLOG_FAVICON: process.env.NEXT_PUBLIC_FAVICON || '/favicon.ico', // blog favicon 配置, 默认使用 /public/favicon.ico支持在线图片如 https://img.imesong.com/favicon.png
IMAGE_COMPRESS_WIDTH: process.env.NEXT_PUBLIC_IMAGE_COMPRESS_WIDTH || 800, // 图片压缩宽度默认值,作用于博客封面和文章内容 越小加载图片越快
IMAGE_ZOOM_IN_WIDTH: process.env.NEXT_PUBLIC_IMAGE_ZOOM_IN_WIDTH || 1200, // 文章图片点击放大后的画质宽度,不代表在网页中的实际展示宽度
RANDOM_IMAGE_URL: process.env.NEXT_PUBLIC_RANDOM_IMAGE_URL || '', // 随机图片API,如果未配置下面的关键字,主页封面,头像,文章封面图都会被替换为随机图片
RANDOM_IMAGE_REPLACE_TEXT: process.env.NEXT_PUBLIC_RANDOM_IMAGE_NOT_REPLACE_TEXT || 'images.unsplash.com', // 触发替换图片的 url 关键字(多个支持用英文逗号分开)只有图片地址中包含此关键字才会替换为上方随机图片url
// eg: images.unsplash.com(notion图床的所有图片都会替换),如果你在 notion 里已经添加了一个随机图片 url恰巧那个服务跑路或者挂掉想一键切换所有配图可以将该 url 配置在这里

View File

@@ -2,7 +2,7 @@ import dynamic from 'next/dynamic'
import mediumZoom from '@fisch0920/medium-zoom'
import { useEffect, useRef } from 'react'
import 'katex/dist/katex.min.css'
import { mapImgUrl } from '@/lib/notion/mapImage'
import { compressImage, mapImgUrl } from '@/lib/notion/mapImage'
import { isBrowser } from '@/lib/utils'
import { siteConfig } from '@/lib/config'
import { NotionRenderer } from 'react-notion-x'
@@ -61,6 +61,11 @@ const Tweet = ({ id }) => {
return <TweetEmbed tweetId={id} />
}
/**
* Notin渲染成网页的核心组件
* @param {*} param0
* @returns
*/
const NotionPage = ({ post, className }) => {
useEffect(() => {
autoScrollToTarget()
@@ -74,6 +79,8 @@ const NotionPage = ({ post, className }) => {
const zoomRef = useRef(zoom ? zoom.clone() : null)
useEffect(() => {
if (!isBrowser) return;
// 将相册gallery下的图片加入放大功能
if (siteConfig('POST_DISABLE_GALLERY_CLICK')) {
setTimeout(() => {
@@ -111,6 +118,30 @@ const NotionPage = ({ post, className }) => {
}
}
}
// 放大图片:调整图片质量
const observer = new MutationObserver((mutationsList, observer) => {
mutationsList.forEach(mutation => {
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
if (mutation.target.classList.contains('medium-zoom-image--opened')) {
// 等待动画完成后替换为更高清的图像
setTimeout(() => {
// 获取该元素的 src 属性
const src = mutation?.target?.getAttribute('src');
// 替换为更高清的图像
mutation?.target?.setAttribute('src', compressImage(src, siteConfig('IMAGE_ZOOM_IN_WIDTH', 1200)));
}, 800);
}
}
});
});
// 监视整个文档中的元素和属性的变化
observer.observe(document.body, { attributes: true, subtree: true, attributeFilter: ['class'] });
return () => {
observer.disconnect();
};
}, [])
if (!post || !post.blockMap) {

View File

@@ -25,7 +25,9 @@ const ThemeSwitch = () => {
const query = router.query
query.theme = newTheme
router.push({ pathname: router.pathname, query }).then(() => {
setIsLoading(false)
setTimeout(() => {
setIsLoading(false)
}, 500);
})
}
@@ -72,8 +74,8 @@ const ThemeSwitch = () => {
</Draggable>
{/* 切换主题加载时的全屏遮罩 */}
<div className={`${isLoading ? 'opacity-50 ' : 'opacity-0'}
w-screen h-screen bg-black text-white shadow-text flex justify-center items-center
<div className={`${isLoading ? 'opacity-90 ' : 'opacity-0'}
w-screen h-screen glassmorphism bg-black text-white shadow-text flex justify-center items-center
transition-all fixed top-0 left-0 pointer-events-none duration-1000 z-50 shadow-inner`}>
<i className='text-3xl mr-5 fas fa-spinner animate-spin' />
</div>

View File

@@ -7,7 +7,7 @@ import { getAllCategories } from './getAllCategories'
import getAllPageIds from './getAllPageIds'
import { getAllTags } from './getAllTags'
import getPageProperties from './getPageProperties'
import { mapImgUrl, compressImage } from './mapImage'
import { compressImage, mapImgUrl } from './mapImage'
import { getConfigMapFromConfigPage } from './getNotionConfig'
/**

View File

@@ -1,4 +1,5 @@
import BLOG from '@/blog.config'
import { siteConfig } from '../config'
/**
* 图片映射
@@ -58,7 +59,7 @@ const mapImgUrl = (img, block, type = 'block', from = 'post') => {
// 统一压缩图片
if (from === 'pageCoverThumbnail' || block.type === 'image' || block.type === 'page') {
const width = block?.format?.block_width || 200
const width = block?.format?.block_width
ret = compressImage(ret, width)
}
@@ -81,19 +82,29 @@ function isEmoji(str) {
* 2. UnPlash 图片可以通过api q=50 控制压缩质量 width=400 控制图片尺寸
* @param {*} image
*/
const compressImage = (image, width = 800, quality = 50, fmt = 'webp') => {
if (!image) {
return null
const compressImage = (image, width, quality = 50, fmt = 'webp') => {
if (!image || image.indexOf('http') !== 0) {
return image
}
if (!width || width === 0) {
width = siteConfig('IMAGE_COMPRESS_WIDTH')
}
// 将URL解析为一个对象
const urlObj = new URL(image)
// 获取URL参数
const params = new URLSearchParams(urlObj.search)
// Notion图床
if (image.indexOf(BLOG.NOTION_HOST) === 0 && image.indexOf('amazonaws.com') > 0) {
return `${image}&width=${width}&cache=v2`
}
// 压缩unsplash图片
if (image.indexOf('https://images.unsplash.com/') === 0) {
// 将URL解析为一个对象
const urlObj = new URL(image)
// 获取URL参数
const params = new URLSearchParams(urlObj.search)
params.set('width', width)
params.set('cache', 'v2')
// 生成新的URL
urlObj.search = params.toString()
return urlObj.toString()
} else if (image.indexOf('https://images.unsplash.com/') === 0) {
// 压缩unsplash图片
// 将q参数的值替换
params.set('q', quality)
// 尺寸
@@ -104,11 +115,9 @@ const compressImage = (image, width = 800, quality = 50, fmt = 'webp') => {
// 生成新的URL
urlObj.search = params.toString()
return urlObj.toString()
}
// 此处还可以添加您的自定义图传的封面图压缩参数。
} else if (image.indexOf('https://your_picture_bed') === 0) {
// 此处还可以添加您的自定义图传的封面图压缩参数。
// .e.g
if (image.indexOf('https://your_picture_bed') === 0) {
return 'do_somethin_here'
}

View File

@@ -30,6 +30,33 @@ export const memorize = (Component) => {
}
return memo(MemoizedComponent)
}
// 转换外链
export function sliceUrlFromHttp(str) {
// 检查字符串是否包含http
if (str.includes('http')) {
// 如果包含找到http的位置
const index = str.indexOf('http');
// 返回http之后的部分
return str.slice(index, str.length);
} else {
// 如果不包含,返回原字符串
return str;
}
}
// 检查是否外链
export function checkContainHttp(str) {
// 检查字符串是否包含http
if (str.includes('http')) {
// 如果包含找到http的位置
return str.indexOf('http') > -1
} else {
// 不包含
return false;
}
}
/**
* 加载外部资源
* @param url 地址 例如 https://xx.com/xx.js

View File

@@ -28,7 +28,7 @@ class MyDocument extends Document {
})}
</Head>
<body className={`${BLOG.FONT_STYLE} font-light scroll-smooth`}>
<body className={`${BLOG.FONT_STYLE} dark:bg-black font-light scroll-smooth`}>
<Main />
<NextScript />
</body>

View File

@@ -950,6 +950,7 @@ code[class*='language-'] {
margin-left: 8px;
white-space: pre-wrap;
word-break: break-word;
overflow: hidden;
}
.notion-toggle {

View File

@@ -1,4 +1,5 @@
import { siteConfig } from '@/lib/config'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
import Link from 'next/link'
/**
@@ -14,8 +15,10 @@ export default function BlogListGroupByDate({ archiveTitle, archivePosts }) {
</div>
<ul>
{archivePosts[archiveTitle].map(post => (
<li
{archivePosts[archiveTitle].map(post => {
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return <li
key={post.id}
className="border-l-2 p-1 text-xs md:text-base items-center hover:scale-x-105 hover:border-gray-500 dark:hover:border-gray-300 dark:border-gray-400 transform duration-500"
>
@@ -24,12 +27,12 @@ export default function BlogListGroupByDate({ archiveTitle, archivePosts }) {
{post?.publishDay}
</span>{' '}
&nbsp;
<Link href={`${siteConfig('SUB_PATH', '')}/${post.slug}`} className="dark:text-gray-400 dark:hover:text-gray-300 overflow-x-hidden hover:underline cursor-pointer text-gray-600">
<Link href={url} className="dark:text-gray-400 dark:hover:text-gray-300 overflow-x-hidden hover:underline cursor-pointer text-gray-600">
{post.title}
</Link>
</div>
</li>
))}
})}
</ul>
</div>
}

View File

@@ -3,9 +3,11 @@ import CONFIG from '../config'
import Link from 'next/link'
import TwikooCommentCount from '@/components/TwikooCommentCount'
import LazyImage from '@/components/LazyImage'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
const BlogPostCard = ({ post }) => {
const showPageCover = siteConfig('EXAMPLE_POST_LIST_COVER', null, CONFIG) && post?.pageCoverThumbnail
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return <article className={`${showPageCover ? 'flex md:flex-row flex-col-reverse' : ''} replace mb-12 `}>
<div className={`${showPageCover ? 'md:w-7/12' : ''}`}>
@@ -41,7 +43,7 @@ const BlogPostCard = ({ post }) => {
{/* 图片封面 */}
{showPageCover && (
<div className="md:w-5/12 w-full h-44 overflow-hidden p-1">
<Link href={`${siteConfig('SUB_PATH', '')}/${post.slug}`} passHref legacyBehavior>
<Link href={url} passHref legacyBehavior>
<LazyImage src={post?.pageCoverThumbnail} className='w-full bg-cover hover:scale-110 duration-200' />
</Link>
</div>

View File

@@ -9,11 +9,14 @@ import Announcement from './Announcement'
import { useRouter } from 'next/router'
import DarkModeButton from '@/components/DarkModeButton'
import SocialButton from './SocialButton'
import { useFukasawaGlobal } from '..'
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, useState } from 'react'
import { isBrowser } from '@/lib/utils'
import { debounce } from 'lodash'
/**
* 侧边栏
@@ -23,39 +26,59 @@ import MailChimpForm from './MailChimpForm'
function AsideLeft(props) {
const { tagOptions, currentTag, categoryOptions, currentCategory, post, slot, notice } = props
const router = useRouter()
const { isCollapsed, setIsCollapse } = useFukasawaGlobal()
const { fullWidth } = useGlobal()
const FUKASAWA_SIDEBAR_COLLAPSE_SATUS_DEFAULT = fullWidth || siteConfig('FUKASAWA_SIDEBAR_COLLAPSE_SATUS_DEFAULT', null, CONFIG)
// 侧边栏折叠从 本地存储中获取 open 状态的初始值
const [isCollapsed, setIsCollapse] = useState(() => {
if (typeof window !== 'undefined') {
return localStorage.getItem('fukasawa-sidebar-collapse') === 'true' || FUKASAWA_SIDEBAR_COLLAPSE_SATUS_DEFAULT
}
return FUKASAWA_SIDEBAR_COLLAPSE_SATUS_DEFAULT
})
// 在组件卸载时保存 open 状态到本地存储中
useEffect(() => {
if (isBrowser) {
localStorage.setItem('fukasawa-sidebar-collapse', isCollapsed)
}
}, [isCollapsed])
// 折叠侧边栏
const toggleOpen = () => {
setIsCollapse(!isCollapsed)
}
// 自动折叠侧边栏 onResize 窗口宽度小于1366 || 滚动条滚动至页面的300px时 ; 将open设置为false
// useEffect(() => {
// const handleResize = debounce(() => {
// if (window.innerWidth < 1366 || window.scrollY >= 100) {
// setIsCollapse(true)
// } else {
// setIsCollapse(false)
// }
// }, 100)
useEffect(() => {
if (!siteConfig('FUKASAWA_SIDEBAR_COLLAPSE_ON_SCROLL', false, CONFIG)) {
return
}
const handleResize = debounce(() => {
if (window.innerWidth < 1366 || window.scrollY >= 1366) {
setIsCollapse(true)
} else {
setIsCollapse(false)
}
}, 100)
// console.log('router', router)
// if (router.pathname === '/[...slug]') {
// window.addEventListener('resize', handleResize)
// window.addEventListener('scroll', handleResize, { passive: true })
// }
if (post) {
window.addEventListener('resize', handleResize)
window.addEventListener('scroll', handleResize, { passive: true })
}
// return () => {
// if (router.pathname === '/[...slug]') {
// window.removeEventListener('resize', handleResize)
// window.removeEventListener('scroll', handleResize, { passive: true })
// }
// }
// }, [])
return () => {
if (post) {
window.removeEventListener('resize', handleResize)
window.removeEventListener('scroll', handleResize, { passive: true })
}
}
}, [])
return <div className={`sideLeft relative ${isCollapsed ? 'w-0' : 'w-80'} duration-150 transition-all bg-white dark:bg-hexo-black-gray min-h-screen hidden lg:block z-20`}>
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={`${isCollapsed ? '' : 'ml-80'} hidden lg:block sticky top-0 mx-2 cursor-pointer hover:scale-110 duration-150 px-3 py-2`} onClick={toggleOpen}>
{siteConfig('FUKASAWA_SIDEBAR_COLLAPSE_BUTTON', null, CONFIG) && <div className={`${isCollapsed ? '' : 'ml-80'} hidden lg:block sticky top-0 mx-2 cursor-pointer hover:scale-110 duration-300 px-3 py-2`} onClick={toggleOpen}>
{isCollapsed ? <i className="fa-solid fa-indent text-xl"></i> : <i className='fas fa-bars text-xl'></i>}
</div>}

View File

@@ -3,7 +3,13 @@ import Link from 'next/link'
import TagItemMini from './TagItemMini'
import CONFIG from '../config'
import LazyImage from '@/components/LazyImage'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
/**
* 文章列表卡片
* @param {*} param0
* @returns
*/
const BlogCard = ({ index, post, showSummary, siteInfo }) => {
const showPreview = siteConfig('FUKASAWA_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap
// fukasawa 强制显示图片
@@ -11,22 +17,29 @@ const BlogCard = ({ index, post, showSummary, siteInfo }) => {
post.pageCoverThumbnail = siteInfo?.pageCover
}
const showPageCover = siteConfig('FUKASAWA_POST_LIST_COVER', null, CONFIG) && post?.pageCoverThumbnail
const SUB_PATH = siteConfig('SUB_PATH', '')
const FUKASAWA_POST_LIST_ANIMATION = siteConfig('FUKASAWA_POST_LIST_ANIMATION', null, CONFIG)
// 动画样式 首屏卡片不用,后面翻出来的加动画
const aosProps = FUKASAWA_POST_LIST_ANIMATION
? {
'data-aos': 'fade-up',
'data-aos-duration': '300',
'data-aos-once': 'true',
'data-aos-anchor-placement': 'top-bottom'
}
: {}
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return (
<div
data-aos="fade-up"
data-aos-duration="600"
data-aos-once="true"
data-aos-anchor-placement="top-bottom"
style={{ maxHeight: '60rem' }}
<div {...aosProps} style={{ maxHeight: '60rem' }}
className="w-full lg:max-w-sm p-3 shadow mb-4 mx-2 bg-white dark:bg-hexo-black-gray hover:shadow-lg duration-200"
>
<div className="flex flex-col justify-between h-full">
{/* 封面图 */}
{showPageCover && (
<div className="flex-grow mb-3 w-full duration-200 cursor-pointer transform overflow-hidden">
<Link href={`${SUB_PATH}/${post.slug}`} passHref legacyBehavior>
<Link href={url} passHref legacyBehavior>
<LazyImage
src={post?.pageCoverThumbnail}
alt={post?.title || siteConfig('TITLE')}
@@ -38,7 +51,7 @@ const BlogCard = ({ index, post, showSummary, siteInfo }) => {
{/* 文字部分 */}
<div className="flex flex-col w-full">
<Link passHref href={`${SUB_PATH}/${post.slug}`}
<Link passHref href={url}
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}

View File

@@ -1,5 +1,6 @@
import Link from 'next/link'
import { siteConfig } from '@/lib/config'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
/**
* 博客归档
@@ -21,8 +22,9 @@ const BlogArchiveItem = ({ posts = [], archiveTitle }) => {
{archiveTitle}
</div>
<ul>
{posts?.map(post => (
<li
{posts?.map(post => {
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return <li
key={post.id}
className="border-l-2 p-1 text-xs md:text-base items-center hover:scale-x-105 hover:border-gray-500 dark:hover:border-gray-300 dark:border-gray-400 transform duration-500"
>
@@ -30,7 +32,7 @@ const BlogArchiveItem = ({ posts = [], archiveTitle }) => {
<span className="text-gray-400">{post.date?.start_date}</span>{' '}
&nbsp;
<Link
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
href={url}
passHref
className="dark:text-gray-400 dark:hover:text-gray-300 overflow-x-hidden hover:underline cursor-pointer text-gray-600">
@@ -39,7 +41,7 @@ const BlogArchiveItem = ({ posts = [], archiveTitle }) => {
</Link>
</div>
</li>
))}
})}
</ul>
</div>
)

View File

@@ -44,7 +44,7 @@ export const MenuItemCollapse = (props) => {
<div><div className={`${link.icon} text-center w-4 mr-4`} />{link.name}</div>
<div className='inline-flex items-center '><i className={`px-2 fas fa-chevron-right transition-all duration-200 ${isOpen ? 'rotate-90' : ''}`}></i></div>
</div>}
</div>
</div>f
{/* 折叠子菜单 */}
{hasSubMenu && <Collapse isOpen={isOpen} onHeightChange={props.onHeightChange}>

View File

@@ -4,6 +4,7 @@ const CONFIG = {
FUKASAWA_POST_LIST_COVER: true, // 文章列表显示图片封面
FUKASAWA_POST_LIST_COVER_FORCE: false, // 即使没有封面也将站点背景图设置为封面
FUKASAWA_POST_LIST_PREVIEW: false, // 显示文章预览
FUKASAWA_POST_LIST_ANIMATION: false, // 博客列表淡入动画
// 菜单
FUKASAWA_MENU_CATEGORY: true, // 显示分类
@@ -12,7 +13,8 @@ const CONFIG = {
FUKASAWA_MENU_SEARCH: false, // 显示搜索
FUKASAWA_SIDEBAR_COLLAPSE_BUTTON: true, // 侧边栏折叠按钮
FUKASAWA_SIDEBAR_COLLAPSE_SATUS_DEFAULT: false // 侧边栏默认折叠收起
FUKASAWA_SIDEBAR_COLLAPSE_SATUS_DEFAULT: false, // 侧边栏默认折叠收起
FUKASAWA_SIDEBAR_COLLAPSE_ON_SCROLL: false // 侧边栏滚动时折叠 仅文章阅读页有效
}
export default CONFIG

View File

@@ -12,7 +12,7 @@ import ArticleDetail from './components/ArticleDetail'
import ArticleLock from './components/ArticleLock'
import TagItemMini from './components/TagItemMini'
import { useRouter } from 'next/router'
import { createContext, useContext, useEffect, useState } from 'react'
import { createContext, useContext, useEffect } from 'react'
import Link from 'next/link'
import { Transition } from '@headlessui/react'
import dynamic from 'next/dynamic'
@@ -48,25 +48,8 @@ const LayoutBase = (props) => {
const leftAreaSlot = <Live2D />
const { onLoading, fullWidth } = useGlobal()
const FUKASAWA_SIDEBAR_COLLAPSE_SATUS_DEFAULT = fullWidth || siteConfig('FUKASAWA_SIDEBAR_COLLAPSE_SATUS_DEFAULT', null, CONFIG)
// 侧边栏折叠从 本地存储中获取 open 状态的初始值
const [isCollapsed, setIsCollapse] = useState(() => {
if (typeof window !== 'undefined') {
return localStorage.getItem('fukasawa-sidebar-collapse') === 'true' || FUKASAWA_SIDEBAR_COLLAPSE_SATUS_DEFAULT
}
return FUKASAWA_SIDEBAR_COLLAPSE_SATUS_DEFAULT
})
// 在组件卸载时保存 open 状态到本地存储中
useEffect(() => {
if (isBrowser) {
localStorage.setItem('fukasawa-sidebar-collapse', isCollapsed)
}
}, [isCollapsed])
return (
<ThemeGlobalFukasawa.Provider value={{ isCollapsed, setIsCollapse }}>
<ThemeGlobalFukasawa.Provider value={{}}>
<div id='theme-fukasawa'>
{/* SEO信息 */}

View File

@@ -1,5 +1,6 @@
import { siteConfig } from '@/lib/config'
import Link from 'next/link'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
/**
* 归档分组
@@ -13,8 +14,10 @@ export default function BlogArchiveItem({ archiveTitle, archivePosts }) {
{archiveTitle}
</div>
<ul>
{archivePosts[archiveTitle]?.map(post => (
<li key={post.id}
{archivePosts[archiveTitle]?.map(post => {
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return <li key={post.id}
className="border-l-2 p-1 text-xs md:text-base items-center hover:scale-x-105 hover:border-gray-500 dark:hover:border-gray-300 dark:border-gray-400 transform duration-500"
>
<div id={post?.publishDay}>
@@ -23,13 +26,13 @@ export default function BlogArchiveItem({ archiveTitle, archivePosts }) {
</span>{' '}
&nbsp;
<Link passHref href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
<Link passHref href={url}
className="dark:text-gray-400 dark:hover:text-gray-300 overflow-x-hidden hover:underline cursor-pointer text-gray-600">
{post.title}
</Link>
</div>
</li>
))}
})}
</ul>
</div>
)

View File

@@ -1,12 +1,14 @@
import { siteConfig } from '@/lib/config'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
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}`
return (
<Link href={`${siteConfig('SUB_PATH', '')}/${post.slug}`} passHref> <div key={post.id} className={`${className} py-1.5 cursor-pointer px-1.5 hover:bg-gray-50 rounded-md dark:hover:bg-gray-600 ${currentSelected ? 'bg-green-50 text-green-500' : ''}`}>
<Link href={url} passHref> <div key={post.id} className={`${className} py-1.5 cursor-pointer px-1.5 hover:bg-gray-50 rounded-md dark:hover:bg-gray-600 ${currentSelected ? 'bg-green-50 text-green-500' : ''}`}>
<div className="flex flex-col w-full select-none">
{post.title}
</div>

View File

@@ -3,6 +3,7 @@ import CONFIG from '../config'
import { useGlobal } from '@/lib/global'
import LazyImage from '@/components/LazyImage'
import { siteConfig } from '@/lib/config'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
/**
* 关联推荐文章
@@ -38,12 +39,13 @@ export default function ArticleRecommend({ recommendPosts, siteInfo }) {
const headerImage = post?.pageCoverThumbnail
? post.pageCoverThumbnail
: siteInfo?.pageCover
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return (
(<Link
key={post.id}
title={post.title}
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
href={url}
passHref
className="flex h-40 cursor-pointer overflow-hidden rounded-2xl">

View File

@@ -3,6 +3,8 @@ import CONFIG from '../config'
import TagItemMini from './TagItemMini'
import LazyImage from '@/components/LazyImage'
import { siteConfig } from '@/lib/config'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
/**
* 博客归档列表
* @param posts 所有文章
@@ -24,6 +26,8 @@ const BlogPostArchive = ({ posts = [], archiveTitle, siteInfo }) => {
</div>
<ul>
{posts?.map(post => {
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
const showPreview = siteConfig('HEO_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap
if (post && !post.pageCoverThumbnail && siteConfig('HEO_POST_LIST_COVER_DEFAULT', null, CONFIG)) {
post.pageCoverThumbnail = siteInfo?.pageCover
@@ -34,7 +38,7 @@ const BlogPostArchive = ({ posts = [], archiveTitle, siteInfo }) => {
{/* 图片封面 */}
{showPageCover && (
<div>
<Link href={`${siteConfig('SUB_PATH', '')}/${post.slug}`} passHref legacyBehavior>
<Link href={url} passHref legacyBehavior>
<LazyImage className={'rounded-xl bg-center bg-cover w-40 h-24'} src={post?.pageCoverThumbnail}/>
</Link>
</div>
@@ -53,7 +57,7 @@ const BlogPostArchive = ({ posts = [], archiveTitle, siteInfo }) => {
{/* 标题 */}
<Link
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
href={url}
passHref
className={' group-hover:text-indigo-700 group-hover:dark:text-indigo-400 text-black dark:text-gray-100 dark:group-hover:text-yellow-600 line-clamp-2 replace cursor-pointer text-xl font-extrabold leading-tight'}>
<span className='menu-link '>{post.title}</span>

View File

@@ -3,6 +3,7 @@ import CONFIG from '../config'
import TagItemMini from './TagItemMini'
import LazyImage from '@/components/LazyImage'
import { siteConfig } from '@/lib/config'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
const showPreview = siteConfig('HEO_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap
@@ -10,6 +11,7 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
post.pageCoverThumbnail = siteInfo?.pageCover
}
const showPageCover = siteConfig('HEO_POST_LIST_COVER', null, CONFIG) && post?.pageCoverThumbnail && !showPreview
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return (
<div className={` ${siteConfig('HEO_POST_LIST_COVER_HOVER_ENLARGE', null, CONFIG) ? ' hover:scale-110 transition-all duration-150' : ''}`} >
@@ -22,7 +24,7 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
{/* 图片封面 */}
{showPageCover && (
<Link href={`${siteConfig('SUB_PATH', '')}/${post.slug}`} passHref legacyBehavior>
<Link href={url} passHref legacyBehavior>
<div className="w-full md:w-5/12 2xl:w-full overflow-hidden">
<LazyImage priority={index === 0} src={post?.pageCoverThumbnail} alt={post?.title} className='h-60 w-full object-cover group-hover:scale-105 group-hover:brightness-75 transition-all duration-300' />
</div>
@@ -42,7 +44,7 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
{/* 标题 */}
<Link
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
href={url}
passHref
className={' group-hover:text-indigo-700 dark:hover:text-yellow-700 dark:group-hover:text-yellow-600 text-black dark:text-gray-100 line-clamp-2 replace cursor-pointer text-xl font-extrabold leading-tight'}>
<span className='menu-link '>{post.title}</span>

View File

@@ -1,6 +1,7 @@
import LazyImage from '@/components/LazyImage'
import { siteConfig } from '@/lib/config'
import Link from 'next/link'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
/**
* 最新文章列表
@@ -18,11 +19,12 @@ const LatestPostsGroup = ({ latestPosts, siteInfo }) => {
return <div className='grid grid-cols-2 gap-4'>
{latestPosts.map(post => {
const headerImage = post?.pageCoverThumbnail ? post.pageCoverThumbnail : siteInfo?.pageCover
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return (
(<Link key={post.id} passHref
title={post.title}
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
href={url}
className={'my-3 flex flex-col w-full'}>

View File

@@ -4,6 +4,7 @@ import { useGlobal } from '@/lib/global'
// import Image from 'next/image'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
/**
* 最新文章列表
@@ -29,14 +30,14 @@ export default function LatestPostsGroupMini ({ latestPosts, siteInfo }) {
</div>
{latestPosts.map(post => {
const selected = currentPath === `${siteConfig('SUB_PATH', '')}/${post.slug}`
const headerImage = post?.pageCoverThumbnail ? post.pageCoverThumbnail : siteInfo?.pageCover
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return (
(<Link
key={post.id}
title={post.title}
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
href={url}
passHref
className={'my-3 flex'}>

View File

@@ -3,6 +3,7 @@ import CONFIG from '../config'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import LazyImage from '@/components/LazyImage'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
/**
* 关联推荐文章
@@ -33,12 +34,13 @@ export default function ArticleRecommend({ recommendPosts, siteInfo }) {
const headerImage = post?.pageCoverThumbnail
? post.pageCoverThumbnail
: siteInfo?.pageCover
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return (
(<Link
key={post.id}
title={post.title}
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
href={url}
passHref
className="flex h-40 cursor-pointer overflow-hidden">

View File

@@ -1,5 +1,6 @@
import Link from 'next/link'
import { siteConfig } from '@/lib/config'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
/**
* 博客归档列表
@@ -21,8 +22,9 @@ const BlogPostArchive = ({ posts = [], archiveTitle }) => {
{archiveTitle}
</div>
<ul>
{posts?.map(post => (
<li
{posts?.map(post => {
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return <li
key={post.id}
className="border-l-2 p-1 text-xs md:text-base items-center hover:scale-x-105 hover:border-indigo-500 dark:hover:border-indigo-300 dark:border-indigo-400 transform duration-500"
>
@@ -30,7 +32,7 @@ const BlogPostArchive = ({ posts = [], archiveTitle }) => {
<span className="text-gray-400">{post.date?.start_date}</span>{' '}
&nbsp;
<Link
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
href={url}
passHref
className="dark:text-gray-400 dark:hover:text-indigo-300 overflow-x-hidden hover:underline cursor-pointer text-gray-600">
@@ -39,7 +41,7 @@ const BlogPostArchive = ({ posts = [], archiveTitle }) => {
</Link>
</div>
</li>
))}
})}
</ul>
</div>
)

View File

@@ -3,7 +3,7 @@ import CONFIG from '../config'
import { BlogPostCardInfo } from './BlogPostCardInfo'
import { siteConfig } from '@/lib/config'
import LazyImage from '@/components/LazyImage'
// import Image from 'next/image'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
const showPreview = siteConfig('HEXO_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap
@@ -12,6 +12,7 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
}
const showPageCover = siteConfig('HEXO_POST_LIST_COVER', null, CONFIG) && post?.pageCoverThumbnail && !showPreview
// const delay = (index % 2) * 200
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return (
@@ -32,7 +33,7 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
{/* 图片封面 */}
{showPageCover && (
<div className="md:w-5/12 overflow-hidden">
<Link href={`${siteConfig('SUB_PATH', '')}/${post.slug}`} passHref legacyBehavior>
<Link href={url} passHref legacyBehavior>
<LazyImage priority={index === 1} src={post?.pageCoverThumbnail} className='h-56 w-full object-cover object-center group-hover:scale-110 duration-500' />
</Link>
</div>

View File

@@ -4,6 +4,7 @@ import TagItemMini from './TagItemMini'
import TwikooCommentCount from '@/components/TwikooCommentCount'
import { siteConfig } from '@/lib/config'
import { formatDateFmt } from '@/lib/formatDate'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
/**
* 博客列表的文字内容
@@ -11,11 +12,12 @@ import { formatDateFmt } from '@/lib/formatDate'
* @returns
*/
export const BlogPostCardInfo = ({ post, showPreview, showPageCover, showSummary }) => {
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return <div className={`flex flex-col justify-between lg:p-6 p-4 ${showPageCover && !showPreview ? 'md:w-7/12 w-full md:max-h-60' : 'w-full'}`}>
<div>
{/* 标题 */}
<Link
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
href={url}
passHref
className={`line-clamp-2 replace cursor-pointer text-2xl ${showPreview ? 'text-center' : ''
} leading-tight font-normal text-gray-600 dark:text-gray-100 hover:text-indigo-700 dark:hover:text-indigo-400`}>

View File

@@ -4,6 +4,7 @@ import { useGlobal } from '@/lib/global'
// import Image from 'next/image'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
/**
* 最新文章列表
@@ -28,15 +29,15 @@ const LatestPostsGroup = ({ latestPosts, siteInfo }) => {
</div>
</div>
{latestPosts.map(post => {
const selected = currentPath === `${siteConfig('SUB_PATH', '')}/${post.slug}`
const headerImage = post?.pageCoverThumbnail ? post.pageCoverThumbnail : siteInfo?.pageCover
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
const selected = currentPath === url
return (
(<Link
key={post.id}
title={post.title}
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
href={url}
passHref
className={'my-3 flex'}>

View File

@@ -3,6 +3,7 @@ import CONFIG from '../config'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import LazyImage from '@/components/LazyImage'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
/**
* 关联推荐文章
@@ -33,12 +34,13 @@ export default function ArticleRecommend({ recommendPosts, siteInfo }) {
const headerImage = post?.pageCoverThumbnail
? post.pageCoverThumbnail
: siteInfo?.pageCover
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return (
(<Link
key={post.id}
title={post.title}
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
href={url}
passHref
className="flex h-40 cursor-pointer overflow-hidden">

View File

@@ -1,5 +1,6 @@
import Link from 'next/link'
import { siteConfig } from '@/lib/config'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
/**
* 博客归档列表
@@ -21,17 +22,17 @@ const BlogPostArchive = ({ posts = [], archiveTitle }) => {
{archiveTitle}
</div>
<ul>
{posts?.map(post => (
<li
{posts?.map(post => {
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return <li
key={post.id}
className="border-l-2 p-1 text-xs md:text-base items-center hover:scale-x-105 hover:border-indigo-500 dark:hover:border-indigo-300 dark:border-indigo-400 transform duration-500"
>
<div id={post?.publishDay}>
<span className="text-gray-400">{post.date?.start_date}</span>{' '}
&nbsp;
<Link
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
passHref
<Link href={url} passHref
className="dark:text-gray-400 dark:hover:text-indigo-300 overflow-x-hidden hover:underline cursor-pointer text-gray-600">
{post.title}
@@ -39,7 +40,7 @@ const BlogPostArchive = ({ posts = [], archiveTitle }) => {
</Link>
</div>
</li>
))}
})}
</ul>
</div>
)

View File

@@ -5,7 +5,7 @@ import CONFIG from '../config'
import TwikooCommentCount from '@/components/TwikooCommentCount'
import LazyImage from '@/components/LazyImage'
import { formatDateFmt } from '@/lib/formatDate'
// import Image from 'next/image'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
const showPreview = siteConfig('MATERY_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap
@@ -15,6 +15,8 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
}
const showPageCover = siteConfig('MATERY_POST_LIST_COVER', null, CONFIG) && post?.pageCoverThumbnail
const delay = (index % 3) * 300
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return (
<div
data-aos="zoom-in"
@@ -29,7 +31,7 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
{/* 头部图片 填充卡片 */}
{showPageCover && (
<Link href={`${siteConfig('SUB_PATH', '')}/${post.slug}`} passHref legacyBehavior>
<Link href={url} passHref legacyBehavior>
<div className="flex flex-grow w-full relative duration-200 = rounded-t-md cursor-pointer transform overflow-hidden">
<LazyImage
src={post?.pageCoverThumbnail}

View File

@@ -1,5 +1,6 @@
import { siteConfig } from '@/lib/config'
import Link from 'next/link'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
/**
* 归档分组
@@ -13,23 +14,25 @@ export default function BlogArchiveItem({ archiveTitle, archivePosts }) {
{archiveTitle}
</div>
<ul>
{archivePosts[archiveTitle]?.map(post => (
<li key={post.id}
{archivePosts[archiveTitle]?.map(post => {
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return <li key={post.id}
className="border-l-2 p-1 text-xs md:text-base items-center hover:scale-x-105 hover:border-gray-500 dark:hover:border-gray-300 dark:border-gray-400 transform duration-500"
>
>
<div id={post?.publishDay}>
<span className="text-gray-400">
{post.date?.start_date}
</span>{' '}
&nbsp;
<Link passHref href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
<Link passHref href={url}
className="dark:text-gray-400 dark:hover:text-gray-300 overflow-x-hidden hover:underline cursor-pointer text-gray-600">
{post.title}
</Link>
</div>
</li>
))}
</li>
})}
</ul>
</div>
)

View File

@@ -7,10 +7,12 @@ import CategoryItem from './CategoryItem'
import TagItemMini from './TagItemMini'
import TwikooCommentCount from '@/components/TwikooCommentCount'
import LazyImage from '@/components/LazyImage'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
const BlogPostCard = ({ post, showSummary }) => {
const showPreview = siteConfig('MEDIUM_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap
const { locale } = useGlobal()
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return (
<div
key={post.id}
@@ -23,7 +25,7 @@ const BlogPostCard = ({ post, showSummary }) => {
<div className="lg:py-8 py-4 flex flex-col w-full">
<Link
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
href={url}
passHref
className={
'cursor-pointer font-bold hover:underline text-3xl leading-tight text-gray-700 dark:text-gray-300 hover:text-green-500 dark:hover:text-green-400'
@@ -62,7 +64,7 @@ const BlogPostCard = ({ post, showSummary }) => {
<div className="pointer-events-none border-t pt-8 border-dashed">
<div className="w-full justify-start flex">
<Link
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
href={url}
passHref
className="hover:bg-opacity-100 hover:scale-105 duration-200 pointer-events-auto transform font-bold text-green-500 cursor-pointer">

View File

@@ -1,5 +1,6 @@
import { siteConfig } from '@/lib/config'
import Link from 'next/link'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
/**
* 归档分组
@@ -13,8 +14,10 @@ export default function BlogArchiveItem({ archiveTitle, archivePosts }) {
{archiveTitle}
</div>
<ul>
{archivePosts[archiveTitle]?.map(post => (
<li key={post.id}
{archivePosts[archiveTitle]?.map(post => {
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return <li key={post.id}
className="border-l-2 p-1 text-xs md:text-base items-center hover:scale-x-105 hover:border-gray-500 dark:hover:border-gray-300 dark:border-gray-400 transform duration-500"
>
<div id={post?.publishDay}>
@@ -23,13 +26,13 @@ export default function BlogArchiveItem({ archiveTitle, archivePosts }) {
</span>{' '}
&nbsp;
<Link passHref href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
<Link passHref href={url}
className="dark:text-gray-400 dark:hover:text-gray-300 overflow-x-hidden hover:underline cursor-pointer text-gray-600">
{post.title}
</Link>
</div>
</li>
))}
})}
</ul>
</div>
)

View File

@@ -2,14 +2,16 @@ import Link from 'next/link'
import NotionIcon from './NotionIcon'
import { useRouter } from 'next/router'
import { siteConfig } from '@/lib/config'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
const BlogPostCard = ({ post, className }) => {
const router = useRouter()
const currentSelected = router.asPath.split('?')[0] === '/' + post.slug
let pageIcon = post.pageIcon !== '' ? post.pageIcon : siteConfig('IMG_LAZY_LOAD_PLACEHOLDER')
pageIcon = post.pageIcon.indexOf('amazonaws.com') !== -1 ? post.pageIcon + '&width=88' : post.pageIcon
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return (
<Link href={`${siteConfig('SUB_PATH', '')}/${removeHttp(post.slug)}`} target={(checkRemoveHttp(post.slug) ? '_blank' : '_self')} passHref>
<Link href={`${url}`} target={(checkContainHttp(post.slug) ? '_blank' : '_self')} passHref>
<div key={post.id} className={`${className} h-full rounded-2xl p-4 dark:bg-neutral-800 cursor-pointer bg-white hover:bg-white dark:hover:bg-gray-800 ${currentSelected ? 'bg-green-50 text-green-500' : ''}`}>
<div className="stack-entry w-full flex space-x-3 select-none dark:text-neutral-200">
<NotionIcon icon={pageIcon} size='10' className='text-6xl w-11 h-11 mx-1 my-0 flex-none' />
@@ -21,28 +23,6 @@ const BlogPostCard = ({ post, className }) => {
</div>
</Link>
)
function removeHttp(str) {
// 检查字符串是否包含http
if (str.includes('http')) {
// 如果包含找到http的位置
const index = str.indexOf('http');
// 返回http之后的部分
return str.slice(index, str.length);
} else {
// 如果不包含,返回原字符串
return str;
}
}
function checkRemoveHttp(str) {
// 检查字符串是否包含http
if (str.includes('http')) {
// 如果包含找到http的位置
return str.indexOf('http') > -1
} else {
// 不包含
return false;
}
}
}
export default BlogPostCard

View File

@@ -13,15 +13,9 @@ import { siteConfig } from '@/lib/config'
* @constructor
*/
const BlogPostListAll = (props) => {
// const { customMenu, posts, category, tag, allNavPages, categoryOptions } = props
// const [filteredNavPages, setFilteredNavPages] = useState(allNavPages)
const { customMenu } = props
// const [filteredNavPages, setFilteredNavPages] = useState(allNavPages)
const { filteredNavPages, setFilteredNavPages, allNavPages } = useNavGlobal()
// const [filteredNavPages] = useState(allNavPages)
// const router = useRouter()
// 对自定义分类格式化,方便后续使用分类名称做索引,检索同步图标信息
// 目前只支持二级分类
const links = customMenu
@@ -29,9 +23,6 @@ const BlogPostListAll = (props) => {
// for循环遍历数组
links?.map((link, i) => {
const linkTitle = link.title + ''
// console.log('####### link')
// console.log(link)
// filterLinks[linkTitle] = link
filterLinks[linkTitle] = { title: link.title, icon: link.icon, pageIcon: link.pageIcon }
if (link?.subMenus) {
link.subMenus?.map((group, index) => {
@@ -44,22 +35,10 @@ const BlogPostListAll = (props) => {
}
})
console.log('####### filterLinks')
console.log(filterLinks)
// console.log('####### filterLinks')
// console.log(filterLinks)
const selectedSth = false
const groupedArray = filteredNavPages?.reduce((groups, item) => {
const categoryName = item?.category ? item?.category : '' // 将category转换为字符串
const categoryIcon = filterLinks[categoryName]?.icon ? filterLinks[categoryName]?.icon : '' // 将pageIcon转换为字符串
// console.log('####### categoryName')
// console.log(categoryName)
// console.log('####### categoryIcon')
// console.log(categoryIcon)
let existingGroup = null
// 开启自动分组排序
if (JSON.parse(siteConfig('NAV_AUTO_SORT', null, CONFIG))) {
@@ -81,17 +60,9 @@ const BlogPostListAll = (props) => {
groupedArray?.map((group) => {
// 自定义分类图标与post的category共用
// 判断自定义分类与Post中category同名的项将icon的值传递给post
// let groupTitle = group?.category
// item.icon = filterLinks[categoryName]?.icon ? filterLinks[categoryName]?.icon : ''
// console.log('####### item')
// console.log(item)
const groupSelected = false
// for (const post of group?.items) {
// if (router.asPath.split('?')[0] === '/' + post.slug) {
// groupSelected = true
// selectedSth = true
// }
// }
group.selected = groupSelected
return null
})
@@ -110,27 +81,6 @@ const BlogPostListAll = (props) => {
</div>
}
// 处理自定义导航菜单项
// let keyword = searchInputRef.current.value
// if (keyword) {
// keyword = keyword.trim()
// } else {
// setFilteredNavPages(allNavPages)
// }
// for (const filterGroup of filterAllNavPages) {
// for (let i = filterGroup.items.length - 1; i >= 0; i--) {
// const post = filterGroup.items[i]
// const articleInfo = post.title + ''
// const hit = articleInfo.toLowerCase().indexOf(keyword.toLowerCase()) > -1
// if (!hit) {
// // 删除
// filterGroup.items.splice(i, 1)
// }
// }
// if (filterGroup.items && filterGroup.items.length > 0) {
// filterPosts.push(filterGroup)
// }
// }
}
export default BlogPostListAll

View File

@@ -1,5 +1,6 @@
import { siteConfig } from '@/lib/config'
import Link from 'next/link'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
/**
* 博客归档列表
@@ -21,8 +22,10 @@ const BlogPostArchive = ({ posts = [], archiveTitle }) => {
{archiveTitle}
</div>
<ul>
{posts?.map(post => (
<li
{posts?.map(post => {
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return <li
key={post.id}
className="border-l-2 p-1 text-xs md:text-base items-center hover:scale-x-105 hover:border-gray-500 dark:hover:border-gray-300 dark:border-gray-400 transform duration-500"
>
@@ -30,7 +33,7 @@ const BlogPostArchive = ({ posts = [], archiveTitle }) => {
<span className="text-gray-500">{post.date?.start_date}</span>{' '}
&nbsp;
<Link
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
href={url}
passHref
className="dark:text-gray-400 dark:hover:text-gray-300 overflow-x-hidden hover:underline cursor-pointer text-gray-600">
@@ -39,7 +42,7 @@ const BlogPostArchive = ({ posts = [], archiveTitle }) => {
</Link>
</div>
</li>
))}
})}
</ul>
</div>
)

View File

@@ -9,6 +9,7 @@ import NotionIcon from '@/components/NotionIcon'
import TwikooCommentCount from '@/components/TwikooCommentCount'
import { formatDateFmt } from '@/lib/formatDate'
import { siteConfig } from '@/lib/config'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
const BlogPostCard = ({ post, index, showSummary }) => {
const { locale } = useGlobal()
@@ -22,6 +23,7 @@ const BlogPostCard = ({ post, index, showSummary }) => {
'data-aos-anchor-placement': 'top-bottom'
}
: {}
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return (
<Card className="w-full">
@@ -34,7 +36,7 @@ const BlogPostCard = ({ post, index, showSummary }) => {
{/* 文章标题 */}
<Link
{...aosProps}
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
href={url}
passHref
className={`cursor-pointer text-3xl ${showPreview ? 'text-center' : ''} leading-tight text-gray-700 dark:text-gray-100 hover:text-blue-500 dark:hover:text-blue-400`}>
@@ -99,7 +101,7 @@ const BlogPostCard = ({ post, index, showSummary }) => {
<div className="text-right border-t pt-8 border-dashed">
<Link
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
href={url}
className="hover:bg-opacity-100 hover:underline transform duration-300 p-3 text-white bg-gray-800 cursor-pointer">
{locale.COMMON.ARTICLE_DETAIL}
@@ -110,7 +112,7 @@ const BlogPostCard = ({ post, index, showSummary }) => {
</div>
{siteConfig('NEXT_POST_LIST_COVER', null, CONFIG) && post?.pageCoverThumbnail && (
<Link href={`${siteConfig('SUB_PATH', '')}/${post.slug}`} passHref legacyBehavior>
<Link href={url} passHref legacyBehavior>
<div className="h-72 w-full relative duration-200 cursor-pointer transform overflow-hidden">
<Image
className="hover:scale-105 transform duration-500"

View File

@@ -2,6 +2,7 @@ import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
/**
* 最新文章列表
@@ -27,11 +28,12 @@ const LatestPostsGroup = ({ latestPosts }) => {
</div>
{latestPosts.map(post => {
const selected = currentPath === `${siteConfig('SUB_PATH', '')}/${post.slug}`
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return (
(<Link
key={post.id}
title={post.title}
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
href={url}
passHref
className={'my-1 flex font-light'}>

View File

@@ -1,5 +1,6 @@
import { siteConfig } from '@/lib/config'
import Link from 'next/link'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
/**
* 归档分组文章
@@ -14,8 +15,10 @@ export default function BlogArchiveItem({ archiveTitle, archivePosts }) {
</div>
<ul>
{archivePosts[archiveTitle].map(post => (
<li
{archivePosts[archiveTitle].map(post => {
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return <li
key={post.id}
className="border-l-2 p-1 text-xs md:text-base items-center hover:scale-x-105 hover:border-gray-500 dark:hover:border-gray-300 dark:border-gray-400 transform duration-500"
>
@@ -25,7 +28,7 @@ export default function BlogArchiveItem({ archiveTitle, archivePosts }) {
</span>{' '}
&nbsp;
<Link
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
href={url}
passHref
className="dark:text-gray-400 dark:hover:text-gray-300 overflow-x-hidden hover:underline cursor-pointer text-gray-600">
@@ -34,7 +37,7 @@ export default function BlogArchiveItem({ archiveTitle, archivePosts }) {
</Link>
</div>
</li>
))}
})}
</ul>
</div>
)

View File

@@ -1,9 +1,12 @@
import Link from 'next/link'
import { siteConfig } from '@/lib/config'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
const BlogPost = ({ post }) => {
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return (
(<Link href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}>
(<Link href={url}>
<article key={post.id} className="mb-6 md:mb-8">
<header className="flex flex-col justify-between md:flex-row md:items-baseline">

View File

@@ -1,5 +1,6 @@
import Link from 'next/link'
import { siteConfig } from '@/lib/config'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
/**
* 归档分组文章
@@ -14,8 +15,10 @@ export default function BlogArchiveItem({ archiveTitle, archivePosts }) {
</div>
<ul>
{archivePosts[archiveTitle].map(post => (
<li
{archivePosts[archiveTitle].map(post => {
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return <li
key={post.id}
className="border-l-2 p-1 text-xs md:text-base items-center hover:scale-x-105 hover:border-gray-500 dark:hover:border-gray-300 dark:border-gray-400 transform duration-500"
>
@@ -25,7 +28,7 @@ export default function BlogArchiveItem({ archiveTitle, archivePosts }) {
</span>{' '}
&nbsp;
<Link
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
href={url}
passHref
className="dark:text-gray-400 dark:hover:text-gray-300 overflow-x-hidden hover:underline cursor-pointer text-gray-600">
@@ -34,7 +37,7 @@ export default function BlogArchiveItem({ archiveTitle, archivePosts }) {
</Link>
</div>
</li>
))}
})}
</ul>
</div>
)

View File

@@ -11,7 +11,7 @@ import LazyImage from '@/components/LazyImage'
*/
const BlogPost = (props) => {
const { post, index, siteInfo } = props
const pageThumbnail = compressImage(post?.pageCoverThumbnail || siteInfo?.pageCover, 800, 80)
const pageThumbnail = compressImage(post?.pageCoverThumbnail || siteInfo?.pageCover)
const { setModalContent, setShowModal } = usePlogGlobal()
const handleClick = () => {
setShowModal(true)

View File

@@ -41,7 +41,7 @@ const LayoutBase = props => {
// 页面切换关闭遮罩
const router = useRouter()
const closeModal = ()=>{
const closeModal = () => {
setShowModal(false)
}
@@ -52,7 +52,6 @@ const LayoutBase = props => {
}
}, [router.events])
return (
<ThemeGlobalPlog.Provider value={{ showModal, setShowModal, modalContent, setModalContent }}>
<div id='theme-plog' className='plog relative dark:text-gray-300 w-full dark:bg-black min-h-screen'>

View File

@@ -1,5 +1,6 @@
import { siteConfig } from '@/lib/config'
import Link from 'next/link'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
/**
* 归档分组文章
@@ -14,8 +15,9 @@ export default function BlogArchiveItem({ archiveTitle, archivePosts }) {
</div>
<ul>
{archivePosts[archiveTitle].map(post => (
<li
{archivePosts[archiveTitle].map(post => {
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return <li
key={post.id}
className="border-l-2 p-1 text-xs md:text-base items-center hover:scale-x-105 hover:border-gray-500 dark:hover:border-gray-300 dark:border-gray-400 transform duration-500"
>
@@ -25,7 +27,7 @@ export default function BlogArchiveItem({ archiveTitle, archivePosts }) {
</span>{' '}
&nbsp;
<Link
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
href={url}
passHref
className="dark:text-gray-400 dark:hover:text-gray-300 overflow-x-hidden hover:underline cursor-pointer text-gray-600">
@@ -34,7 +36,7 @@ export default function BlogArchiveItem({ archiveTitle, archivePosts }) {
</Link>
</div>
</li>
))}
})}
</ul>
</div>
)

View File

@@ -4,10 +4,12 @@ import TwikooCommentCount from '@/components/TwikooCommentCount'
import { formatDateFmt } from '@/lib/formatDate'
import { siteConfig } from '@/lib/config'
import LazyImage from '@/components/LazyImage'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
export const BlogItem = props => {
const { post } = props
const showPageCover = siteConfig('SIMPLE_POST_COVER_ENABLE', false, CONFIG)
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return <div key={post.id} className="h-42 my-6 pb-12 border-b dark:border-gray-800" >
{/* 文章标题 */}
@@ -17,7 +19,7 @@ export const BlogItem = props => {
{/* 图片封面 */}
{showPageCover && (
<div className="overflow-hidden mr-2 w-56 h-full">
<Link href={`${siteConfig('SUB_PATH', '')}/${post.slug}`} passHref legacyBehavior>
<Link href={url} passHref legacyBehavior>
<LazyImage src={post?.pageCoverThumbnail} className='w-56 h-full object-cover object-center group-hover:scale-110 duration-500' />
</Link>
</div>
@@ -27,7 +29,7 @@ export const BlogItem = props => {
<div className='article-info'>
<h2 className="mb-2">
<Link
href={`${siteConfig('SUB_PATH', '')}/${post.slug}`}
href={url}
className="blog-item-title font-bold text-black text-2xl menu-link">
{post.title}
</Link>
@@ -60,7 +62,7 @@ export const BlogItem = props => {
</div>
<div className='block'>
<Link href={`${siteConfig('SUB_PATH', '')}/${post.slug}`} className='inline-block rounded-sm text-blue-600 text-xs dark:border-gray-800 border hover:text-red-400 transition-all duration-200 hover:border-red-300 h-9 leading-8 px-5'>
<Link href={url} className='inline-block rounded-sm text-blue-600 text-xs dark:border-gray-800 border hover:text-red-400 transition-all duration-200 hover:border-red-300 h-9 leading-8 px-5'>
Continue Reading <i className="fa-solid fa-angle-right align-middle"></i>
</Link>
</div>

View File

@@ -3,7 +3,6 @@ import Link from 'next/link'
import CONFIG from '../config'
import SocialButton from './SocialButton'
import { siteConfig } from '@/lib/config'
import { compressImage } from '@/lib/notion/mapImage'
/**
* 网站顶部
@@ -11,7 +10,6 @@ import { compressImage } from '@/lib/notion/mapImage'
*/
export default function Header (props) {
const { siteInfo } = props
const avatar = compressImage(siteInfo?.icon || siteConfig('AVATAR'), 200)
return (
<header className="text-center justify-between items-center px-6 bg-white h-80 dark:bg-black relative z-10">
@@ -20,7 +18,7 @@ export default function Header (props) {
{/* 可使用一张单图作为logo */}
<div className='flex space-x-6'>
<div className='hover:rotate-45 hover:scale-125 transform duration-200 cursor-pointer justify-center items-center flex'>
<LazyImage priority={true} src={avatar} className='rounded-full' width={100} height={100} alt={siteConfig('AUTHOR')} />
<LazyImage priority={true} src={siteInfo?.icon} className='rounded-full' width={100} height={100} alt={siteConfig('AUTHOR')} />
</div>
<div className='flex-col flex justify-center'>