diff --git a/components/CusdisComponent.js b/components/CusdisComponent.js index ad780aea..a276eac6 100644 --- a/components/CusdisComponent.js +++ b/components/CusdisComponent.js @@ -5,7 +5,7 @@ import { useEffect } from 'react' import { loadExternalResource } from '@/lib/utils' const CusdisComponent = ({ frontMatter }) => { - const { locale } = useGlobal() + const { lang } = useGlobal() const router = useRouter() const { isDarkMode } = useGlobal() @@ -18,7 +18,7 @@ const CusdisComponent = ({ frontMatter }) => { }, [isDarkMode]) return
{ const { cRef, className } = props - const { isDarkMode, updateDarkMode } = useGlobal() + const { isDarkMode, toggleDarkMode } = useGlobal() /** * 对外暴露方法 @@ -16,22 +15,12 @@ const DarkModeButton = (props) => { useImperativeHandle(cRef, () => { return { handleChangeDarkMode: () => { - handleChangeDarkMode() + toggleDarkMode() } } }) - // 用户手动设置主题 - const handleChangeDarkMode = () => { - const newStatus = !isDarkMode - saveDarkModeToCookies(newStatus) - updateDarkMode(newStatus) - const htmlElement = document.getElementsByTagName('html')[0] - htmlElement.classList?.remove(newStatus ? 'light' : 'dark') - htmlElement.classList?.add(newStatus ? 'dark' : 'light') - } - - return
+ return
{isDarkMode ? : }
} diff --git a/components/ThemeSwitch.js b/components/ThemeSwitch.js index a4b13f31..0c74a63e 100644 --- a/components/ThemeSwitch.js +++ b/components/ThemeSwitch.js @@ -5,19 +5,21 @@ import { THEMES } from '@/themes/theme' import { useRouter } from 'next/router' import DarkModeButton from './DarkModeButton' import { getQueryParam } from '@/lib/utils' +import LANGS from '@/lib/lang' /** * * @returns 主题切换 */ const ThemeSwitch = () => { - const { theme } = useGlobal() + const { theme, lang, changeLang, locale, isDarkMode, toggleDarkMode } = useGlobal() const router = useRouter() const currentTheme = getQueryParam(router.asPath, 'theme') || theme + // const currentLang = getQueryParam(router.asPath, 'lang') || lang const [isLoading, setIsLoading] = useState(false) // 修改当前路径url中的 theme 参数 // 例如 http://localhost?theme=hexo 跳转到 http://localhost?theme=newTheme - const onSelectChange = (e) => { + const onThemeSelectChange = (e) => { setIsLoading(true) const newTheme = e.target.value const query = router.query @@ -27,27 +29,52 @@ const ThemeSwitch = () => { }) } + const onLangSelectChange = (e) => { + const newLang = e.target.value + changeLang(newLang) + } + return (<> -
-
- -
- + {Object.keys(LANGS)?.map(t => { + return + })} + +
+
+ + {/* 主题切换按钮 */} +
+ +
+
-
- {/* 切换主题加载时的全屏遮罩 */} -
- -
+ + {/* 切换主题加载时的全屏遮罩 */} +
+ +
) } diff --git a/lib/cache/cache_manager.js b/lib/cache/cache_manager.js index 8796d3f4..4928bca9 100644 --- a/lib/cache/cache_manager.js +++ b/lib/cache/cache_manager.js @@ -3,15 +3,6 @@ import FileCache from './local_file_cache' import MongoCache from './mongo_db_cache' import BLOG from '@/blog.config' -let api -if (process.env.MONGO_DB_URL && process.env.MONGO_DB_NAME) { - api = MongoCache -} else if (process.env.ENABLE_FILE_CACHE) { - api = FileCache -} else { - api = MemoryCache -} - /** * 为减少频繁接口请求,notion数据将被缓存 * @param {*} key @@ -19,11 +10,11 @@ if (process.env.MONGO_DB_URL && process.env.MONGO_DB_NAME) { */ export async function getDataFromCache(key, force) { if (BLOG.ENABLE_CACHE || force) { - const dataFromCache = await api.getCache(key) + const dataFromCache = await getApi().getCache(key) if (JSON.stringify(dataFromCache) === '[]') { return null } - return api.getCache(key) + return getApi().getCache(key) } else { return null } @@ -33,12 +24,26 @@ export async function setDataToCache(key, data) { if (!data) { return } - await api.setCache(key, data) + await getApi().setCache(key, data) } export async function delCacheData(key) { if (!BLOG.ENABLE_CACHE) { return } - await api.delCache(key) + await getApi().delCache(key) +} + +/** + * 缓存实现类 + * @returns + */ +function getApi() { + if (process.env.MONGO_DB_URL && process.env.MONGO_DB_NAME) { + return MongoCache + } else if (process.env.ENABLE_FILE_CACHE) { + return FileCache + } else { + return MemoryCache + } } diff --git a/lib/cache/local_file_cache.js b/lib/cache/local_file_cache.js index cda7f35a..c411d6e5 100644 --- a/lib/cache/local_file_cache.js +++ b/lib/cache/local_file_cache.js @@ -41,7 +41,7 @@ export async function setCache (key, data) { fs.writeFileSync(jsonFile, JSON.stringify(json)) } -export async function delCache (key, data) { +export async function delCache (key) { const exist = await fs.existsSync(jsonFile) const json = exist ? JSON.parse(await fs.readFileSync(jsonFile)) : {} delete json.key @@ -49,4 +49,12 @@ export async function delCache (key, data) { fs.writeFileSync(jsonFile, JSON.stringify(json)) } +/** + * 清理缓存 + */ +export async function cleanCache() { + const json = {} + fs.writeFileSync(jsonFile, JSON.stringify(json)) +} + export default { getCache, setCache, delCache } diff --git a/lib/config.js b/lib/config.js index 56ae36ee..36a1112d 100644 --- a/lib/config.js +++ b/lib/config.js @@ -64,7 +64,7 @@ export const siteConfigMap = () => { const val = deepClone(BLOG) for (const key in val) { val[key] = siteConfig(key) - console.log('site', key, val[key], siteConfig(key)) + // console.log('site', key, val[key], siteConfig(key)) } return val } diff --git a/lib/global.js b/lib/global.js index 204fc432..eaabd278 100644 --- a/lib/global.js +++ b/lib/global.js @@ -1,11 +1,10 @@ import { generateLocaleDict, initLocale } from './lang' import { createContext, useContext, useEffect, useState } from 'react' import { useRouter } from 'next/router' -import { THEMES, initDarkMode } from '@/themes/theme' +import { THEMES, initDarkMode, saveDarkModeToCookies } from '@/themes/theme' import BLOG from '@/blog.config' import NProgress from 'nprogress' -import { isBrowser } from './utils' const GlobalContext = createContext() @@ -35,17 +34,34 @@ export function GlobalContextProvider(props) { return newTheme } + // 切换深色模式 + const toggleDarkMode = () => { + const newStatus = !isDarkMode + saveDarkModeToCookies(newStatus) + updateDarkMode(newStatus) + const htmlElement = document.getElementsByTagName('html')[0] + htmlElement.classList?.remove(newStatus ? 'light' : 'dark') + htmlElement.classList?.add(newStatus ? 'dark' : 'light') + } + + /** + * 更新语言 + */ + function changeLang(lang) { + if (lang) { + updateLang(lang) + updateLocale(generateLocaleDict(lang)) + } + } + useEffect(() => { - initLocale(lang, locale, updateLang, updateLocale) initDarkMode(updateDarkMode) - checkThemeDOM() + initLocale(lang, locale, updateLang, updateLocale) }, []) - // 加载默认主题 - // useEffect(() => { - // const queryTheme = getQueryVariable('theme') || theme - // setTheme(queryTheme) - // }, [router]) + useEffect(() => { + checkThemeDOM() + }) // 加载进度条 useEffect(() => { @@ -62,6 +78,7 @@ export function GlobalContextProvider(props) { NProgress.done() setOnLoading(false) } + router.events.on('routeChangeStart', handleStart) router.events.on('routeChangeError', handleStop) router.events.on('routeChangeComplete', handleStop) @@ -75,10 +92,11 @@ export function GlobalContextProvider(props) { return ( { - if (isBrowser) { - setTimeout(() => { - const elements = document.querySelectorAll('[id^="theme-"]') - if (elements?.length > 1) { - elements[elements.length - 1].scrollIntoView() - // 删除前面的元素,只保留最后一个元素 - for (let i = 0; i < elements.length - 1; i++) { - elements[i].parentNode.removeChild(elements[i]) - } - } - }, 500) + const elements = document.querySelectorAll('[id^="theme-"]') + if (elements?.length > 1) { + elements[elements.length - 1].scrollIntoView() + // 删除前面的元素,只保留最后一个元素 + for (let i = 0; i < elements.length - 1; i++) { + elements[i].parentNode.removeChild(elements[i]) + } } } diff --git a/lib/lang.js b/lib/lang.js index 15106572..3e2307f7 100644 --- a/lib/lang.js +++ b/lib/lang.js @@ -12,7 +12,7 @@ import { getQueryVariable, isBrowser, mergeDeep } from './utils' * 在这里配置所有支持的语言 * 国家-地区 */ -const lang = { +const LANGS = { 'en-US': enUS, 'zh-CN': zhCN, 'zh-HK': zhHK, @@ -22,7 +22,7 @@ const lang = { 'ja-JP': jaJP } -export default lang +export default LANGS /** * 获取当前语言字典 @@ -30,7 +30,7 @@ export default lang * @returns 不同语言对应字典 */ export function generateLocaleDict(langString) { - const supportedLocales = Object.keys(lang) + const supportedLocales = Object.keys(LANGS) let userLocale // 将语言字符串拆分为语言和地区代码,例如将 "zh-CN" 拆分为 "zh" 和 "CN" @@ -39,24 +39,24 @@ export function generateLocaleDict(langString) { // 优先匹配语言和地区都匹配的情况 const specificLocale = `${language}-${region}` if (supportedLocales.includes(specificLocale)) { - userLocale = lang[specificLocale] + userLocale = LANGS[specificLocale] } // 然后尝试匹配只有语言匹配的情况 if (!userLocale) { const languageOnlyLocales = supportedLocales.filter(locale => locale.startsWith(language)) if (languageOnlyLocales.length > 0) { - userLocale = lang[languageOnlyLocales[0]] + userLocale = LANGS[languageOnlyLocales[0]] } } // 如果还没匹配到,则返回最接近的语言包 if (!userLocale) { const fallbackLocale = supportedLocales.find(locale => locale.startsWith('en')) - userLocale = lang[fallbackLocale] + userLocale = LANGS[fallbackLocale] } - return mergeDeep({}, lang['en-US'], userLocale) + return mergeDeep({}, LANGS['en-US'], userLocale) } /** @@ -67,10 +67,10 @@ export function initLocale(lang, locale, changeLang, changeLocale) { if (isBrowser) { const queryLang = getQueryVariable('lang') || loadLangFromCookies() let currentLang = lang - if (queryLang !== lang) { + if (queryLang && queryLang !== 'undefined' && queryLang !== lang) { currentLang = queryLang } - console.log('初始化语言', currentLang) + changeLang(currentLang) saveLangToCookies(currentLang) diff --git a/lib/lang/en-US.js b/lib/lang/en-US.js index 51e38115..594ddfc0 100644 --- a/lib/lang/en-US.js +++ b/lib/lang/en-US.js @@ -1,5 +1,5 @@ export default { - LOCALE: 'en-US', + LOCALE: 'English', MENU: { WALK_AROUND: 'Walk Around', CATEGORY: 'Category', diff --git a/lib/lang/fr-FR.js b/lib/lang/fr-FR.js index 30089a70..2bc40057 100644 --- a/lib/lang/fr-FR.js +++ b/lib/lang/fr-FR.js @@ -1,5 +1,5 @@ export default { - LOCALE: 'fr-FR', + LOCALE: 'français', NAV: { INDEX: 'Accueil', RSS: 'RSS', diff --git a/lib/lang/ja-JP.js b/lib/lang/ja-JP.js index ab0e81f8..c27eef0b 100644 --- a/lib/lang/ja-JP.js +++ b/lib/lang/ja-JP.js @@ -1,5 +1,5 @@ export default { - LOCALE: 'ja-JP', + LOCALE: '日本語', NAV: { INDEX: 'ホーム', RSS: '購読', diff --git a/lib/lang/tr-TR.js b/lib/lang/tr-TR.js index 227b3fba..5be7a520 100644 --- a/lib/lang/tr-TR.js +++ b/lib/lang/tr-TR.js @@ -1,5 +1,5 @@ export default { - LOCALE: 'tr-TR', + LOCALE: 'Türkçe', NAV: { INDEX: 'Blog', RSS: 'RSS', diff --git a/lib/lang/zh-CN.js b/lib/lang/zh-CN.js index 91a4600a..e29af3d5 100644 --- a/lib/lang/zh-CN.js +++ b/lib/lang/zh-CN.js @@ -1,5 +1,5 @@ export default { - LOCALE: 'zh-CN', + LOCALE: '中文(简体)', MENU: { WALK_AROUND: '随便逛逛', CATEGORY: '博客分类', diff --git a/lib/lang/zh-HK.js b/lib/lang/zh-HK.js index 6a05df55..f434fe6e 100644 --- a/lib/lang/zh-HK.js +++ b/lib/lang/zh-HK.js @@ -1,4 +1,5 @@ export default { + LOCALE: '中文(繁体香港)', NAV: { INDEX: '網誌', RSS: '訂閱', diff --git a/lib/lang/zh-TW.js b/lib/lang/zh-TW.js index 673fe109..de746c08 100644 --- a/lib/lang/zh-TW.js +++ b/lib/lang/zh-TW.js @@ -1,5 +1,5 @@ export default { - LOCALE: 'zh-TW', + LOCALE: '中文(繁体台湾)', NAV: { INDEX: '部落格', RSS: '訂閱', diff --git a/pages/api/cache.js b/pages/api/cache.js new file mode 100644 index 00000000..97738651 --- /dev/null +++ b/pages/api/cache.js @@ -0,0 +1,15 @@ +import { cleanCache } from '@/lib/cache/local_file_cache' + +/** + * 清理缓存 + * @param {*} req + * @param {*} res + */ +export default async function handler(req, res) { + try { + await cleanCache() + res.status(200).json({ status: 'success', message: 'Clean cache successful!' }) + } catch (error) { + res.status(400).json({ status: 'error', message: 'Clean cache failed!', error }) + } +} diff --git a/themes/next/components/MenuList.js b/themes/next/components/MenuList.js index ec03a7bd..c9131929 100644 --- a/themes/next/components/MenuList.js +++ b/themes/next/components/MenuList.js @@ -40,12 +40,12 @@ export const MenuList = (props) => { data-aos-once="true" data-aos-anchor-placement="top-bottom" className='hidden md:block leading-8 text-gray-500 dark:text-gray-400 font-sans'> - {links.map(link => link && link.show && )} + {links.map((link, index) => link && link.show && )} {/* 移动端菜单 */} )