mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-14 07:26:52 +00:00
Merge pull request #81 from tangly1024/debug-mode
V2.7.0 动态主题+调试模式+修复大量样式问题
This commit is contained in:
@@ -8,11 +8,13 @@ const BLOG = {
|
||||
KEYWORDS: 'Notion, 博客', // 网站关键词 英文逗号隔开
|
||||
NOTION_PAGE_ID: process.env.NOTION_PAGE_ID || '02ab3b8678004aa69e9e415905ef32a5', // Important page_id!!!Duplicate Template from https://www.notion.so/tanghh/02ab3b8678004aa69e9e415905ef32a5
|
||||
NOTION_ACCESS_TOKEN: process.env.NOTION_ACCESS_TOKEN || '', // Useful if you prefer not to make your database public
|
||||
DEBUG: process.env.NEXT_PUBLIC_DEBUG || false, // 是否显示调试按钮
|
||||
|
||||
THEME: process.env.NEXT_PUBLIC_THEME || 'next', // 主题, 支持 ['Next','Hexo',"Fukasawa','Medium']
|
||||
LANG: 'zh-CN', // e.g 'zh-CN','en-US' see /lib/lang.js for more.
|
||||
SINCE: 2021, // e.g if leave this empty, current year will be used.
|
||||
BEI_AN: process.env.NEXT_PUBLIC_BEI_AN || '', // 备案号 闽ICP备XXXXXXX
|
||||
APPEARANCE: 'auto', // ['light', 'dark', 'auto'],
|
||||
APPEARANCE: 'light', // ['light', 'dark', 'auto'], // light 日间模式 , dark夜间模式, auto根据时间和主题自动夜间模式
|
||||
FONT: 'font-serif tracking-wider subpixel-antialiased', // 文章字体 ['font-sans', 'font-serif', 'font-mono'] @see https://www.tailwindcss.cn/docs/font-family
|
||||
FONT_AWESOME_PATH: 'https://cdn.bootcdn.net/ajax/libs/font-awesome/5.15.4/css/all.min.css', // 图标库CDN ,国内推荐BootCDN,国外推荐 CloudFlare https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css
|
||||
BACKGROUND_LIGHT: '#eeeeee', // use hex value, don't forget '#' e.g #fffefc
|
||||
@@ -20,7 +22,7 @@ const BLOG = {
|
||||
PATH: '', // leave this empty unless you want to deploy in a folder
|
||||
|
||||
POST_LIST_STYLE: 'page', // ['page','scroll] 文章列表样式:页码分页、单页滚动加载
|
||||
POST_LIST_PREVIEW: false, // 是否在列表加载文章预览, 会被各主题中的同名配置覆盖,例:/themes/NEXT/config_next.js
|
||||
POST_LIST_PREVIEW: false, // 是否在列表加载文章预览
|
||||
POST_PREVIEW_LINES: 12, // 预览博客行数
|
||||
POSTS_PER_PAGE: 6, // post counts per page
|
||||
POSTS_SORT_BY: 'notion', // 排序方式 'date'按时间,'notion'由notion控制
|
||||
|
||||
124
components/DebugPanel.js
Normal file
124
components/DebugPanel.js
Normal file
@@ -0,0 +1,124 @@
|
||||
import BLOG from '@/blog.config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import * as ThemeMap from '@/themes'
|
||||
import { useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import Select from './Select'
|
||||
import { ALL_THEME } from '@/lib/theme'
|
||||
/**
|
||||
*
|
||||
* @returns 调试面板
|
||||
*/
|
||||
export function DebugPanel () {
|
||||
const [show, setShow] = useState(false)
|
||||
const GlobalConfig = useGlobal()
|
||||
const router = useRouter()
|
||||
const { theme, setTheme } = GlobalConfig
|
||||
const themeOptions = []
|
||||
ALL_THEME.forEach(t => {
|
||||
themeOptions.push({ value: t, text: t })
|
||||
})
|
||||
|
||||
function toggleShow () {
|
||||
setShow(!show)
|
||||
}
|
||||
|
||||
function switchTheme () {
|
||||
const currentIndex = ALL_THEME.indexOf(theme)
|
||||
const newIndex = currentIndex < ALL_THEME.length - 1 ? currentIndex + 1 : 0
|
||||
changeTheme(ALL_THEME[newIndex])
|
||||
}
|
||||
/**
|
||||
* 切换主题
|
||||
*/
|
||||
function changeTheme (theme) {
|
||||
router.query.theme = ''
|
||||
setTheme(theme)
|
||||
}
|
||||
|
||||
function filterResult (text) {
|
||||
switch (text) {
|
||||
case 'true':
|
||||
return <span className='text-green-500'>true</span>
|
||||
case 'false':
|
||||
return <span className='text-red-500'>false</span>
|
||||
case '':
|
||||
return '-'
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* 调试按钮 */}
|
||||
<div>
|
||||
<div
|
||||
style={{ writingMode: 'vertical-lr' }}
|
||||
className={`bg-black text-white shadow-2xl p-2.5 rounded-l-xl cursor-pointer ${show ? 'right-96' : 'right-0'} fixed bottom-36 duration-200 z-50`}
|
||||
onClick={toggleShow}
|
||||
>
|
||||
{show
|
||||
? (
|
||||
<i className="fas fa-times"> 关闭调试</i>
|
||||
)
|
||||
: (
|
||||
<i className="fas fa-tools"> 打开调试</i>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={` ${
|
||||
show ? 'shadow-card' : '-right-96'
|
||||
} w-96 overflow-y-scroll font-sans h-full p-5 bg-white fixed right-0 bottom-0 z-50 duration-200`}
|
||||
>
|
||||
<div className="flex space-x-1 my-12">
|
||||
<Select
|
||||
label="主题切换"
|
||||
value={theme}
|
||||
options={themeOptions}
|
||||
onChange={changeTheme}
|
||||
/>
|
||||
<div className="p-2 cursor-pointer" onClick={switchTheme}>
|
||||
<i className="fas fa-sync" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="font-bold w-18 border-b my-2">
|
||||
站点配置[blog.config.js]
|
||||
</div>
|
||||
<div className="text-xs">
|
||||
{Object.keys(BLOG).map(k => (
|
||||
<div key={k} className="justify-between flex py-1">
|
||||
<span className="bg-blue-400 p-0.5 rounded text-white mr-2">
|
||||
{k}
|
||||
</span>
|
||||
<span className="whitespace-nowrap">
|
||||
{filterResult(BLOG[k] + '')}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="font-bold w-18 border-b my-2">
|
||||
主题配置{'(config_' + theme + '.js)'}:
|
||||
</div>
|
||||
<div className="text-xs">
|
||||
{Object.keys(ThemeMap[theme].THEME_CONFIG).map(k => (
|
||||
<div key={k} className="justify-between flex py-1">
|
||||
<span className="bg-indigo-500 p-0.5 rounded text-white mr-2">
|
||||
{k}
|
||||
</span>
|
||||
<span className="whitespace-nowrap">
|
||||
{filterResult(ThemeMap[theme].THEME_CONFIG[k] + '')}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
40
components/Select.js
Normal file
40
components/Select.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import React from 'react'
|
||||
|
||||
/**
|
||||
* 下拉单选框
|
||||
*/
|
||||
class Select extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.handleChange = this.handleChange.bind(this)
|
||||
}
|
||||
|
||||
handleChange (event) {
|
||||
const { onChange } = this.props
|
||||
onChange(event.target.value)
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className='py-1 space-x-3'>
|
||||
<label className='text-gray-500'>{this.props.label}</label>
|
||||
<select value={this.props.value} onChange={this.handleChange} className='border p-1 rounded cursor-pointer'>
|
||||
{this.props.options?.map(o => (
|
||||
<option key={o.value} value={o.value}>
|
||||
{o.text}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
Select.defaultProps = {
|
||||
label: '',
|
||||
value: '1',
|
||||
options: [
|
||||
{ value: '1', text: '选项1' },
|
||||
{ value: '2', text: '选项2' }
|
||||
]
|
||||
}
|
||||
export default Select
|
||||
@@ -44,7 +44,7 @@ const SideBarDrawer = ({ children, isOpen, onOpen, onClose, className }) => {
|
||||
}
|
||||
|
||||
return <div id='sidebar-wrapper' className={' ' + className}>
|
||||
<div id='sidebar-drawer' className={`${isOpen ? 'ml-0' : '-ml-80'} bg-white dark:bg-gray-900 flex flex-col duration-300 fixed h-full left-0 overflow-y-scroll scroll-hidden top-0 z-50`}>
|
||||
<div id='sidebar-drawer' className={`${isOpen ? 'ml-0' : '-ml-80'} bg-white dark:bg-gray-900 flex flex-col duration-300 fixed h-full left-0 overflow-y-scroll scroll-hidden top-0 z-40`}>
|
||||
{children}
|
||||
</div>
|
||||
{/* 背景蒙版 */}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
"@/*": ["./*"],
|
||||
"@/components/*": ["components/*"],
|
||||
"@/data/*": ["data/*"],
|
||||
"@/layouts/*": ["theme/*"],
|
||||
"@/lib/*": ["lib/*"],
|
||||
"@/styles/*": ["styles/*"]
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* @returns {string}
|
||||
*/
|
||||
export default function formatDate (date, local) {
|
||||
if (!date) return ''
|
||||
const d = new Date(date)
|
||||
const options = { year: 'numeric', month: 'short', day: 'numeric' }
|
||||
const res = d.toLocaleDateString(local, options)
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import lang from './lang'
|
||||
import { useContext, createContext, useState } from 'react'
|
||||
import Router from 'next/router'
|
||||
import { initDarkMode } from './theme'
|
||||
import { ALL_THEME, initDarkMode } from './theme'
|
||||
import BLOG from '@/blog.config'
|
||||
|
||||
const GlobalContext = createContext()
|
||||
let hasInit = false
|
||||
|
||||
@@ -15,6 +17,8 @@ export function GlobalContextProvider ({ children }) {
|
||||
const [locale, updateLocale] = useState(generateLocaleDict('en-US'))
|
||||
const [isDarkMode, updateDarkMode] = useState(false)
|
||||
const [onLoading, changeLoadingState] = useState(false)
|
||||
const [theme, setTheme] = useState(BLOG.THEME)
|
||||
|
||||
Router.events.on('routeChangeStart', (...args) => {
|
||||
changeLoadingState(true)
|
||||
})
|
||||
@@ -29,11 +33,16 @@ export function GlobalContextProvider ({ children }) {
|
||||
hasInit = true
|
||||
initLocale(locale, updateLocale)
|
||||
initDarkMode(isDarkMode, updateDarkMode)
|
||||
// 读取浏览器参数中的主题
|
||||
const userTheme = Router?.router?.query?.theme
|
||||
if (userTheme && ALL_THEME.indexOf(userTheme) > -1) {
|
||||
setTheme(userTheme)
|
||||
}
|
||||
}
|
||||
}, 100)
|
||||
}, 50)
|
||||
|
||||
return (
|
||||
<GlobalContext.Provider value={{ onLoading, locale, isDarkMode, updateDarkMode }}>
|
||||
<GlobalContext.Provider value={{ onLoading, locale, isDarkMode, updateDarkMode, theme, setTheme }}>
|
||||
{children}
|
||||
</GlobalContext.Provider>
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import cookie from 'react-cookies'
|
||||
import BLOG from '@/blog.config'
|
||||
|
||||
export const ALL_THEME = ['next', 'fukasawa', 'hexo', 'empty', 'medium']
|
||||
/**
|
||||
* 初始化主题
|
||||
* @param isDarkMode
|
||||
|
||||
11
pages/404.js
11
pages/404.js
@@ -1,11 +0,0 @@
|
||||
import { Layout404 } from '@/themes'
|
||||
|
||||
/**
|
||||
* 自定义404界面
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
export default function Custom404 (props) {
|
||||
return <Layout404 {...props}/>
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import BLOG from '@/blog.config'
|
||||
import { getPostBlocks } from '@/lib/notion'
|
||||
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
|
||||
import { LayoutSlug } from '@/themes'
|
||||
import Custom404 from '@/pages/404'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import * as ThemeMap from '@/themes'
|
||||
|
||||
/**
|
||||
* 根据notion的slug访问页面,针对类型为Page的页面
|
||||
@@ -10,10 +10,12 @@ import Custom404 from '@/pages/404'
|
||||
* @returns
|
||||
*/
|
||||
const Slug = (props) => {
|
||||
const { theme } = useGlobal()
|
||||
const ThemeComponents = ThemeMap[theme]
|
||||
if (!props.post) {
|
||||
return <Custom404 {...props} />
|
||||
return <ThemeComponents.Layout404 {...props}/>
|
||||
}
|
||||
return <LayoutSlug {...props} showArticleInfo={false}/>
|
||||
return <ThemeComponents.LayoutSlug {...props} showArticleInfo={false}/>
|
||||
}
|
||||
|
||||
export async function getStaticPaths () {
|
||||
|
||||
@@ -14,6 +14,7 @@ import 'prismjs/themes/prism-okaidia.css'
|
||||
import 'katex/dist/katex.min.css'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { GlobalContextProvider } from '@/lib/global'
|
||||
import { DebugPanel } from '@/components/DebugPanel'
|
||||
|
||||
const Ackee = dynamic(() => import('@/components/Ackee'), { ssr: false })
|
||||
const Gtag = dynamic(() => import('@/components/Gtag'), { ssr: false })
|
||||
@@ -23,6 +24,7 @@ const GoogleAdsense = dynamic(() => import('@/components/GoogleAdsense'), { ssr:
|
||||
const MyApp = ({ Component, pageProps }) => {
|
||||
return (
|
||||
<GlobalContextProvider>
|
||||
{BLOG.DEBUG && <DebugPanel/>}
|
||||
{BLOG.ANALYTICS_ACKEE_TRACKER && <Ackee />}
|
||||
{BLOG.ANALYTICS_GOOGLE_ID && <Gtag />}
|
||||
{JSON.parse(BLOG.ANALYTICS_BUSUANZI_ENABLE) && <Busuanzi/>}
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
|
||||
import React from 'react'
|
||||
import { LayoutArchive } from '@/themes'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import * as ThemeMap from '@/themes'
|
||||
|
||||
const ArchiveIndex = (props) => {
|
||||
const { theme } = useGlobal()
|
||||
const ThemeComponents = ThemeMap[theme]
|
||||
return <ThemeComponents.LayoutArchive {...props}/>
|
||||
}
|
||||
|
||||
export async function getStaticProps () {
|
||||
const { allPosts, categories, tags, postCount, customNav } =
|
||||
@@ -18,8 +25,4 @@ export async function getStaticProps () {
|
||||
}
|
||||
}
|
||||
|
||||
const ArchiveIndex = (props) => {
|
||||
return <LayoutArchive {...props}/>
|
||||
}
|
||||
|
||||
export default ArchiveIndex
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import BLOG from '@/blog.config'
|
||||
import { getPostBlocks } from '@/lib/notion'
|
||||
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
|
||||
import { LayoutSlug } from '@/themes'
|
||||
import Custom404 from '@/pages/404'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import * as ThemeMap from '@/themes'
|
||||
|
||||
/**
|
||||
* 根据notion的slug访问页面
|
||||
@@ -10,10 +10,12 @@ import Custom404 from '@/pages/404'
|
||||
* @returns
|
||||
*/
|
||||
const Slug = (props) => {
|
||||
const { theme } = useGlobal()
|
||||
const ThemeComponents = ThemeMap[theme]
|
||||
if (!props.post) {
|
||||
return <Custom404 {...props} />
|
||||
return <ThemeComponents.Layout404 {...props}/>
|
||||
}
|
||||
return <LayoutSlug {...props} showArticleInfo={true}/>
|
||||
return <ThemeComponents.LayoutSlug {...props} showArticleInfo={true}/>
|
||||
}
|
||||
|
||||
export async function getStaticPaths () {
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
|
||||
import React from 'react'
|
||||
import { LayoutCategory } from '@/themes'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import * as ThemeMap from '@/themes'
|
||||
|
||||
export default function Category (props) {
|
||||
return <LayoutCategory {...props} />
|
||||
const { theme } = useGlobal()
|
||||
const ThemeComponents = ThemeMap[theme]
|
||||
return <ThemeComponents.LayoutCategory {...props} />
|
||||
}
|
||||
|
||||
export async function getStaticProps ({ params }) {
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
|
||||
import React from 'react'
|
||||
import { LayoutCategoryIndex } from '@/themes'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import * as ThemeMap from '@/themes'
|
||||
|
||||
export default function Category (props) {
|
||||
return <LayoutCategoryIndex {...props}/>
|
||||
const { theme } = useGlobal()
|
||||
const ThemeComponents = ThemeMap[theme]
|
||||
return <ThemeComponents.LayoutCategoryIndex {...props}/>
|
||||
}
|
||||
|
||||
export async function getStaticProps () {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import BLOG from '@/blog.config'
|
||||
import { getPostBlocks } from '@/lib/notion'
|
||||
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
|
||||
import { LayoutIndex, THEME_CONFIG } from '@/themes'
|
||||
|
||||
import * as ThemeMap from '@/themes'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
const Index = (props) => {
|
||||
return <LayoutIndex {...props}/>
|
||||
const { theme } = useGlobal()
|
||||
const ThemeComponents = ThemeMap[theme]
|
||||
return <ThemeComponents.LayoutIndex {...props}/>
|
||||
}
|
||||
|
||||
export async function getStaticProps () {
|
||||
@@ -26,7 +28,7 @@ export async function getStaticProps () {
|
||||
BLOG.POSTS_PER_PAGE * (page - 1),
|
||||
BLOG.POSTS_PER_PAGE * page
|
||||
)
|
||||
if (THEME_CONFIG.POST_LIST_PREVIEW || BLOG.POST_LIST_PREVIEW) {
|
||||
if (BLOG.POST_LIST_PREVIEW) {
|
||||
for (const i in postsToShow) {
|
||||
const post = postsToShow[i]
|
||||
const blockMap = await getPostBlocks(post.id, 'slug', BLOG.POST_PREVIEW_LINES)
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import BLOG from '@/blog.config'
|
||||
import { getPostBlocks } from '@/lib/notion'
|
||||
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
|
||||
import { LayoutPage, THEME_CONFIG } from '@/themes'
|
||||
import Custom404 from '@/pages/404'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import * as ThemeMap from '@/themes'
|
||||
|
||||
const Page = (props) => {
|
||||
const { theme } = useGlobal()
|
||||
const ThemeComponents = ThemeMap[theme]
|
||||
if (!props?.meta) {
|
||||
return <Custom404 {...props} />
|
||||
return <ThemeComponents.Layout404 {...props}/>
|
||||
}
|
||||
return <LayoutPage {...props} />
|
||||
return <ThemeComponents.LayoutPage {...props} />
|
||||
}
|
||||
|
||||
export async function getStaticPaths () {
|
||||
@@ -43,8 +45,7 @@ export async function getStaticProps ({ params: { page } }) {
|
||||
BLOG.POSTS_PER_PAGE * (page - 1),
|
||||
BLOG.POSTS_PER_PAGE * page
|
||||
)
|
||||
// 加载预览
|
||||
if (THEME_CONFIG.POST_LIST_PREVIEW || BLOG.POST_LIST_PREVIEW) {
|
||||
if (BLOG.POST_LIST_PREVIEW) {
|
||||
for (const i in postsToShow) {
|
||||
const post = postsToShow[i]
|
||||
const blockMap = await getPostBlocks(post.id, 'slug', BLOG.POST_PREVIEW_LINES)
|
||||
|
||||
@@ -1,8 +1,22 @@
|
||||
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
|
||||
import { LayoutSearch } from '@/themes'
|
||||
import BLOG from '@/blog.config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { getDataFromCache } from '@/lib/cache/cache_manager'
|
||||
import * as ThemeMap from '@/themes'
|
||||
|
||||
const Index = (props) => {
|
||||
const { keyword } = props
|
||||
const { locale } = useGlobal()
|
||||
const meta = {
|
||||
title: `${keyword || ''} | ${locale.NAV.SEARCH} | ${BLOG.TITLE} `,
|
||||
description: BLOG.DESCRIPTION,
|
||||
type: 'website'
|
||||
}
|
||||
|
||||
const { theme } = useGlobal()
|
||||
const ThemeComponents = ThemeMap[theme]
|
||||
return <ThemeComponents.LayoutSearch {...props} meta={meta} currentSearch={keyword} />
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务端搜索
|
||||
@@ -33,17 +47,6 @@ export async function getServerSideProps ({ params: { keyword } }) {
|
||||
}
|
||||
}
|
||||
|
||||
const Index = (props) => {
|
||||
const { keyword } = props
|
||||
const { locale } = useGlobal()
|
||||
const meta = {
|
||||
title: `${keyword || ''} | ${locale.NAV.SEARCH} | ${BLOG.TITLE} `,
|
||||
description: BLOG.DESCRIPTION,
|
||||
type: 'website'
|
||||
}
|
||||
return <LayoutSearch {...props} meta={meta} currentSearch={keyword} />
|
||||
}
|
||||
|
||||
/**
|
||||
* 将对象的指定字段拼接到字符串
|
||||
* @param sourceTextArray
|
||||
|
||||
@@ -1,33 +1,8 @@
|
||||
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
|
||||
import { LayoutSearch } from '@/themes'
|
||||
import BLOG from '@/blog.config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
/**
|
||||
* 浏览器前端搜索
|
||||
*/
|
||||
export async function getStaticProps () {
|
||||
const {
|
||||
allPosts,
|
||||
categories,
|
||||
tags,
|
||||
postCount,
|
||||
latestPosts,
|
||||
customNav
|
||||
} = await getGlobalNotionData({ from: 'search-props', pageType: ['Post'] })
|
||||
return {
|
||||
props: {
|
||||
posts: allPosts,
|
||||
tags,
|
||||
categories,
|
||||
postCount,
|
||||
latestPosts,
|
||||
customNav
|
||||
},
|
||||
revalidate: 1
|
||||
}
|
||||
}
|
||||
import * as ThemeMap from '@/themes'
|
||||
|
||||
const Search = (props) => {
|
||||
const { posts } = props
|
||||
@@ -51,7 +26,29 @@ const Search = (props) => {
|
||||
description: BLOG.DESCRIPTION,
|
||||
type: 'website'
|
||||
}
|
||||
return <LayoutSearch {...props} posts={filteredPosts} meta={meta} currentSearch={searchKey} />
|
||||
|
||||
const { theme } = useGlobal()
|
||||
const ThemeComponents = ThemeMap[theme]
|
||||
|
||||
return <ThemeComponents.LayoutSearch {...props} posts={filteredPosts} meta={meta} currentSearch={searchKey} />
|
||||
}
|
||||
|
||||
/**
|
||||
* 浏览器前端搜索
|
||||
*/
|
||||
export async function getStaticProps () {
|
||||
const { allPosts, categories, tags, postCount, latestPosts, customNav } = await getGlobalNotionData({ from: 'search-props', pageType: ['Post'] })
|
||||
return {
|
||||
props: {
|
||||
posts: allPosts,
|
||||
tags,
|
||||
categories,
|
||||
postCount,
|
||||
latestPosts,
|
||||
customNav
|
||||
},
|
||||
revalidate: 1
|
||||
}
|
||||
}
|
||||
|
||||
function getSearchKey () {
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
|
||||
import { LayoutTag } from '@/themes'
|
||||
import * as ThemeMap from '@/themes'
|
||||
|
||||
const Tag = (props) => {
|
||||
return <LayoutTag {...props} />
|
||||
const { theme } = useGlobal()
|
||||
const ThemeComponents = ThemeMap[theme]
|
||||
return <ThemeComponents.LayoutTag {...props} />
|
||||
}
|
||||
|
||||
export async function getStaticProps ({ params }) {
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { getGlobalNotionData } from '@/lib/notion/getNotionData'
|
||||
import React from 'react'
|
||||
import { LayoutTagIndex } from '@/themes'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import * as ThemeMap from '@/themes'
|
||||
|
||||
const TagIndex = (props) => {
|
||||
return <LayoutTagIndex {...props} />
|
||||
const { theme } = useGlobal()
|
||||
const ThemeComponents = ThemeMap[theme]
|
||||
return <ThemeComponents.LayoutTagIndex {...props} />
|
||||
}
|
||||
|
||||
export async function getStaticProps () {
|
||||
|
||||
@@ -992,7 +992,7 @@ svg.notion-page-icon {
|
||||
.notion-board-header {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
z-index: 82;
|
||||
z-index: 30;
|
||||
height: 44px;
|
||||
min-width: 100%;
|
||||
}
|
||||
@@ -1749,7 +1749,7 @@ pre[class*='language-'] {
|
||||
.notion-table-header {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
z-index: 82;
|
||||
z-index:30;
|
||||
height: 33px;
|
||||
color: var(--fg-color-3);
|
||||
min-width: var(--notion-max-width);
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import CommonHead from '@/components/CommonHead'
|
||||
|
||||
/**
|
||||
* 基础布局 采用左右两侧布局,移动端使用顶部导航栏
|
||||
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const LayoutBase = (props) => {
|
||||
const { children, meta } = props
|
||||
return <div>
|
||||
<CommonHead meta={meta} />
|
||||
<main id='wrapper' className='flex justify-center flex-1 pb-12'>
|
||||
{children}
|
||||
</main>
|
||||
</div>
|
||||
}
|
||||
|
||||
export default LayoutBase
|
||||
@@ -1,6 +0,0 @@
|
||||
import LayoutBase from './LayoutBase'
|
||||
|
||||
export const LayoutIndex = (props) => {
|
||||
// const { posts, tags, meta, categories, postCount, latestPosts } = props
|
||||
return <LayoutBase {...props}>Index</LayoutBase>
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import LayoutBase from './LayoutBase'
|
||||
|
||||
export const LayoutSearch = (props) => {
|
||||
return <LayoutBase {...props}>
|
||||
</LayoutBase>
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import CONFIG_EMPTY from './config_empty'
|
||||
export { CONFIG_EMPTY as THEME_CONFIG }
|
||||
export { LayoutIndex } from './LayoutIndex'
|
||||
export { LayoutSearch } from './LayoutSearch'
|
||||
export { LayoutArchive } from './LayoutArchive'
|
||||
export { LayoutSlug } from './LayoutSlug'
|
||||
export { Layout404 } from './Layout404'
|
||||
export { LayoutCategory } from './LayoutCategory'
|
||||
export { LayoutCategoryIndex } from './LayoutCategoryIndex'
|
||||
export { LayoutPage } from './LayoutPage'
|
||||
export { LayoutTag } from './LayoutTag'
|
||||
export { LayoutTagIndex } from './LayoutTagIndex'
|
||||
@@ -1,12 +0,0 @@
|
||||
import CONFIG_FUKA from './config_fuka'
|
||||
export { CONFIG_FUKA as THEME_CONFIG }
|
||||
export { LayoutIndex } from './LayoutIndex'
|
||||
export { LayoutSearch } from './LayoutSearch'
|
||||
export { LayoutArchive } from './LayoutArchive'
|
||||
export { LayoutSlug } from './LayoutSlug'
|
||||
export { Layout404 } from './Layout404'
|
||||
export { LayoutCategory } from './LayoutCategory'
|
||||
export { LayoutCategoryIndex } from './LayoutCategoryIndex'
|
||||
export { LayoutPage } from './LayoutPage'
|
||||
export { LayoutTag } from './LayoutTag'
|
||||
export { LayoutTagIndex } from './LayoutTagIndex'
|
||||
@@ -1,26 +0,0 @@
|
||||
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
import BlogPostListPage from './components/BlogPostListPage'
|
||||
import LayoutBase from './LayoutBase'
|
||||
|
||||
export const LayoutSearch = (props) => {
|
||||
const { keyword } = props
|
||||
const router = useRouter()
|
||||
const currentSearch = keyword || router?.query?.s
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
const container = document.getElementById('container')
|
||||
if (container && container.innerHTML) {
|
||||
const re = new RegExp(`${currentSearch}`, 'gim')
|
||||
container.innerHTML = container.innerHTML.replace(re, `<span class='text-red-500 border-b border-dashed'>${currentSearch}</span>`)
|
||||
}
|
||||
},
|
||||
100)
|
||||
})
|
||||
return <LayoutBase {...props} currentSearch={currentSearch}>
|
||||
<div ic='container'>
|
||||
<BlogPostListPage {...props}/>
|
||||
</div>
|
||||
</LayoutBase>
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import CONFIG_HEXO from './config_hexo'
|
||||
export { LayoutIndex } from './LayoutIndex'
|
||||
export { LayoutSearch } from './LayoutSearch'
|
||||
export { LayoutArchive } from './LayoutArchive'
|
||||
export { LayoutSlug } from './LayoutSlug'
|
||||
export { Layout404 } from './Layout404'
|
||||
export { LayoutCategory } from './LayoutCategory'
|
||||
export { LayoutCategoryIndex } from './LayoutCategoryIndex'
|
||||
export { LayoutPage } from './LayoutPage'
|
||||
export { LayoutTag } from './LayoutTag'
|
||||
export { LayoutTagIndex } from './LayoutTagIndex'
|
||||
export { CONFIG_HEXO as THEME_CONFIG }
|
||||
@@ -1,12 +0,0 @@
|
||||
import CONFIG_MEDIUM from './config_medium'
|
||||
export { CONFIG_MEDIUM as THEME_CONFIG }
|
||||
export { LayoutIndex } from './LayoutIndex'
|
||||
export { LayoutSearch } from './LayoutSearch'
|
||||
export { LayoutArchive } from './LayoutArchive'
|
||||
export { LayoutSlug } from './LayoutSlug'
|
||||
export { Layout404 } from './Layout404'
|
||||
export { LayoutCategory } from './LayoutCategory'
|
||||
export { LayoutCategoryIndex } from './LayoutCategoryIndex'
|
||||
export { LayoutPage } from './LayoutPage'
|
||||
export { LayoutTag } from './LayoutTag'
|
||||
export { LayoutTagIndex } from './LayoutTagIndex'
|
||||
@@ -1,12 +0,0 @@
|
||||
import CONFIG_NEXT from './config_next'
|
||||
export { CONFIG_NEXT as THEME_CONFIG }
|
||||
export { LayoutIndex } from './LayoutIndex'
|
||||
export { LayoutSearch } from './LayoutSearch'
|
||||
export { LayoutArchive } from './LayoutArchive'
|
||||
export { LayoutSlug } from './LayoutSlug'
|
||||
export { Layout404 } from './Layout404'
|
||||
export { LayoutCategory } from './LayoutCategory'
|
||||
export { LayoutCategoryIndex } from './LayoutCategoryIndex'
|
||||
export { LayoutPage } from './LayoutPage'
|
||||
export { LayoutTag } from './LayoutTag'
|
||||
export { LayoutTagIndex } from './LayoutTagIndex'
|
||||
37
themes/empty/LayoutBase.js
Normal file
37
themes/empty/LayoutBase.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import CommonHead from '@/components/CommonHead'
|
||||
import Link from 'next/link'
|
||||
|
||||
/**
|
||||
* 基础布局 采用左右两侧布局,移动端使用顶部导航栏
|
||||
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const LayoutBase = props => {
|
||||
const { children, meta } = props
|
||||
return (
|
||||
<div>
|
||||
<CommonHead meta={meta} />
|
||||
{/* 导航菜单 */}
|
||||
<div className="w-full flex justify-center my-2">
|
||||
<nav className="max-w-6xl space-x-3 underline">
|
||||
<Link href="/">
|
||||
<a>首页</a>
|
||||
</Link>
|
||||
<Link href="/category">
|
||||
<a>分类</a>
|
||||
</Link>
|
||||
<Link href="/tag">
|
||||
<a>标签</a>
|
||||
</Link>
|
||||
</nav>
|
||||
</div>
|
||||
{/* 内容主体 */}
|
||||
<main id="wrapper" className="flex justify-center flex-1 pb-12">
|
||||
<div className="max-w-6xl px-3">{children}</div>
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutBase
|
||||
18
themes/empty/LayoutIndex.js
Normal file
18
themes/empty/LayoutIndex.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import Link from 'next/link'
|
||||
import LayoutBase from './LayoutBase'
|
||||
|
||||
export const LayoutIndex = props => {
|
||||
const { posts } = props
|
||||
return (
|
||||
<LayoutBase {...props}>
|
||||
{posts.map(p => (
|
||||
<div key={p.id} className='border my-12'>
|
||||
<Link href={`/article/${p.slug}`}>
|
||||
<a className='underline cursor-pointer'>{p.title}</a>
|
||||
</Link>
|
||||
<div>{p.summary}</div>
|
||||
</div>
|
||||
))}
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import LayoutBase from '../Empty/LayoutBase'
|
||||
import LayoutBase from './LayoutBase'
|
||||
|
||||
export const LayoutPage = (props) => {
|
||||
const { page } = props
|
||||
42
themes/empty/LayoutSearch.js
Normal file
42
themes/empty/LayoutSearch.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
import LayoutBase from './LayoutBase'
|
||||
|
||||
export const LayoutSearch = props => {
|
||||
const { keyword, posts } = props
|
||||
const router = useRouter()
|
||||
const currentSearch = keyword || router?.query?.s
|
||||
let handleTextColor = false
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
if (currentSearch && !handleTextColor) {
|
||||
const container = document.getElementById('container')
|
||||
if (container && container.innerHTML) {
|
||||
const re = new RegExp(`${currentSearch}`, 'gim')
|
||||
container.innerHTML = container.innerHTML.replace(
|
||||
re,
|
||||
`<span class='text-red-500 border-b border-dashed'>${currentSearch}</span>`
|
||||
)
|
||||
handleTextColor = true
|
||||
}
|
||||
}
|
||||
}, 100)
|
||||
})
|
||||
|
||||
return (
|
||||
<LayoutBase {...props}>
|
||||
<h2>Search</h2>
|
||||
<div id="container">
|
||||
{posts.map(p => (
|
||||
<div key={p.id} className="border my-12">
|
||||
<Link href={`/article/${p.slug}`}>
|
||||
<a className="underline cursor-pointer">{p.title}</a>
|
||||
</Link>
|
||||
<div>{p.summary}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
@@ -6,14 +6,20 @@ import 'prismjs/components/prism-javascript'
|
||||
import 'prismjs/components/prism-markup'
|
||||
import 'prismjs/components/prism-python'
|
||||
import 'prismjs/components/prism-typescript'
|
||||
import { Code, Collection, CollectionRow, Equation, NotionRenderer } from 'react-notion-x'
|
||||
import {
|
||||
Code,
|
||||
Collection,
|
||||
CollectionRow,
|
||||
Equation,
|
||||
NotionRenderer
|
||||
} from 'react-notion-x'
|
||||
import LayoutBase from './LayoutBase'
|
||||
|
||||
const mapPageUrl = id => {
|
||||
return 'https://www.notion.so/' + id.replace(/-/g, '')
|
||||
}
|
||||
|
||||
export const LayoutSlug = (props) => {
|
||||
export const LayoutSlug = props => {
|
||||
const { post } = props
|
||||
const meta = {
|
||||
title: `${post.title} | ${BLOG.TITLE}`,
|
||||
@@ -27,25 +33,27 @@ export const LayoutSlug = (props) => {
|
||||
post.toc = getPageTableOfContents(post, post.blockMap)
|
||||
}
|
||||
|
||||
return <LayoutBase {...props} meta={meta}>
|
||||
<h1>Slug - {post?.title}</h1>
|
||||
<p>
|
||||
{/* Notion文章主体 */}
|
||||
<section id='notion-article' className='px-1'>
|
||||
{post.blockMap && (
|
||||
<NotionRenderer
|
||||
recordMap={post.blockMap}
|
||||
mapPageUrl={mapPageUrl}
|
||||
components={{
|
||||
equation: Equation,
|
||||
code: Code,
|
||||
collectionRow: CollectionRow,
|
||||
collection: Collection
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</section>
|
||||
</p>
|
||||
|
||||
</LayoutBase>
|
||||
return (
|
||||
<LayoutBase {...props} meta={meta}>
|
||||
<div>
|
||||
<h2>{post?.title}</h2>
|
||||
<p>
|
||||
<section id="notion-article" className="px-1">
|
||||
{post.blockMap && (
|
||||
<NotionRenderer
|
||||
recordMap={post.blockMap}
|
||||
mapPageUrl={mapPageUrl}
|
||||
components={{
|
||||
equation: Equation,
|
||||
code: Code,
|
||||
collectionRow: CollectionRow,
|
||||
collection: Collection
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</section>
|
||||
</p>
|
||||
</div>
|
||||
</LayoutBase>
|
||||
)
|
||||
}
|
||||
25
themes/empty/index.js
Normal file
25
themes/empty/index.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import CONFIG_EMPTY from './config_empty'
|
||||
import { LayoutIndex } from './LayoutIndex'
|
||||
import { LayoutSearch } from './LayoutSearch'
|
||||
import { LayoutArchive } from './LayoutArchive'
|
||||
import { LayoutSlug } from './LayoutSlug'
|
||||
import { Layout404 } from './Layout404'
|
||||
import { LayoutCategory } from './LayoutCategory'
|
||||
import { LayoutCategoryIndex } from './LayoutCategoryIndex'
|
||||
import { LayoutPage } from './LayoutPage'
|
||||
import { LayoutTag } from './LayoutTag'
|
||||
import { LayoutTagIndex } from './LayoutTagIndex'
|
||||
|
||||
export {
|
||||
CONFIG_EMPTY as THEME_CONFIG,
|
||||
LayoutIndex,
|
||||
LayoutSearch,
|
||||
LayoutArchive,
|
||||
LayoutSlug,
|
||||
Layout404,
|
||||
LayoutCategory,
|
||||
LayoutCategoryIndex,
|
||||
LayoutPage,
|
||||
LayoutTag,
|
||||
LayoutTagIndex
|
||||
}
|
||||
@@ -28,7 +28,7 @@ const LayoutBase = (props) => {
|
||||
<div className='flex'>
|
||||
<AsideLeft {...props}/>
|
||||
<main id='wrapper' className='flex w-full py-8 justify-center'>
|
||||
<div className='2xl:max-w-6xl md:max-w-3xl w-full'>
|
||||
<div className='2xl:max-w-6xl md:max-w-4xl w-full'>
|
||||
<div> {headerSlot} </div>
|
||||
<div>{children}</div>
|
||||
</div>
|
||||
@@ -125,7 +125,6 @@ export default function ArticleDetail ({ post, recommendPosts, prev, next }) {
|
||||
|
||||
{/* 评论互动 */}
|
||||
<div className="duration-200 shadow px-12 w-screen md:w-full overflow-x-auto dark:border-gray-700 bg-white dark:bg-gray-800">
|
||||
<div className='text-2xl mt-8 mx-8'>发表评论</div>
|
||||
<Comment frontMatter={post} />
|
||||
</div>
|
||||
</div>)
|
||||
25
themes/fukasawa/index.js
Normal file
25
themes/fukasawa/index.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import CONFIG_FUKA from './config_fuka'
|
||||
import { LayoutIndex } from './LayoutIndex'
|
||||
import { LayoutSearch } from './LayoutSearch'
|
||||
import { LayoutArchive } from './LayoutArchive'
|
||||
import { LayoutSlug } from './LayoutSlug'
|
||||
import { Layout404 } from './Layout404'
|
||||
import { LayoutCategory } from './LayoutCategory'
|
||||
import { LayoutCategoryIndex } from './LayoutCategoryIndex'
|
||||
import { LayoutPage } from './LayoutPage'
|
||||
import { LayoutTag } from './LayoutTag'
|
||||
import { LayoutTagIndex } from './LayoutTagIndex'
|
||||
|
||||
export {
|
||||
CONFIG_FUKA as THEME_CONFIG,
|
||||
LayoutIndex,
|
||||
LayoutSearch,
|
||||
LayoutArchive,
|
||||
LayoutSlug,
|
||||
Layout404,
|
||||
LayoutCategory,
|
||||
LayoutCategoryIndex,
|
||||
LayoutPage,
|
||||
LayoutTag,
|
||||
LayoutTagIndex
|
||||
}
|
||||
34
themes/hexo/LayoutSearch.js
Normal file
34
themes/hexo/LayoutSearch.js
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
import BlogPostListPage from './components/BlogPostListPage'
|
||||
import LayoutBase from './LayoutBase'
|
||||
import SearchInput from './components/SearchInput'
|
||||
export const LayoutSearch = (props) => {
|
||||
const { keyword } = props
|
||||
const router = useRouter()
|
||||
const currentSearch = keyword || router?.query?.s
|
||||
let handleTextColor = false
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
if (currentSearch && !handleTextColor) {
|
||||
const container = document.getElementById('container')
|
||||
if (container && container.innerHTML) {
|
||||
const re = new RegExp(`${currentSearch}`, 'gim')
|
||||
container.innerHTML = container.innerHTML.replace(re, `<span class='text-red-500 border-b border-dashed'>${currentSearch}</span>`)
|
||||
handleTextColor = true
|
||||
}
|
||||
}
|
||||
},
|
||||
100)
|
||||
})
|
||||
return <LayoutBase {...props} currentSearch={currentSearch}>
|
||||
<div className='m-3'>
|
||||
<SearchInput {...props}/>
|
||||
</div>
|
||||
<div id='container'>
|
||||
<BlogPostListPage {...props}/>
|
||||
</div>
|
||||
</LayoutBase>
|
||||
}
|
||||
@@ -14,7 +14,7 @@ const BlogPostCard = ({ post, showSummary }) => {
|
||||
|
||||
<div className='lg:p-8 p-4 flex flex-col w-full'>
|
||||
<Link href={`${BLOG.PATH}/article/${post.slug}`} passHref>
|
||||
<a className={`cursor-pointer hover:underline text-3xl font-sans ${showPreview ? 'justify-center' : 'justify-start'} leading-tight text-gray-700 dark:text-gray-100 hover:text-blue-500 dark:hover:text-blue-400`}>
|
||||
<a className={`cursor-pointer hover:underline text-2xl font-sans ${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}
|
||||
</a>
|
||||
</Link>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user