mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-14 15:09:22 +00:00
plog-基础布局
This commit is contained in:
@@ -26,4 +26,10 @@ const User = ({ className }) => {
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M17.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
}
|
||||
export { Moon, Sun, Home, User }
|
||||
|
||||
const ArrowPath = ({ className }) => {
|
||||
return <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className={className}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99" />
|
||||
</svg>
|
||||
}
|
||||
export { Moon, Sun, Home, User, ArrowPath }
|
||||
|
||||
@@ -6,7 +6,7 @@ import BLOG from '@/blog.config'
|
||||
* 2. UnPlash 图片可以通过api q=50 控制压缩质量 width=400 控制图片尺寸
|
||||
* @param {*} image
|
||||
*/
|
||||
const compressImage = (image, width = 300) => {
|
||||
const compressImage = (image, width = 400, quality = 50, fmt = 'webp') => {
|
||||
if (!image) {
|
||||
return null
|
||||
}
|
||||
@@ -20,11 +20,12 @@ const compressImage = (image, width = 300) => {
|
||||
// 获取URL参数
|
||||
const params = new URLSearchParams(urlObj.search)
|
||||
// 将q参数的值替换
|
||||
params.set('q', '50')
|
||||
params.set('q', quality)
|
||||
// 尺寸
|
||||
params.set('width', width)
|
||||
// 格式
|
||||
params.set('fmt', 'webp')
|
||||
params.set('fmt', fmt)
|
||||
params.set('fm', fmt)
|
||||
// 生成新的URL
|
||||
urlObj.search = params.toString()
|
||||
return urlObj.toString()
|
||||
|
||||
@@ -1950,14 +1950,6 @@ svg + .notion-page-title-text {
|
||||
@apply bg-blue-500 text-gray-50 !important;
|
||||
}
|
||||
|
||||
.dark img{
|
||||
@apply opacity-80
|
||||
}
|
||||
|
||||
.dark #live2d {
|
||||
@apply opacity-80
|
||||
}
|
||||
|
||||
/* https://github.com/kchen0x */
|
||||
.notion-quote {
|
||||
display: block;
|
||||
|
||||
@@ -19,7 +19,7 @@ export const BlogListPage = props => {
|
||||
return (
|
||||
<div className="w-full">
|
||||
|
||||
<div id="posts-wrapper" className='grid lg:grid-cols-3 grid-cols-2'>
|
||||
<div id="posts-wrapper" className='grid lg:grid-cols-3 grid-cols-1 md:grid-cols-2'>
|
||||
{posts?.map(post => (
|
||||
<BlogPost key={post.id} post={post} {...props}/>
|
||||
))}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import { compressImage } from '@/lib/notion/mapImage'
|
||||
import Link from 'next/link'
|
||||
import { usePlogGlobal } from '..'
|
||||
|
||||
/**
|
||||
* 博客照片卡牌
|
||||
@@ -6,15 +9,30 @@
|
||||
*/
|
||||
const BlogPost = (props) => {
|
||||
const { post, siteInfo } = props
|
||||
const pageThumbnail = post?.pageCoverThumbnail || siteInfo?.pageCover
|
||||
console.log('缩略图', pageThumbnail, siteInfo)
|
||||
const pageThumbnail = compressImage(post?.pageCoverThumbnail || siteInfo?.pageCover, 800, 80)
|
||||
const { setModalContent, setShowModal } = usePlogGlobal()
|
||||
const handleClick = () => {
|
||||
setShowModal(true)
|
||||
setModalContent(post)
|
||||
}
|
||||
return (
|
||||
<article key={post?.id} className='cursor-pointer relative'>
|
||||
<article
|
||||
onClick={handleClick}
|
||||
data-aos="fade-up"
|
||||
data-aos-duration="500"
|
||||
data-aos-once="true"
|
||||
data-aos-anchor-placement="top-bottom"
|
||||
key={post?.id} className='cursor-pointer relative'>
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img src={pageThumbnail} className='aspect-[16/9] w-full h-full object-cover' />
|
||||
<h2 className="text-md absolute left-0 bottom-0 mb-4 ml-4 text-black dark:text-gray-100 text-shadow">
|
||||
<img src={pageThumbnail} className='aspect-[16/9] w-full h-full object-cover filter contrast-120' />
|
||||
<h2 className="text-md absolute left-0 bottom-0 m-4 text-black dark:text-gray-100 text-shadow">
|
||||
{post?.title}
|
||||
</h2>
|
||||
{post?.category && <div className='text-xs rounded-lg absolute left-0 top-0 m-4 px-2 py-1 bg-black bg-opacity-25 hover:bg-blue-700 hover:text-white duration-200'>
|
||||
<Link href={`/category/${post?.category}`}>
|
||||
{post?.category}
|
||||
</Link>
|
||||
</div>}
|
||||
</article>
|
||||
|
||||
)
|
||||
|
||||
@@ -15,7 +15,7 @@ const BottomNav = props => {
|
||||
const { navBarTitle, siteInfo } = props
|
||||
|
||||
return <>
|
||||
<div id="bottom-nav" className={'px-4 hidden glassmorphism md:fixed bottom-0 w-screen py-4 md:flex flex-row justify-between items-center'}>
|
||||
<div id="bottom-nav" style={{ backgroundColor: '#00000063' }} className={'px-4 hidden glassmorphism md:fixed bottom-0 w-screen py-4 md:flex flex-row justify-between items-center'}>
|
||||
<div className="flex items-center">
|
||||
<Link href="/" aria-label={BLOG.title}>
|
||||
<div className="h-6 w-6">
|
||||
|
||||
83
themes/plog/components/Modal.js
Normal file
83
themes/plog/components/Modal.js
Normal file
@@ -0,0 +1,83 @@
|
||||
import { Fragment, useRef, useState } from 'react'
|
||||
import { Dialog, Transition } from '@headlessui/react'
|
||||
import { usePlogGlobal } from '..'
|
||||
import { ArrowPath } from '@/components/HeroIcons'
|
||||
import Link from 'next/link'
|
||||
|
||||
/**
|
||||
* 弹出框
|
||||
*/
|
||||
export default function Modal(props) {
|
||||
const { showModal, setShowModal, modalContent } = usePlogGlobal()
|
||||
const { siteInfo } = props
|
||||
const cancelButtonRef = useRef(null)
|
||||
const img = modalContent?.pageCover || siteInfo?.pageCover
|
||||
const imgRef = useRef(null)
|
||||
|
||||
// 添加loading状态
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
// 在图片加载完成时设置loading为false
|
||||
async function handleImageLoad() {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
// 关闭弹窗
|
||||
function handleClose() {
|
||||
setShowModal(false)
|
||||
setLoading(true)
|
||||
}
|
||||
return (
|
||||
<Transition.Root show={showModal} as={Fragment}>
|
||||
<Dialog as="div" className="relative z-10" initialFocus={cancelButtonRef} onClose={handleClose}>
|
||||
{/* 遮罩 */}
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div style={{ backgroundColor: '#00000063' }} className="fixed inset-0 glassmorphism transition-opacity" />
|
||||
</Transition.Child>
|
||||
|
||||
<div className="fixed inset-0 z-10 overflow-y-auto">
|
||||
<div className="flex min-h-full justify-center p-4 text-center items-center">
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0 translate-y-4 scale-50 w-0"
|
||||
enterTo={'opacity-100 translate-y-0 max-w-screen'}
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100 translate-y-0 scale-100 max-w-screen"
|
||||
leaveTo="opacity-0 translate-y-4 scale-50 w-0"
|
||||
>
|
||||
<Dialog.Panel className="relative transform overflow-hidden rounded-xl text-left shadow-xl transition-all ">
|
||||
{/* 添加loading状态 */}
|
||||
<div className={`bg-hexo-black-gray w-32 h-32 flex justify-center items-center ${loading ? '' : 'hidden'}`}>
|
||||
<ArrowPath className='w-10 h-10 animate-spin text-gray-200' />
|
||||
</div>
|
||||
{/* 添加onLoad事件处理函数 */}
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img src={img} ref={imgRef} className={'w-full max-w-7xl max-h-[90vh] shadow-xl'} onLoad={handleImageLoad} style={{ display: loading ? 'none' : 'block' }} />
|
||||
{!loading && <div className='absolute bottom-0 left-0 m-4'>
|
||||
<div className='flex'>
|
||||
<h2 style={{ textShadow: '0.1em 0.1em 0.2em black' }} className='text-5xl text-white mb-4 px-2 py-1 rounded-lg'>{modalContent?.title}</h2>
|
||||
</div>
|
||||
<div style={{ textShadow: '0.1em 0.1em 0.2em black' }} className={'text-gray-50 rounded-lg p-2'}>{modalContent?.summary}</div>
|
||||
{modalContent?.category && <div className='flex '>
|
||||
<Link href={`/category/${modalContent?.category}`} className='text-xs rounded-lg mt-3 px-2 py-1 bg-black bg-opacity-20 text-white hover:bg-blue-700 hover:text-white duration-200'>
|
||||
{modalContent?.category}
|
||||
</Link>
|
||||
</div>}
|
||||
</div>}
|
||||
</Dialog.Panel>
|
||||
</Transition.Child>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</Transition.Root>
|
||||
)
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import CONFIG from './config'
|
||||
import CommonHead from '@/components/CommonHead'
|
||||
import React, { useEffect } from 'react'
|
||||
import React, { createContext, useContext, useEffect, useState } from 'react'
|
||||
import Nav from './components/Nav'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
|
||||
@@ -24,6 +24,11 @@ import Link from 'next/link'
|
||||
import { Transition } from '@headlessui/react'
|
||||
import BottomNav from './components/BottomNav'
|
||||
import { saveDarkModeToCookies } from '@/themes/theme'
|
||||
import Modal from './components/Modal'
|
||||
|
||||
// 主题全局状态
|
||||
const ThemeGlobalPlog = createContext()
|
||||
export const usePlogGlobal = () => useContext(ThemeGlobalPlog)
|
||||
|
||||
/**
|
||||
* 基础布局 采用左右两侧布局,移动端使用顶部导航栏
|
||||
@@ -34,6 +39,8 @@ import { saveDarkModeToCookies } from '@/themes/theme'
|
||||
const LayoutBase = props => {
|
||||
const { children, meta, topSlot } = props
|
||||
const { onLoading, updateDarkMode } = useGlobal()
|
||||
const [showModal, setShowModal] = useState(false)
|
||||
const [modalContent, setModalContent] = useState(null)
|
||||
|
||||
// 用户手动设置主题
|
||||
const setDarkMode = () => {
|
||||
@@ -52,6 +59,7 @@ const LayoutBase = props => {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<ThemeGlobalPlog.Provider value={{ showModal, setShowModal, modalContent, setModalContent }}>
|
||||
<div id='theme-plog' className='plog relative dark:text-gray-300 w-full bg-black min-h-screen'>
|
||||
{/* SEO相关 */}
|
||||
<CommonHead meta={meta} />
|
||||
@@ -60,7 +68,7 @@ const LayoutBase = props => {
|
||||
<Nav {...props} />
|
||||
|
||||
{/* 主区 */}
|
||||
<main id='out-wrapper' className={'relative m-auto flex-grow w-full transition-all '}>
|
||||
<main id='out-wrapper' className={'relative m-auto flex-grow w-full transition-all pb-12'}>
|
||||
|
||||
<Transition
|
||||
show={!onLoading}
|
||||
@@ -80,9 +88,13 @@ const LayoutBase = props => {
|
||||
|
||||
</main>
|
||||
|
||||
{/* 弹出框 */}
|
||||
<Modal {...props}/>
|
||||
|
||||
{/* 桌面端底部导航栏 */}
|
||||
<BottomNav {...props} />
|
||||
</div>
|
||||
</ThemeGlobalPlog.Provider >
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user