Skip to content

Commit 10d5641

Browse files
authored
Merge branch 'main' into fix/invisible-tag
2 parents ab1fbe1 + b9738d2 commit 10d5641

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+5041
-119
lines changed

components/CursorDot.js

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { useRouter } from 'next/router';
2+
import { useEffect } from 'react';
3+
/**
4+
* 白点鼠标跟随
5+
* @returns
6+
*/
7+
const CursorDot = () => {
8+
const router = useRouter();
9+
useEffect(() => {
10+
// 创建小白点元素
11+
const dot = document.createElement('div');
12+
dot.classList.add('cursor-dot');
13+
document.body.appendChild(dot);
14+
15+
// 鼠标坐标和缓动目标坐标
16+
let mouse = { x: -100, y: -100 }; // 初始位置在屏幕外
17+
let dotPos = { x: mouse.x, y: mouse.y };
18+
19+
// 监听鼠标移动
20+
const handleMouseMove = (e) => {
21+
mouse.x = e.clientX;
22+
mouse.y = e.clientY;
23+
};
24+
document.addEventListener('mousemove', handleMouseMove);
25+
26+
// 监听鼠标悬停在可点击对象上的事件
27+
const handleMouseEnter = () => {
28+
dot.classList.add('cursor-dot-hover'); // 添加放大样式
29+
};
30+
const handleMouseLeave = () => {
31+
dot.classList.remove('cursor-dot-hover'); // 移除放大样式
32+
};
33+
34+
35+
// 为所有可点击元素和包含 hover 或 group-hover 类名的元素添加事件监听
36+
setTimeout(() => {
37+
const clickableElements = document.querySelectorAll(
38+
'a, button, [role="button"], [onclick], [cursor="pointer"], [class*="hover"], [class*="group-hover"], [class*="cursor-pointer"]'
39+
);
40+
clickableElements.forEach((el) => {
41+
el.addEventListener('mouseenter', handleMouseEnter);
42+
el.addEventListener('mouseleave', handleMouseLeave);
43+
});
44+
}, 200); // 延时 200ms 执行
45+
46+
// 动画循环:延迟更新小白点位置
47+
const updateDotPosition = () => {
48+
const damping = 0.2; // 阻尼系数,值越小延迟越明显
49+
dotPos.x += (mouse.x - dotPos.x) * damping;
50+
dotPos.y += (mouse.y - dotPos.y) * damping;
51+
52+
// 更新DOM
53+
dot.style.left = `${dotPos.x}px`;
54+
dot.style.top = `${dotPos.y}px`;
55+
56+
requestAnimationFrame(updateDotPosition);
57+
};
58+
59+
// 启动动画
60+
updateDotPosition();
61+
62+
// 清理函数
63+
return () => {
64+
document.removeEventListener('mousemove', handleMouseMove);
65+
const clickableElements = document.querySelectorAll(
66+
'a, button, [role="button"], [onclick], [cursor="pointer"], [class*="hover"], [class*="group-hover"], [class*="cursor-pointer"]'
67+
);
68+
clickableElements.forEach((el) => {
69+
el.removeEventListener('mouseenter', handleMouseEnter);
70+
el.removeEventListener('mouseleave', handleMouseLeave);
71+
});
72+
document.body.removeChild(dot);
73+
};
74+
}, [router]);
75+
76+
return (
77+
<style jsx global>{`
78+
.cursor-dot {
79+
position: fixed;
80+
width: 12px;
81+
height: 12px;
82+
background: white;
83+
border-radius: 50%;
84+
pointer-events: none;
85+
transform: translate(-50%, -50%);
86+
z-index: 9999;
87+
transition: transform 100ms ease-out, width 200ms ease, height 200ms ease; /* 添加尺寸平滑过渡 */
88+
mix-blend-mode: difference; /* 可选:增强对比度 */
89+
}
90+
91+
.cursor-dot-hover {
92+
border: 1px solid rgba(167, 167, 167, 0.14); /* 鼠标悬停时的深灰色边框,厚度为1px */
93+
width: 60px; /* 放大 */
94+
height: 60px; /* 放大 */
95+
background: hsla(0, 0%, 100%, 0.04); /* 半透明背景 */
96+
-webkit-backdrop-filter: blur(5px); /* 毛玻璃效果 */
97+
backdrop-filter: blur(5px);
98+
}
99+
100+
.dark .cursor-dot-hover {
101+
border: 1px solid rgba(66, 66, 66, 0.66); /* 鼠标悬停时的深灰色边框,厚度为1px */
102+
}
103+
`}</style>
104+
);
105+
};
106+
107+
export default CursorDot;

components/ExternalPlugins.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ import { initGoogleAdsense } from './GoogleAdsense'
1010
import Head from 'next/head'
1111
import ExternalScript from './ExternalScript'
1212
import WebWhiz from './Webwhiz'
13+
import { useGlobal } from '@/lib/global'
1314
import IconFont from './IconFont'
1415

16+
1517
/**
1618
* 各种插件脚本
1719
* @param {*} props
@@ -20,6 +22,7 @@ import IconFont from './IconFont'
2022
const ExternalPlugin = props => {
2123
// 读取自Notion的配置
2224
const { NOTION_CONFIG } = props
25+
const {lang} = useGlobal()
2326
const DISABLE_PLUGIN = siteConfig('DISABLE_PLUGIN', null, NOTION_CONFIG)
2427
const THEME_SWITCH = siteConfig('THEME_SWITCH', null, NOTION_CONFIG)
2528
const DEBUG = siteConfig('DEBUG', null, NOTION_CONFIG)
@@ -168,8 +171,8 @@ const ExternalPlugin = props => {
168171
}
169172

170173
setTimeout(() => {
171-
// 将notion-id格式的url转成自定义slug
172-
convertInnerUrl(props?.allNavPages)
174+
// 映射url
175+
convertInnerUrl({ allPages:props?.allNavPages, lang:lang })
173176
}, 500)
174177
}, [router])
175178

components/IconFont.js

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,34 @@ export default function IconFont() {
1010
const router = useRouter()
1111

1212
useEffect(() => {
13-
loadExternalResource('/webfonts/iconfont.js').then(u => {
14-
console.log('iconfont loaded')
13+
loadExternalResource('/webfonts/iconfont.js')
14+
.then(u => {
15+
console.log('iconfont loaded:', u);
1516

16-
// 查找所有 <i> 标签且 class 包含 'icon-'
17-
const iElements = document.querySelectorAll('i[class*="icon-"]');
18-
iElements.forEach(element => {
19-
const className = Array.from(element.classList).find(cls => cls.startsWith('icon-'));
20-
if (className) {
21-
// 创建新的 <svg> 元素
22-
const svgElement = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
23-
svgElement.setAttribute('class', 'icon');
24-
svgElement.setAttribute('aria-hidden', 'true');
17+
// 查找所有 <i> 标签且 class 包含 'icon-'
18+
const iElements = document.querySelectorAll('i[class*="icon-"]');
19+
iElements.forEach(element => {
20+
const className = Array.from(element.classList).find(cls => cls.startsWith('icon-'));
21+
if (className) {
22+
// 创建新的 <svg> 元素
23+
const svgElement = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
24+
svgElement.setAttribute('class', 'icon');
25+
svgElement.setAttribute('aria-hidden', 'true');
2526

26-
const useElement = document.createElementNS('http://www.w3.org/2000/svg', 'use');
27-
useElement.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', `#${className}`);
28-
svgElement.appendChild(useElement);
27+
const useElement = document.createElementNS('http://www.w3.org/2000/svg', 'use');
28+
useElement.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', `#${className}`);
29+
svgElement.appendChild(useElement);
2930

30-
// 替换原来的 <i> 元素
31-
element.replaceWith(svgElement);
32-
console.log(`Replaced <i> with class "${className}" to <svg>`);
33-
}
31+
// 替换原来的 <i> 元素
32+
element.replaceWith(svgElement);
33+
// console.log(`Replaced <i> with class "${className}" to <svg>`);
34+
}
35+
});
36+
})
37+
.catch(error => {
38+
console.warn('Failed to load iconfont.js:', error);
3439
});
35-
})
36-
}, [router])
40+
}, [router]);
3741

3842
return <style jsx global>
3943
{`
@@ -43,12 +47,10 @@ export default function IconFont() {
4347
vertical-align: -0.15em;
4448
fill: currentColor;
4549
overflow: hidden;
46-
4750
}
4851
4952
svg.icon {
5053
display: inline;
5154
}
52-
5355
`}</style>
5456
}

components/LazyImage.js

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -129,20 +129,6 @@ export default function LazyImage({
129129
<link rel='preload' as='image' href={adjustImgSize(src, maxWidth)} />
130130
</Head>
131131
)}
132-
<style>
133-
{`
134-
.lazy-image-placeholder{
135-
background:
136-
linear-gradient(90deg,#0001 33%,#0005 50%,#0001 66%)
137-
#f2f2f2;
138-
background-size:300% 100%;
139-
animation: l1 1s infinite linear;
140-
}
141-
@keyframes l1 {
142-
0% {background-position: right}
143-
}
144-
`}
145-
</style>
146132
</>
147133
)
148134
}

components/Lenis.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { useEffect, useRef } from 'react'
2+
import { loadExternalResource } from '@/lib/utils'
3+
4+
/**
5+
* 滚动阻尼特效
6+
* 目前只用在proxio主题
7+
* @returns
8+
*/
9+
const Lenis = () => {
10+
const lenisRef = useRef(null) // 用于存储 Lenis 实例
11+
12+
useEffect(() => {
13+
// 异步加载
14+
async function loadLenis() {
15+
loadExternalResource('/js/lenis.js', 'js').then(() => {
16+
// console.log('Lenis', window.Lenis)
17+
if (!window.Lenis) {
18+
console.error('Lenis not loaded')
19+
return
20+
}
21+
const Lenis = window.Lenis
22+
23+
// 创建 Lenis 实例
24+
const lenis = new Lenis({
25+
duration: 1.2,
26+
easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)), // https://www.desmos.com/calculator/brs54l4xou
27+
direction: 'vertical', // vertical, horizontal
28+
gestureDirection: 'vertical', // vertical, horizontal, both
29+
smooth: true,
30+
mouseMultiplier: 1,
31+
smoothTouch: false,
32+
touchMultiplier: 2,
33+
infinite: false,
34+
})
35+
36+
// 存储实例到 ref
37+
lenisRef.current = lenis
38+
39+
// 监听滚动事件
40+
// lenis.on('scroll', ({ scroll, limit, velocity, direction, progress }) => {
41+
// // console.log({ scroll, limit, velocity, direction, progress })
42+
// })
43+
44+
// 动画帧循环
45+
function raf(time) {
46+
lenis.raf(time)
47+
requestAnimationFrame(raf)
48+
}
49+
50+
requestAnimationFrame(raf)
51+
})
52+
}
53+
54+
loadLenis()
55+
56+
return () => {
57+
// 在组件卸载时清理资源
58+
if (lenisRef.current) {
59+
lenisRef.current.destroy() // 销毁 Lenis 实例
60+
lenisRef.current = null
61+
// console.log('Lenis instance destroyed')
62+
}
63+
}
64+
}, [])
65+
66+
return <></>
67+
}
68+
69+
export default Lenis

lib/cache/cache_manager.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export async function getOrSetDataWithCustomCache(
4040
) {
4141
const dataFromCache = await getDataFromCache(key)
4242
if (dataFromCache) {
43-
console.log('[缓存-->>API]:', key)
43+
// console.log('[缓存-->>API]:', key) // 避免过多的缓存日志输出
4444
return dataFromCache
4545
}
4646
const data = await getDataFunction(...getDataArgs)

lib/global.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,7 @@ import {
88
import { useUser } from '@clerk/nextjs'
99
import { useRouter } from 'next/router'
1010
import { createContext, useContext, useEffect, useState } from 'react'
11-
import {
12-
generateLocaleDict,
13-
initLocale,
14-
redirectUserLang,
15-
saveLangToLocalStorage
16-
} from './lang'
11+
import { generateLocaleDict, initLocale, redirectUserLang } from './lang'
1712

1813
/**
1914
* 全局上下文
@@ -81,7 +76,6 @@ export function GlobalContextProvider(props) {
8176

8277
function changeLang(lang) {
8378
if (lang) {
84-
saveLangToLocalStorage(lang)
8579
updateLang(lang)
8680
updateLocale(generateLocaleDict(lang))
8781
}

lib/lang.js

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import zhCN from './lang/zh-CN'
88
import zhHK from './lang/zh-HK'
99
import zhTW from './lang/zh-TW'
1010
import { extractLangPrefix } from './utils/pageId'
11+
import { useRouter } from 'next/router'
1112

1213
/**
1314
* 在这里配置所有支持的语言
@@ -70,15 +71,9 @@ export function generateLocaleDict(langString) {
7071
*/
7172
export function initLocale(locale, changeLang, updateLocale) {
7273
if (isBrowser) {
73-
// 根据router中的locale对象判断当前语言:表现为前缀中包含 zh、en 等。
74-
let pathLocaleLang = null
75-
if (locale === 'en' || locale === 'zh') {
76-
pathLocaleLang = locale === 'en' ? 'en-US' : 'zh-CN'
77-
}
7874
// 如果有query参数切换语言则优先
7975
const queryLang =
80-
getQueryVariable('locale') || getQueryVariable('lang') || pathLocaleLang
81-
76+
getQueryVariable('locale') || getQueryVariable('lang') || locale
8277
if (queryLang) {
8378
const match = queryLang.match(/[a-zA-Z]{2}(?:-[a-zA-Z]{2})?/)
8479
if (match) {
@@ -91,22 +86,6 @@ export function initLocale(locale, changeLang, updateLocale) {
9186
}
9287
}
9388

94-
/**
95-
* 读取语言
96-
* @returns {*}
97-
*/
98-
export const loadLangFromLocalStorage = () => {
99-
return localStorage.getItem('lang')
100-
}
101-
102-
/**
103-
* 保存语言
104-
* @param newTheme
105-
*/
106-
export const saveLangToLocalStorage = lang => {
107-
localStorage.setItem('lang', lang)
108-
}
109-
11089
/**
11190
* 检测用户的预研偏好,跳转至对应的多语言网站
11291
* @param {*} lang
@@ -142,4 +121,4 @@ export const redirectUserLang = (lang, pageId) => {
142121
}
143122
}
144123
}
145-
}
124+
}

0 commit comments

Comments
 (0)