mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-19 23:16:48 +00:00
feat/theme-switch
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
import { generateLocaleDict, initLocale } from './lang'
|
||||
import { createContext, useContext, useEffect, useState } from 'react'
|
||||
import Router, { useRouter } from 'next/router'
|
||||
import { useRouter } from 'next/router'
|
||||
import BLOG from '@/blog.config'
|
||||
import { ALL_THEME, initDarkMode, initTheme, saveThemeToCookies } from '@/lib/theme'
|
||||
import { ALL_THEME, initDarkMode } from '@/lib/theme'
|
||||
import NProgress from 'nprogress'
|
||||
import LoadingCover from '@/components/LoadingCover'
|
||||
import { isBrowser } from './utils'
|
||||
import { getQueryParam, isBrowser } from './utils'
|
||||
|
||||
const GlobalContext = createContext()
|
||||
|
||||
@@ -16,18 +16,17 @@ const GlobalContext = createContext()
|
||||
* @constructor
|
||||
*/
|
||||
export function GlobalContextProvider({ children }) {
|
||||
const router = useRouter()
|
||||
const [lang, updateLang] = useState(BLOG.LANG) // 默认语言
|
||||
const [locale, updateLocale] = useState(generateLocaleDict(BLOG.LANG)) // 默认语言
|
||||
const [theme, setTheme] = useState(BLOG.THEME) // 默认博客主题
|
||||
const [theme, setTheme] = useState(getQueryParam(router.asPath, 'theme') || BLOG.THEME) // 默认博客主题
|
||||
const [isDarkMode, updateDarkMode] = useState(BLOG.APPEARANCE === 'dark') // 默认深色模式
|
||||
const [onLoading, setOnLoading] = useState(false) // 抓取文章数据
|
||||
const [onReading, setOnReading] = useState(false) // 网页资源加载
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
initLocale(lang, locale, updateLang, updateLocale)
|
||||
initDarkMode(isDarkMode, updateDarkMode)
|
||||
initTheme(theme, changeTheme)
|
||||
if (isBrowser()) {
|
||||
// 监听用户刷新页面
|
||||
const handleBeforeUnload = (event) => {
|
||||
@@ -45,10 +44,17 @@ export function GlobalContextProvider({ children }) {
|
||||
useEffect(() => {
|
||||
const handleStart = (url) => {
|
||||
NProgress.start()
|
||||
const { theme } = router.query
|
||||
if (theme && !url.includes(`theme=${theme}`)) {
|
||||
// TODO
|
||||
const newUrl = `${url}${url.includes('?') ? '&' : '?'}theme=${theme}`
|
||||
router.push(newUrl)
|
||||
}
|
||||
setOnLoading(true)
|
||||
}
|
||||
const handleStop = () => {
|
||||
NProgress.done()
|
||||
setTheme(getQueryParam(router.asPath, 'theme') || BLOG.THEME)
|
||||
setOnLoading(false)
|
||||
}
|
||||
|
||||
@@ -62,24 +68,16 @@ export function GlobalContextProvider({ children }) {
|
||||
}
|
||||
}, [router])
|
||||
|
||||
// 切换主题
|
||||
function switchTheme() {
|
||||
const currentIndex = ALL_THEME.indexOf(theme)
|
||||
const newIndex = currentIndex < ALL_THEME.length - 1 ? currentIndex + 1 : 0
|
||||
const newTheme = ALL_THEME[newIndex]
|
||||
changeTheme(newTheme)
|
||||
const query = { ...router.query, theme: newTheme }
|
||||
router.push({ pathname: router.pathname, query })
|
||||
return newTheme
|
||||
}
|
||||
|
||||
function changeTheme(theme) {
|
||||
Router.query.theme = ''
|
||||
if (ALL_THEME.indexOf(theme) > -1) {
|
||||
setTheme(theme)
|
||||
} else {
|
||||
setTheme(BLOG.THEME)
|
||||
}
|
||||
saveThemeToCookies(theme)
|
||||
}
|
||||
|
||||
return (
|
||||
<GlobalContext.Provider value={{
|
||||
onLoading,
|
||||
@@ -91,7 +89,6 @@ export function GlobalContextProvider({ children }) {
|
||||
theme,
|
||||
setTheme,
|
||||
switchTheme,
|
||||
changeTheme,
|
||||
setOnReading
|
||||
}}>
|
||||
<LoadingCover onReading={onReading} setOnReading={setOnReading}/>
|
||||
|
||||
77
lib/theme.js
77
lib/theme.js
@@ -1,6 +1,7 @@
|
||||
import cookie from 'react-cookies'
|
||||
import BLOG from '@/blog.config'
|
||||
import { isBrowser, getQueryVariable } from './utils'
|
||||
import { getQueryParam, getQueryVariable } from './utils'
|
||||
import dynamic from 'next/dynamic'
|
||||
|
||||
/**
|
||||
* 所有主题枚举
|
||||
@@ -16,6 +17,62 @@ export const ALL_THEME = [
|
||||
'simple'
|
||||
]
|
||||
|
||||
/**
|
||||
* 加载主题文件
|
||||
* @param {*} router
|
||||
* @returns
|
||||
*/
|
||||
export const getLayoutByTheme = (router) => {
|
||||
const theme = getQueryParam(router.asPath, 'theme') || BLOG.THEME
|
||||
let Layout = null
|
||||
// 根据路由 pages的文件名加载主题文件
|
||||
switch (router.pathname) {
|
||||
case '/':
|
||||
Layout = dynamic(() => import(`@/themes/${theme}/LayoutIndex`), { ssr: true })
|
||||
break
|
||||
case '/page/[page]':
|
||||
Layout = dynamic(() => import(`@/themes/${theme}/LayoutPage`), { ssr: true })
|
||||
break
|
||||
case '/archive':
|
||||
Layout = dynamic(() => import(`@/themes/${theme}/LayoutArchive`), { ssr: true })
|
||||
break
|
||||
case '/search':
|
||||
Layout = dynamic(() => import(`@/themes/${theme}/LayoutSearch`), { ssr: true })
|
||||
break
|
||||
case '/search/[keyword]':
|
||||
Layout = dynamic(() => import(`@/themes/${theme}/LayoutSearch`), { ssr: true })
|
||||
break
|
||||
case '/search/[keyword]/page/[page]':
|
||||
Layout = dynamic(() => import(`@/themes/${theme}/LayoutSearch`), { ssr: true })
|
||||
break
|
||||
case '/404':
|
||||
Layout = dynamic(() => import(`@/themes/${theme}/Layout404`), { ssr: true })
|
||||
break
|
||||
case '/tag':
|
||||
Layout = dynamic(() => import(`@/themes/${theme}/LayoutTagIndex`), { ssr: true })
|
||||
break
|
||||
case '/tag/[tag]':
|
||||
Layout = dynamic(() => import(`@/themes/${theme}/LayoutTag`), { ssr: true })
|
||||
break
|
||||
case '/tag/[tag]/page/[page]':
|
||||
Layout = dynamic(() => import(`@/themes/${theme}/LayoutTag`), { ssr: true })
|
||||
break
|
||||
case '/category':
|
||||
Layout = dynamic(() => import(`@/themes/${theme}/LayoutCategoryIndex`), { ssr: true })
|
||||
break
|
||||
case '/category/[category]':
|
||||
Layout = dynamic(() => import(`@/themes/${theme}/LayoutCategory`), { ssr: true })
|
||||
break
|
||||
case '/category/[category]/page/[page]':
|
||||
Layout = dynamic(() => import(`@/themes/${theme}/LayoutCategory`), { ssr: true })
|
||||
break
|
||||
default:
|
||||
Layout = dynamic(() => import(`@/themes/${theme}/LayoutSlug`), { ssr: true })
|
||||
break
|
||||
}
|
||||
return Layout
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化主题 , 优先级 query > cookies > systemPrefer
|
||||
* @param isDarkMode
|
||||
@@ -34,24 +91,6 @@ export const initDarkMode = (isDarkMode, updateDarkMode) => {
|
||||
document.getElementsByTagName('html')[0].setAttribute('class', isDarkMode ? 'dark' : 'light')
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化主题, 优先级 query > cookies > blog.config.js
|
||||
* @param {*} theme
|
||||
* @param {*} changeTheme
|
||||
*/
|
||||
export const initTheme = (theme, changeTheme) => {
|
||||
if (isBrowser()) {
|
||||
// const queryTheme = getQueryVariable('theme') || loadThemeFromCookies() || BLOG.THEME
|
||||
const queryTheme = getQueryVariable('theme') || BLOG.THEME
|
||||
let currentTheme = theme
|
||||
if (queryTheme !== theme && ALL_THEME.indexOf(queryTheme) > -1) {
|
||||
currentTheme = queryTheme
|
||||
}
|
||||
changeTheme(currentTheme)
|
||||
saveThemeToCookies(currentTheme)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否优先深色模式, 根据系统深色模式以及当前时间判断
|
||||
* @returns {*}
|
||||
|
||||
15
lib/utils.js
15
lib/utils.js
@@ -51,16 +51,27 @@ export function loadExternalResource(url, type) {
|
||||
* @param {}} variable
|
||||
* @returns
|
||||
*/
|
||||
export function getQueryVariable(variable) {
|
||||
export function getQueryVariable(key) {
|
||||
const query = isBrowser() ? window.location.search.substring(1) : ''
|
||||
const vars = query.split('&')
|
||||
for (let i = 0; i < vars.length; i++) {
|
||||
const pair = vars[i].split('=')
|
||||
if (pair[0] === variable) { return pair[1] }
|
||||
if (pair[0] === key) { return pair[1] }
|
||||
}
|
||||
return (false)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 URL 中指定参数的值
|
||||
* @param {string} url
|
||||
* @param {string} param
|
||||
* @returns {string|null}
|
||||
*/
|
||||
export function getQueryParam(url, param) {
|
||||
const searchParams = new URLSearchParams(url.split('?')[1])
|
||||
return searchParams.get(param)
|
||||
}
|
||||
|
||||
/**
|
||||
* 深度合并两个对象
|
||||
* @param target
|
||||
|
||||
Reference in New Issue
Block a user