Merge branch 'main' into main

This commit is contained in:
李美哲
2024-02-07 20:33:46 +08:00
committed by GitHub
40 changed files with 382 additions and 242 deletions

View File

@@ -1,5 +1,5 @@
# 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables
NEXT_PUBLIC_VERSION=4.2.3
NEXT_PUBLIC_VERSION=4.2.4
# 可在此添加环境变量,去掉最左边的(# )注释即可

View File

@@ -45,8 +45,9 @@ const BLOG = {
// 默认下会将你上传到 notion的主页封面图和头像也给替换建议将主页封面图和头像放在其他图床在 notion 里配置 link 即可。
// START ************网站字体*****************
FONT_STYLE: process.env.NEXT_PUBLIC_FONT_STYLE || 'font-sans', // ['font-serif','font-sans'] 两种可选,分别是衬线和无衬线: 参考 https://www.jianshu.com/p/55e410bd2115
// ['font-serif','font-sans'] 两种可选,分别是衬线和无衬线: 参考 https://www.jianshu.com/p/55e410bd2115
// 后面空格隔开的font-light的字体粗细留空是默认粗细参考 https://www.tailwindcss.cn/docs/font-weight
FONT_STYLE: process.env.NEXT_PUBLIC_FONT_STYLE || 'font-sans font-light',
// 字体CSS 例如 https://npm.elemecdn.com/lxgw-wenkai-webfont@1.6.0/style.css
FONT_URL: [
// 'https://npm.elemecdn.com/lxgw-wenkai-webfont@1.6.0/style.css',

View File

@@ -119,6 +119,7 @@ export async function getNotionPageData({ pageId, from }) {
/**
* 获取用户自定义单页菜单
* 旧版本不读取Menu菜单而是读取type=Page生成菜单
* @param notionPageData
* @returns {Promise<[]|*[]>}
*/
@@ -126,11 +127,16 @@ function getCustomNav({ allPages }) {
const customNav = []
if (allPages && allPages.length > 0) {
allPages.forEach(p => {
p.to = p.slug
if (p?.slug?.indexOf('http') === 0) {
customNav.push({ icon: p.icon || null, name: p.title, to: p.slug, target: '_blank', show: true })
p.target = '_blank'
} else {
customNav.push({ icon: p.icon || null, name: p.title, to: '/' + p.slug, target: '_self', show: true })
p.target = '_self'
if (p?.slug?.indexOf('/') !== 0) {
p.to = '/' + p.slug
}
}
customNav.push({ icon: p.icon || null, name: p.title, to: p.slug, target: '_blank', show: true })
})
}
return customNav
@@ -142,13 +148,19 @@ function getCustomNav({ allPages }) {
* @returns
*/
function getCustomMenu({ collectionData }) {
const menuPages = collectionData.filter(post => (post?.type === BLOG.NOTION_PROPERTY_NAME.type_menu || post?.type === BLOG.NOTION_PROPERTY_NAME.type_sub_menu) && post.status === 'Published')
const menuPages = collectionData.filter(post => post.status === 'Published' && (post?.type === BLOG.NOTION_PROPERTY_NAME.type_menu || post?.type === BLOG.NOTION_PROPERTY_NAME.type_sub_menu))
const menus = []
if (menuPages && menuPages.length > 0) {
menuPages.forEach(e => {
e.show = true
if (e?.slug?.indexOf('http') === 0) {
e.target = '_blank'
e.to = e.slug
} else {
e.target = '_self'
if (e?.slug?.indexOf('/') !== 0) {
e.to = '/' + e.slug
}
}
if (e.type === BLOG.NOTION_PROPERTY_NAME.type_menu) {
menus.push(e)

View File

@@ -18,10 +18,7 @@ export async function getPostBlocks(id, from, slice) {
return filterPostBlocks(id, pageBlock, slice)
}
const start = new Date().getTime()
pageBlock = await getPageWithRetry(id, from)
const end = new Date().getTime()
console.log('[API耗时]', `${end - start}ms`)
if (pageBlock) {
await setDataToCache(cacheKey, pageBlock)
@@ -38,10 +35,7 @@ export async function getSingleBlock(id, from) {
return pageBlock
}
const start = new Date().getTime()
pageBlock = await getPageWithRetry(id, from)
const end = new Date().getTime()
console.log('[API耗时]', `${end - start}ms`)
if (pageBlock) {
await setDataToCache(cacheKey, pageBlock)
@@ -56,16 +50,17 @@ export async function getSingleBlock(id, from) {
*/
export async function getPageWithRetry(id, from, retryAttempts = 3) {
if (retryAttempts && retryAttempts > 0) {
console.log('[请求API]', `from:${from}`, `id:${id}`, retryAttempts < 3 ? `剩余重试次数:${retryAttempts}` : '')
console.log('[API-->>请求]', `from:${from}`, `id:${id}`, retryAttempts < 3 ? `剩余重试次数:${retryAttempts}` : '')
try {
const authToken = BLOG.NOTION_ACCESS_TOKEN || null
const api = new NotionAPI({ authToken, userTimeZone: Intl.DateTimeFormat().resolvedOptions().timeZone })
const start = new Date().getTime()
const pageData = await api.getPage(id)
// console.log('stringfy', JSON.stringify(pageData))
console.info('[响应成功]:', `from:${from}`)
const end = new Date().getTime()
console.log('[API<<--响应]', `耗时:${end - start}ms - from:${from}`)
return pageData
} catch (e) {
console.warn('[响应异常]:', e)
console.warn('[API<<--异常]:', e)
await delay(1000)
const cacheKey = 'page_block_' + id
const pageBlock = await getDataFromCache(cacheKey)

View File

@@ -16,13 +16,16 @@ function scanSubdirectories(directory) {
const subdirectories = []
fs.readdirSync(directory).forEach(file => {
const fullPath = path.join(directory, file)
const stats = fs.statSync(fullPath)
// 这段代码会将landing排除在可选主题中
// landing主题比较特殊不在可切换的主题中显示
if (stats.isDirectory() && file !== 'landing') {
subdirectories.push(file)
}
// const fullPath = path.join(directory, file)
// const stats = fs.statSync(fullPath)
// landing主题默认隐藏掉一般网站不会用到
// if (stats.isDirectory() && file !== 'landing') {
// subdirectories.push(file)
// }
subdirectories.push(file)
})
return subdirectories
@@ -94,7 +97,7 @@ module.exports = withBundleAnalyzer({
// }
// 动态主题:添加 resolve.alias 配置,将动态路径映射到实际路径
if (!isServer) {
console.log('加载默认主题', path.resolve(__dirname, 'themes', THEME))
console.log('[加载主题]', path.resolve(__dirname, 'themes', THEME))
}
config.resolve.alias['@theme-components'] = path.resolve(__dirname, 'themes', THEME)
return config

View File

@@ -1,77 +1,78 @@
{
"name": "notion-next",
"version": "4.2.3",
"homepage": "https://github.com/tangly1024/NotionNext.git",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/tangly1024/NotionNext.git"
},
"author": {
"name": "tangly",
"email": "mail@tangly1024.com",
"url": "http://tangly1024.com"
},
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"post-build": "next-sitemap --config next-sitemap.config.js",
"export": "next build && next-sitemap --config next-sitemap.config.js && next export",
"bundle-report": "ANALYZE=true yarn build"
},
"dependencies": {
"@giscus/react": "^2.2.6",
"@headlessui/react": "^1.7.15",
"@next/bundle-analyzer": "^12.1.1",
"@vercel/analytics": "^1.0.0",
"algoliasearch": "^4.18.0",
"animejs": "^3.2.1",
"aos": "^3.0.0-beta.6",
"axios": ">=0.21.1",
"copy-to-clipboard": "^3.3.1",
"eslint-plugin-react-hooks": "^4.6.0",
"feed": "^4.2.2",
"js-md5": "^0.7.3",
"localStorage": "^1.0.4",
"lodash.throttle": "^4.1.1",
"memory-cache": "^0.2.0",
"mongodb": "^4.6.0",
"next": "13.3.1",
"notion-client": "6.15.6",
"notion-utils": "6.15.6",
"nprogress": "^0.2.0",
"preact": "^10.5.15",
"prism-themes": "1.9.0",
"react": "^18.2.0",
"react-cookies": "^0.1.1",
"react-dom": "^18.2.0",
"react-facebook": "^8.1.4",
"react-notion-x": "6.16.0",
"react-share": "^4.4.1",
"react-tweet-embed": "~2.0.0",
"typed.js": "^2.0.12"
},
"devDependencies": {
"@waline/client": "^2.5.1",
"autoprefixer": "^10.4.13",
"eslint": "^7.26.0",
"eslint-config-next": "^13.1.1",
"eslint-config-standard": "^16.0.2",
"eslint-plugin-import": "^2.23.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-react": "^7.23.2",
"next-sitemap": "^1.6.203",
"postcss": "^8.4.31",
"tailwindcss": "^3.3.2",
"webpack-bundle-analyzer": "^4.5.0"
},
"resolutions": {
"axios": ">=0.21.1"
},
"bugs": {
"url": "https://github.com/tangly/NotionNext/issues",
"email": "tlyong1992@hotmail.com"
}
}
"name": "notion-next",
"version": "4.2.4",
"homepage": "https://github.com/tangly1024/NotionNext.git",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/tangly1024/NotionNext.git"
},
"author": {
"name": "tangly",
"email": "mail@tangly1024.com",
"url": "http://tangly1024.com"
},
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"post-build": "next-sitemap --config next-sitemap.config.js",
"export": "next build && next-sitemap --config next-sitemap.config.js && next export",
"bundle-report": "ANALYZE=true yarn build"
},
"dependencies": {
"@giscus/react": "^2.2.6",
"@headlessui/react": "^1.7.15",
"@next/bundle-analyzer": "^12.1.1",
"@vercel/analytics": "^1.0.0",
"algoliasearch": "^4.18.0",
"animejs": "^3.2.1",
"aos": "^3.0.0-beta.6",
"axios": ">=0.21.1",
"copy-to-clipboard": "^3.3.1",
"feed": "^4.2.2",
"js-md5": "^0.7.3",
"localStorage": "^1.0.4",
"lodash.throttle": "^4.1.1",
"memory-cache": "^0.2.0",
"mongodb": "^4.6.0",
"next": "13.3.1",
"notion-client": "6.15.6",
"notion-utils": "6.15.6",
"nprogress": "^0.2.0",
"preact": "^10.5.15",
"prism-themes": "1.9.0",
"react": "^18.2.0",
"react-cookies": "^0.1.1",
"react-dom": "^18.2.0",
"react-facebook": "^8.1.4",
"react-notion-x": "6.16.0",
"react-share": "^4.4.1",
"react-tweet-embed": "~2.0.0",
"typed.js": "^2.0.12"
},
"devDependencies": {
"@waline/client": "^2.5.1",
"autoprefixer": "^10.4.13",
"eslint": "^7.26.0",
"eslint-config-next": "^13.1.1",
"eslint-config-standard": "^16.0.2",
"eslint-plugin-import": "^2.23.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-react": "^7.23.2",
"eslint-plugin-react-hooks": "^4.6.0",
"next-sitemap": "^1.6.203",
"postcss": "^8.4.31",
"prettier": "3.2.5",
"tailwindcss": "^3.3.2",
"webpack-bundle-analyzer": "^4.5.0"
},
"resolutions": {
"axios": ">=0.21.1"
},
"bugs": {
"url": "https://github.com/tangly/NotionNext/issues",
"email": "tlyong1992@hotmail.com"
}
}

View File

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

View File

@@ -4,6 +4,7 @@ import Link from 'next/link'
import TwikooCommentCount from '@/components/TwikooCommentCount'
import LazyImage from '@/components/LazyImage'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
import NotionIcon from '@/components/NotionIcon'
const BlogPostCard = ({ post }) => {
const showPageCover = siteConfig('EXAMPLE_POST_LIST_COVER', null, CONFIG) && post?.pageCoverThumbnail
@@ -15,16 +16,18 @@ const BlogPostCard = ({ post }) => {
<Link
href={`/${post.slug}`}
className="text-black dark:text-gray-100 text-xl md:text-2xl no-underline hover:underline">
{post?.title}
<NotionIcon icon={post.pageIcon} />{post?.title}
</Link>
</h2>
<div className="mb-4 text-sm text-gray-700 dark:text-gray-300">
by <a href="#" className="text-gray-700 dark:text-gray-300">{siteConfig('AUTHOR')}</a> on {post.date?.start_date || post.createdTime}
<TwikooCommentCount post={post} className='pl-1'/>
{post.category && <>
<span className="font-bold mx-1"> | </span>
<Link href={`/category/${post.category}`} className="text-gray-700 dark:text-gray-300 hover:underline">{post.category}</Link>
{/* <span className="font-bold mx-1"> | </span> */}
</>}
{/* <span className="font-bold mx-1"> | </span> */}
{/* <a href="#" className="text-gray-700">2 Comments</a> */}
</div>

View File

@@ -1,3 +1,4 @@
import NotionIcon from '@/components/NotionIcon'
import { siteConfig } from '@/lib/config'
/**
@@ -11,7 +12,7 @@ export const Title = (props) => {
const description = post?.description || siteConfig('AUTHOR')
return <div className="text-center px-6 py-12 mb-6 bg-gray-100 dark:bg-hexo-black-gray dark:border-hexo-black-gray border-b">
<h1 className=" text-xl md:text-4xl pb-4">{title}</h1>
<h1 className="text-xl md:text-4xl pb-4"><NotionIcon icon={post?.pageIcon} />{title}</h1>
<p className="leading-loose text-gray-dark">
{description}
</p>

View File

@@ -9,6 +9,7 @@ import { AdSlot } from '@/components/GoogleAdsense'
import LazyImage from '@/components/LazyImage'
import { formatDateFmt } from '@/lib/formatDate'
import WWAds from '@/components/WWAds'
import NotionIcon from '@/components/NotionIcon'
/**
*
@@ -36,7 +37,7 @@ export default function ArticleDetail(props) {
{/* 文章Title */}
<div className="font-bold text-4xl text-black dark:text-white">
{post.title}
<NotionIcon icon={post?.pageIcon} />{post.title}
</div>
<section className="flex-wrap flex mt-2 text-gray-400 dark:text-gray-400 font-light leading-8">

View File

@@ -4,6 +4,7 @@ import TagItemMini from './TagItemMini'
import CONFIG from '../config'
import LazyImage from '@/components/LazyImage'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
import NotionIcon from '@/components/NotionIcon'
/**
* 文章列表卡片
@@ -32,7 +33,7 @@ const BlogCard = ({ index, post, showSummary, siteInfo }) => {
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return (
<div {...aosProps} style={{ maxHeight: '60rem' }}
<article {...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">
@@ -51,16 +52,18 @@ const BlogCard = ({ index, post, showSummary, siteInfo }) => {
{/* 文字部分 */}
<div className="flex flex-col w-full">
<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}
</Link>
<h2>
<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`}
>
<NotionIcon icon={post.pageIcon} /> {post.title}
</Link>
</h2>
{(!showPreview || showSummary) && (
<p className="my-2 tracking-wide line-clamp-3 text-gray-800 dark:text-gray-300 text-md font-light leading-6">
<main className="my-2 tracking-wide line-clamp-3 text-gray-800 dark:text-gray-300 text-md font-light leading-6">
{post.summary}
</p>
</main>
)}
{/* 分类标签 */}
@@ -83,7 +86,7 @@ const BlogCard = ({ index, post, showSummary, siteInfo }) => {
</div>
</div>
</div>
</div>
</article>
)
}

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>f
</div>
{/* 折叠子菜单 */}
{hasSubMenu && <Collapse isOpen={isOpen} onHeightChange={props.onHeightChange}>

View File

@@ -2,6 +2,7 @@ import { siteConfig } from '@/lib/config'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
import NotionIcon from '@/components/NotionIcon'
const BlogPostCard = ({ post, className }) => {
const router = useRouter()
@@ -9,8 +10,8 @@ const BlogPostCard = ({ post, className }) => {
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
return (
<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 className="w-full select-none">
<NotionIcon icon={post?.pageIcon}/> {post.title}
</div>
</div>
</Link>

View File

@@ -4,8 +4,6 @@ import { useRouter } from 'next/router'
export const MenuItemDrop = ({ link }) => {
const [show, changeShow] = useState(false)
// const show = true
// const changeShow = () => {}
const router = useRouter()
if (!link || !link.show) {
@@ -13,7 +11,6 @@ export const MenuItemDrop = ({ link }) => {
}
const hasSubMenu = link?.subMenus?.length > 0
const selected = (router.pathname === link.to) || (router.asPath === link.to)
return <li className='cursor-pointer list-none items-center flex mx-2' onMouseOver={() => changeShow(true)} onMouseOut={() => changeShow(false)} >
{hasSubMenu &&

View File

@@ -33,6 +33,7 @@ import BlogArchiveItem from './components/BlogArchiveItem'
import Link from 'next/link'
import dynamic from 'next/dynamic'
import { siteConfig } from '@/lib/config'
import NotionIcon from '@/components/NotionIcon'
const WWAds = dynamic(() => import('@/components/WWAds'), { ssr: false })
// 主题全局变量
@@ -219,7 +220,7 @@ const LayoutSlug = (props) => {
{!lock && <div id='container'>
{/* title */}
<h1 className="text-3xl pt-12 dark:text-gray-300">{post?.title}</h1>
<h1 className="text-3xl pt-12 dark:text-gray-300"><NotionIcon icon={post?.pageIcon} />{post?.title}</h1>
{/* Notion文章主体 */}
{post && (<section id="article-wrapper" className="px-1">

View File

@@ -4,6 +4,7 @@ import TagItemMini from './TagItemMini'
import LazyImage from '@/components/LazyImage'
import { siteConfig } from '@/lib/config'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
import NotionIcon from '@/components/NotionIcon'
const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
const showPreview = siteConfig('HEO_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap
@@ -13,7 +14,7 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
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' : ''}`} >
<article className={` ${siteConfig('HEO_POST_LIST_COVER_HOVER_ENLARGE', null, CONFIG) ? ' hover:scale-110 transition-all duration-150' : ''}`} >
<div
data-aos="fade-up"
@@ -33,7 +34,7 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
{/* 文字区块 */}
<div className={'flex p-6 2xl:p-4 flex-col justify-between h-48 md:h-full 2xl:h-48 w-full md:w-7/12 2xl:w-full'}>
<div>
<header>
{/* 分类 */}
{post?.category && <div className={`flex mb-1 items-center ${showPreview ? 'justify-center' : 'justify-start'} hidden md:block flex-wrap dark:text-gray-500 text-gray-600 `}>
<Link passHref href={`/category/${post.category}`}
@@ -47,15 +48,15 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
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>
<NotionIcon icon={post.pageIcon} /><span className='menu-link '>{post.title}</span>
</Link>
</div>
</header>
{/* 摘要 */}
{(!showPreview || showSummary) && (
<p className="line-clamp-2 replace my-3 2xl:my-1 text-gray-700 dark:text-gray-300 text-sm font-light leading-tight">
<main className="line-clamp-2 replace my-3 2xl:my-1 text-gray-700 dark:text-gray-300 text-sm font-light leading-tight">
{post.summary}
</p>
</main>
)}
<div className="md:flex-nowrap flex-wrap md:justify-start inline-block">
@@ -70,7 +71,7 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
</div>
</div>
</div>
</article>
)
}

View File

@@ -1,4 +1,5 @@
import Link from 'next/link'
import { useRouter } from 'next/router'
/**
* 标签组
@@ -8,22 +9,34 @@ import Link from 'next/link'
* @constructor
*/
const TagGroups = ({ tags, className }) => {
const router = useRouter()
const { tag: currentTag } = router.query
if (!tags) return <></>
return (
<div id='tags-group' className='dark:border-gray-700 space-y-2'>
{
tags.map((tag, index) => {
return <Link passHref
key={index}
href={`/tag/${encodeURIComponent(tag.name)}`}
className={'cursor-pointer inline-block whitespace-nowrap'}>
<div className={`${className || ''} flex items-center hover:bg-blue-600 dark:hover:bg-yellow-600 hover:scale-110 hover:text-white rounded-lg px-2 py-0.5 duration-150 transition-all`}>
<div className='text-lg'>{tag.name} </div>{tag.count ? <sup className='relative ml-1'>{tag.count}</sup> : <></>}
</div>
return (
<div id="tags-group" className="dark:border-gray-700 space-y-2">
{tags.map((tag, index) => {
const selected = currentTag === tag.name
return (
<Link passHref key={index} href={`/tag/${encodeURIComponent(tag.name)}`}
className={'cursor-pointer inline-block whitespace-nowrap'}
>
<div className={`${className || ''}
${selected ? 'text-white bg-blue-600 dark:bg-yellow-600' : ''}
flex items-center hover:bg-blue-600 dark:hover:bg-yellow-600 hover:scale-110 hover:text-white rounded-lg px-2 py-0.5 duration-150 transition-all`}
>
<div className="text-lg">{tag.name} </div>
{tag.count
? (
<sup className="relative ml-1">{tag.count}</sup>
)
: (
<></>
)}
</div>
</Link>
})
}
)
})}
</div>
)
}

View File

@@ -5,6 +5,7 @@ import TwikooCommentCount from '@/components/TwikooCommentCount'
import { siteConfig } from '@/lib/config'
import { formatDateFmt } from '@/lib/formatDate'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
import NotionIcon from '@/components/NotionIcon'
/**
* 博客列表的文字内容
@@ -13,58 +14,63 @@ import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
*/
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'}`}>
return <article 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={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`}>
<header>
<h2>
{/* 标题 */}
<Link
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`}>
<span className='menu-link '>{post.title}</span>
<NotionIcon icon={post.pageIcon} /><span className='menu-link '>{post.title}</span>
</Link>
</Link>
</h2>
{/* 分类 */}
{ post?.category && <div
className={`flex mt-2 items-center ${showPreview ? 'justify-center' : 'justify-start'
} flex-wrap dark:text-gray-500 text-gray-400 `}
>
<Link
href={`/category/${post.category}`}
passHref
className="cursor-pointer font-light text-sm menu-link hover:text-indigo-700 dark:hover:text-indigo-400 transform">
{/* 分类 */}
{ post?.category && <div
className={`flex mt-2 items-center ${showPreview ? 'justify-center' : 'justify-start'
} flex-wrap dark:text-gray-500 text-gray-400 `}
>
<Link
href={`/category/${post.category}`}
passHref
className="cursor-pointer font-light text-sm menu-link hover:text-indigo-700 dark:hover:text-indigo-400 transform">
<i className="mr-1 far fa-folder" />
{post.category}
<i className="mr-1 far fa-folder" />
{post.category}
</Link>
</Link>
<TwikooCommentCount className='text-sm hover:text-indigo-700 dark:hover:text-indigo-400' post={post}/>
</div>}
<TwikooCommentCount className='text-sm hover:text-indigo-700 dark:hover:text-indigo-400' post={post}/>
</div>}
</header>
{/* 摘要 */}
{(!showPreview || showSummary) && !post.results && (
<p className="line-clamp-2 replace my-3 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
{/* 摘要 */}
{(!showPreview || showSummary) && !post.results && (
<main className="line-clamp-2 replace my-3 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
{post.summary}
</p>
)}
</main>
)}
{/* 搜索结果 */}
{post.results && (
<p className="line-clamp-2 mt-4 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
{post.results.map((r, index) => (
<span key={index}>{r}</span>
))}
</p>
)}
{/* 预览 */}
{showPreview && (
<div className="overflow-ellipsis truncate">
<NotionPage post={post} />
</div>
)}
{/* 搜索结果 */}
{post.results && (
<p className="line-clamp-2 mt-4 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
{post.results.map((r, index) => (
<span key={index}>{r}</span>
))}
</p>
)}
{/* 预览 */}
{showPreview && (
<div className="overflow-ellipsis truncate">
<NotionPage post={post} />
</div>
)}
</div>
@@ -92,5 +98,5 @@ export const BlogPostCardInfo = ({ post, showPreview, showPageCover, showSummary
</div>
</div>
</div>
</div>
</article>
}

View File

@@ -25,7 +25,7 @@ export default function Features() {
<section className="relative">
{/* Section background (needs .relative class on parent and next sibling elements) */}
<div className="absolute inset-0 bg-gray-100 pointer-events-none mb-16" aria-hidden="true"></div>
<div className="absolute inset-0 bg-gray-100 dark:bg-black pointer-events-none mb-16" aria-hidden="true"></div>
<div className="absolute left-0 right-0 m-auto w-px p-px h-20 bg-gray-200 transform -translate-y-1/2"></div>
<div className="relative max-w-6xl mx-auto px-4 sm:px-6">
@@ -33,8 +33,8 @@ export default function Features() {
{/* Section header */}
<div className="max-w-3xl mx-auto text-center pb-12 md:pb-16">
<h1 className="h2 mb-4">{siteConfig('LANDING_FEATURES_HEADER_1', null, CONFIG)}</h1>
<p className="text-xl text-gray-600 leading-relaxed" dangerouslySetInnerHTML={{ __html: siteConfig('LANDING_FEATURES_HEADER_1_P', null, CONFIG) }}></p>
<h1 className="h2 mb-4 dark:text-white">{siteConfig('LANDING_FEATURES_HEADER_1', null, CONFIG)}</h1>
<p className="text-xl text-gray-600 dark:text-gray-400 leading-relaxed" dangerouslySetInnerHTML={{ __html: siteConfig('LANDING_FEATURES_HEADER_1_P', null, CONFIG) }}></p>
</div>
{/* Section content */}
@@ -43,8 +43,8 @@ export default function Features() {
{/* Content */}
<div className="max-w-xl md:max-w-none md:w-full mx-auto md:col-span-7 lg:col-span-6 md:mt-6" data-aos="fade-right">
<div className="md:pr-4 lg:pr-12 xl:pr-16 mb-8">
<h3 className="h3 mb-3">{siteConfig('LANDING_FEATURES_HEADER_2', null, CONFIG)}</h3>
<p className="text-xl text-gray-600">{siteConfig('LANDING_FEATURES_HEADER_2_P', null, CONFIG)}</p>
<h3 className="h3 mb-3 dark:text-white">{siteConfig('LANDING_FEATURES_HEADER_2', null, CONFIG)}</h3>
<p className="text-xl text-gray-600 dark:text-gray-400">{siteConfig('LANDING_FEATURES_HEADER_2_P', null, CONFIG)}</p>
</div>
{/* Tabs buttons */}
<div className="mb-8 md:mb-0">

View File

@@ -6,7 +6,7 @@ export default function FeaturesBlocks() {
<section className="relative">
{/* Section background (needs .relative class on parent and next sibling elements) */}
<div className="absolute inset-0 top-1/2 md:mt-24 lg:mt-0 bg-gray-900 pointer-events-none" aria-hidden="true"></div>
<div className="absolute inset-0 top-1/2 md:mt-24 lg:mt-0 bg-gray-900 dark:bg-black pointer-events-none" aria-hidden="true"></div>
<div className="absolute left-0 right-0 bottom-0 m-auto w-px p-px h-20 bg-gray-200 transform translate-y-1/2"></div>
<div className="relative max-w-6xl mx-auto px-4 sm:px-6">
@@ -14,15 +14,15 @@ export default function FeaturesBlocks() {
{/* Section header */}
<div className="max-w-3xl mx-auto text-center pb-12 md:pb-20">
<h2 className="h2 mb-4">{siteConfig('LANDING_FEATURES_BLOCK_HEADER', null, CONFIG)}</h2>
<p className="text-xl text-gray-600" dangerouslySetInnerHTML={{ __html: siteConfig('LANDING_FEATURES_BLOCK_P', null, CONFIG) }}></p>
<h2 className="h2 mb-4 dark:text-white">{siteConfig('LANDING_FEATURES_BLOCK_HEADER', null, CONFIG)}</h2>
<p className="text-xl text-gray-600 dark:text-gray-400" dangerouslySetInnerHTML={{ __html: siteConfig('LANDING_FEATURES_BLOCK_P', null, CONFIG) }}></p>
</div>
{/* Items */}
<div className="max-w-sm mx-auto grid gap-6 md:grid-cols-2 lg:grid-cols-3 items-start md:max-w-2xl lg:max-w-none">
{/* 1st item */}
<div className="relative flex flex-col items-center p-6 bg-white rounded shadow-xl">
<div className="relative flex flex-col items-center p-6 bg-white rounded-md shadow-xl border">
<svg className="w-16 h-16 p-1 -mt-1 mb-2" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fillRule="evenodd">
<rect className="fill-current text-blue-600" width="64" height="64" rx="32" />
@@ -39,7 +39,7 @@ export default function FeaturesBlocks() {
</div>
{/* 2nd item */}
<div className="relative flex flex-col items-center p-6 bg-white rounded shadow-xl">
<div className="relative flex flex-col items-center p-6 bg-white rounded-md shadow-xl border">
<svg className="w-16 h-16 p-1 -mt-1 mb-2" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fillRule="evenodd">
<rect className="fill-current text-blue-600" width="64" height="64" rx="32" />
@@ -55,7 +55,7 @@ export default function FeaturesBlocks() {
</div>
{/* 3rd item */}
<div className="relative flex flex-col items-center p-6 bg-white rounded shadow-xl">
<div className="relative flex flex-col items-center p-6 bg-white rounded-md shadow-xl border">
<svg className="w-16 h-16 p-1 -mt-1 mb-2" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fillRule="evenodd">
<rect className="fill-current text-blue-600" width="64" height="64" rx="32" />
@@ -72,7 +72,7 @@ export default function FeaturesBlocks() {
</div>
{/* 4th item */}
<div className="relative flex flex-col items-center p-6 bg-white rounded shadow-xl">
<div className="relative flex flex-col items-center p-6 bg-white rounded-md shadow-xl border">
<svg className="w-16 h-16 p-1 -mt-1 mb-2" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fillRule="evenodd">
<rect className="fill-current text-blue-600" width="64" height="64" rx="32" />
@@ -89,7 +89,7 @@ export default function FeaturesBlocks() {
</div>
{/* 5th item */}
<div className="relative flex flex-col items-center p-6 bg-white rounded shadow-xl">
<div className="relative flex flex-col items-center p-6 bg-white rounded-md shadow-xl border">
<svg className="w-16 h-16 p-1 -mt-1 mb-2" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fillRule="evenodd">
<rect className="fill-current text-blue-600" width="64" height="64" rx="32" />
@@ -105,7 +105,7 @@ export default function FeaturesBlocks() {
</div>
{/* 6th item */}
<div className="relative flex flex-col items-center p-6 bg-white rounded shadow-xl">
<div className="relative flex flex-col items-center p-6 bg-white rounded-md shadow-xl border">
<svg className="w-16 h-16 p-1 -mt-1 mb-2" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fillRule="evenodd">
<rect className="fill-current text-blue-600" width="64" height="64" rx="32" />

View File

@@ -149,6 +149,11 @@ export default function Footer() {
{/* Social as */}
<ul className="flex mb-4 md:order-1 md:ml-4 md:mb-0">
<li>
<div className='h-full flex justify-center items-center text-gray-600 hover:text-gray-900 bg-white hover:bg-white-100'>
Powered by<a href='https://github.com/tangly1024/NotionNext' className='mx-1 hover:underline font-semibold'>NotionNext {siteConfig('VERSION')}</a>
</div>
</li>
{/* <li>
<a href="#0" className="flex justify-center items-center text-gray-600 hover:text-gray-900 bg-white hover:bg-white-100 rounded-full shadow transition duration-150 ease-in-out" aria-label="Twitter">
<svg className="w-8 h-8 fill-current" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">

View File

@@ -22,7 +22,7 @@ export default function Header() {
}, [top])
return (
<header className={`fixed w-full z-30 md:bg-opacity-90 transition duration-300 ease-in-out ${!top ? 'bg-white backdrop-blur-sm shadow-lg' : ''}`}>
<header className={`fixed w-full z-50 md:bg-opacity-90 transition duration-300 ease-in-out ${!top ? 'bg-white dark:bg-hexo-black-gray backdrop-blur-sm shadow-lg' : ''}`}>
<div className="max-w-6xl mx-auto px-5 sm:px-6">
<div className="flex items-center justify-between h-16 md:h-20">
@@ -36,7 +36,7 @@ export default function Header() {
{/* Desktop sign in links */}
<ul className="flex grow justify-end flex-wrap items-center">
<li>
<Link href={siteConfig('LANDING_HEADER_BUTTON_1_URL', null, CONFIG)} target='_blank' className="font-medium hover:font-bold text-gray-600 hover:text-gray-900 px-5 py-3 flex items-center transition duration-150 ease-in-out">
<Link href={siteConfig('LANDING_HEADER_BUTTON_1_URL', null, CONFIG)} target='_blank' className="font-medium hover:font-bold text-gray-600 hover:text-gray-900 dark:text-gray-400 px-5 py-3 flex items-center transition duration-150 ease-in-out">
<div>{siteConfig('LANDING_HEADER_BUTTON_1_TITLE', null, CONFIG)}</div>
</Link>
</li>

View File

@@ -34,7 +34,7 @@ export default function Hero() {
<span className="bg-clip-text text-transparent bg-gradient-to-r from-blue-500 to-teal-400">{siteConfig('LANDING_HERO_TITLE_1', null, CONFIG)}</span>
</h1>
<div className="max-w-3xl mx-auto">
<p className="text-xl text-gray-600 mb-8" data-aos="zoom-y-out" data-aos-delay="150">{siteConfig('LANDING_HERO_P_1', null, CONFIG)}</p>
<p className="text-xl text-gray-600 dark:text-gray-400 mb-8" data-aos="zoom-y-out" data-aos-delay="150">{siteConfig('LANDING_HERO_P_1', null, CONFIG)}</p>
<div className="max-w-xs mx-auto sm:max-w-none sm:flex sm:justify-center" data-aos="zoom-y-out" data-aos-delay="300">
<div>
<a target='_blank' className="btn text-white bg-blue-600 hover:bg-blue-700 w-full mb-4 sm:w-auto sm:mb-0"

View File

@@ -0,0 +1,56 @@
import { siteConfig } from '@/lib/config'
import CONFIG from '../config'
import Link from 'next/link'
/**
* 价格收费表
*/
export const Pricing = (props) => {
return <div className="w-full mx-auto bg-white dark:bg-black px-5 py-10 text-gray-800 mb-10">
<div className="text-center max-w-xl mx-auto">
<h1 className="text-5xl md:text-5xl font-bold mb-5 dark:text-white">{siteConfig('LANDING_PRICING_TITLE', null, CONFIG)}</h1>
<h3 className="text-xl font-medium mb-10 dark:text-gray-400">{siteConfig('LANDING_PRICING_P', null, CONFIG)}</h3>
</div>
<div className="max-w-4xl mx-auto md:flex">
<div className="w-full md:w-1/3 md:max-w-none bg-white dark:bg-hexo-black-gray px-8 md:px-10 py-8 md:py-10 mb-3 mx-auto md:my-6 rounded-md shadow-lg shadow-gray-600 md:flex md:flex-col">
<div className="w-full flex-grow dark:text-gray-400">
<h2 className="text-center font-bold uppercase mb-4">{siteConfig('LANDING_PRICING_1_TITLE', null, CONFIG)}</h2>
<h3 className="text-center font-bold text-4xl mb-5">{siteConfig('LANDING_PRICING_1_PRICE', null, CONFIG)}</h3>
<ul className="text-sm px-5 mb-8">
{siteConfig('LANDING_PRICING_1_CONTENT', null, CONFIG)?.split(',').map((item, index) => <li key={index} className="leading-tight"><i className="mdi-check-bold text-lg"></i>{item}</li>
)}
</ul>
</div>
<Link className="w-full" href={siteConfig('LANDING_PRICING_1_URL', null, CONFIG)}>
<button className="font-bold bg-blue-600 hover:bg-blue-700 text-white rounded-md px-10 py-2 transition-colors w-full">{siteConfig('LANDING_PRICING_1_BUTTON', null, CONFIG)}</button>
</Link>
</div>
<div className="w-full md:w-1/3 md:max-w-none bg-white dark:bg-hexo-black-gray px-8 md:px-10 py-8 md:py-10 mb-3 mx-auto md:-mx-3 md:mb-0 rounded-md shadow-lg shadow-gray-600 md:relative md:z-20 md:flex md:flex-col">
<div className="w-full flex-grow dark:text-gray-400">
<h2 className="text-center font-bold uppercase mb-4">{siteConfig('LANDING_PRICING_2_TITLE', null, CONFIG)}</h2>
<h3 className="text-center font-bold text-4xl md:text-5xl mb-5">{siteConfig('LANDING_PRICING_2_PRICE', null, CONFIG)}</h3>
<ul className="text-sm px-5 mb-8">
{siteConfig('LANDING_PRICING_2_CONTENT', null, CONFIG)?.split(',').map((item, index) => <li key={index} className="leading-tight"><i className="mdi-check-bold text-lg"></i>{item}</li>
)}
</ul>
</div>
<Link className="w-full" target='_blank' href={siteConfig('LANDING_PRICING_2_URL', null, CONFIG)}>
<button className="font-bold bg-blue-600 hover:bg-blue-700 text-white rounded-md px-10 py-2 transition-colors w-full">{siteConfig('LANDING_PRICING_2_BUTTON', null, CONFIG)}</button>
</Link>
</div>
<div className="w-full md:w-1/3 md:max-w-none bg-white dark:bg-hexo-black-gray px-8 md:px-10 py-8 md:py-10 mb-3 mx-auto md:my-6 rounded-md shadow-lg shadow-gray-600 md:flex md:flex-col">
<div className="w-full flex-grow dark:text-gray-400">
<h2 className="text-center font-bold uppercase mb-4">{siteConfig('LANDING_PRICING_3_TITLE', null, CONFIG)}</h2>
<h3 className="text-center font-bold text-4xl mb-5">{siteConfig('LANDING_PRICING_3_PRICE', null, CONFIG)}</h3>
<ul className="text-sm px-5 mb-8">
{siteConfig('LANDING_PRICING_3_CONTENT', null, CONFIG)?.split(',').map((item, index) => <li key={index} className="leading-tight"><i className="mdi-check-bold text-lg"></i>{item}</li>
)}
</ul>
</div>
<Link className="w-full" target='_blank' href={siteConfig('LANDING_PRICING_3_URL', null, CONFIG)}>
<button className="font-bold bg-blue-600 hover:bg-blue-700 text-white rounded-md px-10 py-2 transition-colors w-full">{siteConfig('LANDING_PRICING_3_BUTTON', null, CONFIG)}</button>
</Link>
</div>
</div>
</div>
}

View File

@@ -31,8 +31,8 @@ export default function Testimonials() {
{/* Section header */}
<div className="max-w-3xl mx-auto text-center pb-12 md:pb-16">
<h2 className="h2 mb-4">{siteConfig('LANDING_TESTIMONIALS_HEADER', null, CONFIG)}</h2>
<p className="text-xl text-gray-600" data-aos="zoom-y-out">{siteConfig('LANDING_TESTIMONIALS_P', null, CONFIG)}</p>
<h2 className="h2 mb-4 dark:text-white">{siteConfig('LANDING_TESTIMONIALS_HEADER', null, CONFIG)}</h2>
<p className="text-xl text-gray-600 dark:text-gray-400" data-aos="zoom-y-out">{siteConfig('LANDING_TESTIMONIALS_P', null, CONFIG)}</p>
</div>
{/* Testimonials */}

View File

@@ -47,7 +47,7 @@ const CONFIG = {
LANDING_FEATURES_BLOCK_6_P: 'NotionNext助您轻松开始写作',
// 感言
LANDING_TESTIMONIALS_HEADER: '已搭建超5300个网站、总浏览量突破100,000,000+',
LANDING_TESTIMONIALS_HEADER: '已搭建超7000个网站、总浏览量突破100,000,000+',
LANDING_TESTIMONIALS_P: '网站内容涵盖地产、教育、建筑、医学、机械、IT、电子、软件、自媒体、数位游民、短视频、电商、学生、摄影爱好者、旅行爱好者等等各行各业',
LANDING_TESTIMONIALS_AVATAR: 'https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F22de3fcb-d90d-4271-bc01-f815f476122b%2F4FE0A0C0-E487-4C74-BF8E-6F01A27461B8-14186-000008094BC289A6.jpg?table=collection&id=a320a2cc-6ebe-4a8d-95cc-ea94e63bced9&width=200',
@@ -60,6 +60,27 @@ const CONFIG = {
LANDING_POST_REDIRECT_ENABLE: process.env.NEXT_PUBLIC_POST_REDIRECT_ENABLE || false, // 是否开启文章地址重定向 用于迁移旧网站域名
LANDING_POST_REDIRECT_URL: process.env.NEXT_PUBLIC_POST_REDIRECT_URL || 'https://blog.tangly1024.com', // 重定向网站地址
LANDING_PRICING_TITLE: '价格表',
LANDING_PRICING_P: 'NotionNext开源免费此处仅演示订阅付费功能请勿购买',
LANDING_PRICING_1_TITLE: '个人版',
LANDING_PRICING_1_PRICE: '免费',
LANDING_PRICING_1_CONTENT: '项目源代码,部署教程,不定时技术答疑',
LANDING_PRICING_1_BUTTON: '开始体验',
LANDING_PRICING_1_URL: 'https://docs.tangly1024.com/about',
LANDING_PRICING_2_TITLE: '捐赠版',
LANDING_PRICING_2_PRICE: '$9.9/月',
LANDING_PRICING_2_CONTENT: '项目源代码,部署教程,长期技术答疑,代码升级合并,内部社群',
LANDING_PRICING_2_BUTTON: '立即购买',
LANDING_PRICING_2_URL: 'https://tangly1024.lemonsqueezy.com/checkout/buy/0adb9153-0799-4f51-91aa-1f06391ea4e0',
LANDING_PRICING_3_TITLE: '企业版',
LANDING_PRICING_3_PRICE: '$59/月',
LANDING_PRICING_3_CONTENT: '项目源代码,部署教程,VIP技术咨询,代码升级合并,内部社群,定制功能开发,SEO优化',
LANDING_PRICING_3_BUTTON: '立即购买',
LANDING_PRICING_3_URL: 'https://tangly1024.lemonsqueezy.com/checkout/buy/df924d66-09dc-42a4-a632-a6b0c5cc4f28',
LANDING_NEWSLETTER: process.env.NEXT_PUBLIC_THEME_LANDING_NEWSLETTER || false // 是否开启邮件订阅 请先配置mailchimp功能 https://docs.tangly1024.com/article/notion-next-mailchimp
}
export default CONFIG

View File

@@ -20,18 +20,19 @@ import CONFIG from './config'
import Loading from '@/components/Loading'
import { isBrowser } from '@/lib/utils'
import { siteConfig } from '@/lib/config'
import { Pricing } from './components/Pricing'
/**
* 布局框架
* 作为一个基础框架使用,定义了整个主题每个页面必备的顶部导航栏和页脚
* 其它页面都嵌入到此框架中使用
* Landing 主题用作产品落地页展示
* 结合Stripe或者lemonsqueezy插件可以成为saas支付订阅
* @param {*} props
* @returns
*/
const LayoutBase = (props) => {
const { children } = props
return <div id='theme-landing' className="overflow-hidden flex flex-col justify-between bg-white">
return <div id='theme-landing' className="overflow-hidden flex flex-col justify-between bg-white dark:bg-black">
{/* 顶部导航栏 */}
<Header />
@@ -58,6 +59,7 @@ const LayoutIndex = (props) => {
<Features />
<FeaturesBlocks />
<Testimonials />
<Pricing/>
<Newsletter />
</>
)

View File

@@ -6,6 +6,7 @@ import TwikooCommentCount from '@/components/TwikooCommentCount'
import LazyImage from '@/components/LazyImage'
import { formatDateFmt } from '@/lib/formatDate'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
import NotionIcon from '@/components/NotionIcon'
const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
const showPreview = siteConfig('MATERY_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap
@@ -27,7 +28,7 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
className="w-full mb-4 overflow-hidden shadow-md border dark:border-black rounded-xl bg-white dark:bg-hexo-black-gray">
{/* 固定高度 ,空白用图片拉升填充 */}
<div className="group flex flex-col h-80 justify-between">
<header className="group flex flex-col h-80 justify-between">
{/* 头部图片 填充卡片 */}
{showPageCover && (
@@ -38,13 +39,15 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
alt={post.title}
className="h-full w-full group-hover:scale-125 group-hover:brightness-50 brightness-90 rounded-t-md transform object-cover duration-500"
/>
<div className='absolute bottom-0 left-0 text-white p-6 text-2xl replace break-words w-full shadow-text'>{post.title}</div>
<h2 className='absolute bottom-0 left-0 text-white p-6 text-2xl replace break-words w-full shadow-text'>
<NotionIcon icon={post.pageIcon} />{post.title}
</h2>
</div>
</Link>
)}
{/* 文字描述 */}
<div >
<main >
{/* 描述 */}
<div className="px-4 flex flex-col w-full text-gray-700 dark:text-gray-300">
@@ -93,8 +96,8 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
</div>
</div>
</>)}
</div>
</div>
</main>
</header>
</div>
)

View File

@@ -1,4 +1,5 @@
import LazyImage from '@/components/LazyImage'
import NotionIcon from '@/components/NotionIcon'
/**
* 文章背景图
@@ -9,7 +10,7 @@ export default function PostHeader({ post, siteInfo }) {
return (
<div id='header' className="flex h-96 justify-center align-middle items-center w-full relative bg-black">
<div className="z-10 leading-snug font-bold xs:text-4xl sm:text-4xl md:text-5xl md:leading-snug text-4xl shadow-text-md flex justify-center text-center text-white">
{title}
<NotionIcon icon={post?.pageIcon} />{title}
</div>
<LazyImage alt={title} src={headerImage} className='pointer-events-none select-none w-full h-full object-cover opacity-30 absolute'
placeholder='blur' blurDataURL='/bg_image.jpg' />

View File

@@ -1,6 +1,7 @@
import LazyImage from '@/components/LazyImage'
import Link from 'next/link'
import { siteConfig } from '@/lib/config'
import NotionIcon from '@/components/NotionIcon'
/**
* 文章详情页介绍
@@ -12,7 +13,7 @@ export default function ArticleInfo(props) {
return (<>
{/* title */}
<h1 className="text-3xl pt-12 dark:text-gray-300">{post?.title}</h1>
<h1 className="text-3xl pt-12 dark:text-gray-300"><NotionIcon icon={post?.pageIcon} />{post?.title}</h1>
{/* meta */}
<section className="py-2 items-center text-sm px-1">

View File

@@ -8,6 +8,7 @@ import TagItemMini from './TagItemMini'
import TwikooCommentCount from '@/components/TwikooCommentCount'
import LazyImage from '@/components/LazyImage'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
import NotionIcon from '@/components/NotionIcon'
const BlogPostCard = ({ post, showSummary }) => {
const showPreview = siteConfig('MEDIUM_POST_LIST_PREVIEW', null, CONFIG) && post.blockMap
@@ -23,19 +24,19 @@ const BlogPostCard = ({ post, showSummary }) => {
className="mb-6 max-w-7xl border-b dark:border-gray-800 "
>
<div className="lg:py-8 py-4 flex flex-col w-full">
<header className="lg:py-8 py-4 flex flex-col w-full">
<Link
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'
}>
<div>
<h2>
{siteConfig('MEDIUM_POST_LIST_COVER', null, CONFIG) && <div className='w-full max-h-96 object-cover overflow-hidden mb-2'>
<LazyImage src={post.pageCoverThumbnail} style={post.pageCoverThumbnail ? {} : { height: '0px' }} className='w-full max-h-96 object-cover hover:scale-125 duration-150' />
</div>}
{post.title}
</div>
<NotionIcon icon={post.pageIcon} />{post.title}
</h2>
</Link>
@@ -53,9 +54,9 @@ const BlogPostCard = ({ post, showSummary }) => {
<div className="flex"></div>
{(!showPreview || showSummary) && (
<p className="my-4 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
<main className="my-4 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
{post.summary}
</p>
</main>
)}
{showPreview && (
@@ -76,7 +77,7 @@ const BlogPostCard = ({ post, showSummary }) => {
</div>
</div>
)}
</div>
</header>
</div>
)
}

View File

@@ -22,7 +22,7 @@ export const MenuItem = ({ link }) => {
// #号加标题 快速跳转到指定锚点
const isAnchor = link?.to === '#'
const url = isAnchor ? link.to : `#${link.name}`
const url = isAnchor ? `#${link.name}` : link.to
return <>
{/* 菜单 */}
@@ -33,7 +33,7 @@ export const MenuItem = ({ link }) => {
{link?.subMenus
? (<>
<span className='dark:text-neutral-400 dark:hover:text-white font-bold w-full display-block'>
<i className={`text-base ${link?.icon ? link?.icon : (isAnchor ? 'fas fa-hashtag' : '')} mr-1`} />{link?.title}
<i className={`text-base ${link?.icon ? link?.icon : ''} mr-1`} />{link?.title}
</span>
<div className='inline-flex items-center select-none pointer-events-none '>
<i className={`${isOpen ? '-rotate-90' : ''} text-xs dark:text-neutral-500 text-gray-300 hover:text-black dark:hover:text-white-400 px-2 fas fa-chevron-left transition-all duration-200`}></i>

View File

@@ -33,6 +33,7 @@ import LogoBar from './components/LogoBar'
import { siteConfig } from '@/lib/config'
import Live2D from '@/components/Live2D'
import BlogArchiveItem from './components/BlogArchiveItem'
import NotionIcon from '@/components/NotionIcon'
const WWAds = dynamic(() => import('@/components/WWAds'), { ssr: false })
@@ -213,7 +214,6 @@ const LayoutPostList = props => {
*/
const LayoutSlug = (props) => {
const { post, lock, validPassword } = props
return (
<>
{/* 文章锁 */}
@@ -222,7 +222,7 @@ const LayoutSlug = (props) => {
{!lock && <div id='container'>
{/* title */}
<h1 className="text-3xl pt-4 md:pt-12 dark:text-gray-300">{post?.title}</h1>
<h1 className="text-3xl pt-4 md:pt-12 dark:text-gray-300"><NotionIcon icon={post?.pageIcon} />{post?.title}</h1>
{/* Notion文章主体 */}
{post && (<section id="article-wrapper" className="px-1">

View File

@@ -3,6 +3,7 @@ import Image from 'next/image'
import TagItem from './TagItem'
import md5 from 'js-md5'
import { siteConfig } from '@/lib/config'
import NotionIcon from '@/components/NotionIcon'
export const ArticleInfo = (props) => {
const { post } = props
@@ -12,9 +13,9 @@ export const ArticleInfo = (props) => {
return <section className="flex-wrap flex mt-2 text-gray--600 dark:text-gray-400 font-light leading-8">
<div>
<div className="font-bold text-3xl text-black dark:text-white">
{post?.title}
</div>
<h1 className="font-bold text-3xl text-black dark:text-white">
<NotionIcon icon={post?.pageIcon} />{post?.title}
</h1>
{post?.type !== 'Page' && <>
<nav className="flex mt-7 items-start text-gray-500 dark:text-gray-400">

View File

@@ -1,6 +1,7 @@
import Link from 'next/link'
import { siteConfig } from '@/lib/config'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
import NotionIcon from '@/components/NotionIcon'
const BlogPost = ({ post }) => {
const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}`
@@ -11,7 +12,7 @@ const BlogPost = ({ post }) => {
<article key={post.id} className="mb-6 md:mb-8">
<header className="flex flex-col justify-between md:flex-row md:items-baseline">
<h2 className="text-lg md:text-xl font-medium mb-2 cursor-pointer text-black dark:text-gray-100">
{post.title}
<NotionIcon icon={post.pageIcon} />{post.title}
</h2>
<time className="flex-shrink-0 text-gray-600 dark:text-gray-400">
{post?.publishDay}

View File

@@ -3,6 +3,7 @@ import Image from 'next/image'
import TagItem from './TagItem'
import md5 from 'js-md5'
import { siteConfig } from '@/lib/config'
import NotionIcon from '@/components/NotionIcon'
export const ArticleInfo = (props) => {
const { post } = props
@@ -12,9 +13,9 @@ export const ArticleInfo = (props) => {
return <section className="flex-wrap flex mt-2 text-gray--600 dark:text-gray-400 font-light leading-8">
<div>
<div className="font-bold text-3xl text-black dark:text-white">
{post?.title}
</div>
<h1 className="font-bold text-3xl text-black dark:text-white">
<NotionIcon icon={post?.pageIcon} />{post?.title}
</h1>
{post?.type !== 'Page' && <>
<nav className="flex mt-7 items-start text-gray-500 dark:text-gray-400">

View File

@@ -3,6 +3,7 @@ import Link from 'next/link'
import { usePlogGlobal } from '..'
import { isMobile } from '@/lib/utils'
import LazyImage from '@/components/LazyImage'
import NotionIcon from '@/components/NotionIcon'
/**
* 博客照片卡牌
@@ -37,7 +38,7 @@ const BlogPost = (props) => {
<LazyImage 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-gray-100 shadow-text">
{post?.title}
<NotionIcon icon={post.pageIcon} /> {post?.title}
</h2>
{post?.category && <div className='text-xs rounded-lg absolute left-0 top-0 m-4 px-2 py-1 bg-gray-200 dark:bg-black dark:bg-opacity-25 hover:bg-blue-700 hover:text-white duration-200'>
<Link href={`/category/${post?.category}`}>

View File

@@ -3,6 +3,7 @@ import { useGlobal } from '@/lib/global'
import CONFIG from '../config'
import { siteConfig } from '@/lib/config'
import { formatDateFmt } from '@/lib/formatDate'
import NotionIcon from '@/components/NotionIcon'
/**
* 文章描述
@@ -18,7 +19,7 @@ export default function ArticleInfo (props) {
<section className="mt-2 text-gray-600 dark:text-gray-400 leading-8">
<h2
className="blog-item-title mb-5 font-bold text-black text-xl md:text-2xl no-underline">
{post?.title}
<NotionIcon icon={post?.pageIcon} />{post?.title}
</h2>
<div className='flex flex-wrap text-gray-700 dark:text-gray-300'>
@@ -27,7 +28,7 @@ export default function ArticleInfo (props) {
<span> <i className="fa-regular fa-user"></i> <a href={siteConfig('SIMPLE_AUTHOR_LINK', null, CONFIG)}>{siteConfig('AUTHOR')}</a></span>
<span> <i className="fa-regular fa-clock"></i> {post?.publishDay}</span>
{post?.category && <span> <i className="fa-regular fa-folder"></i> <a href={`/category/${post?.category}`} className="hover:text-red-400 transition-all duration-200">{post?.category}</a></span>}
{post?.tags && post?.tags?.length > 0 && post?.tags.map(t => <span key={t}> / <Link href={`/tag/${t}`}><a className=' hover:text-red-400 transition-all duration-200'>{t}</a></Link></span>)}
{post?.tags && post?.tags?.length > 0 && post?.tags.map(t => <span key={t}> / <Link href={`/tag/${t}`}><span className=' hover:text-red-400 transition-all duration-200'>{t}</span></Link></span>)}
</div>)}
{post?.type !== 'Page' && (<div className=''>

View File

@@ -5,6 +5,7 @@ import { formatDateFmt } from '@/lib/formatDate'
import { siteConfig } from '@/lib/config'
import LazyImage from '@/components/LazyImage'
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
import NotionIcon from '@/components/NotionIcon'
export const BlogItem = props => {
const { post } = props
@@ -26,18 +27,18 @@ export const BlogItem = props => {
)}
</div>
<div className='article-info'>
<article className='article-info'>
<h2 className="mb-2">
<Link
href={url}
className="blog-item-title font-bold text-black text-2xl menu-link">
{post.title}
<NotionIcon icon={post.pageIcon} />{post.title}
</Link>
</h2>
{/* 文章信息 */}
<div className="mb-5 text-md text-gray-700 dark:text-gray-300 flex-wrap flex leading-6">
<header className="mb-5 text-md text-gray-700 dark:text-gray-300 flex-wrap flex leading-6">
<div className='space-x-2'>
<span> <a href={siteConfig('SIMPLE_AUTHOR_LINK', null, CONFIG)} className='p-1 hover:text-red-400 transition-all duration-200'><i className="fa-regular fa-user"></i> {siteConfig('AUTHOR')}</a></span>
<span>
@@ -52,13 +53,13 @@ export const BlogItem = props => {
{post.category && <Link href={`/category/${post.category}`} className='p-1'> <span className="hover:text-red-400 transition-all duration-200"><i className="fa-regular fa-folder mr-0.5" />{post.category}</span></Link>}
{post?.tags && post?.tags?.length > 0 && post?.tags.map(t => <Link key={t} href={`/tag/${t}`} className=' hover:text-red-400 transition-all duration-200'><span > /{t}</span></Link>)}
</div>
</div>
</header>
<div className="text-gray-700 dark:text-gray-300 leading-normal mb-6">
<main className="text-gray-700 dark:text-gray-300 leading-normal mb-6">
{post.summary}
{post.summary && <span>...</span>}
</div>
</div>
</main>
</article>
</div>
<div className='block'>

View File

@@ -4131,6 +4131,11 @@ prelude-ls@^1.2.1:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
prettier@3.2.5:
version "3.2.5"
resolved "https://r.cnpmjs.org/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368"
integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==
prism-themes@1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/prism-themes/-/prism-themes-1.9.0.tgz#19c034f3205f1e28d75d89728e54ccd745f7e3dd"