mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-14 07:26:52 +00:00
部分参数配置化
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import BLOG from '@/blog.config'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
/**
|
||||
@@ -6,7 +6,7 @@ import { useEffect } from 'react'
|
||||
*/
|
||||
export default function DisableCopy() {
|
||||
useEffect(() => {
|
||||
if (!JSON.parse(BLOG.CAN_COPY)) {
|
||||
if (!JSON.parse(siteConfig('CAN_COPY'))) {
|
||||
// 全栈添加禁止复制的样式
|
||||
document.getElementsByTagName('html')[0].classList.add('forbid-copy')
|
||||
// 监听复制事件
|
||||
|
||||
@@ -9,10 +9,11 @@ import { deepClone } from './utils'
|
||||
* 1. 优先读取NotionConfig表
|
||||
* 2. 其次读取环境变量
|
||||
* 3. 再读取blog.config.js文件
|
||||
* @param {*} key
|
||||
* @param {*} key ; 参数名
|
||||
* @param {*} defaultVal ; 参数不存在默认返回值
|
||||
* @returns
|
||||
*/
|
||||
export const siteConfig = (key) => {
|
||||
export const siteConfig = (key, defaultVal = null) => {
|
||||
let global = null
|
||||
try {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
@@ -36,7 +37,7 @@ export const siteConfig = (key) => {
|
||||
val = siteInfo?.pageCover // 封面图取Notion的封面
|
||||
break
|
||||
case 'AVATAR':
|
||||
val = siteInfo?.icon // 封面图取Notion的封面
|
||||
val = siteInfo?.icon // 封面图取Notion的头像
|
||||
break
|
||||
case 'TITLE':
|
||||
val = siteInfo?.title // 标题取Notion中的标题
|
||||
@@ -48,7 +49,10 @@ export const siteConfig = (key) => {
|
||||
if (!val) {
|
||||
val = BLOG[key]
|
||||
}
|
||||
console.log('实际配置', key, val)
|
||||
if (!val) {
|
||||
val = defaultVal
|
||||
}
|
||||
// console.log('实际配置', key, val)
|
||||
return val
|
||||
}
|
||||
|
||||
|
||||
50
lib/utils.js
50
lib/utils.js
@@ -75,7 +75,6 @@ export function getQueryVariable(key) {
|
||||
}
|
||||
return (false)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 URL 中指定参数的值
|
||||
* @param {string} url
|
||||
@@ -83,8 +82,10 @@ export function getQueryVariable(key) {
|
||||
* @returns {string|null}
|
||||
*/
|
||||
export function getQueryParam(url, param) {
|
||||
const searchParams = new URLSearchParams(url.split('?')[1])
|
||||
return searchParams.get(param)
|
||||
// 移除哈希部分
|
||||
const urlWithoutHash = url.split('#')[0];
|
||||
const searchParams = new URLSearchParams(urlWithoutHash.split('?')[1]);
|
||||
return searchParams.get(param);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -202,3 +203,46 @@ export const isMobile = () => {
|
||||
|
||||
return isMobile
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫描页面上的所有文本节点,将url格式的文本转为可点击链接
|
||||
* @param {*} node
|
||||
*/
|
||||
export const scanAndConvertToLinks = (node) => {
|
||||
if (node.nodeType === Node.TEXT_NODE) {
|
||||
const text = node.textContent;
|
||||
const urlRegex = /https?:\/\/[^\s]+/g;
|
||||
let lastIndex = 0;
|
||||
let match;
|
||||
|
||||
const newNode = document.createElement('span');
|
||||
|
||||
while ((match = urlRegex.exec(text)) !== null) {
|
||||
const beforeText = text.substring(lastIndex, match.index);
|
||||
const url = match[0];
|
||||
|
||||
if (beforeText) {
|
||||
newNode.appendChild(document.createTextNode(beforeText));
|
||||
}
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.target = '_blank'
|
||||
link.textContent = url;
|
||||
|
||||
newNode.appendChild(link);
|
||||
|
||||
lastIndex = urlRegex.lastIndex;
|
||||
}
|
||||
|
||||
if (lastIndex < text.length) {
|
||||
newNode.appendChild(document.createTextNode(text.substring(lastIndex)));
|
||||
}
|
||||
|
||||
node.parentNode.replaceChild(newNode, node);
|
||||
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
||||
for (const childNode of node.childNodes) {
|
||||
scanAndConvertToLinks(childNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,6 @@ const MyApp = ({ Component, pageProps }) => {
|
||||
loadExternalResource(url, 'css')
|
||||
}
|
||||
}
|
||||
checkThemeDOM()
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -55,18 +54,4 @@ const MyApp = ({ Component, pageProps }) => {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换主题时的特殊处理
|
||||
*/
|
||||
const checkThemeDOM = () => {
|
||||
const elements = document.querySelectorAll('[id^="theme-"]')
|
||||
if (elements?.length > 1) {
|
||||
elements[elements.length - 1].scrollIntoView()
|
||||
// 删除前面的元素,只保留最后一个元素
|
||||
for (let i = 0; i < elements.length - 1; i++) {
|
||||
elements[i].parentNode.removeChild(elements[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default MyApp
|
||||
|
||||
@@ -1,36 +1,101 @@
|
||||
import React from 'react'
|
||||
import BLOG from '@/blog.config'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import Link from 'next/link'
|
||||
|
||||
const Footer = ({ title }) => {
|
||||
/**
|
||||
* 页脚
|
||||
* @param {*} param0
|
||||
* @returns
|
||||
*/
|
||||
const Footer = (props) => {
|
||||
const d = new Date()
|
||||
const currentYear = d.getFullYear()
|
||||
const copyrightDate = (function() {
|
||||
if (Number.isInteger(BLOG.SINCE) && BLOG.SINCE < currentYear) {
|
||||
return BLOG.SINCE + '-' + currentYear
|
||||
}
|
||||
return currentYear
|
||||
})()
|
||||
const since = siteConfig('SINCE')
|
||||
const copyrightDate = parseInt(since) < currentYear ? since + '-' + currentYear : currentYear
|
||||
const { categoryOptions, customMenu } = props
|
||||
|
||||
return (
|
||||
<footer
|
||||
className='relative z-10 dark:bg-black flex-shrink-0 bg-hexo-light-gray justify-center text-center m-auto w-full leading-6 text-gray-600 dark:text-gray-100 text-sm p-6'
|
||||
>
|
||||
{/* <DarkModeButton/> */}
|
||||
return <footer id="footer-wrapper" className='relative bg-[#2A2A2A] justify-center text-center m-auto w-full leading-6 text-gray-300 text-sm p-10'>
|
||||
|
||||
<i className='fas fa-copyright' /> {`${copyrightDate}`} <span><i className='mx-1 animate-pulse fas fa-heart'/> <a href={BLOG.LINK} className='underline font-bold dark:text-gray-300 '>{siteConfig('AUTHOR')}</a>.<br/>
|
||||
<div id='footer-container' className='w-full mx-auto max-w-screen-xl'>
|
||||
|
||||
{BLOG.BEI_AN && <><i className='fas fa-shield-alt' /> <a href='https://beian.miit.gov.cn/' className='mr-2'>{BLOG.BEI_AN}</a><br/></>}
|
||||
<div className='flex'>
|
||||
<div className='flex flex-grow my-6 space-x-20 text-lg'>
|
||||
|
||||
<span className='hidden busuanzi_container_site_pv'>
|
||||
<i className='fas fa-eye'/><span className='px-1 busuanzi_value_site_pv'> </span> </span>
|
||||
<span className='pl-2 hidden busuanzi_container_site_uv'>
|
||||
<i className='fas fa-users'/> <span className='px-1 busuanzi_value_site_uv'> </span> </span>
|
||||
<h1 className='text-xs pt-4 text-light-400 dark:text-gray-400'>{title} {siteConfig('BIO') && <>|</>} {siteConfig('BIO')}</h1>
|
||||
<p className='text-xs pt-2 text-light-500 dark:text-gray-500'>Powered by <a href='https://github.com/tangly1024/NotionNext' className='dark:text-gray-300'>NotionNext {siteConfig('VERSION')}</a>.</p></span><br/>
|
||||
{/* 分类菜单 */}
|
||||
<div>
|
||||
<div className='font-bold mb-4 text-white'>{siteConfig('COMMERCE_TEXT_MENU_GROUP', 'Product Center')}</div>
|
||||
<nav id='home-nav-button' className={'flex flex-col space-y-2 text-start'}>
|
||||
{categoryOptions.map(category => {
|
||||
return (
|
||||
<Link
|
||||
key={`${category.name}`}
|
||||
title={`${category.name}`}
|
||||
href={`/category/${category.name}`}
|
||||
passHref>
|
||||
{category.name}
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
</footer>
|
||||
)
|
||||
{/* 系统菜单 */}
|
||||
<div>
|
||||
<div className='font-bold mb-4 text-white'>{siteConfig('COMMERCE_TEXT_MENU_TITLE', 'About US')}</div>
|
||||
<nav id='home-nav-button' className={'flex flex-col space-y-2 text-start'}>
|
||||
{customMenu.map(menu => {
|
||||
return (
|
||||
<Link
|
||||
key={`${menu.name}`}
|
||||
title={`${menu.name}`}
|
||||
href={`${menu.to}`}
|
||||
passHref>
|
||||
{menu.name}
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{siteConfig('COMMERCE_TEXT_SHOP_LINKS') && <div className='border-l pl-4 border-gray-600 my-6 whitespace-pre-line text-left max-w-md'>
|
||||
<div className='font-bold text-white'>{siteConfig('COMMERCE_TEXT_SHOP_TITLE')}</div>
|
||||
<div>{siteConfig('COMMERCE_TEXT_SHOP_LINKS')}</div>
|
||||
</div>}
|
||||
</div>
|
||||
|
||||
{/* 底部版权相关 */}
|
||||
<div id='footer-copyright-wrapper' className='flex justify-between border-t border-gray-600 pt-8'>
|
||||
<div className='text-start space-y-1'>
|
||||
|
||||
{/* 网站所有者 */}
|
||||
<div> Copyright <i className='fas fa-copyright' /> {`${copyrightDate}`} <a href={siteConfig('LINK')} className='underline font-bold dark:text-gray-300 '>{siteConfig('AUTHOR')}</a> All Rights Reserved.</div>
|
||||
|
||||
{/* 技术支持 */}
|
||||
<div className='text-xs text-light-500 dark:text-gray-700'>Powered by <a href='https://github.com/tangly1024/NotionNext' className='dark:text-gray-300'>NotionNext {siteConfig('VERSION')}</a>.</div>
|
||||
|
||||
{/* 站点统计 */}
|
||||
<div>
|
||||
<span className='hidden busuanzi_container_site_pv'>
|
||||
<i className='fas fa-eye' /><span className='px-1 busuanzi_value_site_pv'> </span> </span>
|
||||
<span className='pl-2 hidden busuanzi_container_site_uv'>
|
||||
<i className='fas fa-users' /> <span className='px-1 busuanzi_value_site_uv'> </span> </span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 右边公司名字 */}
|
||||
<div className='text-right'>
|
||||
<h1 className='text-xs pt-4 text-light-400 dark:text-gray-400'>{siteConfig('TITLE')} {siteConfig('BIO')}</h1>
|
||||
<h2> {siteConfig('DESCRIPTION')}</h2>
|
||||
{/* 可选备案信息 */}
|
||||
{siteConfig('BEI_AN') && <><i className='fas fa-shield-alt' /> <a href='https://beian.miit.gov.cn/' className='mr-2'>{siteConfig('BEI_AN')}</a></>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</footer >
|
||||
}
|
||||
|
||||
export default Footer
|
||||
|
||||
@@ -1,65 +1,24 @@
|
||||
// import Image from 'next/image'
|
||||
import { useEffect, useState } from 'react'
|
||||
import Typed from 'typed.js'
|
||||
import CONFIG from '../config'
|
||||
import NavButtonGroup from './NavButtonGroup'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import LazyImage from '@/components/LazyImage'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
|
||||
let wrapperTop = 0
|
||||
|
||||
/**
|
||||
* 顶部全屏大图
|
||||
* @returns
|
||||
*/
|
||||
const Hero = props => {
|
||||
const [typed, changeType] = useState()
|
||||
const { siteInfo } = props
|
||||
const { locale } = useGlobal()
|
||||
const scrollToWrapper = () => {
|
||||
window.scrollTo({ top: wrapperTop, behavior: 'smooth' })
|
||||
}
|
||||
const GREETING_WORDS = siteConfig('GREETING_WORDS').split(',')
|
||||
useEffect(() => {
|
||||
updateHeaderHeight()
|
||||
|
||||
if (!typed && window && document.getElementById('typed')) {
|
||||
changeType(
|
||||
new Typed('#typed', {
|
||||
strings: GREETING_WORDS,
|
||||
typeSpeed: 200,
|
||||
backSpeed: 100,
|
||||
backDelay: 400,
|
||||
showCursor: true,
|
||||
smartBackspace: true
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
window.addEventListener('resize', updateHeaderHeight)
|
||||
return () => {
|
||||
window.removeEventListener('resize', updateHeaderHeight)
|
||||
}
|
||||
})
|
||||
|
||||
function updateHeaderHeight() {
|
||||
requestAnimationFrame(() => {
|
||||
const wrapperElement = document.getElementById('wrapper')
|
||||
wrapperTop = wrapperElement?.offsetTop
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<header
|
||||
id="header" style={{ zIndex: 1 }}
|
||||
className="w-full h-[52rem] relative bg-black"
|
||||
className="w-full h-auto aspect-[5/2] relative bg-black"
|
||||
>
|
||||
|
||||
<div className="text-white absolute bottom-0 flex flex-col h-full items-center justify-center w-full "></div>
|
||||
|
||||
<LazyImage id='header-cover' src={siteInfo?.pageCover}
|
||||
className={`header-cover w-full h-[52rem] object-cover object-center ${CONFIG.HOME_NAV_BACKGROUND_IMG_FIXED ? 'fixed' : ''}`} />
|
||||
className={`header-cover w-full h-auto aspect-[5/2] object-cover object-center ${CONFIG.HOME_NAV_BACKGROUND_IMG_FIXED ? 'fixed' : ''}`} />
|
||||
|
||||
</header>
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Link from 'next/link'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
// import { siteConfig } from '@/lib/config'
|
||||
import LazyImage from '@/components/LazyImage';
|
||||
|
||||
/**
|
||||
@@ -14,7 +14,7 @@ export default function LogoBar (props) {
|
||||
<Link href='/' className='text-md md:text-xl dark:text-gray-200 r'>
|
||||
<LazyImage className='h-12 mr-3' src={siteInfo?.icon}/>
|
||||
</Link>
|
||||
<div>{siteConfig('TITLE')}</div>
|
||||
{/* <div>{siteConfig('TITLE')}</div> */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,14 +16,14 @@ export const MenuItemDrop = ({ link }) => {
|
||||
{!hasSubMenu &&
|
||||
<Link
|
||||
href={link?.to} target={link?.to?.indexOf('http') === 0 ? '_blank' : '_self'}
|
||||
className={`${selected && 'border-b-2 border-[#D2232A]'} h-full flex whitespace-nowrap items-center font-sans menu-link pl-2 pr-4 dark:text-gray-200 no-underline tracking-widest pb-1`}>
|
||||
{link?.icon && <i className={link?.icon}/>} {link?.name}
|
||||
className={`${selected && 'border-b-2 border-[#D2232A]'} h-full flex space-x-1 whitespace-nowrap items-center font-sans menu-link pl-2 pr-4 dark:text-gray-200 no-underline tracking-widest pb-1`}>
|
||||
{link?.icon && <i className={link?.icon}/>} <div>{link?.name}</div>
|
||||
{/* {hasSubMenu && <i className='px-2 fa fa-angle-down'></i>} */}
|
||||
</Link>}
|
||||
|
||||
{hasSubMenu && <>
|
||||
<div className='h-full flex whitespace-nowrap items-center cursor-pointer font-sans menu-link pl-2 pr-4 dark:text-gray-200 no-underline tracking-widest pb-1'>
|
||||
{link?.icon && <i className={link?.icon}/>} {link?.name}
|
||||
<div className='h-full flex space-x-1 whitespace-nowrap items-center cursor-pointer font-sans menu-link pl-2 pr-4 dark:text-gray-200 no-underline tracking-widest pb-1'>
|
||||
{link?.icon && <i className={link?.icon}/>} <div>{link?.name}</div>
|
||||
{/* <i className={`px-2 fa fa-angle-down duration-300 ${show ? 'rotate-180' : 'rotate-0'}`}></i> */}
|
||||
</div>
|
||||
</>}
|
||||
|
||||
@@ -18,7 +18,7 @@ export const MenuListSide = (props) => {
|
||||
if (customNav) {
|
||||
links = customNav.concat(links)
|
||||
}
|
||||
|
||||
|
||||
for (let i = 0; i < links.length; i++) {
|
||||
if (links[i].id !== i) {
|
||||
links[i].id = i
|
||||
|
||||
@@ -17,7 +17,6 @@ export default function TopNavBar(props) {
|
||||
const { customNav, customMenu } = props
|
||||
const [isOpen, changeShow] = useState(false)
|
||||
const collapseRef = useRef(null)
|
||||
let windowTop = 0
|
||||
|
||||
const { locale } = useGlobal()
|
||||
|
||||
@@ -43,19 +42,17 @@ export default function TopNavBar(props) {
|
||||
}
|
||||
}, [])
|
||||
|
||||
const throttleMs = 200
|
||||
const throttleMs = 150
|
||||
|
||||
const scrollTrigger = throttle(() => {
|
||||
const scrollS = window.scrollY
|
||||
const nav = document.querySelector('#navbar')
|
||||
const nav = document.querySelector('#top-navbar')
|
||||
|
||||
const narrowNav = scrollS >= windowTop || scrollS > 200
|
||||
const narrowNav = scrollS > 50
|
||||
if (narrowNav) {
|
||||
nav && nav.classList.replace('h-24', 'h-16')
|
||||
windowTop = scrollS
|
||||
nav && nav.classList.replace('h-24', 'h-14')
|
||||
} else {
|
||||
nav && nav.classList.replace('h-16', 'h-24')
|
||||
windowTop = scrollS
|
||||
nav && nav.classList.replace('h-14', 'h-24')
|
||||
}
|
||||
}, throttleMs)
|
||||
|
||||
@@ -68,34 +65,32 @@ export default function TopNavBar(props) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div id='top-nav' className={'sticky top-0 w-full z-40 '}>
|
||||
return <div id='top-navbar-wrapper' className={'sticky top-0 w-full z-40 shadow bg-white dark:bg-hexo-black-gray '}>
|
||||
|
||||
{/* 移动端折叠菜单 */}
|
||||
<Collapse type='vertical' collapseRef={collapseRef} isOpen={isOpen} className='md:hidden'>
|
||||
<div className='bg-white dark:bg-hexo-black-gray pt-1 py-2 lg:hidden '>
|
||||
<MenuBarMobile {...props} onHeightChange={(param) => collapseRef.current?.updateCollapseHeight(param)} />
|
||||
</div>
|
||||
</Collapse>
|
||||
{/* 移动端折叠菜单 */}
|
||||
<Collapse type='vertical' collapseRef={collapseRef} isOpen={isOpen} className='md:hidden'>
|
||||
<div className='bg-white dark:bg-hexo-black-gray pt-1 py-2 lg:hidden '>
|
||||
<MenuBarMobile {...props} onHeightChange={(param) => collapseRef.current?.updateCollapseHeight(param)} />
|
||||
</div>
|
||||
</Collapse>
|
||||
|
||||
{/* 导航栏菜单 */}
|
||||
<div id="navbar" className='flex w-full h-24 transition-all duration-200 shadow bg-white dark:bg-hexo-black-gray px-7 items-between'>
|
||||
{/* 导航栏菜单内容 */}
|
||||
<div id="top-navbar" className='flex w-full mx-auto max-w-screen-xl h-24 transition-all duration-200 items-between'>
|
||||
|
||||
{/* 左侧图标Logo */}
|
||||
<LogoBar {...props} />
|
||||
{/* 左侧图标Logo */}
|
||||
<LogoBar {...props} />
|
||||
|
||||
{/* 移动端折叠按钮 */}
|
||||
<div className='mr-1 flex md:hidden justify-end items-center text-sm space-x-4 font-serif dark:text-gray-200'>
|
||||
<div onClick={toggleMenuOpen} className='cursor-pointer'>
|
||||
{isOpen ? <i className='fas fa-times' /> : <i className='fas fa-bars' />}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 桌面端顶部菜单 */}
|
||||
<div className='hidden md:flex items-center'>
|
||||
{links && links?.map(link => <MenuItemDrop key={link?.id} link={link}/>)}
|
||||
{/* 移动端折叠按钮 */}
|
||||
<div className='mr-1 flex md:hidden justify-end items-center text-sm space-x-4 font-serif dark:text-gray-200'>
|
||||
<div onClick={toggleMenuOpen} className='cursor-pointer'>
|
||||
{isOpen ? <i className='fas fa-times' /> : <i className='fas fa-bars' />}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 桌面端顶部菜单 */}
|
||||
<div className='hidden md:flex items-center'>
|
||||
{links && links?.map(link => <MenuItemDrop key={link?.id} link={link} />)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ import CONFIG from './config'
|
||||
import CommonHead from '@/components/CommonHead'
|
||||
import { useEffect, useRef } from 'react'
|
||||
import Footer from './components/Footer'
|
||||
import SideRight from './components/SideRight'
|
||||
// import SideRight from './components/SideRight'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { isBrowser } from '@/lib/utils'
|
||||
import { isBrowser, scanAndConvertToLinks } from '@/lib/utils'
|
||||
import BlogPostListPage from './components/BlogPostListPage'
|
||||
import BlogPostListScroll from './components/BlogPostListScroll'
|
||||
import Hero from './components/Hero'
|
||||
@@ -41,14 +41,19 @@ import TopNavBar from './components/TopNavBar'
|
||||
* @constructor
|
||||
*/
|
||||
const LayoutBase = props => {
|
||||
const { children, headerSlot, floatSlot, slotTop, meta, className } = props
|
||||
const { children, headerSlot, floatSlot, slotTop, slotRight, meta, className } = props
|
||||
const { onLoading } = useGlobal()
|
||||
|
||||
// 查找页面上的 链接,并便成为可点击
|
||||
useEffect(() => {
|
||||
scanAndConvertToLinks(document.getElementById('theme-commerce'))
|
||||
})
|
||||
|
||||
return (
|
||||
<div id='theme-commerce'>
|
||||
{/* 网页SEO */}
|
||||
<CommonHead meta={meta}/>
|
||||
<Style/>
|
||||
<CommonHead meta={meta} />
|
||||
<Style />
|
||||
|
||||
{/* 顶部导航 */}
|
||||
<TopNavBar {...props} />
|
||||
@@ -69,9 +74,9 @@ const LayoutBase = props => {
|
||||
</Transition>
|
||||
|
||||
{/* 主区块 */}
|
||||
<main id="wrapper" className={`${CONFIG.HOME_BANNER_ENABLE ? '' : 'pt-16'} bg-hexo-background-gray dark:bg-black w-full py-8 md:px-8 lg:px-24 min-h-screen relative`}>
|
||||
<main id="wrapper" className={`${CONFIG.HOME_BANNER_ENABLE ? '' : 'pt-16'} bg-hexo-background-gray dark:bg-black w-full py-8 md:px-8 lg:px-24 relative`}>
|
||||
<div id="container-inner" className={(siteConfig('LAYOUT_SIDEBAR_REVERSE') ? 'flex-row-reverse' : '') + ' w-full mx-auto lg:flex lg:space-x-4 justify-center relative z-10'} >
|
||||
<div className={`${className || ''} w-full max-w-4xl h-full overflow-hidden`}>
|
||||
<div className={`${className || ''} w-full h-full max-w-screen-xl overflow-hidden`}>
|
||||
|
||||
<Transition
|
||||
show={!onLoading}
|
||||
@@ -91,8 +96,8 @@ const LayoutBase = props => {
|
||||
</Transition>
|
||||
</div>
|
||||
|
||||
{/* 右侧栏 */}
|
||||
<SideRight {...props} />
|
||||
{slotRight}
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -100,7 +105,7 @@ const LayoutBase = props => {
|
||||
<RightFloatArea floatSlot={floatSlot} />
|
||||
|
||||
{/* 页脚 */}
|
||||
<Footer title={siteConfig('TITLE') || siteConfig('TITLE')} />
|
||||
<Footer {...props} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -112,8 +117,30 @@ const LayoutBase = props => {
|
||||
* @returns
|
||||
*/
|
||||
const LayoutIndex = (props) => {
|
||||
// 首页Banner条
|
||||
const headerSlot = CONFIG.HOME_BANNER_ENABLE && <Hero {...props} />
|
||||
return <LayoutPostList {...props} headerSlot={headerSlot} className='pt-8' />
|
||||
const { notice } = props
|
||||
return <LayoutBase headerSlot={headerSlot} {...props}>
|
||||
|
||||
{/* 产品中心 */}
|
||||
<div className='w-full my-4'>
|
||||
<div className='w-full text-center text-4xl font-bold'>{siteConfig('TEXT_HOME_PRODUCT_CENTER', 'Product Center')}</div>
|
||||
|
||||
<div className='flex'>
|
||||
<div className='hidden md:block w-72 border'> 左侧导航</div>
|
||||
<div className='w-full border'>右侧产品列表</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 企业介绍 + 联系 */}
|
||||
{notice && <div className='w-full my-4'>
|
||||
<div className='w-full text-center text-4xl font-bold'>{siteConfig('TEXT_HOME_ABOUT_US', notice.title)}</div>
|
||||
<NotionPage post={notice} />
|
||||
</div>}
|
||||
|
||||
{/* 铺开导航菜单 */}
|
||||
|
||||
</LayoutBase>
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,12 +5,8 @@ import { siteConfig } from '@/lib/config'
|
||||
export const Footer = (props) => {
|
||||
const d = new Date()
|
||||
const currentYear = d.getFullYear()
|
||||
const copyrightDate = (function() {
|
||||
if (Number.isInteger(BLOG.SINCE) && BLOG.SINCE < currentYear) {
|
||||
return BLOG.SINCE + '-' + currentYear
|
||||
}
|
||||
return currentYear
|
||||
})()
|
||||
const since = siteConfig('SINCE')
|
||||
const copyrightDate = parseInt(since) < currentYear ? since + '-' + currentYear : currentYear
|
||||
|
||||
return <footer className="z-10 relative w-full bg-white px-6 border-t dark:border-hexo-black-gray dark:bg-hexo-black-gray ">
|
||||
<DarkModeButton className='text-center pt-4'/>
|
||||
|
||||
@@ -4,12 +4,8 @@ import { siteConfig } from '@/lib/config'
|
||||
function SiteInfo ({ title }) {
|
||||
const d = new Date()
|
||||
const currentYear = d.getFullYear()
|
||||
const copyrightDate = (function() {
|
||||
if (Number.isInteger(BLOG.SINCE) && BLOG.SINCE < currentYear) {
|
||||
return BLOG.SINCE + '-' + currentYear
|
||||
}
|
||||
return currentYear
|
||||
})()
|
||||
const since = siteConfig('SINCE')
|
||||
const copyrightDate = parseInt(since) < currentYear ? since + '-' + currentYear : currentYear
|
||||
|
||||
return (
|
||||
<footer
|
||||
|
||||
@@ -5,12 +5,8 @@ import { siteConfig } from '@/lib/config'
|
||||
const Footer = ({ siteInfo }) => {
|
||||
const d = new Date()
|
||||
const currentYear = d.getFullYear()
|
||||
const copyrightDate = (function () {
|
||||
if (Number.isInteger(BLOG.SINCE) && BLOG.SINCE < currentYear) {
|
||||
return BLOG.SINCE + '-' + currentYear
|
||||
}
|
||||
return currentYear
|
||||
})()
|
||||
const since = siteConfig('SINCE')
|
||||
const copyrightDate = parseInt(since) < currentYear ? since + '-' + currentYear : currentYear
|
||||
|
||||
return (
|
||||
<footer
|
||||
|
||||
@@ -6,12 +6,8 @@ import { siteConfig } from '@/lib/config'
|
||||
const Footer = ({ title }) => {
|
||||
const d = new Date()
|
||||
const currentYear = d.getFullYear()
|
||||
const copyrightDate = (function () {
|
||||
if (Number.isInteger(BLOG.SINCE) && BLOG.SINCE < currentYear) {
|
||||
return BLOG.SINCE + '-' + currentYear
|
||||
}
|
||||
return currentYear
|
||||
})()
|
||||
const since = siteConfig('SINCE')
|
||||
const copyrightDate = parseInt(since) < currentYear ? since + '-' + currentYear : currentYear
|
||||
|
||||
return (
|
||||
<footer
|
||||
|
||||
@@ -5,12 +5,8 @@ import { siteConfig } from '@/lib/config'
|
||||
const Footer = ({ title }) => {
|
||||
const d = new Date()
|
||||
const currentYear = d.getFullYear()
|
||||
const copyrightDate = (function() {
|
||||
if (Number.isInteger(BLOG.SINCE) && BLOG.SINCE < currentYear) {
|
||||
return BLOG.SINCE + '-' + currentYear
|
||||
}
|
||||
return currentYear
|
||||
})()
|
||||
const since = siteConfig('SINCE')
|
||||
const copyrightDate = parseInt(since) < currentYear ? since + '-' + currentYear : currentYear
|
||||
|
||||
return (
|
||||
<footer
|
||||
|
||||
@@ -6,12 +6,8 @@ import { siteConfig } from '@/lib/config'
|
||||
const Footer = ({ title }) => {
|
||||
const d = new Date()
|
||||
const currentYear = d.getFullYear()
|
||||
const copyrightDate = (function() {
|
||||
if (Number.isInteger(BLOG.SINCE) && BLOG.SINCE < currentYear) {
|
||||
return BLOG.SINCE + '-' + currentYear
|
||||
}
|
||||
return currentYear
|
||||
})()
|
||||
const since = siteConfig('SINCE')
|
||||
const copyrightDate = parseInt(since) < currentYear ? since + '-' + currentYear : currentYear
|
||||
|
||||
return (
|
||||
<footer
|
||||
|
||||
@@ -4,12 +4,8 @@ import { siteConfig } from '@/lib/config'
|
||||
const Footer = ({ siteInfo }) => {
|
||||
const d = new Date()
|
||||
const currentYear = d.getFullYear()
|
||||
const copyrightDate = (function () {
|
||||
if (Number.isInteger(BLOG.SINCE) && BLOG.SINCE < currentYear) {
|
||||
return BLOG.SINCE + '-' + currentYear
|
||||
}
|
||||
return currentYear
|
||||
})()
|
||||
const since = siteConfig('SINCE')
|
||||
const copyrightDate = parseInt(since) < currentYear ? since + '-' + currentYear : currentYear
|
||||
|
||||
return (
|
||||
<footer
|
||||
|
||||
@@ -5,12 +5,8 @@ import DarkModeButton from '@/components/DarkModeButton'
|
||||
const Footer = ({ title }) => {
|
||||
const d = new Date()
|
||||
const currentYear = d.getFullYear()
|
||||
const copyrightDate = (function () {
|
||||
if (Number.isInteger(BLOG.SINCE) && BLOG.SINCE < currentYear) {
|
||||
return BLOG.SINCE + '-' + currentYear
|
||||
}
|
||||
return currentYear
|
||||
})()
|
||||
const since = siteConfig('SINCE')
|
||||
const copyrightDate = parseInt(since) < currentYear ? since + '-' + currentYear : currentYear
|
||||
|
||||
return (
|
||||
<footer
|
||||
|
||||
@@ -8,13 +8,8 @@ export const Footer = (props) => {
|
||||
const currentYear = d.getFullYear()
|
||||
const { post } = props
|
||||
const fullWidth = post?.fullWidth ?? false
|
||||
|
||||
const copyrightDate = (function() {
|
||||
if (Number.isInteger(BLOG.SINCE) && BLOG.SINCE < currentYear) {
|
||||
return BLOG.SINCE + '-' + currentYear
|
||||
}
|
||||
return currentYear
|
||||
})()
|
||||
const since = siteConfig('SINCE')
|
||||
const copyrightDate = parseInt(since) < currentYear ? since + '-' + currentYear : currentYear
|
||||
|
||||
return <footer
|
||||
className={`z-10 relative mt-6 flex-shrink-0 m-auto w-full text-gray-500 dark:text-gray-400 transition-all ${
|
||||
|
||||
@@ -6,12 +6,8 @@ export const Footer = (props) => {
|
||||
const d = new Date()
|
||||
const currentYear = d.getFullYear()
|
||||
|
||||
const copyrightDate = (function() {
|
||||
if (Number.isInteger(BLOG.SINCE) && BLOG.SINCE < currentYear) {
|
||||
return BLOG.SINCE + '-' + currentYear
|
||||
}
|
||||
return currentYear
|
||||
})()
|
||||
const since = siteConfig('SINCE')
|
||||
const copyrightDate = parseInt(since) < currentYear ? since + '-' + currentYear : currentYear
|
||||
|
||||
return <footer className={'z-10 relative mt-6 flex-shrink-0 m-auto w-full text-gray-500 dark:text-gray-400 transition-all' } >
|
||||
<div className="my-4 text-sm leading-6">
|
||||
|
||||
@@ -5,12 +5,8 @@ import { siteConfig } from '@/lib/config'
|
||||
export const Footer = (props) => {
|
||||
const d = new Date()
|
||||
const currentYear = d.getFullYear()
|
||||
const copyrightDate = (function() {
|
||||
if (Number.isInteger(BLOG.SINCE) && BLOG.SINCE < currentYear) {
|
||||
return BLOG.SINCE + '-' + currentYear
|
||||
}
|
||||
return currentYear
|
||||
})()
|
||||
const since = siteConfig('SINCE')
|
||||
const copyrightDate = parseInt(since) < currentYear ? since + '-' + currentYear : currentYear
|
||||
|
||||
return <footer className="relative w-full bg-black px-6 border-t">
|
||||
<DarkModeButton className='text-center pt-4'/>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import cookie from 'react-cookies'
|
||||
import BLOG from '@/blog.config'
|
||||
import { getQueryParam, getQueryVariable } from '../lib/utils'
|
||||
import { getQueryParam, getQueryVariable, isBrowser } from '../lib/utils'
|
||||
import dynamic from 'next/dynamic'
|
||||
import getConfig from 'next/config'
|
||||
import * as ThemeComponents from '@theme-components'
|
||||
@@ -15,13 +15,38 @@ export const { THEMES = [] } = getConfig().publicRuntimeConfig
|
||||
export const getLayoutByTheme = ({ router, theme }) => {
|
||||
const themeQuery = getQueryParam(router.asPath, 'theme') || theme
|
||||
const layoutName = getLayoutNameByPath(router.pathname)
|
||||
|
||||
if (themeQuery !== BLOG.THEME) {
|
||||
return dynamic(() => import(`@/themes/${themeQuery}`).then(m => m[layoutName]), { ssr: true })
|
||||
return dynamic(() => import(`@/themes/${themeQuery}`).then(m => {
|
||||
setTimeout(() => {
|
||||
checkThemeDOM()
|
||||
}, 500);
|
||||
return m[layoutName]
|
||||
}), { ssr: true })
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
checkThemeDOM()
|
||||
}, 100);
|
||||
return ThemeComponents[layoutName]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换主题时的特殊处理
|
||||
*/
|
||||
const checkThemeDOM = () => {
|
||||
if (isBrowser) {
|
||||
const elements = document.querySelectorAll('[id^="theme-"]')
|
||||
if (elements?.length > 1) {
|
||||
elements[elements.length - 1].scrollIntoView()
|
||||
// 删除前面的元素,只保留最后一个元素
|
||||
for (let i = 0; i < elements.length - 1; i++) {
|
||||
elements[i].parentNode.removeChild(elements[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据路径 获取对应的layout
|
||||
* @param {*} path
|
||||
|
||||
Reference in New Issue
Block a user